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