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