xref: /optee_os/core/tee/tee_svc_storage.c (revision 2770e2422a28f1e7b3a68d05fd5a3aa3c23428be)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2014, STMicroelectronics International N.V.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <kernel/mutex.h>
30 #include <kernel/tee_misc.h>
31 #include <kernel/tee_ta_manager.h>
32 #include <mm/tee_mmu.h>
33 #include <string.h>
34 #include <tee_api_defines_extensions.h>
35 #include <tee_api_defines.h>
36 #include <tee/fs_dirfile.h>
37 #include <tee/tee_fs.h>
38 #include <tee/tee_obj.h>
39 #include <tee/tee_pobj.h>
40 #include <tee/tee_svc_cryp.h>
41 #include <tee/tee_svc.h>
42 #include <tee/tee_svc_storage.h>
43 #include <trace.h>
44 
45 const struct tee_file_operations *tee_svc_storage_file_ops(uint32_t storage_id)
46 {
47 
48 	switch (storage_id) {
49 	case TEE_STORAGE_PRIVATE:
50 #if defined(CFG_REE_FS)
51 		return &ree_fs_ops;
52 #elif defined(CFG_RPMB_FS)
53 		return &rpmb_fs_ops;
54 #else
55 #error At least one filesystem must be enabled.
56 #endif
57 #ifdef CFG_REE_FS
58 	case TEE_STORAGE_PRIVATE_REE:
59 		return &ree_fs_ops;
60 #endif
61 #ifdef CFG_RPMB_FS
62 	case TEE_STORAGE_PRIVATE_RPMB:
63 		return &rpmb_fs_ops;
64 #endif
65 	default:
66 		return NULL;
67 	}
68 }
69 
70 /* Header of GP formated secure storage files */
71 struct tee_svc_storage_head {
72 	uint32_t attr_size;
73 	uint32_t keySize;
74 	uint32_t maxKeySize;
75 	uint32_t objectUsage;
76 	uint32_t objectType;
77 	uint32_t have_attrs;
78 };
79 
80 struct tee_storage_enum {
81 	TAILQ_ENTRY(tee_storage_enum) link;
82 	struct tee_fs_dir *dir;
83 	const struct tee_file_operations *fops;
84 };
85 
86 static TEE_Result tee_svc_storage_get_enum(struct user_ta_ctx *utc,
87 					   uint32_t enum_id,
88 					   struct tee_storage_enum **e_out)
89 {
90 	struct tee_storage_enum *e;
91 
92 	TAILQ_FOREACH(e, &utc->storage_enums, link) {
93 		if (enum_id == (vaddr_t)e) {
94 			*e_out = e;
95 			return TEE_SUCCESS;
96 		}
97 	}
98 	return TEE_ERROR_BAD_PARAMETERS;
99 }
100 
101 static TEE_Result tee_svc_close_enum(struct user_ta_ctx *utc,
102 				     struct tee_storage_enum *e)
103 {
104 	if (e == NULL || utc == NULL)
105 		return TEE_ERROR_BAD_PARAMETERS;
106 
107 	TAILQ_REMOVE(&utc->storage_enums, e, link);
108 
109 	if (e->fops)
110 		e->fops->closedir(e->dir);
111 
112 	e->dir = NULL;
113 	e->fops = NULL;
114 
115 	free(e);
116 
117 	return TEE_SUCCESS;
118 }
119 
120 /* "/TA_uuid/object_id" or "/TA_uuid/.object_id" */
121 TEE_Result tee_svc_storage_create_filename(void *buf, size_t blen,
122 					   struct tee_pobj *po, bool transient)
123 {
124 	uint8_t *file = buf;
125 	uint32_t pos = 0;
126 	uint32_t hslen = 1 /* Leading slash */
127 			+ TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID) + po->obj_id_len)
128 			+ 1; /* Intermediate slash */
129 
130 	/* +1 for the '.' (temporary persistent object) */
131 	if (transient)
132 		hslen++;
133 
134 	if (blen < hslen)
135 		return TEE_ERROR_SHORT_BUFFER;
136 
137 	file[pos++] = '/';
138 	pos += tee_b2hs((uint8_t *)&po->uuid, &file[pos],
139 			sizeof(TEE_UUID), hslen);
140 	file[pos++] = '/';
141 
142 	if (transient)
143 		file[pos++] = '.';
144 
145 	tee_b2hs(po->obj_id, file + pos, po->obj_id_len, hslen - pos);
146 
147 	return TEE_SUCCESS;
148 }
149 
150 #ifdef CFG_REE_FS
151 /* "/dirf.db" or "/<file number>" */
152 TEE_Result
153 tee_svc_storage_create_filename_dfh(void *buf, size_t blen,
154 				    const struct tee_fs_dirfile_fileh *dfh)
155 {
156 	char *file = buf;
157 	size_t pos = 0;
158 	size_t l;
159 
160 	if (pos >= blen)
161 		return TEE_ERROR_SHORT_BUFFER;
162 
163 	file[pos] = '/';
164 	pos++;
165 	if (pos >= blen)
166 		return TEE_ERROR_SHORT_BUFFER;
167 
168 	l = blen - pos;
169 	return tee_fs_dirfile_fileh_to_fname(dfh, file + pos, &l);
170 }
171 #endif
172 
173 /* "/TA_uuid" */
174 TEE_Result tee_svc_storage_create_dirname(void *buf, size_t blen,
175 					  const TEE_UUID *uuid)
176 {
177 	uint8_t *dir = buf;
178 	uint32_t hslen = TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID)) + 1;
179 
180 	if (blen < hslen)
181 		return TEE_ERROR_SHORT_BUFFER;
182 
183 	dir[0] = '/';
184 	tee_b2hs((uint8_t *)uuid, dir + 1, sizeof(TEE_UUID), hslen);
185 
186 	return TEE_SUCCESS;
187 }
188 
189 static TEE_Result tee_svc_storage_remove_corrupt_obj(
190 					struct tee_ta_session *sess,
191 					struct tee_obj *o)
192 {
193 	o->pobj->fops->remove(o->pobj);
194 	tee_obj_close(to_user_ta_ctx(sess->ctx), o);
195 
196 	return TEE_SUCCESS;
197 }
198 
199 static TEE_Result tee_svc_storage_read_head(struct tee_obj *o)
200 {
201 	TEE_Result res = TEE_SUCCESS;
202 	size_t bytes;
203 	struct tee_svc_storage_head head;
204 	const struct tee_file_operations *fops = o->pobj->fops;
205 	void *attr = NULL;
206 	size_t size;
207 
208 	assert(!o->fh);
209 	res = fops->open(o->pobj, &size, &o->fh);
210 	if (res != TEE_SUCCESS)
211 		goto exit;
212 
213 	/* read head */
214 	bytes = sizeof(struct tee_svc_storage_head);
215 	res = fops->read(o->fh, 0, &head, &bytes);
216 	if (res != TEE_SUCCESS) {
217 		if (res == TEE_ERROR_CORRUPT_OBJECT)
218 			EMSG("Head corrupt\n");
219 		goto exit;
220 	}
221 
222 	if (bytes != sizeof(struct tee_svc_storage_head)) {
223 		res = TEE_ERROR_BAD_FORMAT;
224 		goto exit;
225 	}
226 
227 	res = tee_obj_set_type(o, head.objectType, head.maxKeySize);
228 	if (res != TEE_SUCCESS)
229 		goto exit;
230 
231 	o->ds_pos = sizeof(struct tee_svc_storage_head) + head.attr_size;
232 	if (head.attr_size) {
233 		attr = malloc(head.attr_size);
234 		if (!attr) {
235 			res = TEE_ERROR_OUT_OF_MEMORY;
236 			goto exit;
237 		}
238 
239 		/* read meta */
240 		bytes = head.attr_size;
241 		res = fops->read(o->fh, sizeof(struct tee_svc_storage_head),
242 				 attr, &bytes);
243 		if (res == TEE_ERROR_OUT_OF_MEMORY)
244 			goto exit;
245 		if (res != TEE_SUCCESS || bytes != head.attr_size)
246 			res = TEE_ERROR_CORRUPT_OBJECT;
247 		if (res)
248 			goto exit;
249 	}
250 
251 	res = tee_obj_attr_from_binary(o, attr, head.attr_size);
252 	if (res != TEE_SUCCESS)
253 		goto exit;
254 
255 	o->info.dataSize = size - sizeof(head) - head.attr_size;
256 	o->info.keySize = head.keySize;
257 	o->info.objectUsage = head.objectUsage;
258 	o->info.objectType = head.objectType;
259 	o->have_attrs = head.have_attrs;
260 
261 exit:
262 	free(attr);
263 
264 	return res;
265 }
266 
267 TEE_Result syscall_storage_obj_open(unsigned long storage_id, void *object_id,
268 			size_t object_id_len, unsigned long flags,
269 			uint32_t *obj)
270 {
271 	TEE_Result res;
272 	struct tee_ta_session *sess;
273 	struct tee_obj *o = NULL;
274 	char *file = NULL;
275 	struct tee_pobj *po = NULL;
276 	struct user_ta_ctx *utc;
277 	size_t attr_size;
278 	const struct tee_file_operations *fops =
279 			tee_svc_storage_file_ops(storage_id);
280 
281 	if (!fops) {
282 		res = TEE_ERROR_ITEM_NOT_FOUND;
283 		goto exit;
284 	}
285 
286 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN) {
287 		res = TEE_ERROR_BAD_PARAMETERS;
288 		goto exit;
289 	}
290 
291 	res = tee_ta_get_current_session(&sess);
292 	if (res != TEE_SUCCESS)
293 		goto err;
294 	utc = to_user_ta_ctx(sess->ctx);
295 
296 	res = tee_mmu_check_access_rights(utc,
297 					  TEE_MEMORY_ACCESS_READ,
298 					  (uaddr_t) object_id,
299 					  object_id_len);
300 	if (res != TEE_SUCCESS)
301 		goto err;
302 
303 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
304 			   object_id_len, flags, false, fops, &po);
305 	if (res != TEE_SUCCESS)
306 		goto err;
307 
308 	o = tee_obj_alloc();
309 	if (o == NULL) {
310 		tee_pobj_release(po);
311 		res = TEE_ERROR_OUT_OF_MEMORY;
312 		goto err;
313 	}
314 
315 	o->info.handleFlags =
316 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
317 	o->flags = flags;
318 	o->pobj = po;
319 	tee_obj_add(utc, o);
320 
321 	res = tee_svc_storage_read_head(o);
322 	if (res != TEE_SUCCESS) {
323 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
324 			EMSG("Object corrupt");
325 			goto err;
326 		}
327 		goto oclose;
328 	}
329 
330 	res = tee_svc_copy_kaddr_to_uref(obj, o);
331 	if (res != TEE_SUCCESS)
332 		goto oclose;
333 
334 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
335 	if (res != TEE_SUCCESS)
336 		goto oclose;
337 
338 	goto exit;
339 
340 oclose:
341 	tee_obj_close(utc, o);
342 	o = NULL;
343 
344 err:
345 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
346 		res = TEE_ERROR_CORRUPT_OBJECT;
347 	if (res == TEE_ERROR_CORRUPT_OBJECT && o)
348 		tee_svc_storage_remove_corrupt_obj(sess, o);
349 
350 exit:
351 	free(file);
352 	file = NULL;
353 	return res;
354 }
355 
356 static TEE_Result tee_svc_storage_init_file(struct tee_obj *o,
357 					    struct tee_obj *attr_o, void *data,
358 					    uint32_t len)
359 {
360 	TEE_Result res = TEE_SUCCESS;
361 	struct tee_svc_storage_head head;
362 	const struct tee_file_operations *fops = o->pobj->fops;
363 	void *attr = NULL;
364 	size_t attr_size = 0;
365 
366 	if (attr_o) {
367 		res = tee_obj_set_type(o, attr_o->info.objectType,
368 				       attr_o->info.maxKeySize);
369 		if (res)
370 			return res;
371 		res = tee_obj_attr_copy_from(o, attr_o);
372 		if (res)
373 			return res;
374 		o->have_attrs = attr_o->have_attrs;
375 		o->info.objectUsage = attr_o->info.objectUsage;
376 		o->info.keySize = attr_o->info.keySize;
377 		res = tee_obj_attr_to_binary(o, NULL, &attr_size);
378 		if (res)
379 			return res;
380 		if (attr_size) {
381 			attr = malloc(attr_size);
382 			if (!attr)
383 				return TEE_ERROR_OUT_OF_MEMORY;
384 			res = tee_obj_attr_to_binary(o, attr, &attr_size);
385 			if (res != TEE_SUCCESS)
386 				goto exit;
387 		}
388 	} else {
389 		res = tee_obj_set_type(o, TEE_TYPE_DATA, 0);
390 		if (res != TEE_SUCCESS)
391 			goto exit;
392 	}
393 
394 	o->ds_pos = sizeof(struct tee_svc_storage_head) + attr_size;
395 
396 	/* write head */
397 	head.attr_size = attr_size;
398 	head.keySize = o->info.keySize;
399 	head.maxKeySize = o->info.maxKeySize;
400 	head.objectUsage = o->info.objectUsage;
401 	head.objectType = o->info.objectType;
402 	head.have_attrs = o->have_attrs;
403 
404 	res = fops->create(o->pobj, !!(o->flags & TEE_DATA_FLAG_OVERWRITE),
405 			   &head, sizeof(head), attr, attr_size, data, len,
406 			   &o->fh);
407 
408 	if (!res)
409 		o->info.dataSize = len;
410 exit:
411 	free(attr);
412 	return res;
413 }
414 
415 TEE_Result syscall_storage_obj_create(unsigned long storage_id, void *object_id,
416 			size_t object_id_len, unsigned long flags,
417 			unsigned long attr, void *data, size_t len,
418 			uint32_t *obj)
419 {
420 	TEE_Result res;
421 	struct tee_ta_session *sess;
422 	struct tee_obj *o = NULL;
423 	struct tee_obj *attr_o = NULL;
424 	struct tee_pobj *po = NULL;
425 	struct user_ta_ctx *utc;
426 	const struct tee_file_operations *fops =
427 			tee_svc_storage_file_ops(storage_id);
428 
429 	if (!fops)
430 		return TEE_ERROR_ITEM_NOT_FOUND;
431 
432 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
433 		return TEE_ERROR_BAD_PARAMETERS;
434 
435 	res = tee_ta_get_current_session(&sess);
436 	if (res != TEE_SUCCESS)
437 		return res;
438 	utc = to_user_ta_ctx(sess->ctx);
439 
440 	res = tee_mmu_check_access_rights(utc,
441 					  TEE_MEMORY_ACCESS_READ,
442 					  (uaddr_t) object_id,
443 					  object_id_len);
444 	if (res != TEE_SUCCESS)
445 		goto err;
446 
447 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
448 			   object_id_len, flags, true, fops, &po);
449 	if (res != TEE_SUCCESS)
450 		goto err;
451 
452 	/* check rights of the provided buffer */
453 	if (data && len) {
454 		res = tee_mmu_check_access_rights(utc,
455 						  TEE_MEMORY_ACCESS_READ |
456 						  TEE_MEMORY_ACCESS_ANY_OWNER,
457 						  (uaddr_t) data, len);
458 
459 		if (res != TEE_SUCCESS)
460 			goto err;
461 	}
462 
463 	o = tee_obj_alloc();
464 	if (o == NULL) {
465 		res = TEE_ERROR_OUT_OF_MEMORY;
466 		goto err;
467 	}
468 
469 	o->info.handleFlags =
470 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
471 	o->flags = flags;
472 	o->pobj = po;
473 
474 	if (attr != TEE_HANDLE_NULL) {
475 		res = tee_obj_get(utc, tee_svc_uref_to_vaddr(attr),
476 				  &attr_o);
477 		if (res != TEE_SUCCESS)
478 			goto err;
479 	}
480 
481 	res = tee_svc_storage_init_file(o, attr_o, data, len);
482 	if (res != TEE_SUCCESS)
483 		goto err;
484 
485 	po = NULL; /* o owns it from now on */
486 	tee_obj_add(utc, o);
487 
488 	res = tee_svc_copy_kaddr_to_uref(obj, o);
489 	if (res != TEE_SUCCESS)
490 		goto oclose;
491 
492 	return TEE_SUCCESS;
493 
494 oclose:
495 	tee_obj_close(utc, o);
496 	return res;
497 
498 err:
499 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
500 		res = TEE_ERROR_CORRUPT_OBJECT;
501 	if (res == TEE_ERROR_CORRUPT_OBJECT && po)
502 		fops->remove(po);
503 	if (o)
504 		fops->close(&o->fh);
505 	if (po)
506 		tee_pobj_release(po);
507 	free(o);
508 
509 	return res;
510 }
511 
512 TEE_Result syscall_storage_obj_del(unsigned long obj)
513 {
514 	TEE_Result res;
515 	struct tee_ta_session *sess;
516 	struct tee_obj *o;
517 	struct user_ta_ctx *utc;
518 
519 	res = tee_ta_get_current_session(&sess);
520 	if (res != TEE_SUCCESS)
521 		return res;
522 	utc = to_user_ta_ctx(sess->ctx);
523 
524 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
525 	if (res != TEE_SUCCESS)
526 		return res;
527 
528 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META))
529 		return TEE_ERROR_ACCESS_CONFLICT;
530 
531 	if (o->pobj == NULL || o->pobj->obj_id == NULL)
532 		return TEE_ERROR_BAD_STATE;
533 
534 	res = o->pobj->fops->remove(o->pobj);
535 	tee_obj_close(utc, o);
536 
537 	return res;
538 }
539 
540 TEE_Result syscall_storage_obj_rename(unsigned long obj, void *object_id,
541 			size_t object_id_len)
542 {
543 	TEE_Result res;
544 	struct tee_ta_session *sess;
545 	struct tee_obj *o;
546 	struct tee_pobj *po = NULL;
547 	char *new_file = NULL;
548 	char *old_file = NULL;
549 	struct user_ta_ctx *utc;
550 	const struct tee_file_operations *fops;
551 
552 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
553 		return TEE_ERROR_BAD_PARAMETERS;
554 
555 	res = tee_ta_get_current_session(&sess);
556 	if (res != TEE_SUCCESS)
557 		return res;
558 	utc = to_user_ta_ctx(sess->ctx);
559 
560 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
561 	if (res != TEE_SUCCESS)
562 		return res;
563 
564 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
565 		res = TEE_ERROR_BAD_STATE;
566 		goto exit;
567 	}
568 
569 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META)) {
570 		res = TEE_ERROR_BAD_STATE;
571 		goto exit;
572 	}
573 
574 	if (o->pobj == NULL || o->pobj->obj_id == NULL) {
575 		res = TEE_ERROR_BAD_STATE;
576 		goto exit;
577 	}
578 
579 	res = tee_mmu_check_access_rights(utc,
580 					TEE_MEMORY_ACCESS_READ,
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