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