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