xref: /optee_os/core/tee/tee_svc_storage.c (revision 2ffdd194063da02d2e82a5f671893fb19ba7846c)
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 	char *dir = NULL;
200 	const struct tee_file_operations *fops = o->pobj->fops;
201 
202 	file = tee_svc_storage_create_filename(sess,
203 					       o->pobj->obj_id,
204 					       o->pobj->obj_id_len,
205 					       false);
206 	if (file == NULL) {
207 		res = TEE_ERROR_OUT_OF_MEMORY;
208 		goto exit;
209 	}
210 
211 	tee_obj_close(to_user_ta_ctx(sess->ctx), o);
212 	fops->remove(file);
213 	free(file);
214 	dir = tee_svc_storage_create_dirname(sess);
215 	if (dir != NULL) {
216 		mutex_lock(&ta_dir_mutex);
217 		fops->rmdir(dir);
218 		mutex_unlock(&ta_dir_mutex);
219 		free(dir);
220 	}
221 
222 	res = TEE_SUCCESS;
223 
224 exit:
225 	return res;
226 }
227 
228 static TEE_Result tee_svc_storage_create_file(struct tee_ta_session *sess,
229 			char *file,
230 			const struct tee_file_operations *fops,
231 			struct tee_file_handle **fh)
232 {
233 	TEE_Result res = TEE_SUCCESS;
234 	char *dir = NULL;
235 	int tmp;
236 	int err;
237 
238 	assert(!*fh);
239 	dir = tee_svc_storage_create_dirname(sess);
240 	if (dir == NULL) {
241 		res = TEE_ERROR_OUT_OF_MEMORY;
242 		goto exit;
243 	}
244 
245 	mutex_lock(&ta_dir_mutex);
246 
247 	/* try and make directory */
248 	err = fops->access(dir, TEE_FS_F_OK);
249 	if (err) {
250 		/* directory does not exists */
251 		tmp = fops->mkdir(dir, TEE_FS_S_IRUSR | TEE_FS_S_IWUSR |
252 				  TEE_FS_S_IXUSR);
253 
254 		if (tmp < 0) {
255 			/* error codes needs better granularity */
256 			res = TEE_ERROR_GENERIC;
257 			goto unlock;
258 		}
259 	}
260 
261 	/* try and open again */
262 	res = fops->create(file, true /* currently always overwrite */, fh);
263 
264 unlock:
265 	mutex_unlock(&ta_dir_mutex);
266 exit:
267 	free(dir);
268 
269 	return res;
270 }
271 
272 static TEE_Result tee_svc_storage_read_head(struct tee_ta_session *sess,
273 				     struct tee_obj *o)
274 {
275 	TEE_Result res = TEE_SUCCESS;
276 	size_t bytes;
277 	struct tee_svc_storage_head head;
278 	char *file = NULL;
279 	const struct tee_file_operations *fops;
280 	void *attr = NULL;
281 
282 	if (o == NULL || o->pobj == NULL)
283 		return TEE_ERROR_BAD_PARAMETERS;
284 
285 	fops = o->pobj->fops;
286 
287 	file = tee_svc_storage_create_filename(sess,
288 					       o->pobj->obj_id,
289 					       o->pobj->obj_id_len,
290 					       false);
291 	if (file == NULL) {
292 		res = TEE_ERROR_OUT_OF_MEMORY;
293 		goto exit;
294 	}
295 
296 	if (fops->access(file, TEE_FS_F_OK)) {
297 		/* file not found */
298 		res = TEE_ERROR_ITEM_NOT_FOUND;
299 		goto exit;
300 	}
301 
302 	assert(!o->fh);
303 	res = fops->open(file, &o->fh);
304 	if (res != TEE_SUCCESS)
305 		goto exit;
306 
307 	/* read head */
308 	bytes = sizeof(struct tee_svc_storage_head);
309 	res = fops->read(o->fh, &head, &bytes);
310 	if (res != TEE_SUCCESS) {
311 		if (res == TEE_ERROR_CORRUPT_OBJECT)
312 			EMSG("Head corrupt\n");
313 		goto exit;
314 	}
315 
316 	if (bytes != sizeof(struct tee_svc_storage_head)) {
317 		res = TEE_ERROR_BAD_FORMAT;
318 		goto exit;
319 	}
320 
321 	res = tee_obj_set_type(o, head.objectType, head.maxKeySize);
322 	if (res != TEE_SUCCESS)
323 		goto exit;
324 
325 	if (head.meta_size) {
326 		attr = malloc(head.meta_size);
327 		if (!attr) {
328 			res = TEE_ERROR_OUT_OF_MEMORY;
329 			goto exit;
330 		}
331 
332 		/* read meta */
333 		bytes = head.meta_size;
334 		res = fops->read(o->fh, attr, &bytes);
335 		if (res != TEE_SUCCESS || bytes != head.meta_size) {
336 			res = TEE_ERROR_CORRUPT_OBJECT;
337 			goto exit;
338 		}
339 	}
340 
341 	res = tee_obj_attr_from_binary(o, attr, head.meta_size);
342 	if (res != TEE_SUCCESS)
343 		goto exit;
344 
345 	o->info.dataSize = head.ds_size;
346 	o->info.keySize = head.keySize;
347 	o->info.objectUsage = head.objectUsage;
348 	o->info.objectType = head.objectType;
349 	o->have_attrs = head.have_attrs;
350 
351 exit:
352 	free(attr);
353 	free(file);
354 
355 	return res;
356 }
357 
358 
359 static TEE_Result tee_svc_storage_init_file(struct tee_ta_session *sess,
360 					    struct tee_obj *o,
361 					    struct tee_obj *attr_o, void *data,
362 					    uint32_t len)
363 {
364 	TEE_Result res = TEE_SUCCESS;
365 	struct tee_svc_storage_head head;
366 	char *tmpfile = NULL;
367 	const struct tee_file_operations *fops;
368 	void *attr = NULL;
369 	size_t attr_size = 0;
370 
371 	if (o == NULL || o->pobj == NULL)
372 		return TEE_ERROR_BAD_PARAMETERS;
373 
374 	fops = o->pobj->fops;
375 
376 	/* create temporary persistent object filename */
377 	tmpfile = tee_svc_storage_create_filename(sess,
378 						   o->pobj->obj_id,
379 						   o->pobj->obj_id_len,
380 						   true);
381 
382 	if (tmpfile == NULL) {
383 		res = TEE_ERROR_OUT_OF_MEMORY;
384 		goto exit;
385 	}
386 
387 	res = tee_svc_storage_create_file(sess, tmpfile, fops, &o->fh);
388 	if (res != TEE_SUCCESS)
389 		goto exit;
390 
391 	if (attr_o) {
392 		res = tee_obj_set_type(o, attr_o->info.objectType,
393 				       attr_o->info.maxKeySize);
394 		if (res != TEE_SUCCESS)
395 			goto exit;
396 		res = tee_obj_attr_copy_from(o, attr_o);
397 		if (res != TEE_SUCCESS)
398 			goto exit;
399 		o->have_attrs = attr_o->have_attrs;
400 		o->info.objectUsage = attr_o->info.objectUsage;
401 		o->info.keySize = attr_o->info.keySize;
402 		res = tee_obj_attr_to_binary(o, NULL, &attr_size);
403 		if (res != TEE_SUCCESS)
404 			goto exit;
405 		if (attr_size) {
406 			attr = malloc(attr_size);
407 			if (!attr) {
408 				res = TEE_ERROR_OUT_OF_MEMORY;
409 				goto exit;
410 			}
411 			res = tee_obj_attr_to_binary(o, attr, &attr_size);
412 			if (res != TEE_SUCCESS)
413 				goto exit;
414 		}
415 	} else {
416 		res = tee_obj_set_type(o, TEE_TYPE_DATA, 0);
417 		if (res != TEE_SUCCESS)
418 			goto exit;
419 	}
420 
421 	/* write head */
422 	head.magic = TEE_SVC_STORAGE_MAGIC;
423 	head.head_size = sizeof(struct tee_svc_storage_head);
424 	head.meta_size = attr_size;
425 	head.ds_size = len;
426 	head.keySize = o->info.keySize;
427 	head.maxKeySize = o->info.maxKeySize;
428 	head.objectUsage = o->info.objectUsage;
429 	head.objectType = o->info.objectType;
430 	head.have_attrs = o->have_attrs;
431 
432 	/* write head */
433 	res = fops->write(o->fh, &head, sizeof(struct tee_svc_storage_head));
434 	if (res != TEE_SUCCESS)
435 		goto exit;
436 
437 	/* write meta */
438 	res = fops->write(o->fh, attr, attr_size);
439 	if (res != TEE_SUCCESS)
440 		goto exit;
441 
442 	/* write init data */
443 	o->info.dataSize = len;
444 
445 	/* write data to fs if needed */
446 	if (data && len)
447 		res = fops->write(o->fh, data, len);
448 
449 exit:
450 	free(attr);
451 	free(tmpfile);
452 	fops->close(&o->fh);
453 
454 	return res;
455 }
456 
457 TEE_Result syscall_storage_obj_open(unsigned long storage_id, void *object_id,
458 			size_t object_id_len, unsigned long flags,
459 			uint32_t *obj)
460 {
461 	TEE_Result res;
462 	struct tee_ta_session *sess;
463 	struct tee_obj *o = NULL;
464 	char *file = NULL;
465 	struct tee_pobj *po = NULL;
466 	struct user_ta_ctx *utc;
467 	const struct tee_file_operations *fops = file_ops(storage_id);
468 	size_t attr_size;
469 
470 	if (!fops) {
471 		res = TEE_ERROR_ITEM_NOT_FOUND;
472 		goto exit;
473 	}
474 
475 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN) {
476 		res = TEE_ERROR_BAD_PARAMETERS;
477 		goto exit;
478 	}
479 
480 	res = tee_ta_get_current_session(&sess);
481 	if (res != TEE_SUCCESS)
482 		goto err;
483 	utc = to_user_ta_ctx(sess->ctx);
484 
485 	res = tee_mmu_check_access_rights(utc,
486 					  TEE_MEMORY_ACCESS_READ |
487 					  TEE_MEMORY_ACCESS_ANY_OWNER,
488 					  (uaddr_t) object_id,
489 					  object_id_len);
490 	if (res != TEE_SUCCESS)
491 		goto err;
492 
493 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
494 			   object_id_len, flags, fops, &po);
495 	if (res != TEE_SUCCESS)
496 		goto err;
497 
498 	o = tee_obj_alloc();
499 	if (o == NULL) {
500 		tee_pobj_release(po);
501 		res = TEE_ERROR_OUT_OF_MEMORY;
502 		goto err;
503 	}
504 
505 	o->info.handleFlags =
506 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
507 	o->flags = flags;
508 	o->pobj = po;
509 	tee_obj_add(utc, o);
510 
511 	res = tee_svc_storage_read_head(sess, o);
512 	if (res != TEE_SUCCESS) {
513 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
514 			EMSG("Object corrupt");
515 			goto err;
516 		}
517 		goto oclose;
518 	}
519 
520 	res = tee_svc_copy_kaddr_to_uref(obj, o);
521 	if (res != TEE_SUCCESS)
522 		goto oclose;
523 
524 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
525 	if (res != TEE_SUCCESS)
526 		goto oclose;
527 
528 	res = fops->seek(o->fh, sizeof(struct tee_svc_storage_head) + attr_size,
529 			 TEE_DATA_SEEK_SET, NULL);
530 	if (res  != TEE_SUCCESS)
531 		goto err;
532 
533 	goto exit;
534 
535 oclose:
536 	tee_obj_close(utc, o);
537 	o = NULL;
538 
539 err:
540 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
541 		res = TEE_ERROR_CORRUPT_OBJECT;
542 	if (res == TEE_ERROR_CORRUPT_OBJECT && o)
543 		tee_svc_storage_remove_corrupt_obj(sess, o);
544 
545 exit:
546 	free(file);
547 	file = NULL;
548 	return res;
549 }
550 
551 TEE_Result syscall_storage_obj_create(unsigned long storage_id, void *object_id,
552 			size_t object_id_len, unsigned long flags,
553 			unsigned long attr, void *data, size_t len,
554 			uint32_t *obj)
555 {
556 	TEE_Result res;
557 	struct tee_ta_session *sess;
558 	struct tee_obj *o = NULL;
559 	struct tee_obj *attr_o = NULL;
560 	char *file = NULL;
561 	struct tee_pobj *po = NULL;
562 	char *tmpfile = NULL;
563 	int filedoesnotexist;
564 	struct user_ta_ctx *utc;
565 	const struct tee_file_operations *fops = file_ops(storage_id);
566 	size_t attr_size;
567 
568 	if (!fops)
569 		return TEE_ERROR_ITEM_NOT_FOUND;
570 
571 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
572 		return TEE_ERROR_BAD_PARAMETERS;
573 
574 	res = tee_ta_get_current_session(&sess);
575 	if (res != TEE_SUCCESS)
576 		return res;
577 	utc = to_user_ta_ctx(sess->ctx);
578 
579 	res = tee_mmu_check_access_rights(utc,
580 					  TEE_MEMORY_ACCESS_READ |
581 					  TEE_MEMORY_ACCESS_ANY_OWNER,
582 					  (uaddr_t) object_id,
583 					  object_id_len);
584 	if (res != TEE_SUCCESS)
585 		goto err;
586 
587 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
588 			   object_id_len, flags, fops, &po);
589 	if (res != TEE_SUCCESS)
590 		goto err;
591 
592 	/* check rights of the provided buffer */
593 	if (data && len) {
594 		res = tee_mmu_check_access_rights(utc,
595 						  TEE_MEMORY_ACCESS_READ |
596 						  TEE_MEMORY_ACCESS_ANY_OWNER,
597 						  (uaddr_t) data, len);
598 
599 		if (res != TEE_SUCCESS)
600 			goto err;
601 	}
602 
603 	o = tee_obj_alloc();
604 	if (o == NULL) {
605 		res = TEE_ERROR_OUT_OF_MEMORY;
606 		goto err;
607 	}
608 
609 	o->info.handleFlags =
610 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
611 	o->flags = flags;
612 	o->pobj = po;
613 
614 	if (attr != TEE_HANDLE_NULL) {
615 		res = tee_obj_get(utc, tee_svc_uref_to_vaddr(attr),
616 				  &attr_o);
617 		if (res != TEE_SUCCESS)
618 			goto err;
619 	}
620 
621 	res = tee_svc_storage_init_file(sess, o, attr_o, data, len);
622 	if (res != TEE_SUCCESS)
623 		goto err;
624 
625 	/* create persistent object filename */
626 	file = tee_svc_storage_create_filename(sess, object_id,
627 					       object_id_len, false);
628 	if (file == NULL) {
629 		res = TEE_ERROR_OUT_OF_MEMORY;
630 		goto err;
631 	}
632 
633 	filedoesnotexist = fops->access(file, TEE_FS_F_OK);
634 	if (!filedoesnotexist) {
635 		/* file exists */
636 		if (!(flags & TEE_DATA_FLAG_OVERWRITE)) {
637 			res = TEE_ERROR_ACCESS_CONFLICT;
638 			goto err;
639 		}
640 	}
641 
642 	/* create temporary persistent object filename */
643 	tmpfile = tee_svc_storage_create_filename(sess, object_id,
644 						  object_id_len,
645 						  true);
646 	if (tmpfile == NULL) {
647 		res = TEE_ERROR_OUT_OF_MEMORY;
648 		goto err;
649 	}
650 
651 	/*
652 	 * remove the file if it exists, because rename does not perform
653 	 * this operation. Note that it delete and rename should be atomic,
654 	 * which is not the case currently.
655 	 * Fixme: unlink must be removed once rename() support prior deletion
656 	 * of the new file name when it already exists.
657 	 */
658 	if (!filedoesnotexist)
659 		fops->remove(file);
660 	/* rename temporary persistent object filename */
661 	res = fops->rename(tmpfile, file);
662 	if (res != TEE_SUCCESS)
663 		goto rmfile;
664 
665 	res = fops->open(file, &o->fh);
666 	if (res != TEE_SUCCESS)
667 		goto err;
668 
669 	tee_obj_add(utc, o);
670 
671 	res = tee_svc_copy_kaddr_to_uref(obj, o);
672 	if (res != TEE_SUCCESS)
673 		goto oclose;
674 
675 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
676 	if (res != TEE_SUCCESS)
677 		goto oclose;
678 
679 	res = fops->seek(o->fh, sizeof(struct tee_svc_storage_head) + attr_size,
680 			 TEE_DATA_SEEK_SET, NULL);
681 	if (res != TEE_SUCCESS)
682 		goto oclose;
683 
684 	goto exit;
685 
686 oclose:
687 	tee_obj_close(utc, o);
688 	goto exit;
689 
690 rmfile:
691 	fops->remove(tmpfile);
692 
693 err:
694 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
695 		res = TEE_ERROR_CORRUPT_OBJECT;
696 	if (res == TEE_ERROR_CORRUPT_OBJECT && file)
697 		fops->remove(file);
698 	if (o)
699 		fops->close(&o->fh);
700 	if (po)
701 		tee_pobj_release(po);
702 	free(o);
703 
704 exit:
705 	free(file);
706 	free(tmpfile);
707 
708 	return res;
709 }
710 
711 TEE_Result syscall_storage_obj_del(unsigned long obj)
712 {
713 	TEE_Result res;
714 	struct tee_ta_session *sess;
715 	struct tee_obj *o;
716 	int err;
717 	char *file;
718 	char *dir;
719 	struct user_ta_ctx *utc;
720 	const struct tee_file_operations *fops;
721 
722 	res = tee_ta_get_current_session(&sess);
723 	if (res != TEE_SUCCESS)
724 		return res;
725 	utc = to_user_ta_ctx(sess->ctx);
726 
727 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
728 	if (res != TEE_SUCCESS)
729 		return res;
730 
731 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META))
732 		return TEE_ERROR_ACCESS_CONFLICT;
733 
734 	if (o->pobj == NULL || o->pobj->obj_id == NULL)
735 		return TEE_ERROR_BAD_STATE;
736 
737 	file = tee_svc_storage_create_filename(sess, o->pobj->obj_id,
738 						o->pobj->obj_id_len, false);
739 	if (file == NULL)
740 		return TEE_ERROR_OUT_OF_MEMORY;
741 
742 	fops = o->pobj->fops;
743 	tee_obj_close(utc, o);
744 
745 	err = fops->access(file, TEE_FS_F_OK);
746 	if (err)
747 		/* file not found */
748 		return TEE_ERROR_STORAGE_NOT_AVAILABLE;
749 
750 	res = fops->remove(file);
751 	free(file);
752 	if (res != TEE_SUCCESS)
753 		return res;
754 
755 	/* try and remove dir */
756 	dir = tee_svc_storage_create_dirname(sess);
757 	if (dir == NULL)
758 		return TEE_ERROR_OUT_OF_MEMORY;
759 	mutex_lock(&ta_dir_mutex);
760 	/* ignore result */
761 	fops->rmdir(dir);
762 	mutex_unlock(&ta_dir_mutex);
763 	free(dir);
764 
765 	return TEE_SUCCESS;
766 }
767 
768 TEE_Result syscall_storage_obj_rename(unsigned long obj, void *object_id,
769 			size_t object_id_len)
770 {
771 	TEE_Result res;
772 	struct tee_ta_session *sess;
773 	struct tee_obj *o;
774 	struct tee_pobj *po = NULL;
775 	char *new_file = NULL;
776 	char *old_file = NULL;
777 	int err = -1;
778 	struct user_ta_ctx *utc;
779 	const struct tee_file_operations *fops;
780 
781 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
782 		return TEE_ERROR_BAD_PARAMETERS;
783 
784 	res = tee_ta_get_current_session(&sess);
785 	if (res != TEE_SUCCESS)
786 		return res;
787 	utc = to_user_ta_ctx(sess->ctx);
788 
789 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
790 	if (res != TEE_SUCCESS)
791 		return res;
792 
793 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
794 		res = TEE_ERROR_BAD_STATE;
795 		goto exit;
796 	}
797 
798 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META)) {
799 		res = TEE_ERROR_BAD_STATE;
800 		goto exit;
801 	}
802 
803 	if (o->pobj == NULL || o->pobj->obj_id == NULL) {
804 		res = TEE_ERROR_BAD_STATE;
805 		goto exit;
806 	}
807 
808 	res = tee_mmu_check_access_rights(utc,
809 					TEE_MEMORY_ACCESS_READ |
810 					TEE_MEMORY_ACCESS_ANY_OWNER,
811 					(uaddr_t) object_id, object_id_len);
812 	if (res != TEE_SUCCESS)
813 		goto exit;
814 
815 	/* get new ds name */
816 	new_file = tee_svc_storage_create_filename(sess, object_id,
817 						   object_id_len, false);
818 	if (new_file == NULL) {
819 		res = TEE_ERROR_OUT_OF_MEMORY;
820 		goto exit;
821 	}
822 
823 	old_file = tee_svc_storage_create_filename(sess, o->pobj->obj_id,
824 						   o->pobj->obj_id_len, false);
825 	if (old_file == NULL) {
826 		res = TEE_ERROR_OUT_OF_MEMORY;
827 		goto exit;
828 	}
829 
830 	/* reserve dest name */
831 	fops = o->pobj->fops;
832 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
833 			   object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META,
834 			   fops, &po);
835 	if (res != TEE_SUCCESS)
836 		goto exit;
837 
838 	err = fops->access(new_file, TEE_FS_F_OK);
839 	if (err == 0) {
840 		/* file exists */
841 		res = TEE_ERROR_ACCESS_CONFLICT;
842 		goto exit;
843 	}
844 
845 	/* move */
846 	err = fops->rename(old_file, new_file);
847 	if (err) {
848 		/* error codes needs better granularity */
849 		res = TEE_ERROR_GENERIC;
850 		goto exit;
851 	}
852 
853 	res = tee_pobj_rename(o->pobj, object_id, object_id_len);
854 
855 exit:
856 	tee_pobj_release(po);
857 
858 	free(new_file);
859 	free(old_file);
860 
861 	return res;
862 }
863 
864 TEE_Result syscall_storage_alloc_enum(uint32_t *obj_enum)
865 {
866 	struct tee_storage_enum *e;
867 	struct tee_ta_session *sess;
868 	TEE_Result res;
869 	struct user_ta_ctx *utc;
870 
871 	if (obj_enum == NULL)
872 		return TEE_ERROR_BAD_PARAMETERS;
873 
874 	res = tee_ta_get_current_session(&sess);
875 	if (res != TEE_SUCCESS)
876 		return res;
877 	utc = to_user_ta_ctx(sess->ctx);
878 
879 	e = malloc(sizeof(struct tee_storage_enum));
880 	if (e == NULL)
881 		return TEE_ERROR_OUT_OF_MEMORY;
882 
883 	e->dir = NULL;
884 	e->fops = NULL;
885 	TAILQ_INSERT_TAIL(&utc->storage_enums, e, link);
886 
887 	return tee_svc_copy_kaddr_to_uref(obj_enum, e);
888 }
889 
890 TEE_Result syscall_storage_free_enum(unsigned long obj_enum)
891 {
892 	struct tee_storage_enum *e;
893 	TEE_Result res;
894 	struct tee_ta_session *sess;
895 	struct user_ta_ctx *utc;
896 
897 	res = tee_ta_get_current_session(&sess);
898 	if (res != TEE_SUCCESS)
899 		return res;
900 	utc = to_user_ta_ctx(sess->ctx);
901 
902 	res = tee_svc_storage_get_enum(utc,
903 			tee_svc_uref_to_vaddr(obj_enum), &e);
904 	if (res != TEE_SUCCESS)
905 		return res;
906 
907 	return tee_svc_close_enum(utc, e);
908 }
909 
910 TEE_Result syscall_storage_reset_enum(unsigned long obj_enum)
911 {
912 	struct tee_storage_enum *e;
913 	TEE_Result res;
914 	struct tee_ta_session *sess;
915 
916 	res = tee_ta_get_current_session(&sess);
917 	if (res != TEE_SUCCESS)
918 		return res;
919 
920 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
921 			tee_svc_uref_to_vaddr(obj_enum), &e);
922 	if (res != TEE_SUCCESS)
923 		return res;
924 
925 	e->fops->closedir(e->dir);
926 	e->dir = NULL;
927 
928 	return TEE_SUCCESS;
929 }
930 
931 static TEE_Result tee_svc_storage_set_enum(char *d_name,
932 			const struct tee_file_operations *fops,
933 			struct tee_obj *o)
934 {
935 	TEE_Result res;
936 	uint32_t blen;
937 	uint32_t hslen;
938 
939 	o->info.handleFlags =
940 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
941 	o->info.objectUsage = TEE_USAGE_DEFAULT;
942 
943 	hslen = strlen(d_name);
944 	blen = TEE_HS2B_BBUF_SIZE(hslen);
945 	o->pobj->obj_id = malloc(blen);
946 	if (!o->pobj->obj_id) {
947 		res = TEE_ERROR_OUT_OF_MEMORY;
948 		goto exit;
949 	}
950 	tee_hs2b((uint8_t *)d_name, o->pobj->obj_id, hslen, blen);
951 	o->pobj->obj_id_len = blen;
952 	o->pobj->fops = fops;
953 
954 	res = TEE_SUCCESS;
955 
956 exit:
957 	return res;
958 
959 }
960 
961 TEE_Result syscall_storage_start_enum(unsigned long obj_enum,
962 				      unsigned long storage_id)
963 {
964 	struct tee_storage_enum *e;
965 	char *dir;
966 	TEE_Result res;
967 	struct tee_ta_session *sess;
968 	const struct tee_file_operations *fops = file_ops(storage_id);
969 
970 	res = tee_ta_get_current_session(&sess);
971 	if (res != TEE_SUCCESS)
972 		return res;
973 
974 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
975 			tee_svc_uref_to_vaddr(obj_enum), &e);
976 	if (res != TEE_SUCCESS)
977 		return res;
978 
979 	if (!fops)
980 		return TEE_ERROR_ITEM_NOT_FOUND;
981 
982 	e->fops = fops;
983 	dir = tee_svc_storage_create_dirname(sess);
984 	if (dir == NULL) {
985 		res = TEE_ERROR_OUT_OF_MEMORY;
986 		goto exit;
987 	}
988 
989 	assert(!e->dir);
990 	res = fops->opendir(dir, &e->dir);
991 	free(dir);
992 exit:
993 	return res;
994 }
995 
996 TEE_Result syscall_storage_next_enum(unsigned long obj_enum,
997 			TEE_ObjectInfo *info, void *obj_id, uint64_t *len)
998 {
999 	struct tee_storage_enum *e;
1000 	struct tee_fs_dirent *d;
1001 	TEE_Result res = TEE_SUCCESS;
1002 	struct tee_ta_session *sess;
1003 	struct tee_obj *o = NULL;
1004 	uint64_t l;
1005 	struct user_ta_ctx *utc;
1006 
1007 	res = tee_ta_get_current_session(&sess);
1008 	if (res != TEE_SUCCESS)
1009 		goto exit;
1010 	utc = to_user_ta_ctx(sess->ctx);
1011 
1012 	res = tee_svc_storage_get_enum(utc,
1013 			tee_svc_uref_to_vaddr(obj_enum), &e);
1014 	if (res != TEE_SUCCESS)
1015 		goto exit;
1016 
1017 	/* check rights of the provided buffers */
1018 	res = tee_mmu_check_access_rights(utc,
1019 					TEE_MEMORY_ACCESS_WRITE |
1020 					TEE_MEMORY_ACCESS_ANY_OWNER,
1021 					(uaddr_t) info,
1022 					sizeof(TEE_ObjectInfo));
1023 	if (res != TEE_SUCCESS)
1024 		goto exit;
1025 
1026 	res = tee_mmu_check_access_rights(utc,
1027 					TEE_MEMORY_ACCESS_WRITE |
1028 					TEE_MEMORY_ACCESS_ANY_OWNER,
1029 					(uaddr_t) obj_id,
1030 					TEE_OBJECT_ID_MAX_LEN);
1031 	if (res != TEE_SUCCESS)
1032 		goto exit;
1033 
1034 	if (!e->fops) {
1035 		res = TEE_ERROR_ITEM_NOT_FOUND;
1036 		goto exit;
1037 	}
1038 
1039 	res = e->fops->readdir(e->dir, &d);
1040 	if (res != TEE_SUCCESS)
1041 		goto exit;
1042 
1043 	o = tee_obj_alloc();
1044 	if (o == NULL) {
1045 		res = TEE_ERROR_OUT_OF_MEMORY;
1046 		goto exit;
1047 	}
1048 	o->flags = TEE_DATA_FLAG_SHARE_READ;
1049 
1050 	o->pobj = calloc(1, sizeof(struct tee_pobj));
1051 	if (!o->pobj) {
1052 		res = TEE_ERROR_OUT_OF_MEMORY;
1053 		goto exit;
1054 	}
1055 
1056 	res = tee_svc_storage_set_enum(d->d_name, e->fops, o);
1057 	if (res != TEE_SUCCESS)
1058 		goto exit;
1059 
1060 	res = tee_svc_storage_read_head(sess, o);
1061 	if (res != TEE_SUCCESS)
1062 		goto exit;
1063 
1064 	memcpy(info, &o->info, sizeof(TEE_ObjectInfo));
1065 	memcpy(obj_id, o->pobj->obj_id, o->pobj->obj_id_len);
1066 
1067 	l = o->pobj->obj_id_len;
1068 	res = tee_svc_copy_to_user(len, &l, sizeof(*len));
1069 
1070 exit:
1071 	if (o) {
1072 		if (o->pobj) {
1073 			o->pobj->fops->close(&o->fh);
1074 			free(o->pobj->obj_id);
1075 		}
1076 		free(o->pobj);
1077 		tee_obj_free(o);
1078 	}
1079 
1080 	return res;
1081 }
1082 
1083 TEE_Result syscall_storage_obj_read(unsigned long obj, void *data, size_t len,
1084 			uint64_t *count)
1085 {
1086 	TEE_Result res;
1087 	struct tee_ta_session *sess;
1088 	struct tee_obj *o;
1089 	uint64_t u_count;
1090 	struct user_ta_ctx *utc;
1091 	size_t bytes;
1092 
1093 	res = tee_ta_get_current_session(&sess);
1094 	if (res != TEE_SUCCESS)
1095 		goto exit;
1096 	utc = to_user_ta_ctx(sess->ctx);
1097 
1098 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
1099 	if (res != TEE_SUCCESS)
1100 		goto exit;
1101 
1102 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1103 		res = TEE_ERROR_BAD_STATE;
1104 		goto exit;
1105 	}
1106 
1107 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_READ)) {
1108 		res = TEE_ERROR_ACCESS_CONFLICT;
1109 		goto exit;
1110 	}
1111 
1112 	/* check rights of the provided buffer */
1113 	res = tee_mmu_check_access_rights(utc,
1114 					TEE_MEMORY_ACCESS_WRITE |
1115 					TEE_MEMORY_ACCESS_ANY_OWNER,
1116 					(uaddr_t) data, len);
1117 	if (res != TEE_SUCCESS)
1118 		goto exit;
1119 
1120 	bytes = len;
1121 	res = o->pobj->fops->read(o->fh, data, &bytes);
1122 	if (res != TEE_SUCCESS) {
1123 		EMSG("Error code=%x\n", (uint32_t)res);
1124 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
1125 			EMSG("Object corrupt\n");
1126 			tee_svc_storage_remove_corrupt_obj(sess, o);
1127 		}
1128 		goto exit;
1129 	}
1130 
1131 	o->info.dataPosition += bytes;
1132 
1133 	u_count = bytes;
1134 	res = tee_svc_copy_to_user(count, &u_count, sizeof(*count));
1135 exit:
1136 	return res;
1137 }
1138 
1139 TEE_Result syscall_storage_obj_write(unsigned long obj, void *data, size_t len)
1140 {
1141 	TEE_Result res;
1142 	struct tee_ta_session *sess;
1143 	struct tee_obj *o;
1144 	struct user_ta_ctx *utc;
1145 
1146 	res = tee_ta_get_current_session(&sess);
1147 	if (res != TEE_SUCCESS)
1148 		goto exit;
1149 	utc = to_user_ta_ctx(sess->ctx);
1150 
1151 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
1152 	if (res != TEE_SUCCESS)
1153 		goto exit;
1154 
1155 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1156 		res = TEE_ERROR_BAD_STATE;
1157 		goto exit;
1158 	}
1159 
1160 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) {
1161 		res = TEE_ERROR_ACCESS_CONFLICT;
1162 		goto exit;
1163 	}
1164 
1165 	/* check rights of the provided buffer */
1166 	res = tee_mmu_check_access_rights(utc,
1167 					TEE_MEMORY_ACCESS_READ |
1168 					TEE_MEMORY_ACCESS_ANY_OWNER,
1169 					(uaddr_t) data, len);
1170 	if (res != TEE_SUCCESS)
1171 		goto exit;
1172 
1173 	res = o->pobj->fops->write(o->fh, data, len);
1174 	if (res != TEE_SUCCESS)
1175 		goto exit;
1176 
1177 	o->info.dataPosition += len;
1178 	if (o->info.dataPosition > o->info.dataSize)
1179 		o->info.dataSize = o->info.dataPosition;
1180 
1181 exit:
1182 	return res;
1183 }
1184 
1185 TEE_Result syscall_storage_obj_trunc(unsigned long obj, size_t len)
1186 {
1187 	TEE_Result res;
1188 	struct tee_ta_session *sess;
1189 	struct tee_obj *o;
1190 	size_t off;
1191 	size_t attr_size;
1192 
1193 	res = tee_ta_get_current_session(&sess);
1194 	if (res != TEE_SUCCESS)
1195 		goto exit;
1196 
1197 	res = tee_obj_get(to_user_ta_ctx(sess->ctx),
1198 			  tee_svc_uref_to_vaddr(obj), &o);
1199 	if (res != TEE_SUCCESS)
1200 		goto exit;
1201 
1202 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1203 		res = TEE_ERROR_BAD_STATE;
1204 		goto exit;
1205 	}
1206 
1207 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) {
1208 		res = TEE_ERROR_ACCESS_CONFLICT;
1209 		goto exit;
1210 	}
1211 
1212 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
1213 	if (res != TEE_SUCCESS)
1214 		goto exit;
1215 
1216 	off = sizeof(struct tee_svc_storage_head) + attr_size;
1217 	res = o->pobj->fops->truncate(o->fh, len + off);
1218 	if (res != TEE_SUCCESS) {
1219 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
1220 			EMSG("Object corrupt\n");
1221 			res = tee_svc_storage_remove_corrupt_obj(sess, o);
1222 			if (res != TEE_SUCCESS)
1223 				goto exit;
1224 			res = TEE_ERROR_CORRUPT_OBJECT;
1225 			goto exit;
1226 		} else
1227 			res = TEE_ERROR_GENERIC;
1228 	}
1229 
1230 exit:
1231 	return res;
1232 }
1233 
1234 TEE_Result syscall_storage_obj_seek(unsigned long obj, int32_t offset,
1235 				    unsigned long whence)
1236 {
1237 	TEE_Result res;
1238 	struct tee_ta_session *sess;
1239 	struct tee_obj *o;
1240 	int32_t off;
1241 	size_t attr_size;
1242 
1243 	res = tee_ta_get_current_session(&sess);
1244 	if (res != TEE_SUCCESS)
1245 		goto exit;
1246 
1247 	res = tee_obj_get(to_user_ta_ctx(sess->ctx),
1248 			  tee_svc_uref_to_vaddr(obj), &o);
1249 	if (res != TEE_SUCCESS)
1250 		goto exit;
1251 
1252 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1253 		res = TEE_ERROR_BAD_STATE;
1254 		goto exit;
1255 	}
1256 
1257 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
1258 	if (res != TEE_SUCCESS)
1259 		goto exit;
1260 
1261 	off = offset;
1262 	if (whence == TEE_DATA_SEEK_SET)
1263 		off += sizeof(struct tee_svc_storage_head) + attr_size;
1264 
1265 	res = o->pobj->fops->seek(o->fh, off, whence, &off);
1266 	if (res != TEE_SUCCESS)
1267 		goto exit;
1268 	o->info.dataPosition = off - (sizeof(struct tee_svc_storage_head) +
1269 				      attr_size);
1270 
1271 exit:
1272 	return res;
1273 }
1274 
1275 void tee_svc_storage_close_all_enum(struct user_ta_ctx *utc)
1276 {
1277 	struct tee_storage_enum_head *eh = &utc->storage_enums;
1278 
1279 	/* disregard return value */
1280 	while (!TAILQ_EMPTY(eh))
1281 		tee_svc_close_enum(utc, TAILQ_FIRST(eh));
1282 }
1283