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