xref: /optee_os/core/tee/tee_svc_storage.c (revision 2ecdb4d793b36537036fa7bbb58e52c8b2134638)
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 	struct tee_fs_dir *dir;
55 };
56 
57 static TEE_Result tee_svc_storage_get_enum(struct user_ta_ctx *utc,
58 					   uint32_t enum_id,
59 					   struct tee_storage_enum **e_out)
60 {
61 	struct tee_storage_enum *e;
62 
63 	TAILQ_FOREACH(e, &utc->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 user_ta_ctx *utc,
73 				     struct tee_storage_enum *e)
74 {
75 	int ret;
76 
77 	if (e == NULL || utc == NULL)
78 		return TEE_ERROR_BAD_PARAMETERS;
79 
80 	TAILQ_REMOVE(&utc->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(to_user_ta_ctx(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(unsigned long storage_id, void *object_id,
402 			size_t object_id_len, unsigned long 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 	struct user_ta_ctx *utc;
416 
417 	if (storage_id != TEE_STORAGE_PRIVATE) {
418 		res = TEE_ERROR_ITEM_NOT_FOUND;
419 		goto exit;
420 	}
421 
422 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN) {
423 		res = TEE_ERROR_BAD_PARAMETERS;
424 		goto exit;
425 	}
426 
427 	res = tee_ta_get_current_session(&sess);
428 	if (res != TEE_SUCCESS)
429 		goto err;
430 	utc = to_user_ta_ctx(sess->ctx);
431 
432 	res = tee_mmu_check_access_rights(utc,
433 					  TEE_MEMORY_ACCESS_READ |
434 					  TEE_MEMORY_ACCESS_ANY_OWNER,
435 					  (tee_uaddr_t) object_id,
436 					  object_id_len);
437 	if (res != TEE_SUCCESS)
438 		goto err;
439 
440 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
441 			   object_id_len, flags, &po);
442 	if (res != TEE_SUCCESS)
443 		goto err;
444 
445 	fs_flags = tee_svc_storage_conv_oflags(flags);
446 
447 	o = calloc(1, sizeof(*o));
448 	if (o == NULL) {
449 		res = TEE_ERROR_OUT_OF_MEMORY;
450 		goto err;
451 	}
452 
453 	o->info.handleFlags =
454 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
455 	o->info.objectUsage = TEE_USAGE_DEFAULT;
456 	o->flags = flags;
457 	o->pobj = po;
458 
459 	res = tee_svc_storage_read_head(sess, o);
460 	if (res != TEE_SUCCESS) {
461 		tee_obj_add(utc, o);
462 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
463 			EMSG("Object corrupt\n");
464 			res = tee_svc_storage_remove_corrupt_obj(sess, o);
465 			if (res != TEE_SUCCESS)
466 				goto exit;
467 			res = TEE_ERROR_CORRUPT_OBJECT;
468 			goto exit;
469 		}
470 		goto oclose;
471 	}
472 
473 	file = tee_svc_storage_create_filename(sess, object_id,
474 					       object_id_len, false);
475 	if (file == NULL) {
476 		res = TEE_ERROR_OUT_OF_MEMORY;
477 		goto err;
478 	}
479 
480 	err = tee_file_ops.access(file, TEE_FS_F_OK);
481 	if (err) {
482 		/* file not found */
483 		res = TEE_ERROR_STORAGE_NOT_AVAILABLE;
484 		goto err;
485 	}
486 
487 	fd = tee_file_ops.open(&res, file, fs_flags);
488 	if (fd < 0) {
489 		goto err;
490 	}
491 	o->fd = fd;
492 
493 	tee_obj_add(utc, o);
494 
495 	res = tee_svc_copy_kaddr_to_uref(sess, obj, o);
496 	if (res != TEE_SUCCESS)
497 		goto oclose;
498 
499 	e_off = sizeof(struct tee_svc_storage_head) + o->data_size;
500 	off = tee_file_ops.lseek(&res, fd, e_off, TEE_FS_SEEK_SET);
501 	if (off != e_off) {
502 		res = TEE_ERROR_NO_DATA;
503 		goto oclose;
504 	}
505 
506 	goto exit;
507 
508 oclose:
509 	tee_obj_close(utc, o);
510 
511 err:
512 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
513 		res = TEE_ERROR_CORRUPT_OBJECT;
514 	if (res == TEE_ERROR_CORRUPT_OBJECT)
515 		tee_file_ops.unlink(file);
516 	if (fd >= 0)
517 		tee_file_ops.close(fd);
518 	if (po)
519 		tee_pobj_release(po);
520 
521 exit:
522 	free(file);
523 	file = NULL;
524 	return res;
525 }
526 
527 TEE_Result syscall_storage_obj_create(unsigned long storage_id, void *object_id,
528 			size_t object_id_len, unsigned long flags,
529 			unsigned long attr, void *data, size_t len,
530 			uint32_t *obj)
531 {
532 	TEE_Result res;
533 	struct tee_ta_session *sess;
534 	struct tee_obj *o = NULL;
535 	struct tee_obj *attr_o = NULL;
536 	char *file = NULL;
537 	int fd = -1;
538 	int fs_flags;
539 	tee_fs_off_t off;
540 	tee_fs_off_t e_off;
541 	struct tee_pobj *po = NULL;
542 	char *tmpfile = NULL;
543 	int err = -1;
544 	int filedoesnotexist;
545 	struct user_ta_ctx *utc;
546 
547 	if (storage_id != TEE_STORAGE_PRIVATE)
548 		return TEE_ERROR_ITEM_NOT_FOUND;
549 
550 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
551 		return TEE_ERROR_BAD_PARAMETERS;
552 
553 	res = tee_ta_get_current_session(&sess);
554 	if (res != TEE_SUCCESS)
555 		return res;
556 	utc = to_user_ta_ctx(sess->ctx);
557 
558 	res = tee_mmu_check_access_rights(utc,
559 					  TEE_MEMORY_ACCESS_READ |
560 					  TEE_MEMORY_ACCESS_ANY_OWNER,
561 					  (tee_uaddr_t) object_id,
562 					  object_id_len);
563 	if (res != TEE_SUCCESS)
564 		goto err;
565 
566 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
567 			   object_id_len, flags, &po);
568 	if (res != TEE_SUCCESS)
569 		goto err;
570 
571 	/* check rights of the provided buffer */
572 	if (data && len) {
573 		res = tee_mmu_check_access_rights(utc,
574 						  TEE_MEMORY_ACCESS_READ |
575 						  TEE_MEMORY_ACCESS_ANY_OWNER,
576 						  (tee_uaddr_t) data, len);
577 
578 		if (res != TEE_SUCCESS)
579 			goto err;
580 	}
581 
582 	o = calloc(1, sizeof(*o));
583 	if (o == NULL) {
584 		res = TEE_ERROR_OUT_OF_MEMORY;
585 		goto err;
586 	}
587 
588 	o->info.handleFlags =
589 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
590 	o->flags = flags;
591 	o->pobj = po;
592 
593 	if (attr != TEE_HANDLE_NULL) {
594 		res = tee_obj_get(utc, tee_svc_uref_to_vaddr(attr),
595 				  &attr_o);
596 		if (res != TEE_SUCCESS)
597 			goto err;
598 	}
599 
600 	res = tee_svc_storage_init_file(sess, o, attr_o, data, len);
601 	if (res != TEE_SUCCESS)
602 		goto err;
603 
604 	/* create persistent object filename */
605 	file = tee_svc_storage_create_filename(sess, object_id,
606 					       object_id_len, false);
607 	if (file == NULL) {
608 		res = TEE_ERROR_OUT_OF_MEMORY;
609 		goto err;
610 	}
611 
612 	filedoesnotexist = tee_file_ops.access(file, TEE_FS_F_OK);
613 	if (!filedoesnotexist) {
614 		/* file exists */
615 		if (!(flags & TEE_DATA_FLAG_OVERWRITE)) {
616 			res = TEE_ERROR_ACCESS_CONFLICT;
617 			goto err;
618 		}
619 	}
620 
621 	/* create temporary persistent object filename */
622 	tmpfile = tee_svc_storage_create_filename(sess, object_id,
623 						  object_id_len,
624 						  true);
625 	if (tmpfile == NULL) {
626 		res = TEE_ERROR_OUT_OF_MEMORY;
627 		goto err;
628 	}
629 
630 	/*
631 	 * remove the file if it exists, because rename does not perform
632 	 * this operation. Note that it delete and rename should be atomic,
633 	 * which is not the case currently.
634 	 * Fixme: unlink must be removed once rename() support prior deletion
635 	 * of the new file name when it already exists.
636 	 */
637 	if (!filedoesnotexist)
638 		tee_file_ops.unlink(file);
639 	/* rename temporary persistent object filename */
640 	err = tee_file_ops.rename(tmpfile, file);
641 	if (err) {
642 		/* error codes needs better granularity */
643 		res = TEE_ERROR_GENERIC;
644 		goto rmfile;
645 	}
646 
647 	fs_flags = tee_svc_storage_conv_oflags(flags);
648 
649 	fd = tee_file_ops.open(&res, file, fs_flags);
650 	if (fd < 0) {
651 		goto err;
652 	}
653 	o->fd = fd;
654 
655 	tee_obj_add(utc, o);
656 
657 	res = tee_svc_copy_kaddr_to_uref(sess, obj, o);
658 	if (res != TEE_SUCCESS)
659 		goto oclose;
660 
661 	e_off = sizeof(struct tee_svc_storage_head) + o->data_size;
662 	off = tee_file_ops.lseek(&res, fd, e_off, TEE_FS_SEEK_SET);
663 	if (off != e_off) {
664 		res = TEE_ERROR_NO_DATA;
665 		goto oclose;
666 	}
667 
668 	goto exit;
669 
670 oclose:
671 	tee_obj_close(utc, o);
672 	goto exit;
673 
674 rmfile:
675 	tee_file_ops.unlink(tmpfile);
676 
677 err:
678 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
679 		res = TEE_ERROR_CORRUPT_OBJECT;
680 	if (res == TEE_ERROR_CORRUPT_OBJECT)
681 		tee_file_ops.unlink(file);
682 	if (fd >= 0)
683 		tee_file_ops.close(fd);
684 	if (po)
685 		tee_pobj_release(po);
686 	if (o)
687 		free(o);
688 
689 exit:
690 	free(file);
691 	file = NULL;
692 	free(tmpfile);
693 	tmpfile = NULL;
694 
695 	return res;
696 }
697 
698 TEE_Result syscall_storage_obj_del(unsigned long obj)
699 {
700 	TEE_Result res;
701 	struct tee_ta_session *sess;
702 	struct tee_obj *o;
703 	int err;
704 	char *file;
705 	char *dir;
706 	struct user_ta_ctx *utc;
707 
708 	res = tee_ta_get_current_session(&sess);
709 	if (res != TEE_SUCCESS)
710 		return res;
711 	utc = to_user_ta_ctx(sess->ctx);
712 
713 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
714 	if (res != TEE_SUCCESS)
715 		return res;
716 
717 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META))
718 		return TEE_ERROR_ACCESS_CONFLICT;
719 
720 	if (o->pobj == NULL || o->pobj->obj_id == NULL)
721 		return TEE_ERROR_BAD_STATE;
722 
723 	file = tee_svc_storage_create_filename(sess, o->pobj->obj_id,
724 						o->pobj->obj_id_len, false);
725 	if (file == NULL)
726 		return TEE_ERROR_OUT_OF_MEMORY;
727 
728 	tee_obj_close(utc, o);
729 
730 	err = tee_file_ops.access(file, TEE_FS_F_OK);
731 	if (err)
732 		/* file not found */
733 		return TEE_ERROR_STORAGE_NOT_AVAILABLE;
734 
735 	err = tee_file_ops.unlink(file);
736 	free(file);
737 	if (err)
738 		/* error codes needs better granularity */
739 		return TEE_ERROR_GENERIC;
740 
741 	/* try and remove dir */
742 	dir = tee_svc_storage_create_dirname(sess);
743 	if (dir == NULL)
744 		return TEE_ERROR_OUT_OF_MEMORY;
745 	/* ignore result */
746 	tee_file_ops.rmdir(dir);
747 	free(dir);
748 
749 	return TEE_SUCCESS;
750 }
751 
752 TEE_Result syscall_storage_obj_rename(unsigned long obj, void *object_id,
753 			size_t object_id_len)
754 {
755 	TEE_Result res;
756 	struct tee_ta_session *sess;
757 	struct tee_obj *o;
758 	struct tee_pobj *po = NULL;
759 	char *new_file = NULL;
760 	char *old_file = NULL;
761 	int err = -1;
762 	struct user_ta_ctx *utc;
763 
764 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
765 		return TEE_ERROR_BAD_PARAMETERS;
766 
767 	res = tee_ta_get_current_session(&sess);
768 	if (res != TEE_SUCCESS)
769 		return res;
770 	utc = to_user_ta_ctx(sess->ctx);
771 
772 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
773 	if (res != TEE_SUCCESS)
774 		return res;
775 
776 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
777 		res = TEE_ERROR_BAD_STATE;
778 		goto exit;
779 	}
780 
781 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META)) {
782 		res = TEE_ERROR_BAD_STATE;
783 		goto exit;
784 	}
785 
786 	if (o->pobj == NULL || o->pobj->obj_id == NULL) {
787 		res = TEE_ERROR_BAD_STATE;
788 		goto exit;
789 	}
790 
791 	res = tee_mmu_check_access_rights(utc,
792 					TEE_MEMORY_ACCESS_READ |
793 					TEE_MEMORY_ACCESS_ANY_OWNER,
794 					(tee_uaddr_t) object_id, object_id_len);
795 	if (res != TEE_SUCCESS)
796 		goto exit;
797 
798 	res = tee_obj_verify(sess, o);
799 	if (res != TEE_SUCCESS)
800 		goto exit;
801 
802 	/* get new ds name */
803 	new_file = tee_svc_storage_create_filename(sess, object_id,
804 						   object_id_len, false);
805 	if (new_file == NULL) {
806 		res = TEE_ERROR_OUT_OF_MEMORY;
807 		goto exit;
808 	}
809 
810 	old_file = tee_svc_storage_create_filename(sess, o->pobj->obj_id,
811 						   o->pobj->obj_id_len, false);
812 	if (old_file == NULL) {
813 		res = TEE_ERROR_OUT_OF_MEMORY;
814 		goto exit;
815 	}
816 
817 	/* reserve dest name */
818 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
819 			   object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META, &po);
820 	if (res != TEE_SUCCESS)
821 		goto exit;
822 
823 	err = tee_file_ops.access(new_file, TEE_FS_F_OK);
824 	if (err == 0) {
825 		/* file exists */
826 		res = TEE_ERROR_ACCESS_CONFLICT;
827 		goto exit;
828 	}
829 
830 	/* move */
831 	err = tee_file_ops.rename(old_file, new_file);
832 	if (err) {
833 		/* error codes needs better granularity */
834 		res = TEE_ERROR_GENERIC;
835 		goto exit;
836 	}
837 
838 	res = tee_pobj_rename(o->pobj, object_id, object_id_len);
839 
840 exit:
841 	tee_pobj_release(po);
842 
843 	free(new_file);
844 	free(old_file);
845 
846 	return res;
847 }
848 
849 TEE_Result syscall_storage_alloc_enum(uint32_t *obj_enum)
850 {
851 	struct tee_storage_enum *e;
852 	struct tee_ta_session *sess;
853 	TEE_Result res;
854 	struct user_ta_ctx *utc;
855 
856 	if (obj_enum == NULL)
857 		return TEE_ERROR_BAD_PARAMETERS;
858 
859 	res = tee_ta_get_current_session(&sess);
860 	if (res != TEE_SUCCESS)
861 		return res;
862 	utc = to_user_ta_ctx(sess->ctx);
863 
864 	e = malloc(sizeof(struct tee_storage_enum));
865 
866 	if (e == NULL)
867 		return TEE_ERROR_OUT_OF_MEMORY;
868 
869 	e->dir = NULL;
870 	TAILQ_INSERT_TAIL(&utc->storage_enums, e, link);
871 
872 	return tee_svc_copy_kaddr_to_uref(sess, obj_enum, e);
873 }
874 
875 TEE_Result syscall_storage_free_enum(unsigned long obj_enum)
876 {
877 	struct tee_storage_enum *e;
878 	TEE_Result res;
879 	struct tee_ta_session *sess;
880 	struct user_ta_ctx *utc;
881 
882 	res = tee_ta_get_current_session(&sess);
883 	if (res != TEE_SUCCESS)
884 		return res;
885 	utc = to_user_ta_ctx(sess->ctx);
886 
887 	res = tee_svc_storage_get_enum(utc,
888 			tee_svc_uref_to_vaddr(obj_enum), &e);
889 	if (res != TEE_SUCCESS)
890 		return res;
891 
892 	return tee_svc_close_enum(utc, e);
893 }
894 
895 TEE_Result syscall_storage_reset_enum(unsigned long obj_enum)
896 {
897 	struct tee_storage_enum *e;
898 	TEE_Result res;
899 	struct tee_ta_session *sess;
900 
901 	res = tee_ta_get_current_session(&sess);
902 	if (res != TEE_SUCCESS)
903 		return res;
904 
905 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
906 			tee_svc_uref_to_vaddr(obj_enum), &e);
907 	if (res != TEE_SUCCESS)
908 		return res;
909 
910 	res = tee_file_ops.closedir(e->dir);
911 	e->dir = NULL;
912 	if (res != 0)
913 		return TEE_ERROR_GENERIC;
914 
915 	return TEE_SUCCESS;
916 }
917 
918 static TEE_Result tee_svc_storage_set_enum(char *d_name, struct tee_obj *o)
919 {
920 	TEE_Result res;
921 	uint32_t blen;
922 	uint32_t hslen;
923 
924 	o->info.handleFlags =
925 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
926 	o->info.objectUsage = TEE_USAGE_DEFAULT;
927 
928 	hslen = strlen(d_name);
929 	blen = TEE_HS2B_BBUF_SIZE(hslen);
930 	o->pobj->obj_id = malloc(blen);
931 	if (!o->pobj->obj_id) {
932 		res = TEE_ERROR_OUT_OF_MEMORY;
933 		goto exit;
934 	}
935 	tee_hs2b((uint8_t *)d_name, o->pobj->obj_id, hslen, blen);
936 	o->pobj->obj_id_len = blen;
937 
938 	res = TEE_SUCCESS;
939 
940 exit:
941 	return res;
942 
943 }
944 
945 TEE_Result syscall_storage_start_enum(unsigned long obj_enum,
946 			unsigned long storage_id)
947 {
948 	struct tee_storage_enum *e;
949 	char *dir;
950 	TEE_Result res;
951 	struct tee_ta_session *sess;
952 	struct tee_fs_dirent *d = NULL;
953 	struct tee_obj *o = NULL;
954 
955 	res = tee_ta_get_current_session(&sess);
956 	if (res != TEE_SUCCESS)
957 		return res;
958 
959 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
960 			tee_svc_uref_to_vaddr(obj_enum), &e);
961 	if (res != TEE_SUCCESS)
962 		return res;
963 
964 	if (storage_id != TEE_STORAGE_PRIVATE)
965 		return TEE_ERROR_ITEM_NOT_FOUND;
966 
967 	dir = tee_svc_storage_create_dirname(sess);
968 	if (dir == NULL)
969 		return TEE_ERROR_OUT_OF_MEMORY;
970 
971 	e->dir = tee_file_ops.opendir(dir);
972 	free(dir);
973 
974 	if (e->dir == NULL)
975 		/* error codes needs better granularity */
976 		return TEE_ERROR_ITEM_NOT_FOUND;
977 
978 	/* verify object */
979 	o = calloc(1, sizeof(struct tee_obj));
980 	if (o == NULL) {
981 		res = TEE_ERROR_OUT_OF_MEMORY;
982 		goto exit;
983 	}
984 
985 	o->pobj = calloc(1, sizeof(struct tee_pobj));
986 	if (!o->pobj) {
987 		res = TEE_ERROR_OUT_OF_MEMORY;
988 		goto exit;
989 	}
990 
991 	/* object enumeration loop */
992 	do {
993 		d = tee_file_ops.readdir(e->dir);
994 		if (d) {
995 			/* allocate obj_id and set object */
996 			res = tee_svc_storage_set_enum(d->d_name, o);
997 			if (res != TEE_SUCCESS)
998 				goto exit;
999 			res = tee_obj_verify(sess, o);
1000 			if (res != TEE_SUCCESS)
1001 				goto exit;
1002 			/* free obj_id for each iteration */
1003 			free(o->pobj->obj_id);
1004 			/* force obj_id to skip freeing at exit statement */
1005 			o->pobj->obj_id = NULL;
1006 		}
1007 	} while (d);
1008 
1009 	/* re-start */
1010 	res = tee_file_ops.closedir(e->dir);
1011 	e->dir = NULL;
1012 	if (res != 0) {
1013 		res = TEE_ERROR_GENERIC;
1014 		goto exit;
1015 	}
1016 
1017 	dir = tee_svc_storage_create_dirname(sess);
1018 	if (dir == NULL) {
1019 		res = TEE_ERROR_OUT_OF_MEMORY;
1020 		goto exit;
1021 	}
1022 
1023 	e->dir = tee_file_ops.opendir(dir);
1024 	free(dir);
1025 
1026 exit:
1027 	if (o) {
1028 		if (o->pobj)
1029 			free(o->pobj->obj_id);
1030 		free(o->pobj);
1031 		free(o->data);
1032 	}
1033 	free(o);
1034 
1035 	return res;
1036 }
1037 
1038 TEE_Result syscall_storage_next_enum(unsigned long obj_enum,
1039 			TEE_ObjectInfo *info, void *obj_id, uint64_t *len)
1040 {
1041 	struct tee_storage_enum *e;
1042 	struct tee_fs_dirent *d;
1043 	TEE_Result res = TEE_SUCCESS;
1044 	struct tee_ta_session *sess;
1045 	struct tee_obj *o = NULL;
1046 	uint64_t l;
1047 	struct user_ta_ctx *utc;
1048 
1049 	res = tee_ta_get_current_session(&sess);
1050 	if (res != TEE_SUCCESS)
1051 		goto exit;
1052 	utc = to_user_ta_ctx(sess->ctx);
1053 
1054 	res = tee_svc_storage_get_enum(utc,
1055 			tee_svc_uref_to_vaddr(obj_enum), &e);
1056 	if (res != TEE_SUCCESS)
1057 		goto exit;
1058 
1059 	/* check rights of the provided buffers */
1060 	res = tee_mmu_check_access_rights(utc,
1061 					TEE_MEMORY_ACCESS_WRITE |
1062 					TEE_MEMORY_ACCESS_ANY_OWNER,
1063 					(tee_uaddr_t) info,
1064 					sizeof(TEE_ObjectInfo));
1065 	if (res != TEE_SUCCESS)
1066 		goto exit;
1067 
1068 	res = tee_mmu_check_access_rights(utc,
1069 					TEE_MEMORY_ACCESS_WRITE |
1070 					TEE_MEMORY_ACCESS_ANY_OWNER,
1071 					(tee_uaddr_t) obj_id,
1072 					TEE_OBJECT_ID_MAX_LEN);
1073 	if (res != TEE_SUCCESS)
1074 		goto exit;
1075 
1076 	d = tee_file_ops.readdir(e->dir);
1077 	if (d == NULL) {
1078 		res = TEE_ERROR_ITEM_NOT_FOUND;
1079 		goto exit;
1080 	}
1081 
1082 	o = calloc(1, sizeof(struct tee_obj));
1083 	if (o == NULL) {
1084 		res = TEE_ERROR_OUT_OF_MEMORY;
1085 		goto exit;
1086 	}
1087 
1088 	o->pobj = calloc(1, sizeof(struct tee_pobj));
1089 	if (!o->pobj) {
1090 		res = TEE_ERROR_OUT_OF_MEMORY;
1091 		goto exit;
1092 	}
1093 
1094 	res = tee_svc_storage_set_enum(d->d_name, o);
1095 	if (res != TEE_SUCCESS)
1096 		goto exit;
1097 
1098 	res = tee_obj_verify(sess, o);
1099 	if (res != TEE_SUCCESS)
1100 		goto exit;
1101 
1102 	res = tee_svc_storage_read_head(sess, o);
1103 	if (res != TEE_SUCCESS)
1104 		goto exit;
1105 
1106 	memcpy(info, &o->info, sizeof(TEE_ObjectInfo));
1107 	memcpy(obj_id, o->pobj->obj_id, o->pobj->obj_id_len);
1108 
1109 	l = o->pobj->obj_id_len;
1110 	res = tee_svc_copy_to_user(sess, len, &l, sizeof(*len));
1111 
1112 exit:
1113 	if (o) {
1114 		if (o->pobj)
1115 			free(o->pobj->obj_id);
1116 		free(o->pobj);
1117 		free(o->data);
1118 	}
1119 	free(o);
1120 
1121 	return res;
1122 }
1123 
1124 TEE_Result syscall_storage_obj_read(unsigned long obj, void *data, size_t len,
1125 			uint64_t *count)
1126 {
1127 	TEE_Result res;
1128 	struct tee_ta_session *sess;
1129 	struct tee_obj *o;
1130 	int n_count;
1131 	uint64_t u_count;
1132 	struct user_ta_ctx *utc;
1133 
1134 	res = tee_ta_get_current_session(&sess);
1135 	if (res != TEE_SUCCESS)
1136 		goto exit;
1137 	utc = to_user_ta_ctx(sess->ctx);
1138 
1139 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
1140 	if (res != TEE_SUCCESS)
1141 		goto exit;
1142 
1143 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1144 		res = TEE_ERROR_BAD_STATE;
1145 		goto exit;
1146 	}
1147 
1148 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_READ)) {
1149 		res = TEE_ERROR_ACCESS_CONFLICT;
1150 		goto exit;
1151 	}
1152 
1153 	/* check rights of the provided buffer */
1154 	res = tee_mmu_check_access_rights(utc,
1155 					TEE_MEMORY_ACCESS_WRITE |
1156 					TEE_MEMORY_ACCESS_ANY_OWNER,
1157 					(tee_uaddr_t) data, len);
1158 	if (res != TEE_SUCCESS)
1159 		goto exit;
1160 
1161 	n_count = tee_file_ops.read(&res, o->fd, data, len);
1162 	if (n_count < 0) {
1163 		EMSG("Error code=%x\n", (uint32_t)res);
1164 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
1165 			EMSG("Object corrupt\n");
1166 			tee_svc_storage_remove_corrupt_obj(sess, o);
1167 		}
1168 		goto exit;
1169 	}
1170 	u_count = (uint64_t)((n_count < 0) ? 0 : n_count);
1171 
1172 	res = tee_svc_copy_to_user(sess, count, &u_count, sizeof(*count));
1173 
1174 	o->info.dataPosition += u_count;
1175 
1176 	res = TEE_SUCCESS;
1177 
1178 exit:
1179 	return res;
1180 }
1181 
1182 TEE_Result syscall_storage_obj_write(unsigned long obj, void *data, size_t len)
1183 {
1184 	TEE_Result res;
1185 	struct tee_ta_session *sess;
1186 	struct tee_obj *o;
1187 	int err;
1188 	struct user_ta_ctx *utc;
1189 
1190 	res = tee_ta_get_current_session(&sess);
1191 	if (res != TEE_SUCCESS)
1192 		goto exit;
1193 	utc = to_user_ta_ctx(sess->ctx);
1194 
1195 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
1196 	if (res != TEE_SUCCESS)
1197 		goto exit;
1198 
1199 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1200 		res = TEE_ERROR_BAD_STATE;
1201 		goto exit;
1202 	}
1203 
1204 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) {
1205 		res = TEE_ERROR_ACCESS_CONFLICT;
1206 		goto exit;
1207 	}
1208 
1209 	/* check rights of the provided buffer */
1210 	res = tee_mmu_check_access_rights(utc,
1211 					TEE_MEMORY_ACCESS_READ |
1212 					TEE_MEMORY_ACCESS_ANY_OWNER,
1213 					(tee_uaddr_t) data, len);
1214 
1215 	err = tee_file_ops.write(&res, o->fd, data, len);
1216 
1217 	if (err != (int)len)
1218 		goto exit;
1219 
1220 	o->info.dataPosition += len;
1221 	if (o->info.dataPosition > o->info.dataSize)
1222 		o->info.dataSize = o->info.dataPosition;
1223 
1224 	res = TEE_SUCCESS;
1225 exit:
1226 	return res;
1227 }
1228 
1229 TEE_Result syscall_storage_obj_trunc(unsigned long obj, size_t len)
1230 {
1231 	TEE_Result res;
1232 	struct tee_ta_session *sess;
1233 	struct tee_obj *o;
1234 	int err;
1235 	tee_fs_off_t off;
1236 
1237 	res = tee_ta_get_current_session(&sess);
1238 	if (res != TEE_SUCCESS)
1239 		goto exit;
1240 
1241 	res = tee_obj_get(to_user_ta_ctx(sess->ctx),
1242 			  tee_svc_uref_to_vaddr(obj), &o);
1243 	if (res != TEE_SUCCESS)
1244 		goto exit;
1245 
1246 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1247 		res = TEE_ERROR_BAD_STATE;
1248 		goto exit;
1249 	}
1250 
1251 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) {
1252 		res = TEE_ERROR_ACCESS_CONFLICT;
1253 		goto exit;
1254 	}
1255 
1256 	res = tee_obj_verify(sess, o);
1257 	if (res != TEE_SUCCESS)
1258 		goto exit;
1259 
1260 	off = sizeof(struct tee_svc_storage_head) + o->data_size;
1261 	err = tee_file_ops.ftruncate(&res, o->fd, len + off);
1262 	if (err) {
1263 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
1264 			EMSG("Object corrupt\n");
1265 			res = tee_svc_storage_remove_corrupt_obj(sess, o);
1266 			if (res != TEE_SUCCESS)
1267 				goto exit;
1268 			res = TEE_ERROR_CORRUPT_OBJECT;
1269 			goto exit;
1270 		} else
1271 			res = TEE_ERROR_GENERIC;
1272 	}
1273 
1274 exit:
1275 	return res;
1276 }
1277 
1278 TEE_Result syscall_storage_obj_seek(unsigned long obj, long offset,
1279 				    unsigned long whence)
1280 {
1281 	TEE_Result res;
1282 	struct tee_ta_session *sess;
1283 	struct tee_obj *o;
1284 	int fw;
1285 	tee_fs_off_t off;
1286 	tee_fs_off_t e_off = 0;
1287 
1288 	res = tee_ta_get_current_session(&sess);
1289 	if (res != TEE_SUCCESS)
1290 		goto exit;
1291 
1292 	res = tee_obj_get(to_user_ta_ctx(sess->ctx),
1293 			  tee_svc_uref_to_vaddr(obj), &o);
1294 	if (res != TEE_SUCCESS)
1295 		goto exit;
1296 
1297 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1298 		res = TEE_ERROR_BAD_STATE;
1299 		goto exit;
1300 	}
1301 
1302 	res = tee_obj_verify(sess, o);
1303 	if (res != TEE_SUCCESS)
1304 		goto exit;
1305 
1306 	fw = tee_svc_storage_conv_whence(whence);
1307 
1308 	if (whence == TEE_DATA_SEEK_SET)
1309 		e_off = sizeof(struct tee_svc_storage_head) + o->data_size;
1310 
1311 	off = tee_file_ops.lseek(&res, o->fd, e_off + offset, fw);
1312 	if (off > -1 && off >= e_off)
1313 		o->info.dataPosition = off -
1314 			(sizeof(struct tee_svc_storage_head) + o->data_size);
1315 	else {
1316 		res = TEE_ERROR_GENERIC;
1317 		goto exit;
1318 	}
1319 
1320 	res = TEE_SUCCESS;
1321 
1322 exit:
1323 	return res;
1324 }
1325 
1326 void tee_svc_storage_close_all_enum(struct user_ta_ctx *utc)
1327 {
1328 	struct tee_storage_enum_head *eh = &utc->storage_enums;
1329 
1330 	/* disregard return value */
1331 	while (!TAILQ_EMPTY(eh))
1332 		tee_svc_close_enum(utc, TAILQ_FIRST(eh));
1333 }
1334