xref: /optee_os/core/tee/tee_svc_storage.c (revision 32b3180828fa15a49ccc86ecb4be9d274c140c89)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2014, STMicroelectronics International N.V.
4  * Copyright (c) 2020, 2022 Linaro Limited
5  */
6 
7 #include <config.h>
8 #include <crypto/crypto.h>
9 #include <kernel/mutex.h>
10 #include <kernel/tee_misc.h>
11 #include <kernel/tee_ta_manager.h>
12 #include <kernel/ts_manager.h>
13 #include <kernel/user_access.h>
14 #include <memtag.h>
15 #include <mm/vm.h>
16 #include <string.h>
17 #include <tee_api_defines_extensions.h>
18 #include <tee_api_defines.h>
19 #include <tee/tee_fs.h>
20 #include <tee/tee_obj.h>
21 #include <tee/tee_pobj.h>
22 #include <tee/tee_svc_cryp.h>
23 #include <tee/tee_svc.h>
24 #include <tee/tee_svc_storage.h>
25 #include <trace.h>
26 
27 /* Header of GP formated secure storage files */
28 struct tee_svc_storage_head {
29 	uint32_t attr_size;
30 	uint32_t objectSize;
31 	uint32_t maxObjectSize;
32 	uint32_t objectUsage;
33 	uint32_t objectType;
34 	uint32_t have_attrs;
35 };
36 
37 struct tee_storage_enum {
38 	TAILQ_ENTRY(tee_storage_enum) link;
39 	struct tee_fs_dir *dir;
40 	const struct tee_file_operations *fops;
41 };
42 
43 static TEE_Result tee_svc_storage_get_enum(struct user_ta_ctx *utc,
44 					   vaddr_t enum_id,
45 					   struct tee_storage_enum **e_out)
46 {
47 	struct tee_storage_enum *e;
48 
49 	TAILQ_FOREACH(e, &utc->storage_enums, link) {
50 		if (enum_id == (vaddr_t)e) {
51 			*e_out = e;
52 			return TEE_SUCCESS;
53 		}
54 	}
55 	return TEE_ERROR_BAD_PARAMETERS;
56 }
57 
58 static TEE_Result tee_svc_close_enum(struct user_ta_ctx *utc,
59 				     struct tee_storage_enum *e)
60 {
61 	if (e == NULL || utc == NULL)
62 		return TEE_ERROR_BAD_PARAMETERS;
63 
64 	TAILQ_REMOVE(&utc->storage_enums, e, link);
65 
66 	if (e->fops)
67 		e->fops->closedir(e->dir);
68 
69 	e->dir = NULL;
70 	e->fops = NULL;
71 
72 	free(e);
73 
74 	return TEE_SUCCESS;
75 }
76 
77 static void remove_corrupt_obj(struct user_ta_ctx *utc, struct tee_obj *o)
78 {
79 	o->pobj->fops->remove(o->pobj);
80 	if (!(utc->ta_ctx.flags & TA_FLAG_DONT_CLOSE_HANDLE_ON_CORRUPT_OBJECT))
81 		tee_obj_close(utc, o);
82 }
83 
84 static TEE_Result tee_svc_storage_read_head(struct tee_obj *o)
85 {
86 	TEE_Result res = TEE_SUCCESS;
87 	size_t bytes;
88 	struct tee_svc_storage_head head;
89 	const struct tee_file_operations *fops = o->pobj->fops;
90 	void *attr = NULL;
91 	size_t size;
92 	size_t tmp = 0;
93 
94 	assert(!o->fh);
95 	res = fops->open(o->pobj, &size, &o->fh);
96 	if (res != TEE_SUCCESS)
97 		goto exit;
98 
99 	/* read head */
100 	bytes = sizeof(struct tee_svc_storage_head);
101 	res = fops->read(o->fh, 0, &head, NULL, &bytes);
102 	if (res != TEE_SUCCESS) {
103 		if (res == TEE_ERROR_CORRUPT_OBJECT)
104 			EMSG("Head corrupt");
105 		goto exit;
106 	}
107 
108 	if (ADD_OVERFLOW(sizeof(head), head.attr_size, &tmp)) {
109 		res = TEE_ERROR_OVERFLOW;
110 		goto exit;
111 	}
112 	if (tmp > size) {
113 		res = TEE_ERROR_CORRUPT_OBJECT;
114 		goto exit;
115 	}
116 
117 	if (bytes != sizeof(struct tee_svc_storage_head)) {
118 		res = TEE_ERROR_BAD_FORMAT;
119 		goto exit;
120 	}
121 
122 	res = tee_obj_set_type(o, head.objectType, head.maxObjectSize);
123 	if (res != TEE_SUCCESS)
124 		goto exit;
125 
126 	o->ds_pos = tmp;
127 
128 	if (head.attr_size) {
129 		attr = malloc(head.attr_size);
130 		if (!attr) {
131 			res = TEE_ERROR_OUT_OF_MEMORY;
132 			goto exit;
133 		}
134 
135 		/* read meta */
136 		bytes = head.attr_size;
137 		res = fops->read(o->fh, sizeof(struct tee_svc_storage_head),
138 				 attr, NULL, &bytes);
139 		if (res == TEE_ERROR_OUT_OF_MEMORY)
140 			goto exit;
141 		if (res != TEE_SUCCESS || bytes != head.attr_size)
142 			res = TEE_ERROR_CORRUPT_OBJECT;
143 		if (res)
144 			goto exit;
145 	}
146 
147 	res = tee_obj_attr_from_binary(o, attr, head.attr_size);
148 	if (res != TEE_SUCCESS)
149 		goto exit;
150 
151 	o->info.dataSize = size - sizeof(head) - head.attr_size;
152 	o->info.objectSize = head.objectSize;
153 	o->info.objectUsage = head.objectUsage;
154 	o->info.objectType = head.objectType;
155 	o->have_attrs = head.have_attrs;
156 
157 exit:
158 	free(attr);
159 
160 	return res;
161 }
162 
163 TEE_Result syscall_storage_obj_open(unsigned long storage_id, void *object_id,
164 				    size_t object_id_len, unsigned long flags,
165 				    uint32_t *obj)
166 {
167 	const unsigned long valid_flags = TEE_DATA_FLAG_ACCESS_READ |
168 					  TEE_DATA_FLAG_ACCESS_WRITE |
169 					  TEE_DATA_FLAG_ACCESS_WRITE_META |
170 					  TEE_DATA_FLAG_SHARE_READ |
171 					  TEE_DATA_FLAG_SHARE_WRITE;
172 	const struct tee_file_operations *fops =
173 			tee_svc_storage_file_ops(storage_id);
174 	struct ts_session *sess = ts_get_current_session();
175 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
176 	TEE_Result res = TEE_SUCCESS;
177 	struct tee_pobj *po = NULL;
178 	struct tee_obj *o = NULL;
179 	void *oid_bbuf = NULL;
180 
181 	if (flags & ~valid_flags)
182 		return TEE_ERROR_BAD_PARAMETERS;
183 
184 	if (!fops) {
185 		res = TEE_ERROR_ITEM_NOT_FOUND;
186 		goto exit;
187 	}
188 
189 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN) {
190 		res = TEE_ERROR_BAD_PARAMETERS;
191 		goto exit;
192 	}
193 
194 	res = bb_memdup_user_private(object_id, object_id_len, &oid_bbuf);
195 	if (res)
196 		goto exit;
197 
198 	res = tee_pobj_get((void *)&sess->ctx->uuid, oid_bbuf,
199 			   object_id_len, flags, TEE_POBJ_USAGE_OPEN, fops,
200 			   &po);
201 	bb_free(oid_bbuf, object_id_len);
202 	if (res != TEE_SUCCESS)
203 		goto err;
204 
205 	o = tee_obj_alloc();
206 	if (o == NULL) {
207 		tee_pobj_release(po);
208 		res = TEE_ERROR_OUT_OF_MEMORY;
209 		goto err;
210 	}
211 
212 	o->info.handleFlags = TEE_HANDLE_FLAG_PERSISTENT |
213 			      TEE_HANDLE_FLAG_INITIALIZED | flags;
214 	o->pobj = po;
215 	tee_obj_add(utc, o);
216 
217 	res = tee_svc_storage_read_head(o);
218 	if (res != TEE_SUCCESS) {
219 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
220 			EMSG("Object corrupt");
221 			goto err;
222 		}
223 		goto oclose;
224 	}
225 
226 	res = copy_kaddr_to_uref(obj, o);
227 	if (res != TEE_SUCCESS)
228 		goto oclose;
229 
230 	goto exit;
231 
232 oclose:
233 	tee_obj_close(utc, o);
234 	o = NULL;
235 
236 err:
237 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
238 		res = TEE_ERROR_CORRUPT_OBJECT;
239 	if (res == TEE_ERROR_CORRUPT_OBJECT && o)
240 		remove_corrupt_obj(utc, o);
241 
242 exit:
243 	return res;
244 }
245 
246 static TEE_Result tee_svc_storage_init_file(struct tee_obj *o, bool overwrite,
247 					    struct tee_obj *attr_o,
248 					    void *data, uint32_t len)
249 {
250 	TEE_Result res = TEE_SUCCESS;
251 	struct tee_svc_storage_head head = { };
252 	const struct tee_file_operations *fops = o->pobj->fops;
253 	void *attr = NULL;
254 	size_t attr_size = 0;
255 
256 	if (attr_o) {
257 		if (o != attr_o) {
258 			res = tee_obj_set_type(o, attr_o->info.objectType,
259 					       attr_o->info.maxObjectSize);
260 			if (res)
261 				return res;
262 			res = tee_obj_attr_copy_from(o, attr_o);
263 			if (res)
264 				return res;
265 			o->have_attrs = attr_o->have_attrs;
266 			o->info.objectUsage = attr_o->info.objectUsage;
267 			o->info.objectSize = attr_o->info.objectSize;
268 		}
269 		res = tee_obj_attr_to_binary(o, NULL, &attr_size);
270 		if (res)
271 			return res;
272 		if (attr_size) {
273 			attr = malloc(attr_size);
274 			if (!attr)
275 				return TEE_ERROR_OUT_OF_MEMORY;
276 			res = tee_obj_attr_to_binary(o, attr, &attr_size);
277 			if (res != TEE_SUCCESS)
278 				goto exit;
279 		}
280 	} else {
281 		res = tee_obj_set_type(o, TEE_TYPE_DATA, 0);
282 		if (res != TEE_SUCCESS)
283 			goto exit;
284 	}
285 
286 	o->ds_pos = sizeof(struct tee_svc_storage_head) + attr_size;
287 
288 	/* write head */
289 	head.attr_size = attr_size;
290 	head.objectSize = o->info.objectSize;
291 	head.maxObjectSize = o->info.maxObjectSize;
292 	head.objectUsage = o->info.objectUsage;
293 	head.objectType = o->info.objectType;
294 	head.have_attrs = o->have_attrs;
295 
296 	res = fops->create(o->pobj, overwrite, &head, sizeof(head), attr,
297 			   attr_size, NULL, data, len, &o->fh);
298 
299 	if (res)
300 		o->ds_pos = 0;
301 	else
302 		o->info.dataSize = len;
303 exit:
304 	free(attr);
305 	return res;
306 }
307 
308 TEE_Result syscall_storage_obj_create(unsigned long storage_id, void *object_id,
309 			size_t object_id_len, unsigned long flags,
310 			unsigned long attr, void *data, size_t len,
311 			uint32_t *obj)
312 {
313 	const unsigned long valid_flags = TEE_DATA_FLAG_ACCESS_READ |
314 					  TEE_DATA_FLAG_ACCESS_WRITE |
315 					  TEE_DATA_FLAG_ACCESS_WRITE_META |
316 					  TEE_DATA_FLAG_SHARE_READ |
317 					  TEE_DATA_FLAG_SHARE_WRITE |
318 					  TEE_DATA_FLAG_OVERWRITE;
319 	const struct tee_file_operations *fops =
320 			tee_svc_storage_file_ops(storage_id);
321 	struct ts_session *sess = ts_get_current_session();
322 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
323 	struct tee_obj *attr_o = NULL;
324 	TEE_Result res = TEE_SUCCESS;
325 	struct tee_pobj *po = NULL;
326 	struct tee_obj *o = NULL;
327 	void *oid_bbuf = NULL;
328 
329 	if (flags & ~valid_flags)
330 		return TEE_ERROR_BAD_PARAMETERS;
331 
332 	if (!fops)
333 		return TEE_ERROR_ITEM_NOT_FOUND;
334 
335 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
336 		return TEE_ERROR_BAD_PARAMETERS;
337 
338 	object_id = memtag_strip_tag(object_id);
339 	data = memtag_strip_tag(data);
340 
341 	/* Check presence of optional buffer */
342 	if (len && !data)
343 		return TEE_ERROR_BAD_PARAMETERS;
344 
345 	res = bb_memdup_user_private(object_id, object_id_len, &oid_bbuf);
346 	if (res)
347 		return res;
348 
349 	res = tee_pobj_get((void *)&sess->ctx->uuid, oid_bbuf,
350 			   object_id_len, flags, TEE_POBJ_USAGE_CREATE,
351 			   fops, &po);
352 	bb_free(oid_bbuf, object_id_len);
353 	if (res != TEE_SUCCESS)
354 		goto err;
355 
356 	if (attr != TEE_HANDLE_NULL) {
357 		res = tee_obj_get(utc, uref_to_vaddr(attr), &attr_o);
358 		if (res != TEE_SUCCESS)
359 			goto err;
360 		/* The supplied handle must be one of an initialized object */
361 		if (!(attr_o->info.handleFlags & TEE_HANDLE_FLAG_INITIALIZED)) {
362 			res = TEE_ERROR_BAD_PARAMETERS;
363 			goto err;
364 		}
365 	}
366 
367 	if (!obj && attr_o &&
368 	    !(attr_o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
369 		/*
370 		 * The caller expects the supplied attributes handle to be
371 		 * transformed into a persistent object.
372 		 */
373 		uint32_t saved_flags = attr_o->info.handleFlags;
374 
375 		attr_o->info.handleFlags = TEE_HANDLE_FLAG_PERSISTENT |
376 					   TEE_HANDLE_FLAG_INITIALIZED | flags;
377 		attr_o->pobj = po;
378 		res = tee_svc_storage_init_file(attr_o,
379 						flags & TEE_DATA_FLAG_OVERWRITE,
380 						attr_o, data, len);
381 		if (res) {
382 			attr_o->info.handleFlags = saved_flags;
383 			attr_o->pobj = NULL;
384 			goto err;
385 		}
386 	} else {
387 		o = tee_obj_alloc();
388 		if (!o) {
389 			res = TEE_ERROR_OUT_OF_MEMORY;
390 			goto err;
391 		}
392 
393 		o->info.handleFlags = TEE_HANDLE_FLAG_PERSISTENT |
394 				      TEE_HANDLE_FLAG_INITIALIZED | flags;
395 		o->pobj = po;
396 
397 		res = tee_svc_storage_init_file(o,
398 						flags & TEE_DATA_FLAG_OVERWRITE,
399 						attr_o, data, len);
400 		if (res != TEE_SUCCESS)
401 			goto err;
402 
403 		po = NULL; /* o owns it from now on */
404 		tee_obj_add(utc, o);
405 
406 		if (obj) {
407 			res = copy_kaddr_to_uref(obj, o);
408 			if (res != TEE_SUCCESS)
409 				goto oclose;
410 		}
411 
412 		tee_pobj_create_final(o->pobj);
413 
414 		if (!obj)
415 			tee_obj_close(utc, o);
416 	}
417 
418 	return TEE_SUCCESS;
419 
420 oclose:
421 	tee_obj_close(utc, o);
422 	return res;
423 
424 err:
425 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
426 		res = TEE_ERROR_CORRUPT_OBJECT;
427 	if (res == TEE_ERROR_CORRUPT_OBJECT && po)
428 		fops->remove(po);
429 	if (o) {
430 		fops->close(&o->fh);
431 		tee_obj_free(o);
432 	}
433 	if (po)
434 		tee_pobj_release(po);
435 
436 	return res;
437 }
438 
439 TEE_Result syscall_storage_obj_del(unsigned long obj)
440 {
441 	struct ts_session *sess = ts_get_current_session();
442 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
443 	TEE_Result res = TEE_SUCCESS;
444 	struct tee_obj *o = NULL;
445 
446 	res = tee_obj_get(utc, uref_to_vaddr(obj), &o);
447 	if (res != TEE_SUCCESS)
448 		return res;
449 
450 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE_META))
451 		return TEE_ERROR_ACCESS_CONFLICT;
452 
453 	if (o->pobj == NULL || o->pobj->obj_id == NULL)
454 		return TEE_ERROR_BAD_STATE;
455 
456 	if (IS_ENABLED(CFG_NXP_SE05X)) {
457 		/* Cryptographic layer house-keeping */
458 		res = crypto_storage_obj_del(o);
459 		if (res)
460 			return res;
461 	}
462 
463 	res = o->pobj->fops->remove(o->pobj);
464 	tee_obj_close(utc, o);
465 
466 	return res;
467 }
468 
469 TEE_Result syscall_storage_obj_rename(unsigned long obj, void *object_id,
470 				      size_t object_id_len)
471 {
472 	const struct tee_file_operations *fops = NULL;
473 	struct ts_session *sess = ts_get_current_session();
474 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
475 	TEE_Result res = TEE_SUCCESS;
476 	struct tee_pobj *po = NULL;
477 	struct tee_obj *o = NULL;
478 	char *new_file = NULL;
479 	char *old_file = NULL;
480 	void *oid_bbuf = NULL;
481 
482 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
483 		return TEE_ERROR_BAD_PARAMETERS;
484 
485 	res = tee_obj_get(utc, uref_to_vaddr(obj), &o);
486 	if (res != TEE_SUCCESS)
487 		return res;
488 
489 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
490 		res = TEE_ERROR_BAD_STATE;
491 		goto exit;
492 	}
493 
494 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE_META)) {
495 		res = TEE_ERROR_BAD_STATE;
496 		goto exit;
497 	}
498 
499 	if (o->pobj == NULL || o->pobj->obj_id == NULL) {
500 		res = TEE_ERROR_BAD_STATE;
501 		goto exit;
502 	}
503 
504 	res = bb_memdup_user_private(object_id, object_id_len, &oid_bbuf);
505 	if (res)
506 		goto exit;
507 
508 	/* reserve dest name */
509 	fops = o->pobj->fops;
510 	res = tee_pobj_get((void *)&sess->ctx->uuid, oid_bbuf,
511 			   object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META,
512 			   TEE_POBJ_USAGE_RENAME, fops, &po);
513 	bb_free(oid_bbuf, object_id_len);
514 	if (res != TEE_SUCCESS)
515 		goto exit;
516 
517 	/* move */
518 	res = fops->rename(o->pobj, po, false /* no overwrite */);
519 	if (res)
520 		goto exit;
521 
522 	res = tee_pobj_rename(o->pobj, po->obj_id, po->obj_id_len);
523 
524 exit:
525 	tee_pobj_release(po);
526 
527 	free(new_file);
528 	free(old_file);
529 
530 	return res;
531 }
532 
533 TEE_Result syscall_storage_alloc_enum(uint32_t *obj_enum)
534 {
535 	struct ts_session *sess = ts_get_current_session();
536 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
537 	struct tee_storage_enum *e = NULL;
538 
539 	if (obj_enum == NULL)
540 		return TEE_ERROR_BAD_PARAMETERS;
541 
542 	e = malloc(sizeof(struct tee_storage_enum));
543 	if (e == NULL)
544 		return TEE_ERROR_OUT_OF_MEMORY;
545 
546 	e->dir = NULL;
547 	e->fops = NULL;
548 	TAILQ_INSERT_TAIL(&utc->storage_enums, e, link);
549 
550 	return copy_kaddr_to_uref(obj_enum, e);
551 }
552 
553 TEE_Result syscall_storage_free_enum(unsigned long obj_enum)
554 {
555 	struct ts_session *sess = ts_get_current_session();
556 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
557 	struct tee_storage_enum *e = NULL;
558 	TEE_Result res = TEE_SUCCESS;
559 
560 	res = tee_svc_storage_get_enum(utc,
561 			uref_to_vaddr(obj_enum), &e);
562 	if (res != TEE_SUCCESS)
563 		return res;
564 
565 	return tee_svc_close_enum(utc, e);
566 }
567 
568 TEE_Result syscall_storage_reset_enum(unsigned long obj_enum)
569 {
570 	struct ts_session *sess = ts_get_current_session();
571 	struct tee_storage_enum *e = NULL;
572 	TEE_Result res = TEE_SUCCESS;
573 
574 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
575 				       uref_to_vaddr(obj_enum), &e);
576 	if (res != TEE_SUCCESS)
577 		return res;
578 
579 	if (e->fops) {
580 		e->fops->closedir(e->dir);
581 		e->fops = NULL;
582 		e->dir = NULL;
583 	}
584 	assert(!e->dir);
585 
586 	return TEE_SUCCESS;
587 }
588 
589 TEE_Result syscall_storage_start_enum(unsigned long obj_enum,
590 				      unsigned long storage_id)
591 {
592 	struct ts_session *sess = ts_get_current_session();
593 	struct tee_storage_enum *e = NULL;
594 	TEE_Result res = TEE_SUCCESS;
595 	const struct tee_file_operations *fops =
596 			tee_svc_storage_file_ops(storage_id);
597 
598 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
599 				       uref_to_vaddr(obj_enum), &e);
600 	if (res != TEE_SUCCESS)
601 		return res;
602 
603 	if (e->dir) {
604 		e->fops->closedir(e->dir);
605 		e->dir = NULL;
606 	}
607 
608 	if (!fops)
609 		return TEE_ERROR_ITEM_NOT_FOUND;
610 
611 	e->fops = fops;
612 
613 	return fops->opendir(&sess->ctx->uuid, &e->dir);
614 }
615 
616 TEE_Result syscall_storage_next_enum(unsigned long obj_enum,
617 				     struct utee_object_info *info,
618 				     void *obj_id, uint64_t *len)
619 {
620 	struct ts_session *sess = ts_get_current_session();
621 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
622 	struct tee_storage_enum *e = NULL;
623 	struct tee_fs_dirent *d = NULL;
624 	TEE_Result res = TEE_SUCCESS;
625 	struct tee_obj *o = NULL;
626 	uint64_t l = 0;
627 	struct utee_object_info bbuf = { };
628 
629 	res = tee_svc_storage_get_enum(utc, uref_to_vaddr(obj_enum), &e);
630 	if (res != TEE_SUCCESS)
631 		goto exit;
632 
633 	info = memtag_strip_tag(info);
634 	obj_id = memtag_strip_tag(obj_id);
635 
636 	/* check rights of the provided buffers */
637 	res = vm_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_WRITE,
638 				     (uaddr_t)info, sizeof(*info));
639 	if (res != TEE_SUCCESS)
640 		goto exit;
641 
642 	res = vm_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_WRITE,
643 				     (uaddr_t)obj_id, TEE_OBJECT_ID_MAX_LEN);
644 	if (res != TEE_SUCCESS)
645 		goto exit;
646 
647 	if (!e->fops) {
648 		res = TEE_ERROR_ITEM_NOT_FOUND;
649 		goto exit;
650 	}
651 
652 	res = e->fops->readdir(e->dir, &d);
653 	if (res != TEE_SUCCESS)
654 		goto exit;
655 
656 	o = tee_obj_alloc();
657 	if (o == NULL) {
658 		res = TEE_ERROR_OUT_OF_MEMORY;
659 		goto exit;
660 	}
661 
662 	res = tee_pobj_get(&sess->ctx->uuid, d->oid, d->oidlen, 0,
663 			   TEE_POBJ_USAGE_ENUM, e->fops, &o->pobj);
664 	if (res)
665 		goto exit;
666 
667 	o->info.handleFlags = o->pobj->flags | TEE_HANDLE_FLAG_PERSISTENT |
668 			      TEE_HANDLE_FLAG_INITIALIZED;
669 
670 	res = tee_svc_storage_read_head(o);
671 	if (res != TEE_SUCCESS)
672 		goto exit;
673 
674 	bbuf = (struct utee_object_info){
675 		.obj_type = o->info.objectType,
676 		.obj_size = o->info.objectSize,
677 		.max_obj_size = o->info.maxObjectSize,
678 		.obj_usage = o->info.objectUsage,
679 		.data_size = o->info.dataSize,
680 		.data_pos = o->info.dataPosition,
681 		.handle_flags = o->info.handleFlags,
682 	};
683 	res = copy_to_user(info, &bbuf, sizeof(bbuf));
684 	if (res)
685 		goto exit;
686 
687 	res = copy_to_user(obj_id, o->pobj->obj_id, o->pobj->obj_id_len);
688 	if (res)
689 		goto exit;
690 
691 	l = o->pobj->obj_id_len;
692 	res = copy_to_user_private(len, &l, sizeof(*len));
693 
694 exit:
695 	if (o) {
696 		if (o->pobj) {
697 			o->pobj->fops->close(&o->fh);
698 			tee_pobj_release(o->pobj);
699 		}
700 		tee_obj_free(o);
701 	}
702 
703 	return res;
704 }
705 
706 TEE_Result syscall_storage_obj_read(unsigned long obj, void *data, size_t len,
707 				    uint64_t *count)
708 {
709 	struct ts_session *sess = ts_get_current_session();
710 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
711 	TEE_Result res = TEE_SUCCESS;
712 	struct tee_obj *o = NULL;
713 	uint64_t u_count = 0;
714 	size_t pos_tmp = 0;
715 	size_t bytes = 0;
716 
717 	res = tee_obj_get(utc, uref_to_vaddr(obj), &o);
718 	if (res != TEE_SUCCESS)
719 		goto exit;
720 
721 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
722 		res = TEE_ERROR_BAD_STATE;
723 		goto exit;
724 	}
725 
726 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_READ)) {
727 		res = TEE_ERROR_ACCESS_CONFLICT;
728 		goto exit;
729 	}
730 
731 	/* Guard o->info.dataPosition += bytes below from overflowing */
732 	if (ADD_OVERFLOW(o->info.dataPosition, len, &pos_tmp)) {
733 		res = TEE_ERROR_OVERFLOW;
734 		goto exit;
735 	}
736 
737 	data = memtag_strip_tag(data);
738 
739 	bytes = len;
740 	if (ADD_OVERFLOW(o->ds_pos, o->info.dataPosition, &pos_tmp)) {
741 		res = TEE_ERROR_OVERFLOW;
742 		goto exit;
743 	}
744 	res = o->pobj->fops->read(o->fh, pos_tmp, NULL, data, &bytes);
745 	if (res != TEE_SUCCESS) {
746 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
747 			EMSG("Object corrupt");
748 			remove_corrupt_obj(utc, o);
749 		}
750 		goto exit;
751 	}
752 
753 	o->info.dataPosition += bytes;
754 
755 	u_count = bytes;
756 	res = copy_to_user_private(count, &u_count, sizeof(*count));
757 exit:
758 	return res;
759 }
760 
761 TEE_Result syscall_storage_obj_write(unsigned long obj, void *data, size_t len)
762 {
763 	struct ts_session *sess = ts_get_current_session();
764 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
765 	TEE_Result res = TEE_SUCCESS;
766 	struct tee_obj *o = NULL;
767 	size_t pos_tmp = 0;
768 
769 	res = tee_obj_get(utc, uref_to_vaddr(obj), &o);
770 	if (res != TEE_SUCCESS)
771 		goto exit;
772 
773 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
774 		res = TEE_ERROR_BAD_STATE;
775 		goto exit;
776 	}
777 
778 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE)) {
779 		res = TEE_ERROR_ACCESS_CONFLICT;
780 		goto exit;
781 	}
782 
783 	/* Guard o->info.dataPosition += bytes below from overflowing */
784 	if (ADD_OVERFLOW(o->info.dataPosition, len, &pos_tmp)) {
785 		res = TEE_ERROR_OVERFLOW;
786 		goto exit;
787 	}
788 
789 	data = memtag_strip_tag(data);
790 
791 	if (ADD_OVERFLOW(o->ds_pos, o->info.dataPosition, &pos_tmp)) {
792 		res = TEE_ERROR_ACCESS_CONFLICT;
793 		goto exit;
794 	}
795 	res = o->pobj->fops->write(o->fh, pos_tmp, NULL, data, len);
796 	if (res != TEE_SUCCESS) {
797 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
798 			EMSG("Object corrupt");
799 			remove_corrupt_obj(utc, o);
800 		}
801 		goto exit;
802 	}
803 
804 	o->info.dataPosition += len;
805 	if (o->info.dataPosition > o->info.dataSize)
806 		o->info.dataSize = o->info.dataPosition;
807 
808 exit:
809 	return res;
810 }
811 
812 TEE_Result syscall_storage_obj_trunc(unsigned long obj, size_t len)
813 {
814 	struct ts_session *sess = ts_get_current_session();
815 	TEE_Result res = TEE_SUCCESS;
816 	struct tee_obj *o = NULL;
817 	size_t off = 0;
818 	size_t attr_size = 0;
819 
820 	res = tee_obj_get(to_user_ta_ctx(sess->ctx), uref_to_vaddr(obj), &o);
821 	if (res != TEE_SUCCESS)
822 		goto exit;
823 
824 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
825 		res = TEE_ERROR_BAD_STATE;
826 		goto exit;
827 	}
828 
829 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE)) {
830 		res = TEE_ERROR_ACCESS_CONFLICT;
831 		goto exit;
832 	}
833 
834 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
835 	if (res != TEE_SUCCESS)
836 		goto exit;
837 
838 	if (ADD_OVERFLOW(sizeof(struct tee_svc_storage_head), attr_size,
839 				&off)) {
840 		res = TEE_ERROR_OVERFLOW;
841 		goto exit;
842 	}
843 	if (ADD_OVERFLOW(len, off, &off)) {
844 		res = TEE_ERROR_OVERFLOW;
845 		goto exit;
846 	}
847 	res = o->pobj->fops->truncate(o->fh, off);
848 	switch (res) {
849 	case TEE_SUCCESS:
850 		o->info.dataSize = len;
851 		break;
852 	case TEE_ERROR_CORRUPT_OBJECT:
853 		EMSG("Object corruption");
854 		remove_corrupt_obj(to_user_ta_ctx(sess->ctx), o);
855 		break;
856 	default:
857 		res = TEE_ERROR_GENERIC;
858 		break;
859 	}
860 
861 exit:
862 	return res;
863 }
864 
865 TEE_Result syscall_storage_obj_seek(unsigned long obj, int32_t offset,
866 				    unsigned long whence)
867 {
868 	struct ts_session *sess = ts_get_current_session();
869 	TEE_Result res = TEE_SUCCESS;
870 	struct tee_obj *o = NULL;
871 	tee_fs_off_t new_pos = 0;
872 
873 	res = tee_obj_get(to_user_ta_ctx(sess->ctx), uref_to_vaddr(obj), &o);
874 	if (res != TEE_SUCCESS)
875 		return res;
876 
877 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT))
878 		return TEE_ERROR_BAD_STATE;
879 
880 	switch (whence) {
881 	case TEE_DATA_SEEK_SET:
882 		new_pos = offset;
883 		break;
884 	case TEE_DATA_SEEK_CUR:
885 		if (ADD_OVERFLOW(o->info.dataPosition, offset, &new_pos))
886 			return TEE_ERROR_OVERFLOW;
887 		break;
888 	case TEE_DATA_SEEK_END:
889 		if (ADD_OVERFLOW(o->info.dataSize, offset, &new_pos))
890 			return TEE_ERROR_OVERFLOW;
891 		break;
892 	default:
893 		return TEE_ERROR_BAD_PARAMETERS;
894 	}
895 
896 	if (new_pos < 0)
897 		new_pos = 0;
898 
899 	if (new_pos > TEE_DATA_MAX_POSITION) {
900 		EMSG("Position is beyond TEE_DATA_MAX_POSITION");
901 		return TEE_ERROR_BAD_PARAMETERS;
902 	}
903 
904 	o->info.dataPosition = new_pos;
905 
906 	return TEE_SUCCESS;
907 }
908 
909 void tee_svc_storage_close_all_enum(struct user_ta_ctx *utc)
910 {
911 	struct tee_storage_enum_head *eh = &utc->storage_enums;
912 
913 	/* disregard return value */
914 	while (!TAILQ_EMPTY(eh))
915 		tee_svc_close_enum(utc, TAILQ_FIRST(eh));
916 }
917