xref: /optee_os/core/tee/tee_svc_storage.c (revision 1bb929836182ecb96d2d9d268daa807c67596396)
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_SUCCESS || bytes != head.attr_size) {
244 			res = TEE_ERROR_CORRUPT_OBJECT;
245 			goto exit;
246 		}
247 	}
248 
249 	res = tee_obj_attr_from_binary(o, attr, head.attr_size);
250 	if (res != TEE_SUCCESS)
251 		goto exit;
252 
253 	o->info.dataSize = size - sizeof(head) - head.attr_size;
254 	o->info.keySize = head.keySize;
255 	o->info.objectUsage = head.objectUsage;
256 	o->info.objectType = head.objectType;
257 	o->have_attrs = head.have_attrs;
258 
259 exit:
260 	free(attr);
261 
262 	return res;
263 }
264 
265 TEE_Result syscall_storage_obj_open(unsigned long storage_id, void *object_id,
266 			size_t object_id_len, unsigned long flags,
267 			uint32_t *obj)
268 {
269 	TEE_Result res;
270 	struct tee_ta_session *sess;
271 	struct tee_obj *o = NULL;
272 	char *file = NULL;
273 	struct tee_pobj *po = NULL;
274 	struct user_ta_ctx *utc;
275 	size_t attr_size;
276 	const struct tee_file_operations *fops =
277 			tee_svc_storage_file_ops(storage_id);
278 
279 	if (!fops) {
280 		res = TEE_ERROR_ITEM_NOT_FOUND;
281 		goto exit;
282 	}
283 
284 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN) {
285 		res = TEE_ERROR_BAD_PARAMETERS;
286 		goto exit;
287 	}
288 
289 	res = tee_ta_get_current_session(&sess);
290 	if (res != TEE_SUCCESS)
291 		goto err;
292 	utc = to_user_ta_ctx(sess->ctx);
293 
294 	res = tee_mmu_check_access_rights(utc,
295 					  TEE_MEMORY_ACCESS_READ |
296 					  TEE_MEMORY_ACCESS_ANY_OWNER,
297 					  (uaddr_t) object_id,
298 					  object_id_len);
299 	if (res != TEE_SUCCESS)
300 		goto err;
301 
302 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
303 			   object_id_len, flags, false, fops, &po);
304 	if (res != TEE_SUCCESS)
305 		goto err;
306 
307 	o = tee_obj_alloc();
308 	if (o == NULL) {
309 		tee_pobj_release(po);
310 		res = TEE_ERROR_OUT_OF_MEMORY;
311 		goto err;
312 	}
313 
314 	o->info.handleFlags =
315 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
316 	o->flags = flags;
317 	o->pobj = po;
318 	tee_obj_add(utc, o);
319 
320 	res = tee_svc_storage_read_head(o);
321 	if (res != TEE_SUCCESS) {
322 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
323 			EMSG("Object corrupt");
324 			goto err;
325 		}
326 		goto oclose;
327 	}
328 
329 	res = tee_svc_copy_kaddr_to_uref(obj, o);
330 	if (res != TEE_SUCCESS)
331 		goto oclose;
332 
333 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
334 	if (res != TEE_SUCCESS)
335 		goto oclose;
336 
337 	goto exit;
338 
339 oclose:
340 	tee_obj_close(utc, o);
341 	o = NULL;
342 
343 err:
344 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
345 		res = TEE_ERROR_CORRUPT_OBJECT;
346 	if (res == TEE_ERROR_CORRUPT_OBJECT && o)
347 		tee_svc_storage_remove_corrupt_obj(sess, o);
348 
349 exit:
350 	free(file);
351 	file = NULL;
352 	return res;
353 }
354 
355 static TEE_Result tee_svc_storage_init_file(struct tee_obj *o,
356 					    struct tee_obj *attr_o, void *data,
357 					    uint32_t len)
358 {
359 	TEE_Result res = TEE_SUCCESS;
360 	struct tee_svc_storage_head head;
361 	const struct tee_file_operations *fops = o->pobj->fops;
362 	void *attr = NULL;
363 	size_t attr_size = 0;
364 
365 	if (attr_o) {
366 		res = tee_obj_set_type(o, attr_o->info.objectType,
367 				       attr_o->info.maxKeySize);
368 		if (res)
369 			return res;
370 		res = tee_obj_attr_copy_from(o, attr_o);
371 		if (res)
372 			return res;
373 		o->have_attrs = attr_o->have_attrs;
374 		o->info.objectUsage = attr_o->info.objectUsage;
375 		o->info.keySize = attr_o->info.keySize;
376 		res = tee_obj_attr_to_binary(o, NULL, &attr_size);
377 		if (res)
378 			return res;
379 		if (attr_size) {
380 			attr = malloc(attr_size);
381 			if (!attr)
382 				return TEE_ERROR_OUT_OF_MEMORY;
383 			res = tee_obj_attr_to_binary(o, attr, &attr_size);
384 			if (res != TEE_SUCCESS)
385 				goto exit;
386 		}
387 	} else {
388 		res = tee_obj_set_type(o, TEE_TYPE_DATA, 0);
389 		if (res != TEE_SUCCESS)
390 			goto exit;
391 	}
392 
393 	o->ds_pos = sizeof(struct tee_svc_storage_head) + attr_size;
394 
395 	/* write head */
396 	head.attr_size = attr_size;
397 	head.keySize = o->info.keySize;
398 	head.maxKeySize = o->info.maxKeySize;
399 	head.objectUsage = o->info.objectUsage;
400 	head.objectType = o->info.objectType;
401 	head.have_attrs = o->have_attrs;
402 
403 	res = fops->create(o->pobj, !!(o->flags & TEE_DATA_FLAG_OVERWRITE),
404 			   &head, sizeof(head), attr, attr_size, data, len,
405 			   &o->fh);
406 
407 	if (!res)
408 		o->info.dataSize = len;
409 exit:
410 	free(attr);
411 	return res;
412 }
413 
414 TEE_Result syscall_storage_obj_create(unsigned long storage_id, void *object_id,
415 			size_t object_id_len, unsigned long flags,
416 			unsigned long attr, void *data, size_t len,
417 			uint32_t *obj)
418 {
419 	TEE_Result res;
420 	struct tee_ta_session *sess;
421 	struct tee_obj *o = NULL;
422 	struct tee_obj *attr_o = NULL;
423 	struct tee_pobj *po = NULL;
424 	struct user_ta_ctx *utc;
425 	const struct tee_file_operations *fops =
426 			tee_svc_storage_file_ops(storage_id);
427 
428 	if (!fops)
429 		return TEE_ERROR_ITEM_NOT_FOUND;
430 
431 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
432 		return TEE_ERROR_BAD_PARAMETERS;
433 
434 	res = tee_ta_get_current_session(&sess);
435 	if (res != TEE_SUCCESS)
436 		return res;
437 	utc = to_user_ta_ctx(sess->ctx);
438 
439 	res = tee_mmu_check_access_rights(utc,
440 					  TEE_MEMORY_ACCESS_READ |
441 					  TEE_MEMORY_ACCESS_ANY_OWNER,
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 					TEE_MEMORY_ACCESS_ANY_OWNER,
582 					(uaddr_t) object_id, object_id_len);
583 	if (res != TEE_SUCCESS)
584 		goto exit;
585 
586 	/* reserve dest name */
587 	fops = o->pobj->fops;
588 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
589 			   object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META,
590 			   false, fops, &po);
591 	if (res != TEE_SUCCESS)
592 		goto exit;
593 
594 	/* move */
595 	res = fops->rename(o->pobj, po, false /* no overwrite */);
596 	if (res == TEE_ERROR_GENERIC)
597 		goto exit;
598 
599 	res = tee_pobj_rename(o->pobj, object_id, object_id_len);
600 
601 exit:
602 	tee_pobj_release(po);
603 
604 	free(new_file);
605 	free(old_file);
606 
607 	return res;
608 }
609 
610 TEE_Result syscall_storage_alloc_enum(uint32_t *obj_enum)
611 {
612 	struct tee_storage_enum *e;
613 	struct tee_ta_session *sess;
614 	TEE_Result res;
615 	struct user_ta_ctx *utc;
616 
617 	if (obj_enum == NULL)
618 		return TEE_ERROR_BAD_PARAMETERS;
619 
620 	res = tee_ta_get_current_session(&sess);
621 	if (res != TEE_SUCCESS)
622 		return res;
623 	utc = to_user_ta_ctx(sess->ctx);
624 
625 	e = malloc(sizeof(struct tee_storage_enum));
626 	if (e == NULL)
627 		return TEE_ERROR_OUT_OF_MEMORY;
628 
629 	e->dir = NULL;
630 	e->fops = NULL;
631 	TAILQ_INSERT_TAIL(&utc->storage_enums, e, link);
632 
633 	return tee_svc_copy_kaddr_to_uref(obj_enum, e);
634 }
635 
636 TEE_Result syscall_storage_free_enum(unsigned long obj_enum)
637 {
638 	struct tee_storage_enum *e;
639 	TEE_Result res;
640 	struct tee_ta_session *sess;
641 	struct user_ta_ctx *utc;
642 
643 	res = tee_ta_get_current_session(&sess);
644 	if (res != TEE_SUCCESS)
645 		return res;
646 	utc = to_user_ta_ctx(sess->ctx);
647 
648 	res = tee_svc_storage_get_enum(utc,
649 			tee_svc_uref_to_vaddr(obj_enum), &e);
650 	if (res != TEE_SUCCESS)
651 		return res;
652 
653 	return tee_svc_close_enum(utc, e);
654 }
655 
656 TEE_Result syscall_storage_reset_enum(unsigned long obj_enum)
657 {
658 	struct tee_storage_enum *e;
659 	TEE_Result res;
660 	struct tee_ta_session *sess;
661 
662 	res = tee_ta_get_current_session(&sess);
663 	if (res != TEE_SUCCESS)
664 		return res;
665 
666 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
667 			tee_svc_uref_to_vaddr(obj_enum), &e);
668 	if (res != TEE_SUCCESS)
669 		return res;
670 
671 	if (e->fops) {
672 		e->fops->closedir(e->dir);
673 		e->fops = NULL;
674 		e->dir = NULL;
675 	}
676 	assert(!e->dir);
677 
678 	return TEE_SUCCESS;
679 }
680 
681 static TEE_Result tee_svc_storage_set_enum(struct tee_fs_dirent *d,
682 			const struct tee_file_operations *fops,
683 			struct tee_obj *o)
684 {
685 	o->info.handleFlags =
686 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
687 	o->info.objectUsage = TEE_USAGE_DEFAULT;
688 
689 	o->pobj->obj_id = malloc(d->oidlen);
690 	if (!o->pobj->obj_id)
691 		return TEE_ERROR_OUT_OF_MEMORY;
692 
693 	memcpy(o->pobj->obj_id, d->oid, d->oidlen);
694 	o->pobj->obj_id_len = d->oidlen;
695 	o->pobj->fops = fops;
696 
697 	return TEE_SUCCESS;
698 }
699 
700 TEE_Result syscall_storage_start_enum(unsigned long obj_enum,
701 				      unsigned long storage_id)
702 {
703 	struct tee_storage_enum *e;
704 	TEE_Result res;
705 	struct tee_ta_session *sess;
706 	const struct tee_file_operations *fops =
707 			tee_svc_storage_file_ops(storage_id);
708 
709 	res = tee_ta_get_current_session(&sess);
710 	if (res != TEE_SUCCESS)
711 		return res;
712 
713 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
714 			tee_svc_uref_to_vaddr(obj_enum), &e);
715 	if (res != TEE_SUCCESS)
716 		return res;
717 
718 	if (!fops)
719 		return TEE_ERROR_ITEM_NOT_FOUND;
720 
721 	e->fops = fops;
722 	assert(!e->dir);
723 	return fops->opendir(&sess->ctx->uuid, &e->dir);
724 }
725 
726 TEE_Result syscall_storage_next_enum(unsigned long obj_enum,
727 			TEE_ObjectInfo *info, void *obj_id, uint64_t *len)
728 {
729 	struct tee_storage_enum *e;
730 	struct tee_fs_dirent *d;
731 	TEE_Result res = TEE_SUCCESS;
732 	struct tee_ta_session *sess;
733 	struct tee_obj *o = NULL;
734 	uint64_t l;
735 	struct user_ta_ctx *utc;
736 
737 	res = tee_ta_get_current_session(&sess);
738 	if (res != TEE_SUCCESS)
739 		goto exit;
740 	utc = to_user_ta_ctx(sess->ctx);
741 
742 	res = tee_svc_storage_get_enum(utc,
743 			tee_svc_uref_to_vaddr(obj_enum), &e);
744 	if (res != TEE_SUCCESS)
745 		goto exit;
746 
747 	/* check rights of the provided buffers */
748 	res = tee_mmu_check_access_rights(utc,
749 					TEE_MEMORY_ACCESS_WRITE |
750 					TEE_MEMORY_ACCESS_ANY_OWNER,
751 					(uaddr_t) info,
752 					sizeof(TEE_ObjectInfo));
753 	if (res != TEE_SUCCESS)
754 		goto exit;
755 
756 	res = tee_mmu_check_access_rights(utc,
757 					TEE_MEMORY_ACCESS_WRITE |
758 					TEE_MEMORY_ACCESS_ANY_OWNER,
759 					(uaddr_t) obj_id,
760 					TEE_OBJECT_ID_MAX_LEN);
761 	if (res != TEE_SUCCESS)
762 		goto exit;
763 
764 	if (!e->fops) {
765 		res = TEE_ERROR_ITEM_NOT_FOUND;
766 		goto exit;
767 	}
768 
769 	res = e->fops->readdir(e->dir, &d);
770 	if (res != TEE_SUCCESS)
771 		goto exit;
772 
773 	o = tee_obj_alloc();
774 	if (o == NULL) {
775 		res = TEE_ERROR_OUT_OF_MEMORY;
776 		goto exit;
777 	}
778 	o->flags = TEE_DATA_FLAG_SHARE_READ;
779 
780 	o->pobj = calloc(1, sizeof(struct tee_pobj));
781 	if (!o->pobj) {
782 		res = TEE_ERROR_OUT_OF_MEMORY;
783 		goto exit;
784 	}
785 
786 	o->pobj->uuid = sess->ctx->uuid;
787 	res = tee_svc_storage_set_enum(d, e->fops, o);
788 	if (res != TEE_SUCCESS)
789 		goto exit;
790 
791 	res = tee_svc_storage_read_head(o);
792 	if (res != TEE_SUCCESS)
793 		goto exit;
794 
795 	memcpy(info, &o->info, sizeof(TEE_ObjectInfo));
796 	memcpy(obj_id, o->pobj->obj_id, o->pobj->obj_id_len);
797 
798 	l = o->pobj->obj_id_len;
799 	res = tee_svc_copy_to_user(len, &l, sizeof(*len));
800 
801 exit:
802 	if (o) {
803 		if (o->pobj) {
804 			o->pobj->fops->close(&o->fh);
805 			free(o->pobj->obj_id);
806 		}
807 		free(o->pobj);
808 		tee_obj_free(o);
809 	}
810 
811 	return res;
812 }
813 
814 TEE_Result syscall_storage_obj_read(unsigned long obj, void *data, size_t len,
815 			uint64_t *count)
816 {
817 	TEE_Result res;
818 	struct tee_ta_session *sess;
819 	struct tee_obj *o;
820 	uint64_t u_count;
821 	struct user_ta_ctx *utc;
822 	size_t bytes;
823 
824 	res = tee_ta_get_current_session(&sess);
825 	if (res != TEE_SUCCESS)
826 		goto exit;
827 	utc = to_user_ta_ctx(sess->ctx);
828 
829 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
830 	if (res != TEE_SUCCESS)
831 		goto exit;
832 
833 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
834 		res = TEE_ERROR_BAD_STATE;
835 		goto exit;
836 	}
837 
838 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_READ)) {
839 		res = TEE_ERROR_ACCESS_CONFLICT;
840 		goto exit;
841 	}
842 
843 	/* check rights of the provided buffer */
844 	res = tee_mmu_check_access_rights(utc,
845 					TEE_MEMORY_ACCESS_WRITE |
846 					TEE_MEMORY_ACCESS_ANY_OWNER,
847 					(uaddr_t) data, len);
848 	if (res != TEE_SUCCESS)
849 		goto exit;
850 
851 	bytes = len;
852 	res = o->pobj->fops->read(o->fh, o->ds_pos + o->info.dataPosition,
853 				  data, &bytes);
854 	if (res != TEE_SUCCESS) {
855 		EMSG("Error code=%x\n", (uint32_t)res);
856 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
857 			EMSG("Object corrupt\n");
858 			tee_svc_storage_remove_corrupt_obj(sess, o);
859 		}
860 		goto exit;
861 	}
862 
863 	o->info.dataPosition += bytes;
864 
865 	u_count = bytes;
866 	res = tee_svc_copy_to_user(count, &u_count, sizeof(*count));
867 exit:
868 	return res;
869 }
870 
871 TEE_Result syscall_storage_obj_write(unsigned long obj, void *data, size_t len)
872 {
873 	TEE_Result res;
874 	struct tee_ta_session *sess;
875 	struct tee_obj *o;
876 	struct user_ta_ctx *utc;
877 
878 	res = tee_ta_get_current_session(&sess);
879 	if (res != TEE_SUCCESS)
880 		goto exit;
881 	utc = to_user_ta_ctx(sess->ctx);
882 
883 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
884 	if (res != TEE_SUCCESS)
885 		goto exit;
886 
887 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
888 		res = TEE_ERROR_BAD_STATE;
889 		goto exit;
890 	}
891 
892 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) {
893 		res = TEE_ERROR_ACCESS_CONFLICT;
894 		goto exit;
895 	}
896 
897 	/* check rights of the provided buffer */
898 	res = tee_mmu_check_access_rights(utc,
899 					TEE_MEMORY_ACCESS_READ |
900 					TEE_MEMORY_ACCESS_ANY_OWNER,
901 					(uaddr_t) data, len);
902 	if (res != TEE_SUCCESS)
903 		goto exit;
904 
905 	res = o->pobj->fops->write(o->fh, o->ds_pos + o->info.dataPosition,
906 				   data, len);
907 	if (res != TEE_SUCCESS)
908 		goto exit;
909 
910 	o->info.dataPosition += len;
911 	if (o->info.dataPosition > o->info.dataSize)
912 		o->info.dataSize = o->info.dataPosition;
913 
914 exit:
915 	return res;
916 }
917 
918 TEE_Result syscall_storage_obj_trunc(unsigned long obj, size_t len)
919 {
920 	TEE_Result res;
921 	struct tee_ta_session *sess;
922 	struct tee_obj *o;
923 	size_t off;
924 	size_t attr_size;
925 
926 	res = tee_ta_get_current_session(&sess);
927 	if (res != TEE_SUCCESS)
928 		goto exit;
929 
930 	res = tee_obj_get(to_user_ta_ctx(sess->ctx),
931 			  tee_svc_uref_to_vaddr(obj), &o);
932 	if (res != TEE_SUCCESS)
933 		goto exit;
934 
935 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
936 		res = TEE_ERROR_BAD_STATE;
937 		goto exit;
938 	}
939 
940 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) {
941 		res = TEE_ERROR_ACCESS_CONFLICT;
942 		goto exit;
943 	}
944 
945 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
946 	if (res != TEE_SUCCESS)
947 		goto exit;
948 
949 	off = sizeof(struct tee_svc_storage_head) + attr_size;
950 	res = o->pobj->fops->truncate(o->fh, len + off);
951 	if (res != TEE_SUCCESS) {
952 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
953 			EMSG("Object corrupt\n");
954 			res = tee_svc_storage_remove_corrupt_obj(sess, o);
955 			if (res != TEE_SUCCESS)
956 				goto exit;
957 			res = TEE_ERROR_CORRUPT_OBJECT;
958 			goto exit;
959 		} else
960 			res = TEE_ERROR_GENERIC;
961 	}
962 
963 exit:
964 	return res;
965 }
966 
967 TEE_Result syscall_storage_obj_seek(unsigned long obj, int32_t offset,
968 				    unsigned long whence)
969 {
970 	TEE_Result res;
971 	struct tee_ta_session *sess;
972 	struct tee_obj *o;
973 	size_t attr_size;
974 	tee_fs_off_t new_pos;
975 
976 	res = tee_ta_get_current_session(&sess);
977 	if (res != TEE_SUCCESS)
978 		return res;
979 
980 	res = tee_obj_get(to_user_ta_ctx(sess->ctx),
981 			  tee_svc_uref_to_vaddr(obj), &o);
982 	if (res != TEE_SUCCESS)
983 		return res;
984 
985 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT))
986 		return TEE_ERROR_BAD_STATE;
987 
988 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
989 	if (res != TEE_SUCCESS)
990 		return res;
991 
992 	switch (whence) {
993 	case TEE_DATA_SEEK_SET:
994 		new_pos = offset;
995 		break;
996 	case TEE_DATA_SEEK_CUR:
997 		new_pos = o->info.dataPosition + offset;
998 		break;
999 	case TEE_DATA_SEEK_END:
1000 		new_pos = o->info.dataSize + offset;
1001 		break;
1002 	default:
1003 		return TEE_ERROR_BAD_PARAMETERS;
1004 	}
1005 
1006 	if (new_pos < 0)
1007 		new_pos = 0;
1008 
1009 	if (new_pos > TEE_DATA_MAX_POSITION) {
1010 		EMSG("Position is beyond TEE_DATA_MAX_POSITION");
1011 		return TEE_ERROR_BAD_PARAMETERS;
1012 	}
1013 
1014 	o->info.dataPosition = new_pos;
1015 
1016 	return TEE_SUCCESS;
1017 }
1018 
1019 void tee_svc_storage_close_all_enum(struct user_ta_ctx *utc)
1020 {
1021 	struct tee_storage_enum_head *eh = &utc->storage_enums;
1022 
1023 	/* disregard return value */
1024 	while (!TAILQ_EMPTY(eh))
1025 		tee_svc_close_enum(utc, TAILQ_FIRST(eh));
1026 }
1027