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