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