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