xref: /optee_os/core/tee/tee_svc_storage.c (revision 79f8990d9d28539864d8f97f9f1cb32e289e595f)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2014, STMicroelectronics International N.V.
4  * Copyright (c) 2020, 2022-2023 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->pobj->obj_info_usage = 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 	tee_pobj_lock_usage(o->pobj);
218 	res = tee_svc_storage_read_head(o);
219 	tee_pobj_unlock_usage(o->pobj);
220 	if (res != TEE_SUCCESS) {
221 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
222 			EMSG("Object corrupt");
223 			goto err;
224 		}
225 		goto oclose;
226 	}
227 
228 	res = copy_kaddr_to_uref(obj, o);
229 	if (res != TEE_SUCCESS)
230 		goto oclose;
231 
232 	goto exit;
233 
234 oclose:
235 	tee_obj_close(utc, o);
236 	o = NULL;
237 
238 err:
239 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
240 		res = TEE_ERROR_CORRUPT_OBJECT;
241 	if (res == TEE_ERROR_CORRUPT_OBJECT && o)
242 		remove_corrupt_obj(utc, o);
243 
244 exit:
245 	return res;
246 }
247 
248 static TEE_Result tee_svc_storage_init_file(struct tee_obj *o, bool overwrite,
249 					    struct tee_obj *attr_o,
250 					    void *data, uint32_t len)
251 {
252 	TEE_Result res = TEE_SUCCESS;
253 	struct tee_svc_storage_head head = { };
254 	const struct tee_file_operations *fops = o->pobj->fops;
255 	void *attr = NULL;
256 	size_t attr_size = 0;
257 
258 	if (attr_o) {
259 		if (o != attr_o) {
260 			res = tee_obj_set_type(o, attr_o->info.objectType,
261 					       attr_o->info.maxObjectSize);
262 			if (res)
263 				return res;
264 			res = tee_obj_attr_copy_from(o, attr_o);
265 			if (res)
266 				return res;
267 			o->have_attrs = attr_o->have_attrs;
268 			o->pobj->obj_info_usage = attr_o->info.objectUsage;
269 			o->info.objectSize = attr_o->info.objectSize;
270 		}
271 		res = tee_obj_attr_to_binary(o, NULL, &attr_size);
272 		if (res)
273 			return res;
274 		if (attr_size) {
275 			attr = malloc(attr_size);
276 			if (!attr)
277 				return TEE_ERROR_OUT_OF_MEMORY;
278 			res = tee_obj_attr_to_binary(o, attr, &attr_size);
279 			if (res != TEE_SUCCESS)
280 				goto exit;
281 		}
282 	} else {
283 		res = tee_obj_set_type(o, TEE_TYPE_DATA, 0);
284 		if (res != TEE_SUCCESS)
285 			goto exit;
286 	}
287 
288 	o->ds_pos = sizeof(struct tee_svc_storage_head) + attr_size;
289 
290 	/* write head */
291 	head.attr_size = attr_size;
292 	head.objectSize = o->info.objectSize;
293 	head.maxObjectSize = o->info.maxObjectSize;
294 	head.objectUsage = o->pobj->obj_info_usage;
295 	head.objectType = o->info.objectType;
296 	head.have_attrs = o->have_attrs;
297 
298 	res = fops->create(o->pobj, overwrite, &head, sizeof(head), attr,
299 			   attr_size, NULL, data, len, &o->fh);
300 
301 	if (res)
302 		o->ds_pos = 0;
303 	else
304 		o->info.dataSize = len;
305 exit:
306 	free(attr);
307 	return res;
308 }
309 
310 TEE_Result syscall_storage_obj_create(unsigned long storage_id, void *object_id,
311 			size_t object_id_len, unsigned long flags,
312 			unsigned long attr, void *data, size_t len,
313 			uint32_t *obj)
314 {
315 	const unsigned long valid_flags = TEE_DATA_FLAG_ACCESS_READ |
316 					  TEE_DATA_FLAG_ACCESS_WRITE |
317 					  TEE_DATA_FLAG_ACCESS_WRITE_META |
318 					  TEE_DATA_FLAG_SHARE_READ |
319 					  TEE_DATA_FLAG_SHARE_WRITE |
320 					  TEE_DATA_FLAG_OVERWRITE;
321 	const struct tee_file_operations *fops =
322 			tee_svc_storage_file_ops(storage_id);
323 	struct ts_session *sess = ts_get_current_session();
324 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
325 	struct tee_obj *attr_o = NULL;
326 	TEE_Result res = TEE_SUCCESS;
327 	struct tee_pobj *po = NULL;
328 	struct tee_obj *o = NULL;
329 	void *oid_bbuf = NULL;
330 
331 	if (flags & ~valid_flags)
332 		return TEE_ERROR_BAD_PARAMETERS;
333 
334 	if (!fops)
335 		return TEE_ERROR_ITEM_NOT_FOUND;
336 
337 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
338 		return TEE_ERROR_BAD_PARAMETERS;
339 
340 	object_id = memtag_strip_tag(object_id);
341 	data = memtag_strip_tag(data);
342 
343 	/* Check presence of optional buffer */
344 	if (len && !data)
345 		return TEE_ERROR_BAD_PARAMETERS;
346 
347 	res = bb_memdup_user_private(object_id, object_id_len, &oid_bbuf);
348 	if (res)
349 		return res;
350 
351 	res = tee_pobj_get((void *)&sess->ctx->uuid, oid_bbuf,
352 			   object_id_len, flags, TEE_POBJ_USAGE_CREATE,
353 			   fops, &po);
354 	bb_free(oid_bbuf, object_id_len);
355 	if (res != TEE_SUCCESS)
356 		goto err;
357 
358 	if (attr != TEE_HANDLE_NULL) {
359 		res = tee_obj_get(utc, uref_to_vaddr(attr), &attr_o);
360 		if (res != TEE_SUCCESS)
361 			goto err;
362 		/* The supplied handle must be one of an initialized object */
363 		if (!(attr_o->info.handleFlags & TEE_HANDLE_FLAG_INITIALIZED)) {
364 			res = TEE_ERROR_BAD_PARAMETERS;
365 			goto err;
366 		}
367 	}
368 
369 	if (!obj && attr_o &&
370 	    !(attr_o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
371 		/*
372 		 * The caller expects the supplied attributes handle to be
373 		 * transformed into a persistent object.
374 		 *
375 		 * Persistent object keeps the objectUsage field in the
376 		 * pobj so move the field below.
377 		 */
378 		uint32_t saved_flags = attr_o->info.handleFlags;
379 
380 		attr_o->info.handleFlags = TEE_HANDLE_FLAG_PERSISTENT |
381 					   TEE_HANDLE_FLAG_INITIALIZED | flags;
382 		attr_o->pobj = po;
383 		po->obj_info_usage = attr_o->info.objectUsage;
384 		res = tee_svc_storage_init_file(attr_o,
385 						flags & TEE_DATA_FLAG_OVERWRITE,
386 						attr_o, data, len);
387 		if (res) {
388 			attr_o->info.handleFlags = saved_flags;
389 			attr_o->pobj = NULL;
390 			goto err;
391 		}
392 		attr_o->info.objectUsage = 0;
393 	} else {
394 		o = tee_obj_alloc();
395 		if (!o) {
396 			res = TEE_ERROR_OUT_OF_MEMORY;
397 			goto err;
398 		}
399 
400 		o->info.handleFlags = TEE_HANDLE_FLAG_PERSISTENT |
401 				      TEE_HANDLE_FLAG_INITIALIZED | flags;
402 		o->pobj = po;
403 
404 		res = tee_svc_storage_init_file(o,
405 						flags & TEE_DATA_FLAG_OVERWRITE,
406 						attr_o, data, len);
407 		if (res != TEE_SUCCESS)
408 			goto err;
409 
410 		po = NULL; /* o owns it from now on */
411 		tee_obj_add(utc, o);
412 
413 		if (obj) {
414 			res = copy_kaddr_to_uref(obj, o);
415 			if (res != TEE_SUCCESS)
416 				goto oclose;
417 		}
418 
419 		tee_pobj_create_final(o->pobj);
420 
421 		if (!obj)
422 			tee_obj_close(utc, o);
423 	}
424 
425 	return TEE_SUCCESS;
426 
427 oclose:
428 	tee_obj_close(utc, o);
429 	return res;
430 
431 err:
432 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
433 		res = TEE_ERROR_CORRUPT_OBJECT;
434 	if (res == TEE_ERROR_CORRUPT_OBJECT && po)
435 		fops->remove(po);
436 	if (o) {
437 		fops->close(&o->fh);
438 		tee_obj_free(o);
439 	}
440 	if (po)
441 		tee_pobj_release(po);
442 
443 	return res;
444 }
445 
446 TEE_Result syscall_storage_obj_del(unsigned long obj)
447 {
448 	struct ts_session *sess = ts_get_current_session();
449 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
450 	TEE_Result res = TEE_SUCCESS;
451 	struct tee_obj *o = NULL;
452 
453 	res = tee_obj_get(utc, uref_to_vaddr(obj), &o);
454 	if (res != TEE_SUCCESS)
455 		return res;
456 
457 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE_META))
458 		return TEE_ERROR_ACCESS_CONFLICT;
459 
460 	if (o->pobj == NULL || o->pobj->obj_id == NULL)
461 		return TEE_ERROR_BAD_STATE;
462 
463 	if (IS_ENABLED(CFG_NXP_SE05X)) {
464 		/* Cryptographic layer house-keeping */
465 		res = crypto_storage_obj_del(o);
466 		if (res)
467 			return res;
468 	}
469 
470 	res = o->pobj->fops->remove(o->pobj);
471 	tee_obj_close(utc, o);
472 
473 	return res;
474 }
475 
476 TEE_Result syscall_storage_obj_rename(unsigned long obj, void *object_id,
477 				      size_t object_id_len)
478 {
479 	const struct tee_file_operations *fops = NULL;
480 	struct ts_session *sess = ts_get_current_session();
481 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
482 	TEE_Result res = TEE_SUCCESS;
483 	struct tee_pobj *po = NULL;
484 	struct tee_obj *o = NULL;
485 	char *new_file = NULL;
486 	char *old_file = NULL;
487 	void *oid_bbuf = NULL;
488 
489 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
490 		return TEE_ERROR_BAD_PARAMETERS;
491 
492 	res = tee_obj_get(utc, uref_to_vaddr(obj), &o);
493 	if (res != TEE_SUCCESS)
494 		return res;
495 
496 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
497 		res = TEE_ERROR_BAD_STATE;
498 		goto exit;
499 	}
500 
501 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE_META)) {
502 		res = TEE_ERROR_BAD_STATE;
503 		goto exit;
504 	}
505 
506 	if (o->pobj == NULL || o->pobj->obj_id == NULL) {
507 		res = TEE_ERROR_BAD_STATE;
508 		goto exit;
509 	}
510 
511 	res = bb_memdup_user_private(object_id, object_id_len, &oid_bbuf);
512 	if (res)
513 		goto exit;
514 
515 	/* reserve dest name */
516 	fops = o->pobj->fops;
517 	res = tee_pobj_get((void *)&sess->ctx->uuid, oid_bbuf,
518 			   object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META,
519 			   TEE_POBJ_USAGE_RENAME, fops, &po);
520 	bb_free(oid_bbuf, object_id_len);
521 	if (res != TEE_SUCCESS)
522 		goto exit;
523 
524 	/* move */
525 	res = fops->rename(o->pobj, po, false /* no overwrite */);
526 	if (res)
527 		goto exit;
528 
529 	res = tee_pobj_rename(o->pobj, po->obj_id, po->obj_id_len);
530 
531 exit:
532 	tee_pobj_release(po);
533 
534 	free(new_file);
535 	free(old_file);
536 
537 	return res;
538 }
539 
540 TEE_Result syscall_storage_alloc_enum(uint32_t *obj_enum)
541 {
542 	struct ts_session *sess = ts_get_current_session();
543 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
544 	struct tee_storage_enum *e = NULL;
545 
546 	if (obj_enum == NULL)
547 		return TEE_ERROR_BAD_PARAMETERS;
548 
549 	e = malloc(sizeof(struct tee_storage_enum));
550 	if (e == NULL)
551 		return TEE_ERROR_OUT_OF_MEMORY;
552 
553 	e->dir = NULL;
554 	e->fops = NULL;
555 	TAILQ_INSERT_TAIL(&utc->storage_enums, e, link);
556 
557 	return copy_kaddr_to_uref(obj_enum, e);
558 }
559 
560 TEE_Result syscall_storage_free_enum(unsigned long obj_enum)
561 {
562 	struct ts_session *sess = ts_get_current_session();
563 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
564 	struct tee_storage_enum *e = NULL;
565 	TEE_Result res = TEE_SUCCESS;
566 
567 	res = tee_svc_storage_get_enum(utc,
568 			uref_to_vaddr(obj_enum), &e);
569 	if (res != TEE_SUCCESS)
570 		return res;
571 
572 	return tee_svc_close_enum(utc, e);
573 }
574 
575 TEE_Result syscall_storage_reset_enum(unsigned long obj_enum)
576 {
577 	struct ts_session *sess = ts_get_current_session();
578 	struct tee_storage_enum *e = NULL;
579 	TEE_Result res = TEE_SUCCESS;
580 
581 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
582 				       uref_to_vaddr(obj_enum), &e);
583 	if (res != TEE_SUCCESS)
584 		return res;
585 
586 	if (e->fops) {
587 		e->fops->closedir(e->dir);
588 		e->fops = NULL;
589 		e->dir = NULL;
590 	}
591 	assert(!e->dir);
592 
593 	return TEE_SUCCESS;
594 }
595 
596 TEE_Result syscall_storage_start_enum(unsigned long obj_enum,
597 				      unsigned long storage_id)
598 {
599 	struct ts_session *sess = ts_get_current_session();
600 	struct tee_storage_enum *e = NULL;
601 	TEE_Result res = TEE_SUCCESS;
602 	const struct tee_file_operations *fops =
603 			tee_svc_storage_file_ops(storage_id);
604 
605 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
606 				       uref_to_vaddr(obj_enum), &e);
607 	if (res != TEE_SUCCESS)
608 		return res;
609 
610 	if (e->dir) {
611 		e->fops->closedir(e->dir);
612 		e->dir = NULL;
613 	}
614 
615 	if (!fops)
616 		return TEE_ERROR_ITEM_NOT_FOUND;
617 
618 	e->fops = fops;
619 
620 	return fops->opendir(&sess->ctx->uuid, &e->dir);
621 }
622 
623 TEE_Result syscall_storage_next_enum(unsigned long obj_enum,
624 				     struct utee_object_info *info,
625 				     void *obj_id, uint64_t *len)
626 {
627 	struct ts_session *sess = ts_get_current_session();
628 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
629 	struct tee_storage_enum *e = NULL;
630 	struct tee_fs_dirent *d = NULL;
631 	TEE_Result res = TEE_SUCCESS;
632 	struct tee_obj *o = NULL;
633 	uint64_t l = 0;
634 	struct utee_object_info bbuf = { };
635 
636 	res = tee_svc_storage_get_enum(utc, uref_to_vaddr(obj_enum), &e);
637 	if (res != TEE_SUCCESS)
638 		goto exit;
639 
640 	info = memtag_strip_tag(info);
641 	obj_id = memtag_strip_tag(obj_id);
642 
643 	/* check rights of the provided buffers */
644 	res = vm_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_WRITE,
645 				     (uaddr_t)info, sizeof(*info));
646 	if (res != TEE_SUCCESS)
647 		goto exit;
648 
649 	res = vm_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_WRITE,
650 				     (uaddr_t)obj_id, TEE_OBJECT_ID_MAX_LEN);
651 	if (res != TEE_SUCCESS)
652 		goto exit;
653 
654 	if (!e->fops) {
655 		res = TEE_ERROR_ITEM_NOT_FOUND;
656 		goto exit;
657 	}
658 
659 	res = e->fops->readdir(e->dir, &d);
660 	if (res != TEE_SUCCESS)
661 		goto exit;
662 
663 	o = tee_obj_alloc();
664 	if (o == NULL) {
665 		res = TEE_ERROR_OUT_OF_MEMORY;
666 		goto exit;
667 	}
668 
669 	res = tee_pobj_get(&sess->ctx->uuid, d->oid, d->oidlen, 0,
670 			   TEE_POBJ_USAGE_ENUM, e->fops, &o->pobj);
671 	if (res)
672 		goto exit;
673 
674 	o->info.handleFlags = o->pobj->flags | TEE_HANDLE_FLAG_PERSISTENT |
675 			      TEE_HANDLE_FLAG_INITIALIZED;
676 
677 	tee_pobj_lock_usage(o->pobj);
678 	res = tee_svc_storage_read_head(o);
679 	bbuf = (struct utee_object_info){
680 		.obj_type = o->info.objectType,
681 		.obj_size = o->info.objectSize,
682 		.max_obj_size = o->info.maxObjectSize,
683 		.obj_usage = o->pobj->obj_info_usage,
684 		.data_size = o->info.dataSize,
685 		.data_pos = o->info.dataPosition,
686 		.handle_flags = o->info.handleFlags,
687 	};
688 	tee_pobj_unlock_usage(o->pobj);
689 	if (res != TEE_SUCCESS)
690 		goto exit;
691 
692 	res = copy_to_user(info, &bbuf, sizeof(bbuf));
693 	if (res)
694 		goto exit;
695 
696 	res = copy_to_user(obj_id, o->pobj->obj_id, o->pobj->obj_id_len);
697 	if (res)
698 		goto exit;
699 
700 	l = o->pobj->obj_id_len;
701 	res = copy_to_user_private(len, &l, sizeof(*len));
702 
703 exit:
704 	if (o) {
705 		if (o->pobj) {
706 			o->pobj->fops->close(&o->fh);
707 			tee_pobj_release(o->pobj);
708 		}
709 		tee_obj_free(o);
710 	}
711 
712 	return res;
713 }
714 
715 TEE_Result syscall_storage_obj_read(unsigned long obj, void *data, size_t len,
716 				    uint64_t *count)
717 {
718 	struct ts_session *sess = ts_get_current_session();
719 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
720 	TEE_Result res = TEE_SUCCESS;
721 	struct tee_obj *o = NULL;
722 	uint64_t u_count = 0;
723 	size_t pos_tmp = 0;
724 	size_t bytes = 0;
725 
726 	res = tee_obj_get(utc, uref_to_vaddr(obj), &o);
727 	if (res != TEE_SUCCESS)
728 		goto exit;
729 
730 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
731 		res = TEE_ERROR_BAD_STATE;
732 		goto exit;
733 	}
734 
735 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_READ)) {
736 		res = TEE_ERROR_ACCESS_CONFLICT;
737 		goto exit;
738 	}
739 
740 	/* Guard o->info.dataPosition += bytes below from overflowing */
741 	if (ADD_OVERFLOW(o->info.dataPosition, len, &pos_tmp)) {
742 		res = TEE_ERROR_OVERFLOW;
743 		goto exit;
744 	}
745 
746 	data = memtag_strip_tag(data);
747 
748 	bytes = len;
749 	if (ADD_OVERFLOW(o->ds_pos, o->info.dataPosition, &pos_tmp)) {
750 		res = TEE_ERROR_OVERFLOW;
751 		goto exit;
752 	}
753 	res = o->pobj->fops->read(o->fh, pos_tmp, NULL, data, &bytes);
754 	if (res != TEE_SUCCESS) {
755 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
756 			EMSG("Object corrupt");
757 			remove_corrupt_obj(utc, o);
758 		}
759 		goto exit;
760 	}
761 
762 	o->info.dataPosition += bytes;
763 
764 	u_count = bytes;
765 	res = copy_to_user_private(count, &u_count, sizeof(*count));
766 exit:
767 	return res;
768 }
769 
770 TEE_Result syscall_storage_obj_write(unsigned long obj, void *data, size_t len)
771 {
772 	struct ts_session *sess = ts_get_current_session();
773 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
774 	TEE_Result res = TEE_SUCCESS;
775 	struct tee_obj *o = NULL;
776 	size_t pos_tmp = 0;
777 
778 	res = tee_obj_get(utc, uref_to_vaddr(obj), &o);
779 	if (res != TEE_SUCCESS)
780 		goto exit;
781 
782 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
783 		res = TEE_ERROR_BAD_STATE;
784 		goto exit;
785 	}
786 
787 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE)) {
788 		res = TEE_ERROR_ACCESS_CONFLICT;
789 		goto exit;
790 	}
791 
792 	/* Guard o->info.dataPosition += bytes below from overflowing */
793 	if (ADD_OVERFLOW(o->info.dataPosition, len, &pos_tmp)) {
794 		res = TEE_ERROR_OVERFLOW;
795 		goto exit;
796 	}
797 
798 	data = memtag_strip_tag(data);
799 
800 	if (ADD_OVERFLOW(o->ds_pos, o->info.dataPosition, &pos_tmp)) {
801 		res = TEE_ERROR_ACCESS_CONFLICT;
802 		goto exit;
803 	}
804 	res = o->pobj->fops->write(o->fh, pos_tmp, NULL, data, len);
805 	if (res != TEE_SUCCESS) {
806 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
807 			EMSG("Object corrupt");
808 			remove_corrupt_obj(utc, o);
809 		}
810 		goto exit;
811 	}
812 
813 	o->info.dataPosition += len;
814 	if (o->info.dataPosition > o->info.dataSize)
815 		o->info.dataSize = o->info.dataPosition;
816 
817 exit:
818 	return res;
819 }
820 
821 TEE_Result tee_svc_storage_write_usage(struct tee_obj *o, uint32_t usage)
822 {
823 	const size_t pos = offsetof(struct tee_svc_storage_head, objectUsage);
824 
825 	return o->pobj->fops->write(o->fh, pos, &usage, NULL, sizeof(usage));
826 }
827 
828 TEE_Result syscall_storage_obj_trunc(unsigned long obj, size_t len)
829 {
830 	struct ts_session *sess = ts_get_current_session();
831 	TEE_Result res = TEE_SUCCESS;
832 	struct tee_obj *o = NULL;
833 	size_t off = 0;
834 	size_t attr_size = 0;
835 
836 	res = tee_obj_get(to_user_ta_ctx(sess->ctx), uref_to_vaddr(obj), &o);
837 	if (res != TEE_SUCCESS)
838 		goto exit;
839 
840 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
841 		res = TEE_ERROR_BAD_STATE;
842 		goto exit;
843 	}
844 
845 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE)) {
846 		res = TEE_ERROR_ACCESS_CONFLICT;
847 		goto exit;
848 	}
849 
850 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
851 	if (res != TEE_SUCCESS)
852 		goto exit;
853 
854 	if (ADD_OVERFLOW(sizeof(struct tee_svc_storage_head), attr_size,
855 				&off)) {
856 		res = TEE_ERROR_OVERFLOW;
857 		goto exit;
858 	}
859 	if (ADD_OVERFLOW(len, off, &off)) {
860 		res = TEE_ERROR_OVERFLOW;
861 		goto exit;
862 	}
863 	res = o->pobj->fops->truncate(o->fh, off);
864 	switch (res) {
865 	case TEE_SUCCESS:
866 		o->info.dataSize = len;
867 		break;
868 	case TEE_ERROR_CORRUPT_OBJECT:
869 		EMSG("Object corruption");
870 		remove_corrupt_obj(to_user_ta_ctx(sess->ctx), o);
871 		break;
872 	default:
873 		res = TEE_ERROR_GENERIC;
874 		break;
875 	}
876 
877 exit:
878 	return res;
879 }
880 
881 TEE_Result syscall_storage_obj_seek(unsigned long obj, int32_t offset,
882 				    unsigned long whence)
883 {
884 	struct ts_session *sess = ts_get_current_session();
885 	TEE_Result res = TEE_SUCCESS;
886 	struct tee_obj *o = NULL;
887 	tee_fs_off_t new_pos = 0;
888 
889 	res = tee_obj_get(to_user_ta_ctx(sess->ctx), uref_to_vaddr(obj), &o);
890 	if (res != TEE_SUCCESS)
891 		return res;
892 
893 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT))
894 		return TEE_ERROR_BAD_STATE;
895 
896 	switch (whence) {
897 	case TEE_DATA_SEEK_SET:
898 		new_pos = offset;
899 		break;
900 	case TEE_DATA_SEEK_CUR:
901 		if (ADD_OVERFLOW(o->info.dataPosition, offset, &new_pos))
902 			return TEE_ERROR_OVERFLOW;
903 		break;
904 	case TEE_DATA_SEEK_END:
905 		if (ADD_OVERFLOW(o->info.dataSize, offset, &new_pos))
906 			return TEE_ERROR_OVERFLOW;
907 		break;
908 	default:
909 		return TEE_ERROR_BAD_PARAMETERS;
910 	}
911 
912 	if (new_pos < 0)
913 		new_pos = 0;
914 
915 	if (new_pos > TEE_DATA_MAX_POSITION) {
916 		EMSG("Position is beyond TEE_DATA_MAX_POSITION");
917 		return TEE_ERROR_BAD_PARAMETERS;
918 	}
919 
920 	o->info.dataPosition = new_pos;
921 
922 	return TEE_SUCCESS;
923 }
924 
925 void tee_svc_storage_close_all_enum(struct user_ta_ctx *utc)
926 {
927 	struct tee_storage_enum_head *eh = &utc->storage_enums;
928 
929 	/* disregard return value */
930 	while (!TAILQ_EMPTY(eh))
931 		tee_svc_close_enum(utc, TAILQ_FIRST(eh));
932 }
933