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