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