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