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