xref: /optee_os/core/tee/tee_svc_storage.c (revision 9bdc34f232fcac3c42210f9ae8fa0c54fc44ddb2)
1 /*
2  * Copyright (c) 2014, STMicroelectronics International N.V.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <tee/tee_svc_storage.h>
29 
30 #include <kernel/tee_ta_manager.h>
31 #include <tee_api_defines.h>
32 #include <kernel/tee_misc.h>
33 #include <tee/tee_fs.h>
34 #include <tee/tee_fs_defs.h>
35 #include <tee/tee_obj.h>
36 #include <tee/tee_svc.h>
37 #include <mm/tee_mmu.h>
38 #include <tee/tee_pobj.h>
39 #include <trace.h>
40 
41 /* SSF (Secure Storage File version 00 */
42 #define TEE_SVC_STORAGE_MAGIC 0x53534600;
43 
44 /* Header of GP formated secure storage files */
45 struct tee_svc_storage_head {
46 	uint32_t magic;
47 	uint32_t head_size;
48 	uint32_t meta_size;
49 	uint32_t ds_size;
50 };
51 
52 struct tee_storage_enum {
53 	TAILQ_ENTRY(tee_storage_enum) link;
54 	tee_fs_dir *dir;
55 };
56 
57 static TEE_Result tee_svc_storage_get_enum(struct tee_ta_ctx *ctx,
58 					   uint32_t enum_id,
59 					   struct tee_storage_enum **e_out)
60 {
61 	struct tee_storage_enum *e;
62 
63 	TAILQ_FOREACH(e, &ctx->storage_enums, link) {
64 		if (enum_id == (vaddr_t)e) {
65 			*e_out = e;
66 			return TEE_SUCCESS;
67 		}
68 	}
69 	return TEE_ERROR_BAD_PARAMETERS;
70 }
71 
72 static TEE_Result tee_svc_close_enum(struct tee_ta_ctx *ctx,
73 				     struct tee_storage_enum *e)
74 {
75 	int ret;
76 
77 	if (e == NULL || ctx == NULL)
78 		return TEE_ERROR_BAD_PARAMETERS;
79 
80 	TAILQ_REMOVE(&ctx->storage_enums, e, link);
81 
82 	ret = tee_file_ops.closedir(e->dir);
83 	e->dir = NULL;
84 
85 	free(e);
86 
87 	if (ret != 0)
88 		return TEE_ERROR_ITEM_NOT_FOUND;
89 
90 	return TEE_SUCCESS;
91 }
92 
93 char *tee_svc_storage_create_filename(struct tee_ta_session *sess,
94 				      void *object_id,
95 				      uint32_t object_id_len,
96 				      bool transient)
97 {
98 	uint8_t *file = NULL;
99 	/* +1 for the '/' (default) */
100 	uint32_t hslen =
101 	    TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID) + object_id_len) + 1;
102 	uint32_t pos;
103 
104 	/* +1 for the '.' (temporary persistent object) */
105 	if (transient)
106 		hslen++;
107 
108 	file = malloc(hslen);
109 
110 	if (file == NULL)
111 		return NULL;
112 
113 	pos = tee_b2hs((uint8_t *)&sess->ctx->uuid, file,
114 		       sizeof(TEE_UUID), hslen);
115 	file[pos] = '/';
116 	pos++;
117 
118 	/* temporary persistent object : uuid/.object_id_len_of(object_id) */
119 	if (transient) {
120 		file[pos] = '.';
121 		pos++;
122 	}
123 
124 	tee_b2hs(object_id, file + pos, object_id_len, hslen - pos);
125 
126 	return (char *)file;
127 }
128 
129 char *tee_svc_storage_create_dirname(struct tee_ta_session *sess)
130 {
131 	uint8_t *dir = NULL;
132 	uint32_t hslen = TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID));
133 
134 	dir = malloc(hslen);
135 
136 	if (dir == NULL)
137 		return NULL;
138 
139 	tee_b2hs((uint8_t *)&sess->ctx->uuid, dir, sizeof(TEE_UUID),
140 		 hslen);
141 
142 	return (char *)dir;
143 }
144 
145 static TEE_Result tee_svc_storage_remove_corrupt_obj(
146 					struct tee_ta_session *sess,
147 					struct tee_obj *o)
148 {
149 	TEE_Result res;
150 	char *file = NULL;
151 	char *dir = NULL;
152 
153 	file = tee_svc_storage_create_filename(sess,
154 					       o->pobj->obj_id,
155 					       o->pobj->obj_id_len,
156 					       false);
157 	if (file == NULL) {
158 		res = TEE_ERROR_OUT_OF_MEMORY;
159 		goto exit;
160 	}
161 
162 	tee_obj_close(sess->ctx, o);
163 	tee_file_ops.unlink(file);
164 	free(file);
165 	dir = tee_svc_storage_create_dirname(sess);
166 	if (dir != NULL) {
167 		tee_file_ops.rmdir(dir);
168 		free(dir);
169 	}
170 
171 	res = TEE_SUCCESS;
172 
173 exit:
174 	return res;
175 }
176 
177 static uint32_t tee_svc_storage_conv_oflags(uint32_t flags)
178 {
179 	uint32_t out = 0;
180 
181 	if (flags & (TEE_DATA_FLAG_ACCESS_READ | TEE_DATA_FLAG_SHARE_READ)) {
182 		if (flags & (TEE_DATA_FLAG_ACCESS_WRITE |
183 			     TEE_DATA_FLAG_ACCESS_WRITE_META |
184 			     TEE_DATA_FLAG_SHARE_WRITE))
185 			out |= TEE_FS_O_RDWR;
186 		else
187 			out |= TEE_FS_O_RDONLY;
188 	} else {
189 		if (flags & (TEE_DATA_FLAG_ACCESS_WRITE |
190 			     TEE_DATA_FLAG_ACCESS_WRITE_META |
191 			     TEE_DATA_FLAG_SHARE_WRITE))
192 			out |= TEE_FS_O_WRONLY;
193 	}
194 
195 	return out;
196 }
197 
198 static int tee_svc_storage_conv_whence(TEE_Whence whence)
199 {
200 	switch (whence) {
201 	case TEE_DATA_SEEK_SET:
202 		return TEE_FS_SEEK_SET;
203 	case TEE_DATA_SEEK_CUR:
204 		return TEE_FS_SEEK_CUR;
205 	case TEE_DATA_SEEK_END:
206 		return TEE_FS_SEEK_END;
207 	default:
208 		return -1;
209 	}
210 }
211 
212 static TEE_Result tee_svc_storage_create_file(struct tee_ta_session *sess,
213 					      char *file, int *fd)
214 {
215 	TEE_Result res = TEE_SUCCESS;
216 	char *dir = NULL;
217 	int tmp;
218 	int err;
219 	uint32_t cflags = TEE_FS_O_WRONLY |
220 			TEE_FS_O_CREATE | TEE_FS_O_TRUNC;
221 
222 	dir = tee_svc_storage_create_dirname(sess);
223 	if (dir == NULL) {
224 		res = TEE_ERROR_OUT_OF_MEMORY;
225 		goto exit;
226 	}
227 
228 	/* try and make directory */
229 	err = tee_file_ops.access(dir, TEE_FS_F_OK);
230 	if (err) {
231 		/* directory does not exists */
232 		tmp = tee_file_ops.mkdir(dir, TEE_FS_S_IRUSR | TEE_FS_S_IWUSR);
233 
234 		if (tmp < 0) {
235 			/* error codes needs better granularity */
236 			res = TEE_ERROR_GENERIC;
237 			goto exit;
238 		}
239 	}
240 
241 	/* try and open again */
242 	*fd = tee_file_ops.open(&res, file, cflags);
243 
244 exit:
245 	free(dir);
246 
247 	return res;
248 }
249 
250 static TEE_Result tee_svc_storage_read_head(struct tee_ta_session *sess,
251 				     struct tee_obj *o)
252 {
253 	TEE_Result res = TEE_SUCCESS;
254 	int fd = -1;
255 	int err;
256 	struct tee_svc_storage_head head;
257 	char *file = NULL;
258 
259 	if (o == NULL || o->pobj == NULL)
260 		return TEE_ERROR_BAD_PARAMETERS;
261 
262 	file = tee_svc_storage_create_filename(sess,
263 					       o->pobj->obj_id,
264 					       o->pobj->obj_id_len,
265 					       false);
266 	if (file == NULL) {
267 		res = TEE_ERROR_OUT_OF_MEMORY;
268 		goto exit;
269 	}
270 
271 	fd = tee_file_ops.open(&res, file, TEE_FS_O_RDONLY);
272 	free(file);
273 	if (fd < 0)
274 		goto exit;
275 
276 	/* read head */
277 	err = tee_file_ops.read(&res, fd, &head,
278 				sizeof(struct tee_svc_storage_head));
279 	if (err < 0) {
280 		if (res == TEE_ERROR_CORRUPT_OBJECT)
281 			EMSG("Head corrupt\n");
282 		goto exit;
283 	}
284 
285 	if (err != sizeof(struct tee_svc_storage_head)) {
286 		res = TEE_ERROR_BAD_FORMAT;
287 		goto exit;
288 	}
289 
290 	o->data_size = head.meta_size;
291 	o->info.dataSize = head.ds_size;
292 
293 	o->data = malloc(o->data_size);
294 	if (o->data == NULL) {
295 		res = TEE_ERROR_OUT_OF_MEMORY;
296 		goto exit;
297 	}
298 
299 	/* read meta */
300 	err = tee_file_ops.read(&res, fd, o->data, o->data_size);
301 	if (err != (int)o->data_size) {
302 		free(o->data);
303 		o->data = NULL;
304 	}
305 
306 exit:
307 	if (fd >= 0)
308 		tee_file_ops.close(fd);
309 
310 	return res;
311 }
312 
313 static TEE_Result tee_svc_storage_init_file(struct tee_ta_session *sess,
314 					    struct tee_obj *o,
315 					    struct tee_obj *attr_o, void *data,
316 					    uint32_t len)
317 {
318 	TEE_Result res = TEE_SUCCESS;
319 	int fd = -1;
320 	int err = -1;
321 	struct tee_svc_storage_head head;
322 	char *tmpfile = NULL;
323 
324 	if (o == NULL || o->pobj == NULL)
325 		return TEE_ERROR_BAD_PARAMETERS;
326 
327 	free(o->data);
328 
329 	/* create temporary persistent object filename */
330 	tmpfile = tee_svc_storage_create_filename(sess,
331 						   o->pobj->obj_id,
332 						   o->pobj->obj_id_len,
333 						   true);
334 
335 	if (tmpfile == NULL) {
336 		res = TEE_ERROR_OUT_OF_MEMORY;
337 		goto exit;
338 	}
339 
340 	res = tee_svc_storage_create_file(sess, tmpfile, &fd);
341 	if (res != TEE_SUCCESS)
342 		goto exit;
343 
344 	if (attr_o && attr_o->data_size) {
345 		o->data_size = attr_o->data_size;
346 		o->data = malloc(attr_o->data_size);
347 		if (o->data == NULL) {
348 			res = TEE_ERROR_OUT_OF_MEMORY;
349 			goto exit;
350 		}
351 
352 		memcpy(o->data, attr_o->data, attr_o->data_size);
353 		o->have_attrs = attr_o->have_attrs;
354 		o->info.objectUsage = attr_o->info.objectUsage;
355 		o->info.objectType = attr_o->info.objectType;
356 	} else {
357 		o->data = NULL;
358 		o->data_size = 0;
359 		o->have_attrs = 0;
360 		o->info.objectUsage = TEE_USAGE_DEFAULT;
361 		o->info.objectType = TEE_TYPE_DATA;
362 	}
363 
364 	/* write head */
365 	head.magic = TEE_SVC_STORAGE_MAGIC;
366 	head.head_size = sizeof(struct tee_svc_storage_head);
367 	head.meta_size = o->data_size;
368 	head.ds_size = len;
369 
370 	/* write head */
371 	err = tee_file_ops.write(&res, fd, &head,
372 			sizeof(struct tee_svc_storage_head));
373 	/* error codes needs better granularity */
374 	if (err != sizeof(struct tee_svc_storage_head))
375 		goto exit;
376 
377 	/* write meta */
378 	err = tee_file_ops.write(&res, fd, o->data, o->data_size);
379 	if (err != (int)o->data_size)
380 		goto exit;
381 
382 	/* write init data */
383 	o->info.dataSize = len;
384 
385 	/* write data to fs if needed */
386 	if (data && len) {
387 		err = tee_file_ops.write(&res, fd, data, len);
388 		if (err != (int)len)
389 			goto exit;
390 	}
391 
392 exit:
393 	free(tmpfile);
394 	tmpfile = NULL;
395 	if (fd != -1)
396 		tee_file_ops.close(fd);
397 
398 	return res;
399 }
400 
401 TEE_Result syscall_storage_obj_open(uint32_t storage_id, void *object_id,
402 				    uint32_t object_id_len, uint32_t flags,
403 				    uint32_t *obj)
404 {
405 	TEE_Result res;
406 	struct tee_ta_session *sess;
407 	struct tee_obj *o;
408 	char *file = NULL;
409 	int fs_flags;
410 	int fd = -1;
411 	tee_fs_off_t off;
412 	tee_fs_off_t e_off;
413 	struct tee_pobj *po = NULL;
414 	int err = -1;
415 
416 	if (storage_id != TEE_STORAGE_PRIVATE) {
417 		res = TEE_ERROR_ITEM_NOT_FOUND;
418 		goto exit;
419 	}
420 
421 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN) {
422 		res = TEE_ERROR_BAD_PARAMETERS;
423 		goto exit;
424 	}
425 
426 	res = tee_ta_get_current_session(&sess);
427 	if (res != TEE_SUCCESS)
428 		goto err;
429 
430 	res = tee_mmu_check_access_rights(sess->ctx,
431 					  TEE_MEMORY_ACCESS_READ |
432 					  TEE_MEMORY_ACCESS_ANY_OWNER,
433 					  (tee_uaddr_t) object_id,
434 					  object_id_len);
435 	if (res != TEE_SUCCESS)
436 		goto err;
437 
438 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
439 			   object_id_len, flags, &po);
440 	if (res != TEE_SUCCESS)
441 		goto err;
442 
443 	fs_flags = tee_svc_storage_conv_oflags(flags);
444 
445 	o = calloc(1, sizeof(*o));
446 	if (o == NULL) {
447 		res = TEE_ERROR_OUT_OF_MEMORY;
448 		goto err;
449 	}
450 
451 	o->info.handleFlags =
452 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
453 	o->info.objectUsage = TEE_USAGE_DEFAULT;
454 	o->flags = flags;
455 	o->pobj = po;
456 
457 	res = tee_svc_storage_read_head(sess, o);
458 	if (res != TEE_SUCCESS) {
459 		tee_obj_add(sess->ctx, o);
460 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
461 			EMSG("Object corrupt\n");
462 			res = tee_svc_storage_remove_corrupt_obj(sess, o);
463 			if (res != TEE_SUCCESS)
464 				goto exit;
465 			res = TEE_ERROR_CORRUPT_OBJECT;
466 			goto exit;
467 		}
468 		goto oclose;
469 	}
470 
471 	file = tee_svc_storage_create_filename(sess, object_id,
472 					       object_id_len, false);
473 	if (file == NULL) {
474 		res = TEE_ERROR_OUT_OF_MEMORY;
475 		goto err;
476 	}
477 
478 	err = tee_file_ops.access(file, TEE_FS_F_OK);
479 	if (err) {
480 		/* file not found */
481 		res = TEE_ERROR_STORAGE_NOT_AVAILABLE;
482 		goto err;
483 	}
484 
485 	fd = tee_file_ops.open(&res, file, fs_flags);
486 	if (fd < 0) {
487 		goto err;
488 	}
489 	o->fd = fd;
490 
491 	tee_obj_add(sess->ctx, o);
492 
493 	res = tee_svc_copy_kaddr_to_user32(sess, obj, o);
494 	if (res != TEE_SUCCESS)
495 		goto oclose;
496 
497 	e_off = sizeof(struct tee_svc_storage_head) + o->data_size;
498 	off = tee_file_ops.lseek(&res, fd, e_off, TEE_FS_SEEK_SET);
499 	if (off != e_off) {
500 		res = TEE_ERROR_NO_DATA;
501 		goto oclose;
502 	}
503 
504 	goto exit;
505 
506 oclose:
507 	tee_obj_close(sess->ctx, o);
508 
509 err:
510 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
511 		res = TEE_ERROR_CORRUPT_OBJECT;
512 	if (res == TEE_ERROR_CORRUPT_OBJECT)
513 		tee_file_ops.unlink(file);
514 	if (fd >= 0)
515 		tee_file_ops.close(fd);
516 	if (po)
517 		tee_pobj_release(po);
518 
519 exit:
520 	free(file);
521 	file = NULL;
522 	return res;
523 }
524 
525 TEE_Result syscall_storage_obj_create(uint32_t storage_id, void *object_id,
526 				      uint32_t object_id_len, uint32_t flags,
527 				      uint32_t attr, void *data, uint32_t len,
528 				      uint32_t *obj)
529 {
530 	TEE_Result res;
531 	struct tee_ta_session *sess;
532 	struct tee_obj *o = NULL;
533 	struct tee_obj *attr_o = NULL;
534 	char *file = NULL;
535 	int fd = -1;
536 	int fs_flags;
537 	tee_fs_off_t off;
538 	tee_fs_off_t e_off;
539 	struct tee_pobj *po = NULL;
540 	char *tmpfile = NULL;
541 	int err = -1;
542 
543 	if (storage_id != TEE_STORAGE_PRIVATE)
544 		return TEE_ERROR_ITEM_NOT_FOUND;
545 
546 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
547 		return TEE_ERROR_BAD_PARAMETERS;
548 
549 	res = tee_ta_get_current_session(&sess);
550 	if (res != TEE_SUCCESS)
551 		return res;
552 
553 	res = tee_mmu_check_access_rights(sess->ctx,
554 					  TEE_MEMORY_ACCESS_READ |
555 					  TEE_MEMORY_ACCESS_ANY_OWNER,
556 					  (tee_uaddr_t) object_id,
557 					  object_id_len);
558 	if (res != TEE_SUCCESS)
559 		goto err;
560 
561 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
562 			   object_id_len, flags, &po);
563 	if (res != TEE_SUCCESS)
564 		goto err;
565 
566 	/* check rights of the provided buffer */
567 	if (data && len) {
568 		res = tee_mmu_check_access_rights(sess->ctx,
569 						  TEE_MEMORY_ACCESS_READ |
570 						  TEE_MEMORY_ACCESS_ANY_OWNER,
571 						  (tee_uaddr_t) data, len);
572 
573 		if (res != TEE_SUCCESS)
574 			goto err;
575 	}
576 
577 	o = calloc(1, sizeof(*o));
578 	if (o == NULL) {
579 		res = TEE_ERROR_OUT_OF_MEMORY;
580 		goto err;
581 	}
582 
583 	o->info.handleFlags =
584 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
585 	o->flags = flags;
586 	o->pobj = po;
587 
588 	if (attr != TEE_HANDLE_NULL) {
589 		/* init attributes  if provided */
590 		res = tee_obj_get(sess->ctx, attr, &attr_o);
591 		if (res != TEE_SUCCESS)
592 			goto err;
593 	}
594 
595 	res = tee_svc_storage_init_file(sess, o, attr_o, data, len);
596 	if (res != TEE_SUCCESS)
597 		goto err;
598 
599 	/* create persistent object filename */
600 	file = tee_svc_storage_create_filename(sess, object_id,
601 					       object_id_len, false);
602 	if (file == NULL) {
603 		res = TEE_ERROR_OUT_OF_MEMORY;
604 		goto err;
605 	}
606 
607 	err = tee_file_ops.access(file, TEE_FS_F_OK);
608 	if (!err) {
609 		/* file exists */
610 		if (!(flags & TEE_DATA_FLAG_OVERWRITE)) {
611 			res = TEE_ERROR_ACCESS_CONFLICT;
612 			goto err;
613 		}
614 	}
615 
616 	/* create temporary persistent object filename */
617 	tmpfile = tee_svc_storage_create_filename(sess, object_id,
618 						  object_id_len,
619 						  true);
620 	if (tmpfile == NULL) {
621 		res = TEE_ERROR_OUT_OF_MEMORY;
622 		goto err;
623 	}
624 
625 	/* rename temporary persistent object filename */
626 	err = tee_file_ops.rename(tmpfile, file);
627 	if (err) {
628 		/* error codes needs better granularity */
629 		res = TEE_ERROR_GENERIC;
630 		goto rmfile;
631 	}
632 
633 	fs_flags = tee_svc_storage_conv_oflags(flags);
634 
635 	fd = tee_file_ops.open(&res, file, fs_flags);
636 	if (fd < 0) {
637 		goto err;
638 	}
639 	o->fd = fd;
640 
641 	tee_obj_add(sess->ctx, o);
642 
643 	res = tee_svc_copy_kaddr_to_user32(sess, obj, o);
644 	if (res != TEE_SUCCESS)
645 		goto oclose;
646 
647 	e_off = sizeof(struct tee_svc_storage_head) + o->data_size;
648 	off = tee_file_ops.lseek(&res, fd, e_off, TEE_FS_SEEK_SET);
649 	if (off != e_off) {
650 		res = TEE_ERROR_NO_DATA;
651 		goto oclose;
652 	}
653 
654 	goto exit;
655 
656 oclose:
657 	tee_obj_close(sess->ctx, o);
658 	goto exit;
659 
660 rmfile:
661 	tee_file_ops.unlink(tmpfile);
662 
663 err:
664 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
665 		res = TEE_ERROR_CORRUPT_OBJECT;
666 	if (res == TEE_ERROR_CORRUPT_OBJECT)
667 		tee_file_ops.unlink(file);
668 	if (fd >= 0)
669 		tee_file_ops.close(fd);
670 	if (po)
671 		tee_pobj_release(po);
672 	if (o)
673 		free(o);
674 
675 exit:
676 	free(file);
677 	file = NULL;
678 	free(tmpfile);
679 	tmpfile = NULL;
680 
681 	return res;
682 }
683 
684 TEE_Result syscall_storage_obj_del(uint32_t obj)
685 {
686 	TEE_Result res;
687 	struct tee_ta_session *sess;
688 	struct tee_obj *o;
689 	int err;
690 	char *file;
691 	char *dir;
692 
693 	res = tee_ta_get_current_session(&sess);
694 	if (res != TEE_SUCCESS)
695 		return res;
696 
697 	res = tee_obj_get(sess->ctx, obj, &o);
698 	if (res != TEE_SUCCESS)
699 		return res;
700 
701 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META))
702 		return TEE_ERROR_ACCESS_CONFLICT;
703 
704 	if (o->pobj == NULL || o->pobj->obj_id == NULL)
705 		return TEE_ERROR_BAD_STATE;
706 
707 	file = tee_svc_storage_create_filename(sess, o->pobj->obj_id,
708 						o->pobj->obj_id_len, false);
709 	if (file == NULL)
710 		return TEE_ERROR_OUT_OF_MEMORY;
711 
712 	tee_obj_close(sess->ctx, o);
713 
714 	err = tee_file_ops.access(file, TEE_FS_F_OK);
715 	if (err)
716 		/* file not found */
717 		return TEE_ERROR_STORAGE_NOT_AVAILABLE;
718 
719 	err = tee_file_ops.unlink(file);
720 	free(file);
721 	if (err)
722 		/* error codes needs better granularity */
723 		return TEE_ERROR_GENERIC;
724 
725 	/* try and remove dir */
726 	dir = tee_svc_storage_create_dirname(sess);
727 	if (dir == NULL)
728 		return TEE_ERROR_OUT_OF_MEMORY;
729 	/* ignore result */
730 	tee_file_ops.rmdir(dir);
731 	free(dir);
732 
733 	return TEE_SUCCESS;
734 }
735 
736 TEE_Result syscall_storage_obj_rename(uint32_t obj, void *object_id,
737 				      uint32_t object_id_len)
738 {
739 	TEE_Result res;
740 	struct tee_ta_session *sess;
741 	struct tee_obj *o;
742 	struct tee_pobj *po = NULL;
743 	char *new_file = NULL;
744 	char *old_file = NULL;
745 	int err = -1;
746 
747 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
748 		return TEE_ERROR_BAD_PARAMETERS;
749 
750 	res = tee_ta_get_current_session(&sess);
751 	if (res != TEE_SUCCESS)
752 		return res;
753 
754 	res = tee_obj_get(sess->ctx, obj, &o);
755 	if (res != TEE_SUCCESS)
756 		return res;
757 
758 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
759 		res = TEE_ERROR_BAD_STATE;
760 		goto exit;
761 	}
762 
763 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META)) {
764 		res = TEE_ERROR_BAD_STATE;
765 		goto exit;
766 	}
767 
768 	if (o->pobj == NULL || o->pobj->obj_id == NULL) {
769 		res = TEE_ERROR_BAD_STATE;
770 		goto exit;
771 	}
772 
773 	res = tee_mmu_check_access_rights(sess->ctx,
774 					TEE_MEMORY_ACCESS_READ |
775 					TEE_MEMORY_ACCESS_ANY_OWNER,
776 					(tee_uaddr_t) object_id, object_id_len);
777 	if (res != TEE_SUCCESS)
778 		goto exit;
779 
780 	res = tee_obj_verify(sess, o);
781 	if (res != TEE_SUCCESS)
782 		goto exit;
783 
784 	/* get new ds name */
785 	new_file = tee_svc_storage_create_filename(sess, object_id,
786 						   object_id_len, false);
787 	if (new_file == NULL) {
788 		res = TEE_ERROR_OUT_OF_MEMORY;
789 		goto exit;
790 	}
791 
792 	old_file = tee_svc_storage_create_filename(sess, o->pobj->obj_id,
793 						   o->pobj->obj_id_len, false);
794 	if (old_file == NULL) {
795 		res = TEE_ERROR_OUT_OF_MEMORY;
796 		goto exit;
797 	}
798 
799 	/* reserve dest name */
800 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
801 			   object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META, &po);
802 	if (res != TEE_SUCCESS)
803 		goto exit;
804 
805 	err = tee_file_ops.access(new_file, TEE_FS_F_OK);
806 	if (err == 0) {
807 		/* file exists */
808 		res = TEE_ERROR_ACCESS_CONFLICT;
809 		goto exit;
810 	}
811 
812 	/* move */
813 	err = tee_file_ops.rename(old_file, new_file);
814 	if (err) {
815 		/* error codes needs better granularity */
816 		res = TEE_ERROR_GENERIC;
817 		goto exit;
818 	}
819 
820 	res = tee_pobj_rename(o->pobj, object_id, object_id_len);
821 
822 exit:
823 	tee_pobj_release(po);
824 
825 	free(new_file);
826 	free(old_file);
827 
828 	return res;
829 }
830 
831 TEE_Result syscall_storage_alloc_enum(uint32_t *obj_enum)
832 {
833 	struct tee_storage_enum *e;
834 	struct tee_ta_session *sess;
835 	TEE_Result res;
836 
837 	if (obj_enum == NULL)
838 		return TEE_ERROR_BAD_PARAMETERS;
839 
840 	res = tee_ta_get_current_session(&sess);
841 	if (res != TEE_SUCCESS)
842 		return res;
843 
844 	e = malloc(sizeof(struct tee_storage_enum));
845 
846 	if (e == NULL)
847 		return TEE_ERROR_OUT_OF_MEMORY;
848 
849 	e->dir = NULL;
850 	TAILQ_INSERT_TAIL(&sess->ctx->storage_enums, e, link);
851 
852 	return tee_svc_copy_kaddr_to_user32(sess, obj_enum, e);
853 }
854 
855 TEE_Result syscall_storage_free_enum(uint32_t obj_enum)
856 {
857 	struct tee_storage_enum *e;
858 	TEE_Result res;
859 	struct tee_ta_session *sess;
860 
861 	if (obj_enum == TEE_HANDLE_NULL)
862 		return TEE_SUCCESS;
863 
864 	res = tee_ta_get_current_session(&sess);
865 	if (res != TEE_SUCCESS)
866 		return res;
867 
868 	res = tee_svc_storage_get_enum(sess->ctx, obj_enum, &e);
869 	if (res != TEE_SUCCESS)
870 		return res;
871 
872 	return tee_svc_close_enum(sess->ctx, e);
873 }
874 
875 TEE_Result syscall_storage_reset_enum(uint32_t obj_enum)
876 {
877 	struct tee_storage_enum *e;
878 	int res;
879 	struct tee_ta_session *sess;
880 
881 	res = tee_ta_get_current_session(&sess);
882 	if (res != TEE_SUCCESS)
883 		return res;
884 
885 	if (obj_enum == TEE_HANDLE_NULL)
886 		return TEE_SUCCESS;
887 
888 	res = tee_svc_storage_get_enum(sess->ctx, obj_enum, &e);
889 	if (res != TEE_SUCCESS)
890 		return res;
891 
892 	res = tee_file_ops.closedir(e->dir);
893 	e->dir = NULL;
894 	if (res != 0)
895 		return TEE_ERROR_GENERIC;
896 
897 	return TEE_SUCCESS;
898 }
899 
900 static TEE_Result tee_svc_storage_set_enum(char *d_name, struct tee_obj *o)
901 {
902 	TEE_Result res;
903 	uint32_t blen;
904 	uint32_t hslen;
905 
906 	o->info.handleFlags =
907 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
908 	o->info.objectUsage = TEE_USAGE_DEFAULT;
909 
910 	hslen = strlen(d_name);
911 	blen = TEE_HS2B_BBUF_SIZE(hslen);
912 	o->pobj->obj_id = malloc(blen);
913 	if (!o->pobj->obj_id) {
914 		res = TEE_ERROR_OUT_OF_MEMORY;
915 		goto exit;
916 	}
917 	tee_hs2b((uint8_t *)d_name, o->pobj->obj_id, hslen, blen);
918 	o->pobj->obj_id_len = blen;
919 
920 	res = TEE_SUCCESS;
921 
922 exit:
923 	return res;
924 
925 }
926 
927 TEE_Result syscall_storage_start_enum(uint32_t obj_enum, uint32_t storage_id)
928 {
929 	struct tee_storage_enum *e;
930 	char *dir;
931 	TEE_Result res;
932 	struct tee_ta_session *sess;
933 	struct tee_fs_dirent *d = NULL;
934 	struct tee_obj *o = NULL;
935 
936 	if (obj_enum == TEE_HANDLE_NULL)
937 		return TEE_ERROR_BAD_PARAMETERS;
938 
939 	res = tee_ta_get_current_session(&sess);
940 	if (res != TEE_SUCCESS)
941 		return res;
942 
943 	res = tee_svc_storage_get_enum(sess->ctx, obj_enum, &e);
944 	if (res != TEE_SUCCESS)
945 		return res;
946 
947 	if (storage_id != TEE_STORAGE_PRIVATE)
948 		return TEE_ERROR_ITEM_NOT_FOUND;
949 
950 	dir = tee_svc_storage_create_dirname(sess);
951 	if (dir == NULL)
952 		return TEE_ERROR_OUT_OF_MEMORY;
953 
954 	e->dir = tee_file_ops.opendir(dir);
955 	free(dir);
956 
957 	if (e->dir == NULL)
958 		/* error codes needs better granularity */
959 		return TEE_ERROR_ITEM_NOT_FOUND;
960 
961 	/* verify object */
962 	o = calloc(1, sizeof(struct tee_obj));
963 	if (o == NULL) {
964 		res = TEE_ERROR_OUT_OF_MEMORY;
965 		goto exit;
966 	}
967 
968 	o->pobj = calloc(1, sizeof(struct tee_pobj));
969 	if (!o->pobj) {
970 		res = TEE_ERROR_OUT_OF_MEMORY;
971 		goto exit;
972 	}
973 
974 	/* object enumeration loop */
975 	do {
976 		d = tee_file_ops.readdir(e->dir);
977 		if (d) {
978 			/* allocate obj_id and set object */
979 			res = tee_svc_storage_set_enum(d->d_name, o);
980 			if (res != TEE_SUCCESS)
981 				goto exit;
982 			res = tee_obj_verify(sess, o);
983 			if (res != TEE_SUCCESS)
984 				goto exit;
985 			/* free obj_id for each iteration */
986 			free(o->pobj->obj_id);
987 			/* force obj_id to skip freeing at exit statement */
988 			o->pobj->obj_id = NULL;
989 		}
990 	} while (d);
991 
992 	/* re-start */
993 	res = tee_file_ops.closedir(e->dir);
994 	e->dir = NULL;
995 	if (res != 0) {
996 		res = TEE_ERROR_GENERIC;
997 		goto exit;
998 	}
999 
1000 	dir = tee_svc_storage_create_dirname(sess);
1001 	if (dir == NULL) {
1002 		res = TEE_ERROR_OUT_OF_MEMORY;
1003 		goto exit;
1004 	}
1005 
1006 	e->dir = tee_file_ops.opendir(dir);
1007 	free(dir);
1008 
1009 exit:
1010 	if (o) {
1011 		if (o->pobj)
1012 			free(o->pobj->obj_id);
1013 		free(o->pobj);
1014 		free(o->data);
1015 	}
1016 	free(o);
1017 
1018 	return res;
1019 }
1020 
1021 TEE_Result syscall_storage_next_enum(uint32_t obj_enum, TEE_ObjectInfo *info,
1022 				     void *obj_id, uint32_t *len)
1023 {
1024 	struct tee_storage_enum *e;
1025 	struct tee_fs_dirent *d;
1026 	TEE_Result res = TEE_SUCCESS;
1027 	struct tee_ta_session *sess;
1028 	struct tee_obj *o = NULL;
1029 
1030 	if (obj_enum == TEE_HANDLE_NULL) {
1031 		res = TEE_ERROR_BAD_PARAMETERS;
1032 		goto exit;
1033 	}
1034 
1035 	res = tee_ta_get_current_session(&sess);
1036 	if (res != TEE_SUCCESS)
1037 		goto exit;
1038 
1039 	res = tee_svc_storage_get_enum(sess->ctx, obj_enum, &e);
1040 	if (res != TEE_SUCCESS)
1041 		goto exit;
1042 
1043 	/* check rights of the provided buffers */
1044 	res = tee_mmu_check_access_rights(sess->ctx,
1045 					TEE_MEMORY_ACCESS_WRITE |
1046 					TEE_MEMORY_ACCESS_ANY_OWNER,
1047 					(tee_uaddr_t) info,
1048 					sizeof(TEE_ObjectInfo));
1049 	if (res != TEE_SUCCESS)
1050 		goto exit;
1051 
1052 	res = tee_mmu_check_access_rights(sess->ctx,
1053 					TEE_MEMORY_ACCESS_WRITE |
1054 					TEE_MEMORY_ACCESS_ANY_OWNER,
1055 					(tee_uaddr_t) obj_id,
1056 					TEE_OBJECT_ID_MAX_LEN);
1057 	if (res != TEE_SUCCESS)
1058 		goto exit;
1059 
1060 	d = tee_file_ops.readdir(e->dir);
1061 	if (d == NULL) {
1062 		res = TEE_ERROR_ITEM_NOT_FOUND;
1063 		goto exit;
1064 	}
1065 
1066 	o = calloc(1, sizeof(struct tee_obj));
1067 	if (o == NULL) {
1068 		res = TEE_ERROR_OUT_OF_MEMORY;
1069 		goto exit;
1070 	}
1071 
1072 	o->pobj = calloc(1, sizeof(struct tee_pobj));
1073 	if (!o->pobj) {
1074 		res = TEE_ERROR_OUT_OF_MEMORY;
1075 		goto exit;
1076 	}
1077 
1078 	res = tee_svc_storage_set_enum(d->d_name, o);
1079 	if (res != TEE_SUCCESS)
1080 		goto exit;
1081 
1082 	res = tee_obj_verify(sess, o);
1083 	if (res != TEE_SUCCESS)
1084 		goto exit;
1085 
1086 	res = tee_svc_storage_read_head(sess, o);
1087 	if (res != TEE_SUCCESS)
1088 		goto exit;
1089 
1090 	memcpy(info, &o->info, sizeof(TEE_ObjectInfo));
1091 	memcpy(obj_id, o->pobj->obj_id, o->pobj->obj_id_len);
1092 
1093 	res = tee_svc_copy_to_user(sess, len, &o->pobj->obj_id_len,
1094 				 sizeof(uint32_t));
1095 
1096 exit:
1097 	if (o) {
1098 		if (o->pobj)
1099 			free(o->pobj->obj_id);
1100 		free(o->pobj);
1101 		free(o->data);
1102 	}
1103 	free(o);
1104 
1105 	return res;
1106 }
1107 
1108 TEE_Result syscall_storage_obj_read(uint32_t obj, void *data, size_t len,
1109 				    uint32_t *count)
1110 {
1111 	TEE_Result res;
1112 	struct tee_ta_session *sess;
1113 	struct tee_obj *o;
1114 	int n_count;
1115 	uint32_t u_count;
1116 
1117 	res = tee_ta_get_current_session(&sess);
1118 	if (res != TEE_SUCCESS)
1119 		goto exit;
1120 
1121 	res = tee_obj_get(sess->ctx, obj, &o);
1122 	if (res != TEE_SUCCESS)
1123 		goto exit;
1124 
1125 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1126 		res = TEE_ERROR_BAD_STATE;
1127 		goto exit;
1128 	}
1129 
1130 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_READ)) {
1131 		res = TEE_ERROR_ACCESS_CONFLICT;
1132 		goto exit;
1133 	}
1134 
1135 	/* check rights of the provided buffer */
1136 	res = tee_mmu_check_access_rights(sess->ctx,
1137 					TEE_MEMORY_ACCESS_WRITE |
1138 					TEE_MEMORY_ACCESS_ANY_OWNER,
1139 					(tee_uaddr_t) data, len);
1140 	if (res != TEE_SUCCESS)
1141 		goto exit;
1142 
1143 	n_count = tee_file_ops.read(&res, o->fd, data, len);
1144 	if (n_count < 0) {
1145 		EMSG("Error code=%x\n", (uint32_t)res);
1146 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
1147 			EMSG("Object corrupt\n");
1148 			tee_svc_storage_remove_corrupt_obj(sess, o);
1149 		}
1150 		goto exit;
1151 	}
1152 	u_count = (uint32_t) ((n_count < 0) ? 0 : n_count);
1153 
1154 	res = tee_svc_copy_to_user(sess, count, &u_count, sizeof(uint32_t));
1155 
1156 	o->info.dataPosition += u_count;
1157 
1158 	res = TEE_SUCCESS;
1159 
1160 exit:
1161 	return res;
1162 }
1163 
1164 TEE_Result syscall_storage_obj_write(uint32_t obj, void *data, size_t len)
1165 {
1166 	TEE_Result res;
1167 	struct tee_ta_session *sess;
1168 	struct tee_obj *o;
1169 	int err;
1170 
1171 	res = tee_ta_get_current_session(&sess);
1172 	if (res != TEE_SUCCESS)
1173 		goto exit;
1174 
1175 	res = tee_obj_get(sess->ctx, obj, &o);
1176 	if (res != TEE_SUCCESS)
1177 		goto exit;
1178 
1179 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1180 		res = TEE_ERROR_BAD_STATE;
1181 		goto exit;
1182 	}
1183 
1184 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) {
1185 		res = TEE_ERROR_ACCESS_CONFLICT;
1186 		goto exit;
1187 	}
1188 
1189 	/* check rights of the provided buffer */
1190 	res = tee_mmu_check_access_rights(sess->ctx,
1191 					TEE_MEMORY_ACCESS_READ |
1192 					TEE_MEMORY_ACCESS_ANY_OWNER,
1193 					(tee_uaddr_t) data, len);
1194 
1195 	err = tee_file_ops.write(&res, o->fd, data, len);
1196 
1197 	if (err != (int)len)
1198 		goto exit;
1199 
1200 	o->info.dataPosition += len;
1201 	if (o->info.dataPosition > o->info.dataSize)
1202 		o->info.dataSize = o->info.dataPosition;
1203 
1204 	res = TEE_SUCCESS;
1205 exit:
1206 	return res;
1207 }
1208 
1209 TEE_Result syscall_storage_obj_trunc(uint32_t obj, size_t len)
1210 {
1211 	TEE_Result res;
1212 	struct tee_ta_session *sess;
1213 	struct tee_obj *o;
1214 	int err;
1215 	tee_fs_off_t off;
1216 
1217 	res = tee_ta_get_current_session(&sess);
1218 	if (res != TEE_SUCCESS)
1219 		goto exit;
1220 
1221 	res = tee_obj_get(sess->ctx, obj, &o);
1222 	if (res != TEE_SUCCESS)
1223 		goto exit;
1224 
1225 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1226 		res = TEE_ERROR_BAD_STATE;
1227 		goto exit;
1228 	}
1229 
1230 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) {
1231 		res = TEE_ERROR_ACCESS_CONFLICT;
1232 		goto exit;
1233 	}
1234 
1235 	res = tee_obj_verify(sess, o);
1236 	if (res != TEE_SUCCESS)
1237 		goto exit;
1238 
1239 	off = sizeof(struct tee_svc_storage_head) + o->data_size;
1240 	err = tee_file_ops.ftruncate(&res, o->fd, len + off);
1241 	if (err) {
1242 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
1243 			EMSG("Object corrupt\n");
1244 			res = tee_svc_storage_remove_corrupt_obj(sess, o);
1245 			if (res != TEE_SUCCESS)
1246 				goto exit;
1247 			res = TEE_ERROR_CORRUPT_OBJECT;
1248 			goto exit;
1249 		} else
1250 			res = TEE_ERROR_GENERIC;
1251 	}
1252 
1253 exit:
1254 	return res;
1255 }
1256 
1257 TEE_Result syscall_storage_obj_seek(uint32_t obj, int32_t offset,
1258 				    TEE_Whence whence)
1259 {
1260 	TEE_Result res;
1261 	struct tee_ta_session *sess;
1262 	struct tee_obj *o;
1263 	int fw;
1264 	tee_fs_off_t off;
1265 	tee_fs_off_t e_off = 0;
1266 
1267 	res = tee_ta_get_current_session(&sess);
1268 	if (res != TEE_SUCCESS)
1269 		goto exit;
1270 
1271 	res = tee_obj_get(sess->ctx, obj, &o);
1272 	if (res != TEE_SUCCESS)
1273 		goto exit;
1274 
1275 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1276 		res = TEE_ERROR_BAD_STATE;
1277 		goto exit;
1278 	}
1279 
1280 	res = tee_obj_verify(sess, o);
1281 	if (res != TEE_SUCCESS)
1282 		goto exit;
1283 
1284 	fw = tee_svc_storage_conv_whence(whence);
1285 
1286 	if (whence == TEE_DATA_SEEK_SET)
1287 		e_off = sizeof(struct tee_svc_storage_head) + o->data_size;
1288 
1289 	off = tee_file_ops.lseek(&res, o->fd, e_off + offset, fw);
1290 	if (off > -1 && off >= e_off)
1291 		o->info.dataPosition = off -
1292 			(sizeof(struct tee_svc_storage_head) + o->data_size);
1293 	else {
1294 		res = TEE_ERROR_GENERIC;
1295 		goto exit;
1296 	}
1297 
1298 	res = TEE_SUCCESS;
1299 
1300 exit:
1301 	return res;
1302 }
1303 
1304 void tee_svc_storage_close_all_enum(struct tee_ta_ctx *ctx)
1305 {
1306 	struct tee_storage_enum_head *eh = &ctx->storage_enums;
1307 
1308 	/* disregard return value */
1309 	while (!TAILQ_EMPTY(eh))
1310 		tee_svc_close_enum(ctx, TAILQ_FIRST(eh));
1311 }
1312