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