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