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