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