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