xref: /optee_os/core/tee/tee_svc_storage.c (revision c9fc200380f1d02d4a9f377d4d0f3700958be8a8)
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 <kernel/mutex.h>
29 #include <kernel/tee_misc.h>
30 #include <kernel/tee_ta_manager.h>
31 #include <mm/tee_mmu.h>
32 #include <string.h>
33 #include <tee_api_defines_extensions.h>
34 #include <tee_api_defines.h>
35 #include <tee/tee_fs_defs.h>
36 #include <tee/tee_fs.h>
37 #include <tee/tee_obj.h>
38 #include <tee/tee_pobj.h>
39 #include <tee/tee_svc_cryp.h>
40 #include <tee/tee_svc.h>
41 #include <tee/tee_svc_storage.h>
42 #include <trace.h>
43 
44 /*
45  * Returns the appropriate tee_file_operations for the specified storage ID.
46  * The value TEE_STORAGE_PRIVATE will select the REE FS if available, otherwise
47  * RPMB.
48  */
49 static const struct tee_file_operations *file_ops(uint32_t storage_id)
50 {
51 
52 	switch (storage_id) {
53 	case TEE_STORAGE_PRIVATE:
54 #if defined(CFG_REE_FS)
55 		return &ree_fs_ops;
56 #elif defined(CFG_RPMB_FS)
57 		return &rpmb_fs_ops;
58 #elif defined(CFG_SQL_FS)
59 		return &sql_fs_ops;
60 #else
61 #error At least one filesystem must be enabled.
62 #endif
63 #ifdef CFG_REE_FS
64 	case TEE_STORAGE_PRIVATE_REE:
65 		return &ree_fs_ops;
66 #endif
67 #ifdef CFG_RPMB_FS
68 	case TEE_STORAGE_PRIVATE_RPMB:
69 		return &rpmb_fs_ops;
70 #endif
71 #ifdef CFG_SQL_FS
72 	case TEE_STORAGE_PRIVATE_SQL:
73 		return &sql_fs_ops;
74 #endif
75 	default:
76 		return NULL;
77 	}
78 }
79 
80 /* SSF (Secure Storage File version 00 */
81 #define TEE_SVC_STORAGE_MAGIC 0x53534600;
82 
83 /* Header of GP formated secure storage files */
84 struct tee_svc_storage_head {
85 	uint32_t magic;
86 	uint32_t head_size;
87 	uint32_t meta_size;
88 	uint32_t ds_size;
89 	uint32_t keySize;
90 	uint32_t maxKeySize;
91 	uint32_t objectUsage;
92 	uint32_t objectType;
93 	uint32_t have_attrs;
94 };
95 
96 struct tee_storage_enum {
97 	TAILQ_ENTRY(tee_storage_enum) link;
98 	struct tee_fs_dir *dir;
99 	const struct tee_file_operations *fops;
100 };
101 
102 /*
103  * Protect TA storage directory: avoid race conditions between (create
104  * directory + create file) and (remove directory)
105  */
106 static struct mutex ta_dir_mutex = MUTEX_INITIALIZER;
107 
108 static TEE_Result tee_svc_storage_get_enum(struct user_ta_ctx *utc,
109 					   uint32_t enum_id,
110 					   struct tee_storage_enum **e_out)
111 {
112 	struct tee_storage_enum *e;
113 
114 	TAILQ_FOREACH(e, &utc->storage_enums, link) {
115 		if (enum_id == (vaddr_t)e) {
116 			*e_out = e;
117 			return TEE_SUCCESS;
118 		}
119 	}
120 	return TEE_ERROR_BAD_PARAMETERS;
121 }
122 
123 static TEE_Result tee_svc_close_enum(struct user_ta_ctx *utc,
124 				     struct tee_storage_enum *e)
125 {
126 	if (e == NULL || utc == NULL)
127 		return TEE_ERROR_BAD_PARAMETERS;
128 
129 	TAILQ_REMOVE(&utc->storage_enums, e, link);
130 
131 	if (!e->fops)
132 		return TEE_ERROR_ITEM_NOT_FOUND;
133 
134 	e->fops->closedir(e->dir);
135 	e->dir = NULL;
136 	e->fops = NULL;
137 
138 	free(e);
139 
140 	return TEE_SUCCESS;
141 }
142 
143 /* "/TA_uuid/object_id" or "/TA_uuid/.object_id" */
144 char *tee_svc_storage_create_filename(struct tee_ta_session *sess,
145 				      void *object_id,
146 				      uint32_t object_id_len,
147 				      bool transient)
148 {
149 	uint8_t *file;
150 	uint32_t pos = 0;
151 	uint32_t hslen = 1 /* Leading slash */
152 			+ TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID) + object_id_len)
153 			+ 1; /* Intermediate slash */
154 
155 	/* +1 for the '.' (temporary persistent object) */
156 	if (transient)
157 		hslen++;
158 
159 	file = malloc(hslen);
160 	if (!file)
161 		return NULL;
162 
163 	file[pos++] = '/';
164 	pos += tee_b2hs((uint8_t *)&sess->ctx->uuid, &file[pos],
165 			sizeof(TEE_UUID), hslen);
166 	file[pos++] = '/';
167 
168 	if (transient)
169 		file[pos++] = '.';
170 
171 	tee_b2hs(object_id, file + pos, object_id_len, hslen - pos);
172 
173 	return (char *)file;
174 }
175 
176 /* "/TA_uuid" */
177 char *tee_svc_storage_create_dirname(struct tee_ta_session *sess)
178 {
179 	uint8_t *dir;
180 	uint32_t hslen = TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID)) + 1;
181 
182 	dir = malloc(hslen);
183 	if (!dir)
184 		return NULL;
185 
186 	dir[0] = '/';
187 	tee_b2hs((uint8_t *)&sess->ctx->uuid, dir + 1, sizeof(TEE_UUID),
188 		 hslen);
189 
190 	return (char *)dir;
191 }
192 
193 static TEE_Result tee_svc_storage_remove_corrupt_obj(
194 					struct tee_ta_session *sess,
195 					struct tee_obj *o)
196 {
197 	TEE_Result res;
198 	char *file = NULL;
199 	const struct tee_file_operations *fops = o->pobj->fops;
200 
201 	file = tee_svc_storage_create_filename(sess,
202 					       o->pobj->obj_id,
203 					       o->pobj->obj_id_len,
204 					       false);
205 	if (file == NULL) {
206 		res = TEE_ERROR_OUT_OF_MEMORY;
207 		goto exit;
208 	}
209 
210 	tee_obj_close(to_user_ta_ctx(sess->ctx), o);
211 	fops->remove(file);
212 	free(file);
213 
214 	res = TEE_SUCCESS;
215 
216 exit:
217 	return res;
218 }
219 
220 static TEE_Result tee_svc_storage_create_file(struct tee_ta_session *sess,
221 			char *file,
222 			const struct tee_file_operations *fops,
223 			struct tee_file_handle **fh)
224 {
225 	TEE_Result res = TEE_SUCCESS;
226 	char *dir = NULL;
227 
228 	assert(!*fh);
229 	dir = tee_svc_storage_create_dirname(sess);
230 	if (dir == NULL) {
231 		res = TEE_ERROR_OUT_OF_MEMORY;
232 		goto exit;
233 	}
234 
235 	mutex_lock(&ta_dir_mutex);
236 
237 	res = fops->create(file, true /* currently always overwrite */, fh);
238 
239 	mutex_unlock(&ta_dir_mutex);
240 exit:
241 	free(dir);
242 
243 	return res;
244 }
245 
246 static TEE_Result tee_svc_storage_read_head(struct tee_ta_session *sess,
247 				     struct tee_obj *o)
248 {
249 	TEE_Result res = TEE_SUCCESS;
250 	size_t bytes;
251 	struct tee_svc_storage_head head;
252 	char *file = NULL;
253 	const struct tee_file_operations *fops;
254 	void *attr = NULL;
255 
256 	if (o == NULL || o->pobj == NULL)
257 		return TEE_ERROR_BAD_PARAMETERS;
258 
259 	fops = o->pobj->fops;
260 
261 	file = tee_svc_storage_create_filename(sess,
262 					       o->pobj->obj_id,
263 					       o->pobj->obj_id_len,
264 					       false);
265 	if (file == NULL) {
266 		res = TEE_ERROR_OUT_OF_MEMORY;
267 		goto exit;
268 	}
269 
270 	if (fops->access(file, TEE_FS_F_OK)) {
271 		/* file not found */
272 		res = TEE_ERROR_ITEM_NOT_FOUND;
273 		goto exit;
274 	}
275 
276 	assert(!o->fh);
277 	res = fops->open(file, &o->fh);
278 	if (res != TEE_SUCCESS)
279 		goto exit;
280 
281 	/* read head */
282 	bytes = sizeof(struct tee_svc_storage_head);
283 	res = fops->read(o->fh, &head, &bytes);
284 	if (res != TEE_SUCCESS) {
285 		if (res == TEE_ERROR_CORRUPT_OBJECT)
286 			EMSG("Head corrupt\n");
287 		goto exit;
288 	}
289 
290 	if (bytes != sizeof(struct tee_svc_storage_head)) {
291 		res = TEE_ERROR_BAD_FORMAT;
292 		goto exit;
293 	}
294 
295 	res = tee_obj_set_type(o, head.objectType, head.maxKeySize);
296 	if (res != TEE_SUCCESS)
297 		goto exit;
298 
299 	if (head.meta_size) {
300 		attr = malloc(head.meta_size);
301 		if (!attr) {
302 			res = TEE_ERROR_OUT_OF_MEMORY;
303 			goto exit;
304 		}
305 
306 		/* read meta */
307 		bytes = head.meta_size;
308 		res = fops->read(o->fh, attr, &bytes);
309 		if (res != TEE_SUCCESS || bytes != head.meta_size) {
310 			res = TEE_ERROR_CORRUPT_OBJECT;
311 			goto exit;
312 		}
313 	}
314 
315 	res = tee_obj_attr_from_binary(o, attr, head.meta_size);
316 	if (res != TEE_SUCCESS)
317 		goto exit;
318 
319 	o->info.dataSize = head.ds_size;
320 	o->info.keySize = head.keySize;
321 	o->info.objectUsage = head.objectUsage;
322 	o->info.objectType = head.objectType;
323 	o->have_attrs = head.have_attrs;
324 
325 exit:
326 	free(attr);
327 	free(file);
328 
329 	return res;
330 }
331 
332 
333 static TEE_Result tee_svc_storage_init_file(struct tee_ta_session *sess,
334 					    struct tee_obj *o,
335 					    struct tee_obj *attr_o, void *data,
336 					    uint32_t len)
337 {
338 	TEE_Result res = TEE_SUCCESS;
339 	struct tee_svc_storage_head head;
340 	char *tmpfile = NULL;
341 	const struct tee_file_operations *fops;
342 	void *attr = NULL;
343 	size_t attr_size = 0;
344 
345 	if (o == NULL || o->pobj == NULL)
346 		return TEE_ERROR_BAD_PARAMETERS;
347 
348 	fops = o->pobj->fops;
349 
350 	/* create temporary persistent object filename */
351 	tmpfile = tee_svc_storage_create_filename(sess,
352 						   o->pobj->obj_id,
353 						   o->pobj->obj_id_len,
354 						   true);
355 
356 	if (tmpfile == NULL) {
357 		res = TEE_ERROR_OUT_OF_MEMORY;
358 		goto exit;
359 	}
360 
361 	res = tee_svc_storage_create_file(sess, tmpfile, fops, &o->fh);
362 	if (res != TEE_SUCCESS)
363 		goto exit;
364 
365 	if (attr_o) {
366 		res = tee_obj_set_type(o, attr_o->info.objectType,
367 				       attr_o->info.maxKeySize);
368 		if (res != TEE_SUCCESS)
369 			goto exit;
370 		res = tee_obj_attr_copy_from(o, attr_o);
371 		if (res != TEE_SUCCESS)
372 			goto exit;
373 		o->have_attrs = attr_o->have_attrs;
374 		o->info.objectUsage = attr_o->info.objectUsage;
375 		o->info.keySize = attr_o->info.keySize;
376 		res = tee_obj_attr_to_binary(o, NULL, &attr_size);
377 		if (res != TEE_SUCCESS)
378 			goto exit;
379 		if (attr_size) {
380 			attr = malloc(attr_size);
381 			if (!attr) {
382 				res = TEE_ERROR_OUT_OF_MEMORY;
383 				goto exit;
384 			}
385 			res = tee_obj_attr_to_binary(o, attr, &attr_size);
386 			if (res != TEE_SUCCESS)
387 				goto exit;
388 		}
389 	} else {
390 		res = tee_obj_set_type(o, TEE_TYPE_DATA, 0);
391 		if (res != TEE_SUCCESS)
392 			goto exit;
393 	}
394 
395 	/* write head */
396 	head.magic = TEE_SVC_STORAGE_MAGIC;
397 	head.head_size = sizeof(struct tee_svc_storage_head);
398 	head.meta_size = attr_size;
399 	head.ds_size = len;
400 	head.keySize = o->info.keySize;
401 	head.maxKeySize = o->info.maxKeySize;
402 	head.objectUsage = o->info.objectUsage;
403 	head.objectType = o->info.objectType;
404 	head.have_attrs = o->have_attrs;
405 
406 	/* write head */
407 	res = fops->write(o->fh, &head, sizeof(struct tee_svc_storage_head));
408 	if (res != TEE_SUCCESS)
409 		goto exit;
410 
411 	/* write meta */
412 	res = fops->write(o->fh, attr, attr_size);
413 	if (res != TEE_SUCCESS)
414 		goto exit;
415 
416 	/* write init data */
417 	o->info.dataSize = len;
418 
419 	/* write data to fs if needed */
420 	if (data && len)
421 		res = fops->write(o->fh, data, len);
422 
423 exit:
424 	free(attr);
425 	free(tmpfile);
426 	fops->close(&o->fh);
427 
428 	return res;
429 }
430 
431 TEE_Result syscall_storage_obj_open(unsigned long storage_id, void *object_id,
432 			size_t object_id_len, unsigned long flags,
433 			uint32_t *obj)
434 {
435 	TEE_Result res;
436 	struct tee_ta_session *sess;
437 	struct tee_obj *o = NULL;
438 	char *file = NULL;
439 	struct tee_pobj *po = NULL;
440 	struct user_ta_ctx *utc;
441 	const struct tee_file_operations *fops = file_ops(storage_id);
442 	size_t attr_size;
443 
444 	if (!fops) {
445 		res = TEE_ERROR_ITEM_NOT_FOUND;
446 		goto exit;
447 	}
448 
449 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN) {
450 		res = TEE_ERROR_BAD_PARAMETERS;
451 		goto exit;
452 	}
453 
454 	res = tee_ta_get_current_session(&sess);
455 	if (res != TEE_SUCCESS)
456 		goto err;
457 	utc = to_user_ta_ctx(sess->ctx);
458 
459 	res = tee_mmu_check_access_rights(utc,
460 					  TEE_MEMORY_ACCESS_READ |
461 					  TEE_MEMORY_ACCESS_ANY_OWNER,
462 					  (uaddr_t) object_id,
463 					  object_id_len);
464 	if (res != TEE_SUCCESS)
465 		goto err;
466 
467 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
468 			   object_id_len, flags, fops, &po);
469 	if (res != TEE_SUCCESS)
470 		goto err;
471 
472 	o = tee_obj_alloc();
473 	if (o == NULL) {
474 		tee_pobj_release(po);
475 		res = TEE_ERROR_OUT_OF_MEMORY;
476 		goto err;
477 	}
478 
479 	o->info.handleFlags =
480 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
481 	o->flags = flags;
482 	o->pobj = po;
483 	tee_obj_add(utc, o);
484 
485 	res = tee_svc_storage_read_head(sess, o);
486 	if (res != TEE_SUCCESS) {
487 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
488 			EMSG("Object corrupt");
489 			goto err;
490 		}
491 		goto oclose;
492 	}
493 
494 	res = tee_svc_copy_kaddr_to_uref(obj, o);
495 	if (res != TEE_SUCCESS)
496 		goto oclose;
497 
498 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
499 	if (res != TEE_SUCCESS)
500 		goto oclose;
501 
502 	res = fops->seek(o->fh, sizeof(struct tee_svc_storage_head) + attr_size,
503 			 TEE_DATA_SEEK_SET, NULL);
504 	if (res  != TEE_SUCCESS)
505 		goto err;
506 
507 	goto exit;
508 
509 oclose:
510 	tee_obj_close(utc, o);
511 	o = NULL;
512 
513 err:
514 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
515 		res = TEE_ERROR_CORRUPT_OBJECT;
516 	if (res == TEE_ERROR_CORRUPT_OBJECT && o)
517 		tee_svc_storage_remove_corrupt_obj(sess, o);
518 
519 exit:
520 	free(file);
521 	file = NULL;
522 	return res;
523 }
524 
525 TEE_Result syscall_storage_obj_create(unsigned long storage_id, void *object_id,
526 			size_t object_id_len, unsigned long flags,
527 			unsigned long attr, void *data, size_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 	struct tee_pobj *po = NULL;
536 	char *tmpfile = NULL;
537 	int filedoesnotexist;
538 	struct user_ta_ctx *utc;
539 	const struct tee_file_operations *fops = file_ops(storage_id);
540 	size_t attr_size;
541 
542 	if (!fops)
543 		return TEE_ERROR_ITEM_NOT_FOUND;
544 
545 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
546 		return TEE_ERROR_BAD_PARAMETERS;
547 
548 	res = tee_ta_get_current_session(&sess);
549 	if (res != TEE_SUCCESS)
550 		return res;
551 	utc = to_user_ta_ctx(sess->ctx);
552 
553 	res = tee_mmu_check_access_rights(utc,
554 					  TEE_MEMORY_ACCESS_READ |
555 					  TEE_MEMORY_ACCESS_ANY_OWNER,
556 					  (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, fops, &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(utc,
569 						  TEE_MEMORY_ACCESS_READ |
570 						  TEE_MEMORY_ACCESS_ANY_OWNER,
571 						  (uaddr_t) data, len);
572 
573 		if (res != TEE_SUCCESS)
574 			goto err;
575 	}
576 
577 	o = tee_obj_alloc();
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 		res = tee_obj_get(utc, tee_svc_uref_to_vaddr(attr),
590 				  &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 	filedoesnotexist = fops->access(file, TEE_FS_F_OK);
608 	if (!filedoesnotexist) {
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 	/*
626 	 * remove the file if it exists, because rename does not perform
627 	 * this operation. Note that it delete and rename should be atomic,
628 	 * which is not the case currently.
629 	 * Fixme: unlink must be removed once rename() support prior deletion
630 	 * of the new file name when it already exists.
631 	 */
632 	if (!filedoesnotexist)
633 		fops->remove(file);
634 	/* rename temporary persistent object filename */
635 	res = fops->rename(tmpfile, file);
636 	if (res != TEE_SUCCESS)
637 		goto rmfile;
638 
639 	res = fops->open(file, &o->fh);
640 	if (res != TEE_SUCCESS)
641 		goto err;
642 
643 	tee_obj_add(utc, o);
644 
645 	res = tee_svc_copy_kaddr_to_uref(obj, o);
646 	if (res != TEE_SUCCESS)
647 		goto oclose;
648 
649 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
650 	if (res != TEE_SUCCESS)
651 		goto oclose;
652 
653 	res = fops->seek(o->fh, sizeof(struct tee_svc_storage_head) + attr_size,
654 			 TEE_DATA_SEEK_SET, NULL);
655 	if (res != TEE_SUCCESS)
656 		goto oclose;
657 
658 	goto exit;
659 
660 oclose:
661 	tee_obj_close(utc, o);
662 	goto exit;
663 
664 rmfile:
665 	fops->remove(tmpfile);
666 
667 err:
668 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
669 		res = TEE_ERROR_CORRUPT_OBJECT;
670 	if (res == TEE_ERROR_CORRUPT_OBJECT && file)
671 		fops->remove(file);
672 	if (o)
673 		fops->close(&o->fh);
674 	if (po)
675 		tee_pobj_release(po);
676 	free(o);
677 
678 exit:
679 	free(file);
680 	free(tmpfile);
681 
682 	return res;
683 }
684 
685 TEE_Result syscall_storage_obj_del(unsigned long obj)
686 {
687 	TEE_Result res;
688 	struct tee_ta_session *sess;
689 	struct tee_obj *o;
690 	int err;
691 	char *file;
692 	struct user_ta_ctx *utc;
693 	const struct tee_file_operations *fops;
694 
695 	res = tee_ta_get_current_session(&sess);
696 	if (res != TEE_SUCCESS)
697 		return res;
698 	utc = to_user_ta_ctx(sess->ctx);
699 
700 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
701 	if (res != TEE_SUCCESS)
702 		return res;
703 
704 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META))
705 		return TEE_ERROR_ACCESS_CONFLICT;
706 
707 	if (o->pobj == NULL || o->pobj->obj_id == NULL)
708 		return TEE_ERROR_BAD_STATE;
709 
710 	file = tee_svc_storage_create_filename(sess, o->pobj->obj_id,
711 						o->pobj->obj_id_len, false);
712 	if (file == NULL)
713 		return TEE_ERROR_OUT_OF_MEMORY;
714 
715 	fops = o->pobj->fops;
716 	tee_obj_close(utc, o);
717 
718 	err = fops->access(file, TEE_FS_F_OK);
719 	if (err)
720 		/* file not found */
721 		return TEE_ERROR_STORAGE_NOT_AVAILABLE;
722 
723 	res = fops->remove(file);
724 	free(file);
725 	if (res != TEE_SUCCESS)
726 		return res;
727 
728 	return TEE_SUCCESS;
729 }
730 
731 TEE_Result syscall_storage_obj_rename(unsigned long obj, void *object_id,
732 			size_t object_id_len)
733 {
734 	TEE_Result res;
735 	struct tee_ta_session *sess;
736 	struct tee_obj *o;
737 	struct tee_pobj *po = NULL;
738 	char *new_file = NULL;
739 	char *old_file = NULL;
740 	int err = -1;
741 	struct user_ta_ctx *utc;
742 	const struct tee_file_operations *fops;
743 
744 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
745 		return TEE_ERROR_BAD_PARAMETERS;
746 
747 	res = tee_ta_get_current_session(&sess);
748 	if (res != TEE_SUCCESS)
749 		return res;
750 	utc = to_user_ta_ctx(sess->ctx);
751 
752 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
753 	if (res != TEE_SUCCESS)
754 		return res;
755 
756 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
757 		res = TEE_ERROR_BAD_STATE;
758 		goto exit;
759 	}
760 
761 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META)) {
762 		res = TEE_ERROR_BAD_STATE;
763 		goto exit;
764 	}
765 
766 	if (o->pobj == NULL || o->pobj->obj_id == NULL) {
767 		res = TEE_ERROR_BAD_STATE;
768 		goto exit;
769 	}
770 
771 	res = tee_mmu_check_access_rights(utc,
772 					TEE_MEMORY_ACCESS_READ |
773 					TEE_MEMORY_ACCESS_ANY_OWNER,
774 					(uaddr_t) object_id, object_id_len);
775 	if (res != TEE_SUCCESS)
776 		goto exit;
777 
778 	/* get new ds name */
779 	new_file = tee_svc_storage_create_filename(sess, object_id,
780 						   object_id_len, false);
781 	if (new_file == NULL) {
782 		res = TEE_ERROR_OUT_OF_MEMORY;
783 		goto exit;
784 	}
785 
786 	old_file = tee_svc_storage_create_filename(sess, o->pobj->obj_id,
787 						   o->pobj->obj_id_len, false);
788 	if (old_file == NULL) {
789 		res = TEE_ERROR_OUT_OF_MEMORY;
790 		goto exit;
791 	}
792 
793 	/* reserve dest name */
794 	fops = o->pobj->fops;
795 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
796 			   object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META,
797 			   fops, &po);
798 	if (res != TEE_SUCCESS)
799 		goto exit;
800 
801 	err = fops->access(new_file, TEE_FS_F_OK);
802 	if (err == 0) {
803 		/* file exists */
804 		res = TEE_ERROR_ACCESS_CONFLICT;
805 		goto exit;
806 	}
807 
808 	/* move */
809 	err = fops->rename(old_file, new_file);
810 	if (err) {
811 		/* error codes needs better granularity */
812 		res = TEE_ERROR_GENERIC;
813 		goto exit;
814 	}
815 
816 	res = tee_pobj_rename(o->pobj, object_id, object_id_len);
817 
818 exit:
819 	tee_pobj_release(po);
820 
821 	free(new_file);
822 	free(old_file);
823 
824 	return res;
825 }
826 
827 TEE_Result syscall_storage_alloc_enum(uint32_t *obj_enum)
828 {
829 	struct tee_storage_enum *e;
830 	struct tee_ta_session *sess;
831 	TEE_Result res;
832 	struct user_ta_ctx *utc;
833 
834 	if (obj_enum == NULL)
835 		return TEE_ERROR_BAD_PARAMETERS;
836 
837 	res = tee_ta_get_current_session(&sess);
838 	if (res != TEE_SUCCESS)
839 		return res;
840 	utc = to_user_ta_ctx(sess->ctx);
841 
842 	e = malloc(sizeof(struct tee_storage_enum));
843 	if (e == NULL)
844 		return TEE_ERROR_OUT_OF_MEMORY;
845 
846 	e->dir = NULL;
847 	e->fops = NULL;
848 	TAILQ_INSERT_TAIL(&utc->storage_enums, e, link);
849 
850 	return tee_svc_copy_kaddr_to_uref(obj_enum, e);
851 }
852 
853 TEE_Result syscall_storage_free_enum(unsigned long obj_enum)
854 {
855 	struct tee_storage_enum *e;
856 	TEE_Result res;
857 	struct tee_ta_session *sess;
858 	struct user_ta_ctx *utc;
859 
860 	res = tee_ta_get_current_session(&sess);
861 	if (res != TEE_SUCCESS)
862 		return res;
863 	utc = to_user_ta_ctx(sess->ctx);
864 
865 	res = tee_svc_storage_get_enum(utc,
866 			tee_svc_uref_to_vaddr(obj_enum), &e);
867 	if (res != TEE_SUCCESS)
868 		return res;
869 
870 	return tee_svc_close_enum(utc, e);
871 }
872 
873 TEE_Result syscall_storage_reset_enum(unsigned long obj_enum)
874 {
875 	struct tee_storage_enum *e;
876 	TEE_Result res;
877 	struct tee_ta_session *sess;
878 
879 	res = tee_ta_get_current_session(&sess);
880 	if (res != TEE_SUCCESS)
881 		return res;
882 
883 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
884 			tee_svc_uref_to_vaddr(obj_enum), &e);
885 	if (res != TEE_SUCCESS)
886 		return res;
887 
888 	e->fops->closedir(e->dir);
889 	e->dir = NULL;
890 
891 	return TEE_SUCCESS;
892 }
893 
894 static TEE_Result tee_svc_storage_set_enum(char *d_name,
895 			const struct tee_file_operations *fops,
896 			struct tee_obj *o)
897 {
898 	TEE_Result res;
899 	uint32_t blen;
900 	uint32_t hslen;
901 
902 	o->info.handleFlags =
903 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
904 	o->info.objectUsage = TEE_USAGE_DEFAULT;
905 
906 	hslen = strlen(d_name);
907 	blen = TEE_HS2B_BBUF_SIZE(hslen);
908 	o->pobj->obj_id = malloc(blen);
909 	if (!o->pobj->obj_id) {
910 		res = TEE_ERROR_OUT_OF_MEMORY;
911 		goto exit;
912 	}
913 	tee_hs2b((uint8_t *)d_name, o->pobj->obj_id, hslen, blen);
914 	o->pobj->obj_id_len = blen;
915 	o->pobj->fops = fops;
916 
917 	res = TEE_SUCCESS;
918 
919 exit:
920 	return res;
921 
922 }
923 
924 TEE_Result syscall_storage_start_enum(unsigned long obj_enum,
925 				      unsigned long storage_id)
926 {
927 	struct tee_storage_enum *e;
928 	char *dir;
929 	TEE_Result res;
930 	struct tee_ta_session *sess;
931 	const struct tee_file_operations *fops = file_ops(storage_id);
932 
933 	res = tee_ta_get_current_session(&sess);
934 	if (res != TEE_SUCCESS)
935 		return res;
936 
937 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
938 			tee_svc_uref_to_vaddr(obj_enum), &e);
939 	if (res != TEE_SUCCESS)
940 		return res;
941 
942 	if (!fops)
943 		return TEE_ERROR_ITEM_NOT_FOUND;
944 
945 	e->fops = fops;
946 	dir = tee_svc_storage_create_dirname(sess);
947 	if (dir == NULL) {
948 		res = TEE_ERROR_OUT_OF_MEMORY;
949 		goto exit;
950 	}
951 
952 	assert(!e->dir);
953 	res = fops->opendir(dir, &e->dir);
954 	free(dir);
955 exit:
956 	return res;
957 }
958 
959 TEE_Result syscall_storage_next_enum(unsigned long obj_enum,
960 			TEE_ObjectInfo *info, void *obj_id, uint64_t *len)
961 {
962 	struct tee_storage_enum *e;
963 	struct tee_fs_dirent *d;
964 	TEE_Result res = TEE_SUCCESS;
965 	struct tee_ta_session *sess;
966 	struct tee_obj *o = NULL;
967 	uint64_t l;
968 	struct user_ta_ctx *utc;
969 
970 	res = tee_ta_get_current_session(&sess);
971 	if (res != TEE_SUCCESS)
972 		goto exit;
973 	utc = to_user_ta_ctx(sess->ctx);
974 
975 	res = tee_svc_storage_get_enum(utc,
976 			tee_svc_uref_to_vaddr(obj_enum), &e);
977 	if (res != TEE_SUCCESS)
978 		goto exit;
979 
980 	/* check rights of the provided buffers */
981 	res = tee_mmu_check_access_rights(utc,
982 					TEE_MEMORY_ACCESS_WRITE |
983 					TEE_MEMORY_ACCESS_ANY_OWNER,
984 					(uaddr_t) info,
985 					sizeof(TEE_ObjectInfo));
986 	if (res != TEE_SUCCESS)
987 		goto exit;
988 
989 	res = tee_mmu_check_access_rights(utc,
990 					TEE_MEMORY_ACCESS_WRITE |
991 					TEE_MEMORY_ACCESS_ANY_OWNER,
992 					(uaddr_t) obj_id,
993 					TEE_OBJECT_ID_MAX_LEN);
994 	if (res != TEE_SUCCESS)
995 		goto exit;
996 
997 	if (!e->fops) {
998 		res = TEE_ERROR_ITEM_NOT_FOUND;
999 		goto exit;
1000 	}
1001 
1002 	res = e->fops->readdir(e->dir, &d);
1003 	if (res != TEE_SUCCESS)
1004 		goto exit;
1005 
1006 	o = tee_obj_alloc();
1007 	if (o == NULL) {
1008 		res = TEE_ERROR_OUT_OF_MEMORY;
1009 		goto exit;
1010 	}
1011 	o->flags = TEE_DATA_FLAG_SHARE_READ;
1012 
1013 	o->pobj = calloc(1, sizeof(struct tee_pobj));
1014 	if (!o->pobj) {
1015 		res = TEE_ERROR_OUT_OF_MEMORY;
1016 		goto exit;
1017 	}
1018 
1019 	res = tee_svc_storage_set_enum(d->d_name, e->fops, o);
1020 	if (res != TEE_SUCCESS)
1021 		goto exit;
1022 
1023 	res = tee_svc_storage_read_head(sess, o);
1024 	if (res != TEE_SUCCESS)
1025 		goto exit;
1026 
1027 	memcpy(info, &o->info, sizeof(TEE_ObjectInfo));
1028 	memcpy(obj_id, o->pobj->obj_id, o->pobj->obj_id_len);
1029 
1030 	l = o->pobj->obj_id_len;
1031 	res = tee_svc_copy_to_user(len, &l, sizeof(*len));
1032 
1033 exit:
1034 	if (o) {
1035 		if (o->pobj) {
1036 			o->pobj->fops->close(&o->fh);
1037 			free(o->pobj->obj_id);
1038 		}
1039 		free(o->pobj);
1040 		tee_obj_free(o);
1041 	}
1042 
1043 	return res;
1044 }
1045 
1046 TEE_Result syscall_storage_obj_read(unsigned long obj, void *data, size_t len,
1047 			uint64_t *count)
1048 {
1049 	TEE_Result res;
1050 	struct tee_ta_session *sess;
1051 	struct tee_obj *o;
1052 	uint64_t u_count;
1053 	struct user_ta_ctx *utc;
1054 	size_t bytes;
1055 
1056 	res = tee_ta_get_current_session(&sess);
1057 	if (res != TEE_SUCCESS)
1058 		goto exit;
1059 	utc = to_user_ta_ctx(sess->ctx);
1060 
1061 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
1062 	if (res != TEE_SUCCESS)
1063 		goto exit;
1064 
1065 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1066 		res = TEE_ERROR_BAD_STATE;
1067 		goto exit;
1068 	}
1069 
1070 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_READ)) {
1071 		res = TEE_ERROR_ACCESS_CONFLICT;
1072 		goto exit;
1073 	}
1074 
1075 	/* check rights of the provided buffer */
1076 	res = tee_mmu_check_access_rights(utc,
1077 					TEE_MEMORY_ACCESS_WRITE |
1078 					TEE_MEMORY_ACCESS_ANY_OWNER,
1079 					(uaddr_t) data, len);
1080 	if (res != TEE_SUCCESS)
1081 		goto exit;
1082 
1083 	bytes = len;
1084 	res = o->pobj->fops->read(o->fh, data, &bytes);
1085 	if (res != TEE_SUCCESS) {
1086 		EMSG("Error code=%x\n", (uint32_t)res);
1087 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
1088 			EMSG("Object corrupt\n");
1089 			tee_svc_storage_remove_corrupt_obj(sess, o);
1090 		}
1091 		goto exit;
1092 	}
1093 
1094 	o->info.dataPosition += bytes;
1095 
1096 	u_count = bytes;
1097 	res = tee_svc_copy_to_user(count, &u_count, sizeof(*count));
1098 exit:
1099 	return res;
1100 }
1101 
1102 TEE_Result syscall_storage_obj_write(unsigned long obj, void *data, size_t len)
1103 {
1104 	TEE_Result res;
1105 	struct tee_ta_session *sess;
1106 	struct tee_obj *o;
1107 	struct user_ta_ctx *utc;
1108 
1109 	res = tee_ta_get_current_session(&sess);
1110 	if (res != TEE_SUCCESS)
1111 		goto exit;
1112 	utc = to_user_ta_ctx(sess->ctx);
1113 
1114 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
1115 	if (res != TEE_SUCCESS)
1116 		goto exit;
1117 
1118 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1119 		res = TEE_ERROR_BAD_STATE;
1120 		goto exit;
1121 	}
1122 
1123 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) {
1124 		res = TEE_ERROR_ACCESS_CONFLICT;
1125 		goto exit;
1126 	}
1127 
1128 	/* check rights of the provided buffer */
1129 	res = tee_mmu_check_access_rights(utc,
1130 					TEE_MEMORY_ACCESS_READ |
1131 					TEE_MEMORY_ACCESS_ANY_OWNER,
1132 					(uaddr_t) data, len);
1133 	if (res != TEE_SUCCESS)
1134 		goto exit;
1135 
1136 	res = o->pobj->fops->write(o->fh, data, len);
1137 	if (res != TEE_SUCCESS)
1138 		goto exit;
1139 
1140 	o->info.dataPosition += len;
1141 	if (o->info.dataPosition > o->info.dataSize)
1142 		o->info.dataSize = o->info.dataPosition;
1143 
1144 exit:
1145 	return res;
1146 }
1147 
1148 TEE_Result syscall_storage_obj_trunc(unsigned long obj, size_t len)
1149 {
1150 	TEE_Result res;
1151 	struct tee_ta_session *sess;
1152 	struct tee_obj *o;
1153 	size_t off;
1154 	size_t attr_size;
1155 
1156 	res = tee_ta_get_current_session(&sess);
1157 	if (res != TEE_SUCCESS)
1158 		goto exit;
1159 
1160 	res = tee_obj_get(to_user_ta_ctx(sess->ctx),
1161 			  tee_svc_uref_to_vaddr(obj), &o);
1162 	if (res != TEE_SUCCESS)
1163 		goto exit;
1164 
1165 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1166 		res = TEE_ERROR_BAD_STATE;
1167 		goto exit;
1168 	}
1169 
1170 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) {
1171 		res = TEE_ERROR_ACCESS_CONFLICT;
1172 		goto exit;
1173 	}
1174 
1175 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
1176 	if (res != TEE_SUCCESS)
1177 		goto exit;
1178 
1179 	off = sizeof(struct tee_svc_storage_head) + attr_size;
1180 	res = o->pobj->fops->truncate(o->fh, len + off);
1181 	if (res != TEE_SUCCESS) {
1182 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
1183 			EMSG("Object corrupt\n");
1184 			res = tee_svc_storage_remove_corrupt_obj(sess, o);
1185 			if (res != TEE_SUCCESS)
1186 				goto exit;
1187 			res = TEE_ERROR_CORRUPT_OBJECT;
1188 			goto exit;
1189 		} else
1190 			res = TEE_ERROR_GENERIC;
1191 	}
1192 
1193 exit:
1194 	return res;
1195 }
1196 
1197 TEE_Result syscall_storage_obj_seek(unsigned long obj, int32_t offset,
1198 				    unsigned long whence)
1199 {
1200 	TEE_Result res;
1201 	struct tee_ta_session *sess;
1202 	struct tee_obj *o;
1203 	int32_t off;
1204 	size_t attr_size;
1205 
1206 	res = tee_ta_get_current_session(&sess);
1207 	if (res != TEE_SUCCESS)
1208 		goto exit;
1209 
1210 	res = tee_obj_get(to_user_ta_ctx(sess->ctx),
1211 			  tee_svc_uref_to_vaddr(obj), &o);
1212 	if (res != TEE_SUCCESS)
1213 		goto exit;
1214 
1215 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1216 		res = TEE_ERROR_BAD_STATE;
1217 		goto exit;
1218 	}
1219 
1220 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
1221 	if (res != TEE_SUCCESS)
1222 		goto exit;
1223 
1224 	off = offset;
1225 	if (whence == TEE_DATA_SEEK_SET)
1226 		off += sizeof(struct tee_svc_storage_head) + attr_size;
1227 
1228 	res = o->pobj->fops->seek(o->fh, off, whence, &off);
1229 	if (res != TEE_SUCCESS)
1230 		goto exit;
1231 	o->info.dataPosition = off - (sizeof(struct tee_svc_storage_head) +
1232 				      attr_size);
1233 
1234 exit:
1235 	return res;
1236 }
1237 
1238 void tee_svc_storage_close_all_enum(struct user_ta_ctx *utc)
1239 {
1240 	struct tee_storage_enum_head *eh = &utc->storage_enums;
1241 
1242 	/* disregard return value */
1243 	while (!TAILQ_EMPTY(eh))
1244 		tee_svc_close_enum(utc, TAILQ_FIRST(eh));
1245 }
1246