xref: /optee_os/core/tee/tee_svc_storage.c (revision 06b0fe0854f65729800d877868c39ffa83113d1b)
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 unsigned long valid_flags = TEE_DATA_FLAG_ACCESS_READ |
260 					  TEE_DATA_FLAG_ACCESS_WRITE |
261 					  TEE_DATA_FLAG_ACCESS_WRITE_META |
262 					  TEE_DATA_FLAG_SHARE_READ |
263 					  TEE_DATA_FLAG_SHARE_WRITE;
264 	const struct tee_file_operations *fops =
265 			tee_svc_storage_file_ops(storage_id);
266 	struct tee_ta_session *sess = NULL;
267 	struct user_ta_ctx *utc = NULL;
268 	TEE_Result res = TEE_SUCCESS;
269 	struct tee_pobj *po = NULL;
270 	struct tee_obj *o = NULL;
271 	char *file = NULL;
272 
273 	if (flags & ~valid_flags)
274 		return TEE_ERROR_BAD_PARAMETERS;
275 
276 	if (!fops) {
277 		res = TEE_ERROR_ITEM_NOT_FOUND;
278 		goto exit;
279 	}
280 
281 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN) {
282 		res = TEE_ERROR_BAD_PARAMETERS;
283 		goto exit;
284 	}
285 
286 	res = tee_ta_get_current_session(&sess);
287 	if (res != TEE_SUCCESS)
288 		goto err;
289 	utc = to_user_ta_ctx(sess->ctx);
290 
291 	res = tee_mmu_check_access_rights(&utc->uctx,
292 					  TEE_MEMORY_ACCESS_READ,
293 					  (uaddr_t) object_id,
294 					  object_id_len);
295 	if (res != TEE_SUCCESS)
296 		goto err;
297 
298 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
299 			   object_id_len, flags, false, fops, &po);
300 	if (res != TEE_SUCCESS)
301 		goto err;
302 
303 	o = tee_obj_alloc();
304 	if (o == NULL) {
305 		tee_pobj_release(po);
306 		res = TEE_ERROR_OUT_OF_MEMORY;
307 		goto err;
308 	}
309 
310 	o->info.handleFlags = TEE_HANDLE_FLAG_PERSISTENT |
311 			      TEE_HANDLE_FLAG_INITIALIZED | flags;
312 	o->pobj = po;
313 	tee_obj_add(utc, o);
314 
315 	res = tee_svc_storage_read_head(o);
316 	if (res != TEE_SUCCESS) {
317 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
318 			EMSG("Object corrupt");
319 			goto err;
320 		}
321 		goto oclose;
322 	}
323 
324 	res = tee_svc_copy_kaddr_to_uref(obj, o);
325 	if (res != TEE_SUCCESS)
326 		goto oclose;
327 
328 	goto exit;
329 
330 oclose:
331 	tee_obj_close(utc, o);
332 	o = NULL;
333 
334 err:
335 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
336 		res = TEE_ERROR_CORRUPT_OBJECT;
337 	if (res == TEE_ERROR_CORRUPT_OBJECT && o)
338 		tee_svc_storage_remove_corrupt_obj(sess, o);
339 
340 exit:
341 	free(file);
342 	file = NULL;
343 	return res;
344 }
345 
346 static TEE_Result tee_svc_storage_init_file(struct tee_obj *o, bool overwrite,
347 					    struct tee_obj *attr_o, void *data,
348 					    uint32_t len)
349 {
350 	TEE_Result res = TEE_SUCCESS;
351 	struct tee_svc_storage_head head;
352 	const struct tee_file_operations *fops = o->pobj->fops;
353 	void *attr = NULL;
354 	size_t attr_size = 0;
355 
356 	if (attr_o) {
357 		res = tee_obj_set_type(o, attr_o->info.objectType,
358 				       attr_o->info.maxKeySize);
359 		if (res)
360 			return res;
361 		res = tee_obj_attr_copy_from(o, attr_o);
362 		if (res)
363 			return res;
364 		o->have_attrs = attr_o->have_attrs;
365 		o->info.objectUsage = attr_o->info.objectUsage;
366 		o->info.keySize = attr_o->info.keySize;
367 		res = tee_obj_attr_to_binary(o, NULL, &attr_size);
368 		if (res)
369 			return res;
370 		if (attr_size) {
371 			attr = malloc(attr_size);
372 			if (!attr)
373 				return TEE_ERROR_OUT_OF_MEMORY;
374 			res = tee_obj_attr_to_binary(o, attr, &attr_size);
375 			if (res != TEE_SUCCESS)
376 				goto exit;
377 		}
378 	} else {
379 		res = tee_obj_set_type(o, TEE_TYPE_DATA, 0);
380 		if (res != TEE_SUCCESS)
381 			goto exit;
382 	}
383 
384 	o->ds_pos = sizeof(struct tee_svc_storage_head) + attr_size;
385 
386 	/* write head */
387 	head.attr_size = attr_size;
388 	head.keySize = o->info.keySize;
389 	head.maxKeySize = o->info.maxKeySize;
390 	head.objectUsage = o->info.objectUsage;
391 	head.objectType = o->info.objectType;
392 	head.have_attrs = o->have_attrs;
393 
394 	res = fops->create(o->pobj, overwrite, &head, sizeof(head), attr,
395 			   attr_size, data, len, &o->fh);
396 
397 	if (!res)
398 		o->info.dataSize = len;
399 exit:
400 	free(attr);
401 	return res;
402 }
403 
404 TEE_Result syscall_storage_obj_create(unsigned long storage_id, void *object_id,
405 			size_t object_id_len, unsigned long flags,
406 			unsigned long attr, void *data, size_t len,
407 			uint32_t *obj)
408 {
409 	const unsigned long valid_flags = TEE_DATA_FLAG_ACCESS_READ |
410 					  TEE_DATA_FLAG_ACCESS_WRITE |
411 					  TEE_DATA_FLAG_ACCESS_WRITE_META |
412 					  TEE_DATA_FLAG_SHARE_READ |
413 					  TEE_DATA_FLAG_SHARE_WRITE |
414 					  TEE_DATA_FLAG_OVERWRITE;
415 	const struct tee_file_operations *fops =
416 			tee_svc_storage_file_ops(storage_id);
417 	struct tee_ta_session *sess = NULL;
418 	struct user_ta_ctx *utc = NULL;
419 	struct tee_obj *attr_o = NULL;
420 	TEE_Result res = TEE_SUCCESS;
421 	struct tee_pobj *po = NULL;
422 	struct tee_obj *o = NULL;
423 
424 	if (flags & ~valid_flags)
425 		return TEE_ERROR_BAD_PARAMETERS;
426 
427 	if (!fops)
428 		return TEE_ERROR_ITEM_NOT_FOUND;
429 
430 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
431 		return TEE_ERROR_BAD_PARAMETERS;
432 
433 	res = tee_ta_get_current_session(&sess);
434 	if (res != TEE_SUCCESS)
435 		return res;
436 	utc = to_user_ta_ctx(sess->ctx);
437 
438 	res = tee_mmu_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_READ,
439 					  (uaddr_t)object_id, object_id_len);
440 	if (res != TEE_SUCCESS)
441 		goto err;
442 
443 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
444 			   object_id_len, flags, true, fops, &po);
445 	if (res != TEE_SUCCESS)
446 		goto err;
447 
448 	/* check rights of the provided buffer */
449 	if (len) {
450 		if (data) {
451 			uint32_t f = TEE_MEMORY_ACCESS_READ |
452 				     TEE_MEMORY_ACCESS_ANY_OWNER;
453 
454 			res = tee_mmu_check_access_rights(&utc->uctx, f,
455 							  (uaddr_t)data, len);
456 
457 			if (res != TEE_SUCCESS)
458 				goto err;
459 		} else {
460 			res = TEE_ERROR_BAD_PARAMETERS;
461 			goto err;
462 		}
463 	}
464 
465 	o = tee_obj_alloc();
466 	if (o == NULL) {
467 		res = TEE_ERROR_OUT_OF_MEMORY;
468 		goto err;
469 	}
470 
471 	o->info.handleFlags = TEE_HANDLE_FLAG_PERSISTENT |
472 			      TEE_HANDLE_FLAG_INITIALIZED | flags;
473 	o->pobj = po;
474 
475 	if (attr != TEE_HANDLE_NULL) {
476 		res = tee_obj_get(utc, tee_svc_uref_to_vaddr(attr),
477 				  &attr_o);
478 		if (res != TEE_SUCCESS)
479 			goto err;
480 		/* The supplied handle must be one of an initialized object */
481 		if (!(attr_o->info.handleFlags & TEE_HANDLE_FLAG_INITIALIZED)) {
482 			res = TEE_ERROR_BAD_PARAMETERS;
483 			goto err;
484 		}
485 	}
486 
487 	res = tee_svc_storage_init_file(o, flags & TEE_DATA_FLAG_OVERWRITE,
488 					attr_o, data, len);
489 	if (res != TEE_SUCCESS)
490 		goto err;
491 
492 	po = NULL; /* o owns it from now on */
493 	tee_obj_add(utc, o);
494 
495 	res = tee_svc_copy_kaddr_to_uref(obj, o);
496 	if (res != TEE_SUCCESS)
497 		goto oclose;
498 
499 	return TEE_SUCCESS;
500 
501 oclose:
502 	tee_obj_close(utc, o);
503 	return res;
504 
505 err:
506 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
507 		res = TEE_ERROR_CORRUPT_OBJECT;
508 	if (res == TEE_ERROR_CORRUPT_OBJECT && po)
509 		fops->remove(po);
510 	if (o) {
511 		fops->close(&o->fh);
512 		tee_obj_free(o);
513 	}
514 	if (po)
515 		tee_pobj_release(po);
516 
517 	return res;
518 }
519 
520 TEE_Result syscall_storage_obj_del(unsigned long obj)
521 {
522 	TEE_Result res;
523 	struct tee_ta_session *sess;
524 	struct tee_obj *o;
525 	struct user_ta_ctx *utc;
526 
527 	res = tee_ta_get_current_session(&sess);
528 	if (res != TEE_SUCCESS)
529 		return res;
530 	utc = to_user_ta_ctx(sess->ctx);
531 
532 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
533 	if (res != TEE_SUCCESS)
534 		return res;
535 
536 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE_META))
537 		return TEE_ERROR_ACCESS_CONFLICT;
538 
539 	if (o->pobj == NULL || o->pobj->obj_id == NULL)
540 		return TEE_ERROR_BAD_STATE;
541 
542 	res = o->pobj->fops->remove(o->pobj);
543 	tee_obj_close(utc, o);
544 
545 	return res;
546 }
547 
548 TEE_Result syscall_storage_obj_rename(unsigned long obj, void *object_id,
549 				      size_t object_id_len)
550 {
551 	const struct tee_file_operations *fops = NULL;
552 	struct tee_ta_session *sess = NULL;
553 	struct user_ta_ctx *utc = NULL;
554 	TEE_Result res = TEE_SUCCESS;
555 	struct tee_pobj *po = NULL;
556 	struct tee_obj *o = NULL;
557 	char *new_file = NULL;
558 	char *old_file = NULL;
559 
560 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
561 		return TEE_ERROR_BAD_PARAMETERS;
562 
563 	res = tee_ta_get_current_session(&sess);
564 	if (res != TEE_SUCCESS)
565 		return res;
566 	utc = to_user_ta_ctx(sess->ctx);
567 
568 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
569 	if (res != TEE_SUCCESS)
570 		return res;
571 
572 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
573 		res = TEE_ERROR_BAD_STATE;
574 		goto exit;
575 	}
576 
577 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE_META)) {
578 		res = TEE_ERROR_BAD_STATE;
579 		goto exit;
580 	}
581 
582 	if (o->pobj == NULL || o->pobj->obj_id == NULL) {
583 		res = TEE_ERROR_BAD_STATE;
584 		goto exit;
585 	}
586 
587 	res = tee_mmu_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_READ,
588 					  (uaddr_t)object_id, object_id_len);
589 	if (res != TEE_SUCCESS)
590 		goto exit;
591 
592 	/* reserve dest name */
593 	fops = o->pobj->fops;
594 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
595 			   object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META,
596 			   false, fops, &po);
597 	if (res != TEE_SUCCESS)
598 		goto exit;
599 
600 	/* move */
601 	res = fops->rename(o->pobj, po, false /* no overwrite */);
602 	if (res)
603 		goto exit;
604 
605 	res = tee_pobj_rename(o->pobj, object_id, object_id_len);
606 
607 exit:
608 	tee_pobj_release(po);
609 
610 	free(new_file);
611 	free(old_file);
612 
613 	return res;
614 }
615 
616 TEE_Result syscall_storage_alloc_enum(uint32_t *obj_enum)
617 {
618 	struct tee_storage_enum *e;
619 	struct tee_ta_session *sess;
620 	TEE_Result res;
621 	struct user_ta_ctx *utc;
622 
623 	if (obj_enum == NULL)
624 		return TEE_ERROR_BAD_PARAMETERS;
625 
626 	res = tee_ta_get_current_session(&sess);
627 	if (res != TEE_SUCCESS)
628 		return res;
629 	utc = to_user_ta_ctx(sess->ctx);
630 
631 	e = malloc(sizeof(struct tee_storage_enum));
632 	if (e == NULL)
633 		return TEE_ERROR_OUT_OF_MEMORY;
634 
635 	e->dir = NULL;
636 	e->fops = NULL;
637 	TAILQ_INSERT_TAIL(&utc->storage_enums, e, link);
638 
639 	return tee_svc_copy_kaddr_to_uref(obj_enum, e);
640 }
641 
642 TEE_Result syscall_storage_free_enum(unsigned long obj_enum)
643 {
644 	struct tee_storage_enum *e;
645 	TEE_Result res;
646 	struct tee_ta_session *sess;
647 	struct user_ta_ctx *utc;
648 
649 	res = tee_ta_get_current_session(&sess);
650 	if (res != TEE_SUCCESS)
651 		return res;
652 	utc = to_user_ta_ctx(sess->ctx);
653 
654 	res = tee_svc_storage_get_enum(utc,
655 			tee_svc_uref_to_vaddr(obj_enum), &e);
656 	if (res != TEE_SUCCESS)
657 		return res;
658 
659 	return tee_svc_close_enum(utc, e);
660 }
661 
662 TEE_Result syscall_storage_reset_enum(unsigned long obj_enum)
663 {
664 	struct tee_storage_enum *e;
665 	TEE_Result res;
666 	struct tee_ta_session *sess;
667 
668 	res = tee_ta_get_current_session(&sess);
669 	if (res != TEE_SUCCESS)
670 		return res;
671 
672 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
673 			tee_svc_uref_to_vaddr(obj_enum), &e);
674 	if (res != TEE_SUCCESS)
675 		return res;
676 
677 	if (e->fops) {
678 		e->fops->closedir(e->dir);
679 		e->fops = NULL;
680 		e->dir = NULL;
681 	}
682 	assert(!e->dir);
683 
684 	return TEE_SUCCESS;
685 }
686 
687 static TEE_Result tee_svc_storage_set_enum(struct tee_fs_dirent *d,
688 			const struct tee_file_operations *fops,
689 			struct tee_obj *o)
690 {
691 	o->info.handleFlags =
692 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
693 	o->info.objectUsage = TEE_USAGE_DEFAULT;
694 
695 	if (d->oidlen > TEE_OBJECT_ID_MAX_LEN)
696 		return TEE_ERROR_CORRUPT_OBJECT;
697 
698 	o->pobj->obj_id = malloc(d->oidlen);
699 	if (!o->pobj->obj_id)
700 		return TEE_ERROR_OUT_OF_MEMORY;
701 
702 	memcpy(o->pobj->obj_id, d->oid, d->oidlen);
703 	o->pobj->obj_id_len = d->oidlen;
704 	o->pobj->fops = fops;
705 
706 	return TEE_SUCCESS;
707 }
708 
709 TEE_Result syscall_storage_start_enum(unsigned long obj_enum,
710 				      unsigned long storage_id)
711 {
712 	struct tee_storage_enum *e;
713 	TEE_Result res;
714 	struct tee_ta_session *sess;
715 	const struct tee_file_operations *fops =
716 			tee_svc_storage_file_ops(storage_id);
717 
718 	res = tee_ta_get_current_session(&sess);
719 	if (res != TEE_SUCCESS)
720 		return res;
721 
722 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
723 			tee_svc_uref_to_vaddr(obj_enum), &e);
724 	if (res != TEE_SUCCESS)
725 		return res;
726 
727 	if (e->dir) {
728 		e->fops->closedir(e->dir);
729 		e->dir = NULL;
730 	}
731 
732 	if (!fops)
733 		return TEE_ERROR_ITEM_NOT_FOUND;
734 
735 	e->fops = fops;
736 
737 	return fops->opendir(&sess->ctx->uuid, &e->dir);
738 }
739 
740 TEE_Result syscall_storage_next_enum(unsigned long obj_enum,
741 			TEE_ObjectInfo *info, void *obj_id, uint64_t *len)
742 {
743 	struct tee_ta_session *sess = NULL;
744 	struct tee_storage_enum *e = NULL;
745 	struct tee_fs_dirent *d = NULL;
746 	struct user_ta_ctx *utc = NULL;
747 	TEE_Result res = TEE_SUCCESS;
748 	struct tee_obj *o = NULL;
749 	uint64_t l = 0;
750 
751 	res = tee_ta_get_current_session(&sess);
752 	if (res != TEE_SUCCESS)
753 		goto exit;
754 	utc = to_user_ta_ctx(sess->ctx);
755 
756 	res = tee_svc_storage_get_enum(utc,
757 			tee_svc_uref_to_vaddr(obj_enum), &e);
758 	if (res != TEE_SUCCESS)
759 		goto exit;
760 
761 	/* check rights of the provided buffers */
762 	res = tee_mmu_check_access_rights(&utc->uctx,
763 					  TEE_MEMORY_ACCESS_WRITE |
764 					  TEE_MEMORY_ACCESS_ANY_OWNER,
765 					  (uaddr_t)info,
766 					  sizeof(TEE_ObjectInfo));
767 	if (res != TEE_SUCCESS)
768 		goto exit;
769 
770 	res = tee_mmu_check_access_rights(&utc->uctx,
771 					  TEE_MEMORY_ACCESS_WRITE |
772 					  TEE_MEMORY_ACCESS_ANY_OWNER,
773 					  (uaddr_t)obj_id,
774 					  TEE_OBJECT_ID_MAX_LEN);
775 	if (res != TEE_SUCCESS)
776 		goto exit;
777 
778 	if (!e->fops) {
779 		res = TEE_ERROR_ITEM_NOT_FOUND;
780 		goto exit;
781 	}
782 
783 	res = e->fops->readdir(e->dir, &d);
784 	if (res != TEE_SUCCESS)
785 		goto exit;
786 
787 	o = tee_obj_alloc();
788 	if (o == NULL) {
789 		res = TEE_ERROR_OUT_OF_MEMORY;
790 		goto exit;
791 	}
792 	o->info.handleFlags = TEE_DATA_FLAG_SHARE_READ;
793 
794 	o->pobj = calloc(1, sizeof(struct tee_pobj));
795 	if (!o->pobj) {
796 		res = TEE_ERROR_OUT_OF_MEMORY;
797 		goto exit;
798 	}
799 
800 	o->pobj->uuid = sess->ctx->uuid;
801 	res = tee_svc_storage_set_enum(d, e->fops, o);
802 	if (res != TEE_SUCCESS)
803 		goto exit;
804 
805 	res = tee_svc_storage_read_head(o);
806 	if (res != TEE_SUCCESS)
807 		goto exit;
808 
809 	memcpy(info, &o->info, sizeof(TEE_ObjectInfo));
810 	memcpy(obj_id, o->pobj->obj_id, o->pobj->obj_id_len);
811 
812 	l = o->pobj->obj_id_len;
813 	res = tee_svc_copy_to_user(len, &l, sizeof(*len));
814 
815 exit:
816 	if (o) {
817 		if (o->pobj) {
818 			if (o->pobj->fops)
819 				o->pobj->fops->close(&o->fh);
820 			free(o->pobj->obj_id);
821 		}
822 		free(o->pobj);
823 		tee_obj_free(o);
824 	}
825 
826 	return res;
827 }
828 
829 TEE_Result syscall_storage_obj_read(unsigned long obj, void *data, size_t len,
830 				    uint64_t *count)
831 {
832 	struct tee_ta_session *sess = NULL;
833 	struct user_ta_ctx *utc = NULL;
834 	TEE_Result res = TEE_SUCCESS;
835 	struct tee_obj *o = NULL;
836 	uint64_t u_count = 0;
837 	size_t pos_tmp = 0;
838 	size_t bytes = 0;
839 
840 	res = tee_ta_get_current_session(&sess);
841 	if (res != TEE_SUCCESS)
842 		goto exit;
843 	utc = to_user_ta_ctx(sess->ctx);
844 
845 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
846 	if (res != TEE_SUCCESS)
847 		goto exit;
848 
849 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
850 		res = TEE_ERROR_BAD_STATE;
851 		goto exit;
852 	}
853 
854 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_READ)) {
855 		res = TEE_ERROR_ACCESS_CONFLICT;
856 		goto exit;
857 	}
858 
859 	/* Guard o->info.dataPosition += bytes below from overflowing */
860 	if (ADD_OVERFLOW(o->info.dataPosition, len, &pos_tmp)) {
861 		res = TEE_ERROR_OVERFLOW;
862 		goto exit;
863 	}
864 
865 	/* check rights of the provided buffer */
866 	res = tee_mmu_check_access_rights(&utc->uctx,
867 					  TEE_MEMORY_ACCESS_WRITE |
868 					  TEE_MEMORY_ACCESS_ANY_OWNER,
869 					  (uaddr_t)data, len);
870 	if (res != TEE_SUCCESS)
871 		goto exit;
872 
873 	bytes = len;
874 	if (ADD_OVERFLOW(o->ds_pos, o->info.dataPosition, &pos_tmp)) {
875 		res = TEE_ERROR_OVERFLOW;
876 		goto exit;
877 	}
878 	res = o->pobj->fops->read(o->fh, pos_tmp, data, &bytes);
879 	if (res != TEE_SUCCESS) {
880 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
881 			EMSG("Object corrupt");
882 			tee_svc_storage_remove_corrupt_obj(sess, o);
883 		}
884 		goto exit;
885 	}
886 
887 	o->info.dataPosition += bytes;
888 
889 	u_count = bytes;
890 	res = tee_svc_copy_to_user(count, &u_count, sizeof(*count));
891 exit:
892 	return res;
893 }
894 
895 TEE_Result syscall_storage_obj_write(unsigned long obj, void *data, size_t len)
896 {
897 	struct tee_ta_session *sess = NULL;
898 	struct user_ta_ctx *utc = NULL;
899 	TEE_Result res = TEE_SUCCESS;
900 	struct tee_obj *o = NULL;
901 	size_t pos_tmp = 0;
902 
903 	res = tee_ta_get_current_session(&sess);
904 	if (res != TEE_SUCCESS)
905 		goto exit;
906 	utc = to_user_ta_ctx(sess->ctx);
907 
908 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
909 	if (res != TEE_SUCCESS)
910 		goto exit;
911 
912 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
913 		res = TEE_ERROR_BAD_STATE;
914 		goto exit;
915 	}
916 
917 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE)) {
918 		res = TEE_ERROR_ACCESS_CONFLICT;
919 		goto exit;
920 	}
921 
922 	/* Guard o->info.dataPosition += bytes below from overflowing */
923 	if (ADD_OVERFLOW(o->info.dataPosition, len, &pos_tmp)) {
924 		res = TEE_ERROR_OVERFLOW;
925 		goto exit;
926 	}
927 
928 	/* check rights of the provided buffer */
929 	res = tee_mmu_check_access_rights(&utc->uctx,
930 					  TEE_MEMORY_ACCESS_READ |
931 					  TEE_MEMORY_ACCESS_ANY_OWNER,
932 					  (uaddr_t)data, len);
933 	if (res != TEE_SUCCESS)
934 		goto exit;
935 
936 	if (ADD_OVERFLOW(o->ds_pos, o->info.dataPosition, &pos_tmp)) {
937 		res = TEE_ERROR_ACCESS_CONFLICT;
938 		goto exit;
939 	}
940 	res = o->pobj->fops->write(o->fh, pos_tmp, data, len);
941 	if (res != TEE_SUCCESS)
942 		goto exit;
943 
944 	o->info.dataPosition += len;
945 	if (o->info.dataPosition > o->info.dataSize)
946 		o->info.dataSize = o->info.dataPosition;
947 
948 exit:
949 	return res;
950 }
951 
952 TEE_Result syscall_storage_obj_trunc(unsigned long obj, size_t len)
953 {
954 	TEE_Result res;
955 	struct tee_ta_session *sess;
956 	struct tee_obj *o;
957 	size_t off;
958 	size_t attr_size;
959 
960 	res = tee_ta_get_current_session(&sess);
961 	if (res != TEE_SUCCESS)
962 		goto exit;
963 
964 	res = tee_obj_get(to_user_ta_ctx(sess->ctx),
965 			  tee_svc_uref_to_vaddr(obj), &o);
966 	if (res != TEE_SUCCESS)
967 		goto exit;
968 
969 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
970 		res = TEE_ERROR_BAD_STATE;
971 		goto exit;
972 	}
973 
974 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE)) {
975 		res = TEE_ERROR_ACCESS_CONFLICT;
976 		goto exit;
977 	}
978 
979 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
980 	if (res != TEE_SUCCESS)
981 		goto exit;
982 
983 	if (ADD_OVERFLOW(sizeof(struct tee_svc_storage_head), attr_size,
984 				&off)) {
985 		res = TEE_ERROR_OVERFLOW;
986 		goto exit;
987 	}
988 	if (ADD_OVERFLOW(len, off, &off)) {
989 		res = TEE_ERROR_OVERFLOW;
990 		goto exit;
991 	}
992 	res = o->pobj->fops->truncate(o->fh, off);
993 	switch (res) {
994 	case TEE_SUCCESS:
995 		o->info.dataSize = len;
996 		break;
997 	case TEE_ERROR_CORRUPT_OBJECT:
998 		EMSG("Object corruption");
999 		(void)tee_svc_storage_remove_corrupt_obj(sess, o);
1000 		break;
1001 	default:
1002 		res = TEE_ERROR_GENERIC;
1003 		break;
1004 	}
1005 
1006 exit:
1007 	return res;
1008 }
1009 
1010 TEE_Result syscall_storage_obj_seek(unsigned long obj, int32_t offset,
1011 				    unsigned long whence)
1012 {
1013 	TEE_Result res;
1014 	struct tee_ta_session *sess;
1015 	struct tee_obj *o;
1016 	tee_fs_off_t new_pos;
1017 
1018 	res = tee_ta_get_current_session(&sess);
1019 	if (res != TEE_SUCCESS)
1020 		return res;
1021 
1022 	res = tee_obj_get(to_user_ta_ctx(sess->ctx),
1023 			  tee_svc_uref_to_vaddr(obj), &o);
1024 	if (res != TEE_SUCCESS)
1025 		return res;
1026 
1027 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT))
1028 		return TEE_ERROR_BAD_STATE;
1029 
1030 	switch (whence) {
1031 	case TEE_DATA_SEEK_SET:
1032 		new_pos = offset;
1033 		break;
1034 	case TEE_DATA_SEEK_CUR:
1035 		if (ADD_OVERFLOW(o->info.dataPosition, offset, &new_pos))
1036 			return TEE_ERROR_OVERFLOW;
1037 		break;
1038 	case TEE_DATA_SEEK_END:
1039 		if (ADD_OVERFLOW(o->info.dataSize, offset, &new_pos))
1040 			return TEE_ERROR_OVERFLOW;
1041 		break;
1042 	default:
1043 		return TEE_ERROR_BAD_PARAMETERS;
1044 	}
1045 
1046 	if (new_pos < 0)
1047 		new_pos = 0;
1048 
1049 	if (new_pos > TEE_DATA_MAX_POSITION) {
1050 		EMSG("Position is beyond TEE_DATA_MAX_POSITION");
1051 		return TEE_ERROR_BAD_PARAMETERS;
1052 	}
1053 
1054 	o->info.dataPosition = new_pos;
1055 
1056 	return TEE_SUCCESS;
1057 }
1058 
1059 void tee_svc_storage_close_all_enum(struct user_ta_ctx *utc)
1060 {
1061 	struct tee_storage_enum_head *eh = &utc->storage_enums;
1062 
1063 	/* disregard return value */
1064 	while (!TAILQ_EMPTY(eh))
1065 		tee_svc_close_enum(utc, TAILQ_FIRST(eh));
1066 }
1067