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