xref: /optee_os/core/tee/tee_svc_storage.c (revision 6885abf2f7ef758b0a9c5f3580af167a53ec28dd)
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 	size_t tmp = 0;
185 
186 	assert(!o->fh);
187 	res = fops->open(o->pobj, &size, &o->fh);
188 	if (res != TEE_SUCCESS)
189 		goto exit;
190 
191 	/* read head */
192 	bytes = sizeof(struct tee_svc_storage_head);
193 	res = fops->read(o->fh, 0, &head, &bytes);
194 	if (res != TEE_SUCCESS) {
195 		if (res == TEE_ERROR_CORRUPT_OBJECT)
196 			EMSG("Head corrupt");
197 		goto exit;
198 	}
199 
200 	if (ADD_OVERFLOW(sizeof(head), head.attr_size, &tmp)) {
201 		res = TEE_ERROR_OVERFLOW;
202 		goto exit;
203 	}
204 	if (tmp > size) {
205 		res = TEE_ERROR_CORRUPT_OBJECT;
206 		goto exit;
207 	}
208 
209 	if (bytes != sizeof(struct tee_svc_storage_head)) {
210 		res = TEE_ERROR_BAD_FORMAT;
211 		goto exit;
212 	}
213 
214 	res = tee_obj_set_type(o, head.objectType, head.maxKeySize);
215 	if (res != TEE_SUCCESS)
216 		goto exit;
217 
218 	o->ds_pos = tmp;
219 
220 	if (head.attr_size) {
221 		attr = malloc(head.attr_size);
222 		if (!attr) {
223 			res = TEE_ERROR_OUT_OF_MEMORY;
224 			goto exit;
225 		}
226 
227 		/* read meta */
228 		bytes = head.attr_size;
229 		res = fops->read(o->fh, sizeof(struct tee_svc_storage_head),
230 				 attr, &bytes);
231 		if (res == TEE_ERROR_OUT_OF_MEMORY)
232 			goto exit;
233 		if (res != TEE_SUCCESS || bytes != head.attr_size)
234 			res = TEE_ERROR_CORRUPT_OBJECT;
235 		if (res)
236 			goto exit;
237 	}
238 
239 	res = tee_obj_attr_from_binary(o, attr, head.attr_size);
240 	if (res != TEE_SUCCESS)
241 		goto exit;
242 
243 	o->info.dataSize = size - sizeof(head) - head.attr_size;
244 	o->info.keySize = head.keySize;
245 	o->info.objectUsage = head.objectUsage;
246 	o->info.objectType = head.objectType;
247 	o->have_attrs = head.have_attrs;
248 
249 exit:
250 	free(attr);
251 
252 	return res;
253 }
254 
255 TEE_Result syscall_storage_obj_open(unsigned long storage_id, void *object_id,
256 				    size_t object_id_len, unsigned long flags,
257 				    uint32_t *obj)
258 {
259 	const unsigned long valid_flags = TEE_DATA_FLAG_ACCESS_READ |
260 					  TEE_DATA_FLAG_ACCESS_WRITE |
261 					  TEE_DATA_FLAG_ACCESS_WRITE_META |
262 					  TEE_DATA_FLAG_SHARE_READ |
263 					  TEE_DATA_FLAG_SHARE_WRITE;
264 	const struct tee_file_operations *fops =
265 			tee_svc_storage_file_ops(storage_id);
266 	struct tee_ta_session *sess = NULL;
267 	struct user_ta_ctx *utc = NULL;
268 	TEE_Result res = TEE_SUCCESS;
269 	struct tee_pobj *po = NULL;
270 	struct tee_obj *o = NULL;
271 	char *file = NULL;
272 
273 	if (flags & ~valid_flags)
274 		return TEE_ERROR_BAD_PARAMETERS;
275 
276 	if (!fops) {
277 		res = TEE_ERROR_ITEM_NOT_FOUND;
278 		goto exit;
279 	}
280 
281 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN) {
282 		res = TEE_ERROR_BAD_PARAMETERS;
283 		goto exit;
284 	}
285 
286 	res = tee_ta_get_current_session(&sess);
287 	if (res != TEE_SUCCESS)
288 		goto err;
289 	utc = to_user_ta_ctx(sess->ctx);
290 
291 	res = tee_mmu_check_access_rights(&utc->uctx,
292 					  TEE_MEMORY_ACCESS_READ,
293 					  (uaddr_t) object_id,
294 					  object_id_len);
295 	if (res != TEE_SUCCESS)
296 		goto err;
297 
298 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
299 			   object_id_len, flags, TEE_POBJ_USAGE_OPEN, fops,
300 			   &po);
301 	if (res != TEE_SUCCESS)
302 		goto err;
303 
304 	o = tee_obj_alloc();
305 	if (o == NULL) {
306 		tee_pobj_release(po);
307 		res = TEE_ERROR_OUT_OF_MEMORY;
308 		goto err;
309 	}
310 
311 	o->info.handleFlags = TEE_HANDLE_FLAG_PERSISTENT |
312 			      TEE_HANDLE_FLAG_INITIALIZED | flags;
313 	o->pobj = po;
314 	tee_obj_add(utc, o);
315 
316 	res = tee_svc_storage_read_head(o);
317 	if (res != TEE_SUCCESS) {
318 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
319 			EMSG("Object corrupt");
320 			goto err;
321 		}
322 		goto oclose;
323 	}
324 
325 	res = tee_svc_copy_kaddr_to_uref(obj, o);
326 	if (res != TEE_SUCCESS)
327 		goto oclose;
328 
329 	goto exit;
330 
331 oclose:
332 	tee_obj_close(utc, o);
333 	o = NULL;
334 
335 err:
336 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
337 		res = TEE_ERROR_CORRUPT_OBJECT;
338 	if (res == TEE_ERROR_CORRUPT_OBJECT && o)
339 		tee_svc_storage_remove_corrupt_obj(sess, o);
340 
341 exit:
342 	free(file);
343 	file = NULL;
344 	return res;
345 }
346 
347 static TEE_Result tee_svc_storage_init_file(struct tee_obj *o, bool overwrite,
348 					    struct tee_obj *attr_o, void *data,
349 					    uint32_t len)
350 {
351 	TEE_Result res = TEE_SUCCESS;
352 	struct tee_svc_storage_head head;
353 	const struct tee_file_operations *fops = o->pobj->fops;
354 	void *attr = NULL;
355 	size_t attr_size = 0;
356 
357 	if (attr_o) {
358 		res = tee_obj_set_type(o, attr_o->info.objectType,
359 				       attr_o->info.maxKeySize);
360 		if (res)
361 			return res;
362 		res = tee_obj_attr_copy_from(o, attr_o);
363 		if (res)
364 			return res;
365 		o->have_attrs = attr_o->have_attrs;
366 		o->info.objectUsage = attr_o->info.objectUsage;
367 		o->info.keySize = attr_o->info.keySize;
368 		res = tee_obj_attr_to_binary(o, NULL, &attr_size);
369 		if (res)
370 			return res;
371 		if (attr_size) {
372 			attr = malloc(attr_size);
373 			if (!attr)
374 				return TEE_ERROR_OUT_OF_MEMORY;
375 			res = tee_obj_attr_to_binary(o, attr, &attr_size);
376 			if (res != TEE_SUCCESS)
377 				goto exit;
378 		}
379 	} else {
380 		res = tee_obj_set_type(o, TEE_TYPE_DATA, 0);
381 		if (res != TEE_SUCCESS)
382 			goto exit;
383 	}
384 
385 	o->ds_pos = sizeof(struct tee_svc_storage_head) + attr_size;
386 
387 	/* write head */
388 	head.attr_size = attr_size;
389 	head.keySize = o->info.keySize;
390 	head.maxKeySize = o->info.maxKeySize;
391 	head.objectUsage = o->info.objectUsage;
392 	head.objectType = o->info.objectType;
393 	head.have_attrs = o->have_attrs;
394 
395 	res = fops->create(o->pobj, overwrite, &head, sizeof(head), attr,
396 			   attr_size, data, len, &o->fh);
397 
398 	if (!res)
399 		o->info.dataSize = len;
400 exit:
401 	free(attr);
402 	return res;
403 }
404 
405 TEE_Result syscall_storage_obj_create(unsigned long storage_id, void *object_id,
406 			size_t object_id_len, unsigned long flags,
407 			unsigned long attr, void *data, size_t len,
408 			uint32_t *obj)
409 {
410 	const unsigned long valid_flags = TEE_DATA_FLAG_ACCESS_READ |
411 					  TEE_DATA_FLAG_ACCESS_WRITE |
412 					  TEE_DATA_FLAG_ACCESS_WRITE_META |
413 					  TEE_DATA_FLAG_SHARE_READ |
414 					  TEE_DATA_FLAG_SHARE_WRITE |
415 					  TEE_DATA_FLAG_OVERWRITE;
416 	const struct tee_file_operations *fops =
417 			tee_svc_storage_file_ops(storage_id);
418 	struct tee_ta_session *sess = NULL;
419 	struct user_ta_ctx *utc = NULL;
420 	struct tee_obj *attr_o = NULL;
421 	TEE_Result res = TEE_SUCCESS;
422 	struct tee_pobj *po = NULL;
423 	struct tee_obj *o = NULL;
424 
425 	if (flags & ~valid_flags)
426 		return TEE_ERROR_BAD_PARAMETERS;
427 
428 	if (!fops)
429 		return TEE_ERROR_ITEM_NOT_FOUND;
430 
431 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
432 		return TEE_ERROR_BAD_PARAMETERS;
433 
434 	res = tee_ta_get_current_session(&sess);
435 	if (res != TEE_SUCCESS)
436 		return res;
437 	utc = to_user_ta_ctx(sess->ctx);
438 
439 	res = tee_mmu_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_READ,
440 					  (uaddr_t)object_id, object_id_len);
441 	if (res != TEE_SUCCESS)
442 		goto err;
443 
444 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
445 			   object_id_len, flags, TEE_POBJ_USAGE_CREATE,
446 			   fops, &po);
447 	if (res != TEE_SUCCESS)
448 		goto err;
449 
450 	/* check rights of the provided buffer */
451 	if (len) {
452 		if (data) {
453 			uint32_t f = TEE_MEMORY_ACCESS_READ |
454 				     TEE_MEMORY_ACCESS_ANY_OWNER;
455 
456 			res = tee_mmu_check_access_rights(&utc->uctx, f,
457 							  (uaddr_t)data, len);
458 
459 			if (res != TEE_SUCCESS)
460 				goto err;
461 		} else {
462 			res = TEE_ERROR_BAD_PARAMETERS;
463 			goto err;
464 		}
465 	}
466 
467 	o = tee_obj_alloc();
468 	if (o == NULL) {
469 		res = TEE_ERROR_OUT_OF_MEMORY;
470 		goto err;
471 	}
472 
473 	o->info.handleFlags = TEE_HANDLE_FLAG_PERSISTENT |
474 			      TEE_HANDLE_FLAG_INITIALIZED | flags;
475 	o->pobj = po;
476 
477 	if (attr != TEE_HANDLE_NULL) {
478 		res = tee_obj_get(utc, tee_svc_uref_to_vaddr(attr),
479 				  &attr_o);
480 		if (res != TEE_SUCCESS)
481 			goto err;
482 		/* The supplied handle must be one of an initialized object */
483 		if (!(attr_o->info.handleFlags & TEE_HANDLE_FLAG_INITIALIZED)) {
484 			res = TEE_ERROR_BAD_PARAMETERS;
485 			goto err;
486 		}
487 	}
488 
489 	res = tee_svc_storage_init_file(o, flags & TEE_DATA_FLAG_OVERWRITE,
490 					attr_o, data, len);
491 	if (res != TEE_SUCCESS)
492 		goto err;
493 
494 	po = NULL; /* o owns it from now on */
495 	tee_obj_add(utc, o);
496 
497 	res = tee_svc_copy_kaddr_to_uref(obj, o);
498 	if (res != TEE_SUCCESS)
499 		goto oclose;
500 
501 	return TEE_SUCCESS;
502 
503 oclose:
504 	tee_obj_close(utc, o);
505 	return res;
506 
507 err:
508 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
509 		res = TEE_ERROR_CORRUPT_OBJECT;
510 	if (res == TEE_ERROR_CORRUPT_OBJECT && po)
511 		fops->remove(po);
512 	if (o) {
513 		fops->close(&o->fh);
514 		tee_obj_free(o);
515 	}
516 	if (po)
517 		tee_pobj_release(po);
518 
519 	return res;
520 }
521 
522 TEE_Result syscall_storage_obj_del(unsigned long obj)
523 {
524 	TEE_Result res;
525 	struct tee_ta_session *sess;
526 	struct tee_obj *o;
527 	struct user_ta_ctx *utc;
528 
529 	res = tee_ta_get_current_session(&sess);
530 	if (res != TEE_SUCCESS)
531 		return res;
532 	utc = to_user_ta_ctx(sess->ctx);
533 
534 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
535 	if (res != TEE_SUCCESS)
536 		return res;
537 
538 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE_META))
539 		return TEE_ERROR_ACCESS_CONFLICT;
540 
541 	if (o->pobj == NULL || o->pobj->obj_id == NULL)
542 		return TEE_ERROR_BAD_STATE;
543 
544 	res = o->pobj->fops->remove(o->pobj);
545 	tee_obj_close(utc, o);
546 
547 	return res;
548 }
549 
550 TEE_Result syscall_storage_obj_rename(unsigned long obj, void *object_id,
551 				      size_t object_id_len)
552 {
553 	const struct tee_file_operations *fops = NULL;
554 	struct tee_ta_session *sess = NULL;
555 	struct user_ta_ctx *utc = NULL;
556 	TEE_Result res = TEE_SUCCESS;
557 	struct tee_pobj *po = NULL;
558 	struct tee_obj *o = NULL;
559 	char *new_file = NULL;
560 	char *old_file = NULL;
561 
562 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
563 		return TEE_ERROR_BAD_PARAMETERS;
564 
565 	res = tee_ta_get_current_session(&sess);
566 	if (res != TEE_SUCCESS)
567 		return res;
568 	utc = to_user_ta_ctx(sess->ctx);
569 
570 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
571 	if (res != TEE_SUCCESS)
572 		return res;
573 
574 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
575 		res = TEE_ERROR_BAD_STATE;
576 		goto exit;
577 	}
578 
579 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE_META)) {
580 		res = TEE_ERROR_BAD_STATE;
581 		goto exit;
582 	}
583 
584 	if (o->pobj == NULL || o->pobj->obj_id == NULL) {
585 		res = TEE_ERROR_BAD_STATE;
586 		goto exit;
587 	}
588 
589 	res = tee_mmu_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_READ,
590 					  (uaddr_t)object_id, object_id_len);
591 	if (res != TEE_SUCCESS)
592 		goto exit;
593 
594 	/* reserve dest name */
595 	fops = o->pobj->fops;
596 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
597 			   object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META,
598 			   TEE_POBJ_USAGE_RENAME, fops, &po);
599 	if (res != TEE_SUCCESS)
600 		goto exit;
601 
602 	/* move */
603 	res = fops->rename(o->pobj, po, false /* no overwrite */);
604 	if (res)
605 		goto exit;
606 
607 	res = tee_pobj_rename(o->pobj, object_id, object_id_len);
608 
609 exit:
610 	tee_pobj_release(po);
611 
612 	free(new_file);
613 	free(old_file);
614 
615 	return res;
616 }
617 
618 TEE_Result syscall_storage_alloc_enum(uint32_t *obj_enum)
619 {
620 	struct tee_storage_enum *e;
621 	struct tee_ta_session *sess;
622 	TEE_Result res;
623 	struct user_ta_ctx *utc;
624 
625 	if (obj_enum == NULL)
626 		return TEE_ERROR_BAD_PARAMETERS;
627 
628 	res = tee_ta_get_current_session(&sess);
629 	if (res != TEE_SUCCESS)
630 		return res;
631 	utc = to_user_ta_ctx(sess->ctx);
632 
633 	e = malloc(sizeof(struct tee_storage_enum));
634 	if (e == NULL)
635 		return TEE_ERROR_OUT_OF_MEMORY;
636 
637 	e->dir = NULL;
638 	e->fops = NULL;
639 	TAILQ_INSERT_TAIL(&utc->storage_enums, e, link);
640 
641 	return tee_svc_copy_kaddr_to_uref(obj_enum, e);
642 }
643 
644 TEE_Result syscall_storage_free_enum(unsigned long obj_enum)
645 {
646 	struct tee_storage_enum *e;
647 	TEE_Result res;
648 	struct tee_ta_session *sess;
649 	struct user_ta_ctx *utc;
650 
651 	res = tee_ta_get_current_session(&sess);
652 	if (res != TEE_SUCCESS)
653 		return res;
654 	utc = to_user_ta_ctx(sess->ctx);
655 
656 	res = tee_svc_storage_get_enum(utc,
657 			tee_svc_uref_to_vaddr(obj_enum), &e);
658 	if (res != TEE_SUCCESS)
659 		return res;
660 
661 	return tee_svc_close_enum(utc, e);
662 }
663 
664 TEE_Result syscall_storage_reset_enum(unsigned long obj_enum)
665 {
666 	struct tee_storage_enum *e;
667 	TEE_Result res;
668 	struct tee_ta_session *sess;
669 
670 	res = tee_ta_get_current_session(&sess);
671 	if (res != TEE_SUCCESS)
672 		return res;
673 
674 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
675 			tee_svc_uref_to_vaddr(obj_enum), &e);
676 	if (res != TEE_SUCCESS)
677 		return res;
678 
679 	if (e->fops) {
680 		e->fops->closedir(e->dir);
681 		e->fops = NULL;
682 		e->dir = NULL;
683 	}
684 	assert(!e->dir);
685 
686 	return TEE_SUCCESS;
687 }
688 
689 static TEE_Result tee_svc_storage_set_enum(struct tee_fs_dirent *d,
690 			const struct tee_file_operations *fops,
691 			struct tee_obj *o)
692 {
693 	o->info.handleFlags =
694 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
695 	o->info.objectUsage = TEE_USAGE_DEFAULT;
696 
697 	if (d->oidlen > TEE_OBJECT_ID_MAX_LEN)
698 		return TEE_ERROR_CORRUPT_OBJECT;
699 
700 	o->pobj->obj_id = malloc(d->oidlen);
701 	if (!o->pobj->obj_id)
702 		return TEE_ERROR_OUT_OF_MEMORY;
703 
704 	memcpy(o->pobj->obj_id, d->oid, d->oidlen);
705 	o->pobj->obj_id_len = d->oidlen;
706 	o->pobj->fops = fops;
707 
708 	return TEE_SUCCESS;
709 }
710 
711 TEE_Result syscall_storage_start_enum(unsigned long obj_enum,
712 				      unsigned long storage_id)
713 {
714 	struct tee_storage_enum *e;
715 	TEE_Result res;
716 	struct tee_ta_session *sess;
717 	const struct tee_file_operations *fops =
718 			tee_svc_storage_file_ops(storage_id);
719 
720 	res = tee_ta_get_current_session(&sess);
721 	if (res != TEE_SUCCESS)
722 		return res;
723 
724 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
725 			tee_svc_uref_to_vaddr(obj_enum), &e);
726 	if (res != TEE_SUCCESS)
727 		return res;
728 
729 	if (e->dir) {
730 		e->fops->closedir(e->dir);
731 		e->dir = NULL;
732 	}
733 
734 	if (!fops)
735 		return TEE_ERROR_ITEM_NOT_FOUND;
736 
737 	e->fops = fops;
738 
739 	return fops->opendir(&sess->ctx->uuid, &e->dir);
740 }
741 
742 TEE_Result syscall_storage_next_enum(unsigned long obj_enum,
743 			TEE_ObjectInfo *info, void *obj_id, uint64_t *len)
744 {
745 	struct tee_ta_session *sess = NULL;
746 	struct tee_storage_enum *e = NULL;
747 	struct tee_fs_dirent *d = NULL;
748 	struct user_ta_ctx *utc = NULL;
749 	TEE_Result res = TEE_SUCCESS;
750 	struct tee_obj *o = NULL;
751 	uint64_t l = 0;
752 
753 	res = tee_ta_get_current_session(&sess);
754 	if (res != TEE_SUCCESS)
755 		goto exit;
756 	utc = to_user_ta_ctx(sess->ctx);
757 
758 	res = tee_svc_storage_get_enum(utc,
759 			tee_svc_uref_to_vaddr(obj_enum), &e);
760 	if (res != TEE_SUCCESS)
761 		goto exit;
762 
763 	/* check rights of the provided buffers */
764 	res = tee_mmu_check_access_rights(&utc->uctx,
765 					  TEE_MEMORY_ACCESS_WRITE |
766 					  TEE_MEMORY_ACCESS_ANY_OWNER,
767 					  (uaddr_t)info,
768 					  sizeof(TEE_ObjectInfo));
769 	if (res != TEE_SUCCESS)
770 		goto exit;
771 
772 	res = tee_mmu_check_access_rights(&utc->uctx,
773 					  TEE_MEMORY_ACCESS_WRITE |
774 					  TEE_MEMORY_ACCESS_ANY_OWNER,
775 					  (uaddr_t)obj_id,
776 					  TEE_OBJECT_ID_MAX_LEN);
777 	if (res != TEE_SUCCESS)
778 		goto exit;
779 
780 	if (!e->fops) {
781 		res = TEE_ERROR_ITEM_NOT_FOUND;
782 		goto exit;
783 	}
784 
785 	res = e->fops->readdir(e->dir, &d);
786 	if (res != TEE_SUCCESS)
787 		goto exit;
788 
789 	o = tee_obj_alloc();
790 	if (o == NULL) {
791 		res = TEE_ERROR_OUT_OF_MEMORY;
792 		goto exit;
793 	}
794 	o->info.handleFlags = TEE_DATA_FLAG_SHARE_READ;
795 
796 	o->pobj = calloc(1, sizeof(struct tee_pobj));
797 	if (!o->pobj) {
798 		res = TEE_ERROR_OUT_OF_MEMORY;
799 		goto exit;
800 	}
801 
802 	o->pobj->uuid = sess->ctx->uuid;
803 	res = tee_svc_storage_set_enum(d, e->fops, o);
804 	if (res != TEE_SUCCESS)
805 		goto exit;
806 
807 	res = tee_svc_storage_read_head(o);
808 	if (res != TEE_SUCCESS)
809 		goto exit;
810 
811 	memcpy(info, &o->info, sizeof(TEE_ObjectInfo));
812 	memcpy(obj_id, o->pobj->obj_id, o->pobj->obj_id_len);
813 
814 	l = o->pobj->obj_id_len;
815 	res = tee_svc_copy_to_user(len, &l, sizeof(*len));
816 
817 exit:
818 	if (o) {
819 		if (o->pobj) {
820 			if (o->pobj->fops)
821 				o->pobj->fops->close(&o->fh);
822 			free(o->pobj->obj_id);
823 		}
824 		free(o->pobj);
825 		tee_obj_free(o);
826 	}
827 
828 	return res;
829 }
830 
831 TEE_Result syscall_storage_obj_read(unsigned long obj, void *data, size_t len,
832 				    uint64_t *count)
833 {
834 	struct tee_ta_session *sess = NULL;
835 	struct user_ta_ctx *utc = NULL;
836 	TEE_Result res = TEE_SUCCESS;
837 	struct tee_obj *o = NULL;
838 	uint64_t u_count = 0;
839 	size_t pos_tmp = 0;
840 	size_t bytes = 0;
841 
842 	res = tee_ta_get_current_session(&sess);
843 	if (res != TEE_SUCCESS)
844 		goto exit;
845 	utc = to_user_ta_ctx(sess->ctx);
846 
847 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
848 	if (res != TEE_SUCCESS)
849 		goto exit;
850 
851 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
852 		res = TEE_ERROR_BAD_STATE;
853 		goto exit;
854 	}
855 
856 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_READ)) {
857 		res = TEE_ERROR_ACCESS_CONFLICT;
858 		goto exit;
859 	}
860 
861 	/* Guard o->info.dataPosition += bytes below from overflowing */
862 	if (ADD_OVERFLOW(o->info.dataPosition, len, &pos_tmp)) {
863 		res = TEE_ERROR_OVERFLOW;
864 		goto exit;
865 	}
866 
867 	/* check rights of the provided buffer */
868 	res = tee_mmu_check_access_rights(&utc->uctx,
869 					  TEE_MEMORY_ACCESS_WRITE |
870 					  TEE_MEMORY_ACCESS_ANY_OWNER,
871 					  (uaddr_t)data, len);
872 	if (res != TEE_SUCCESS)
873 		goto exit;
874 
875 	bytes = len;
876 	if (ADD_OVERFLOW(o->ds_pos, o->info.dataPosition, &pos_tmp)) {
877 		res = TEE_ERROR_OVERFLOW;
878 		goto exit;
879 	}
880 	res = o->pobj->fops->read(o->fh, pos_tmp, data, &bytes);
881 	if (res != TEE_SUCCESS) {
882 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
883 			EMSG("Object corrupt");
884 			tee_svc_storage_remove_corrupt_obj(sess, o);
885 		}
886 		goto exit;
887 	}
888 
889 	o->info.dataPosition += bytes;
890 
891 	u_count = bytes;
892 	res = tee_svc_copy_to_user(count, &u_count, sizeof(*count));
893 exit:
894 	return res;
895 }
896 
897 TEE_Result syscall_storage_obj_write(unsigned long obj, void *data, size_t len)
898 {
899 	struct tee_ta_session *sess = NULL;
900 	struct user_ta_ctx *utc = NULL;
901 	TEE_Result res = TEE_SUCCESS;
902 	struct tee_obj *o = NULL;
903 	size_t pos_tmp = 0;
904 
905 	res = tee_ta_get_current_session(&sess);
906 	if (res != TEE_SUCCESS)
907 		goto exit;
908 	utc = to_user_ta_ctx(sess->ctx);
909 
910 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
911 	if (res != TEE_SUCCESS)
912 		goto exit;
913 
914 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
915 		res = TEE_ERROR_BAD_STATE;
916 		goto exit;
917 	}
918 
919 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE)) {
920 		res = TEE_ERROR_ACCESS_CONFLICT;
921 		goto exit;
922 	}
923 
924 	/* Guard o->info.dataPosition += bytes below from overflowing */
925 	if (ADD_OVERFLOW(o->info.dataPosition, len, &pos_tmp)) {
926 		res = TEE_ERROR_OVERFLOW;
927 		goto exit;
928 	}
929 
930 	/* check rights of the provided buffer */
931 	res = tee_mmu_check_access_rights(&utc->uctx,
932 					  TEE_MEMORY_ACCESS_READ |
933 					  TEE_MEMORY_ACCESS_ANY_OWNER,
934 					  (uaddr_t)data, len);
935 	if (res != TEE_SUCCESS)
936 		goto exit;
937 
938 	if (ADD_OVERFLOW(o->ds_pos, o->info.dataPosition, &pos_tmp)) {
939 		res = TEE_ERROR_ACCESS_CONFLICT;
940 		goto exit;
941 	}
942 	res = o->pobj->fops->write(o->fh, pos_tmp, data, len);
943 	if (res != TEE_SUCCESS)
944 		goto exit;
945 
946 	o->info.dataPosition += len;
947 	if (o->info.dataPosition > o->info.dataSize)
948 		o->info.dataSize = o->info.dataPosition;
949 
950 exit:
951 	return res;
952 }
953 
954 TEE_Result syscall_storage_obj_trunc(unsigned long obj, size_t len)
955 {
956 	TEE_Result res;
957 	struct tee_ta_session *sess;
958 	struct tee_obj *o;
959 	size_t off;
960 	size_t attr_size;
961 
962 	res = tee_ta_get_current_session(&sess);
963 	if (res != TEE_SUCCESS)
964 		goto exit;
965 
966 	res = tee_obj_get(to_user_ta_ctx(sess->ctx),
967 			  tee_svc_uref_to_vaddr(obj), &o);
968 	if (res != TEE_SUCCESS)
969 		goto exit;
970 
971 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
972 		res = TEE_ERROR_BAD_STATE;
973 		goto exit;
974 	}
975 
976 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE)) {
977 		res = TEE_ERROR_ACCESS_CONFLICT;
978 		goto exit;
979 	}
980 
981 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
982 	if (res != TEE_SUCCESS)
983 		goto exit;
984 
985 	if (ADD_OVERFLOW(sizeof(struct tee_svc_storage_head), attr_size,
986 				&off)) {
987 		res = TEE_ERROR_OVERFLOW;
988 		goto exit;
989 	}
990 	if (ADD_OVERFLOW(len, off, &off)) {
991 		res = TEE_ERROR_OVERFLOW;
992 		goto exit;
993 	}
994 	res = o->pobj->fops->truncate(o->fh, off);
995 	switch (res) {
996 	case TEE_SUCCESS:
997 		o->info.dataSize = len;
998 		break;
999 	case TEE_ERROR_CORRUPT_OBJECT:
1000 		EMSG("Object corruption");
1001 		(void)tee_svc_storage_remove_corrupt_obj(sess, o);
1002 		break;
1003 	default:
1004 		res = TEE_ERROR_GENERIC;
1005 		break;
1006 	}
1007 
1008 exit:
1009 	return res;
1010 }
1011 
1012 TEE_Result syscall_storage_obj_seek(unsigned long obj, int32_t offset,
1013 				    unsigned long whence)
1014 {
1015 	TEE_Result res;
1016 	struct tee_ta_session *sess;
1017 	struct tee_obj *o;
1018 	tee_fs_off_t new_pos;
1019 
1020 	res = tee_ta_get_current_session(&sess);
1021 	if (res != TEE_SUCCESS)
1022 		return res;
1023 
1024 	res = tee_obj_get(to_user_ta_ctx(sess->ctx),
1025 			  tee_svc_uref_to_vaddr(obj), &o);
1026 	if (res != TEE_SUCCESS)
1027 		return res;
1028 
1029 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT))
1030 		return TEE_ERROR_BAD_STATE;
1031 
1032 	switch (whence) {
1033 	case TEE_DATA_SEEK_SET:
1034 		new_pos = offset;
1035 		break;
1036 	case TEE_DATA_SEEK_CUR:
1037 		if (ADD_OVERFLOW(o->info.dataPosition, offset, &new_pos))
1038 			return TEE_ERROR_OVERFLOW;
1039 		break;
1040 	case TEE_DATA_SEEK_END:
1041 		if (ADD_OVERFLOW(o->info.dataSize, offset, &new_pos))
1042 			return TEE_ERROR_OVERFLOW;
1043 		break;
1044 	default:
1045 		return TEE_ERROR_BAD_PARAMETERS;
1046 	}
1047 
1048 	if (new_pos < 0)
1049 		new_pos = 0;
1050 
1051 	if (new_pos > TEE_DATA_MAX_POSITION) {
1052 		EMSG("Position is beyond TEE_DATA_MAX_POSITION");
1053 		return TEE_ERROR_BAD_PARAMETERS;
1054 	}
1055 
1056 	o->info.dataPosition = new_pos;
1057 
1058 	return TEE_SUCCESS;
1059 }
1060 
1061 void tee_svc_storage_close_all_enum(struct user_ta_ctx *utc)
1062 {
1063 	struct tee_storage_enum_head *eh = &utc->storage_enums;
1064 
1065 	/* disregard return value */
1066 	while (!TAILQ_EMPTY(eh))
1067 		tee_svc_close_enum(utc, TAILQ_FIRST(eh));
1068 }
1069