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