xref: /optee_os/core/tee/tee_svc_storage.c (revision 9fc2442cc66c279cb962c90c4375746fc9b28bb9)
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 const struct tee_file_operations *tee_svc_storage_file_ops(uint32_t storage_id)
28 {
29 
30 	switch (storage_id) {
31 	case TEE_STORAGE_PRIVATE:
32 #if defined(CFG_REE_FS)
33 		return &ree_fs_ops;
34 #elif defined(CFG_RPMB_FS)
35 		return &rpmb_fs_ops;
36 #else
37 #error At least one filesystem must be enabled.
38 #endif
39 #ifdef CFG_REE_FS
40 	case TEE_STORAGE_PRIVATE_REE:
41 		return &ree_fs_ops;
42 #endif
43 #ifdef CFG_RPMB_FS
44 	case TEE_STORAGE_PRIVATE_RPMB:
45 		return &rpmb_fs_ops;
46 #endif
47 	default:
48 		return NULL;
49 	}
50 }
51 
52 /* Header of GP formated secure storage files */
53 struct tee_svc_storage_head {
54 	uint32_t attr_size;
55 	uint32_t keySize;
56 	uint32_t maxKeySize;
57 	uint32_t objectUsage;
58 	uint32_t objectType;
59 	uint32_t have_attrs;
60 };
61 
62 struct tee_storage_enum {
63 	TAILQ_ENTRY(tee_storage_enum) link;
64 	struct tee_fs_dir *dir;
65 	const struct tee_file_operations *fops;
66 };
67 
68 static TEE_Result tee_svc_storage_get_enum(struct user_ta_ctx *utc,
69 					   vaddr_t enum_id,
70 					   struct tee_storage_enum **e_out)
71 {
72 	struct tee_storage_enum *e;
73 
74 	TAILQ_FOREACH(e, &utc->storage_enums, link) {
75 		if (enum_id == (vaddr_t)e) {
76 			*e_out = e;
77 			return TEE_SUCCESS;
78 		}
79 	}
80 	return TEE_ERROR_BAD_PARAMETERS;
81 }
82 
83 static TEE_Result tee_svc_close_enum(struct user_ta_ctx *utc,
84 				     struct tee_storage_enum *e)
85 {
86 	if (e == NULL || utc == NULL)
87 		return TEE_ERROR_BAD_PARAMETERS;
88 
89 	TAILQ_REMOVE(&utc->storage_enums, e, link);
90 
91 	if (e->fops)
92 		e->fops->closedir(e->dir);
93 
94 	e->dir = NULL;
95 	e->fops = NULL;
96 
97 	free(e);
98 
99 	return TEE_SUCCESS;
100 }
101 
102 /* "/TA_uuid/object_id" or "/TA_uuid/.object_id" */
103 TEE_Result tee_svc_storage_create_filename(void *buf, size_t blen,
104 					   struct tee_pobj *po, bool transient)
105 {
106 	uint8_t *file = buf;
107 	uint32_t pos = 0;
108 	uint32_t hslen = 1 /* Leading slash */
109 			+ TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID) + po->obj_id_len)
110 			+ 1; /* Intermediate slash */
111 
112 	/* +1 for the '.' (temporary persistent object) */
113 	if (transient)
114 		hslen++;
115 
116 	if (blen < hslen)
117 		return TEE_ERROR_SHORT_BUFFER;
118 
119 	file[pos++] = '/';
120 	pos += tee_b2hs((uint8_t *)&po->uuid, &file[pos],
121 			sizeof(TEE_UUID), hslen);
122 	file[pos++] = '/';
123 
124 	if (transient)
125 		file[pos++] = '.';
126 
127 	tee_b2hs(po->obj_id, file + pos, po->obj_id_len, hslen - pos);
128 
129 	return TEE_SUCCESS;
130 }
131 
132 #ifdef CFG_REE_FS
133 /* "/dirf.db" or "/<file number>" */
134 TEE_Result
135 tee_svc_storage_create_filename_dfh(void *buf, size_t blen,
136 				    const struct tee_fs_dirfile_fileh *dfh)
137 {
138 	char *file = buf;
139 	size_t pos = 0;
140 	size_t l;
141 
142 	if (pos >= blen)
143 		return TEE_ERROR_SHORT_BUFFER;
144 
145 	file[pos] = '/';
146 	pos++;
147 	if (pos >= blen)
148 		return TEE_ERROR_SHORT_BUFFER;
149 
150 	l = blen - pos;
151 	return tee_fs_dirfile_fileh_to_fname(dfh, file + pos, &l);
152 }
153 #endif
154 
155 /* "/TA_uuid" */
156 TEE_Result tee_svc_storage_create_dirname(void *buf, size_t blen,
157 					  const TEE_UUID *uuid)
158 {
159 	uint8_t *dir = buf;
160 	uint32_t hslen = TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID)) + 1;
161 
162 	if (blen < hslen)
163 		return TEE_ERROR_SHORT_BUFFER;
164 
165 	dir[0] = '/';
166 	tee_b2hs((uint8_t *)uuid, dir + 1, sizeof(TEE_UUID), hslen);
167 
168 	return TEE_SUCCESS;
169 }
170 
171 static TEE_Result tee_svc_storage_remove_corrupt_obj(struct ts_session *sess,
172 						     struct tee_obj *o)
173 {
174 	o->pobj->fops->remove(o->pobj);
175 	tee_obj_close(to_user_ta_ctx(sess->ctx), o);
176 
177 	return TEE_SUCCESS;
178 }
179 
180 static TEE_Result tee_svc_storage_read_head(struct tee_obj *o)
181 {
182 	TEE_Result res = TEE_SUCCESS;
183 	size_t bytes;
184 	struct tee_svc_storage_head head;
185 	const struct tee_file_operations *fops = o->pobj->fops;
186 	void *attr = NULL;
187 	size_t size;
188 	size_t tmp = 0;
189 
190 	assert(!o->fh);
191 	res = fops->open(o->pobj, &size, &o->fh);
192 	if (res != TEE_SUCCESS)
193 		goto exit;
194 
195 	/* read head */
196 	bytes = sizeof(struct tee_svc_storage_head);
197 	res = fops->read(o->fh, 0, &head, &bytes);
198 	if (res != TEE_SUCCESS) {
199 		if (res == TEE_ERROR_CORRUPT_OBJECT)
200 			EMSG("Head corrupt");
201 		goto exit;
202 	}
203 
204 	if (ADD_OVERFLOW(sizeof(head), head.attr_size, &tmp)) {
205 		res = TEE_ERROR_OVERFLOW;
206 		goto exit;
207 	}
208 	if (tmp > size) {
209 		res = TEE_ERROR_CORRUPT_OBJECT;
210 		goto exit;
211 	}
212 
213 	if (bytes != sizeof(struct tee_svc_storage_head)) {
214 		res = TEE_ERROR_BAD_FORMAT;
215 		goto exit;
216 	}
217 
218 	res = tee_obj_set_type(o, head.objectType, head.maxKeySize);
219 	if (res != TEE_SUCCESS)
220 		goto exit;
221 
222 	o->ds_pos = tmp;
223 
224 	if (head.attr_size) {
225 		attr = malloc(head.attr_size);
226 		if (!attr) {
227 			res = TEE_ERROR_OUT_OF_MEMORY;
228 			goto exit;
229 		}
230 
231 		/* read meta */
232 		bytes = head.attr_size;
233 		res = fops->read(o->fh, sizeof(struct tee_svc_storage_head),
234 				 attr, &bytes);
235 		if (res == TEE_ERROR_OUT_OF_MEMORY)
236 			goto exit;
237 		if (res != TEE_SUCCESS || bytes != head.attr_size)
238 			res = TEE_ERROR_CORRUPT_OBJECT;
239 		if (res)
240 			goto exit;
241 	}
242 
243 	res = tee_obj_attr_from_binary(o, attr, head.attr_size);
244 	if (res != TEE_SUCCESS)
245 		goto exit;
246 
247 	o->info.dataSize = size - sizeof(head) - head.attr_size;
248 	o->info.keySize = head.keySize;
249 	o->info.objectUsage = head.objectUsage;
250 	o->info.objectType = head.objectType;
251 	o->have_attrs = head.have_attrs;
252 
253 exit:
254 	free(attr);
255 
256 	return res;
257 }
258 
259 TEE_Result syscall_storage_obj_open(unsigned long storage_id, void *object_id,
260 				    size_t object_id_len, unsigned long flags,
261 				    uint32_t *obj)
262 {
263 	const unsigned long valid_flags = TEE_DATA_FLAG_ACCESS_READ |
264 					  TEE_DATA_FLAG_ACCESS_WRITE |
265 					  TEE_DATA_FLAG_ACCESS_WRITE_META |
266 					  TEE_DATA_FLAG_SHARE_READ |
267 					  TEE_DATA_FLAG_SHARE_WRITE;
268 	const struct tee_file_operations *fops =
269 			tee_svc_storage_file_ops(storage_id);
270 	struct ts_session *sess = ts_get_current_session();
271 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
272 	TEE_Result res = TEE_SUCCESS;
273 	struct tee_pobj *po = NULL;
274 	struct tee_obj *o = NULL;
275 	char *file = NULL;
276 
277 	if (flags & ~valid_flags)
278 		return TEE_ERROR_BAD_PARAMETERS;
279 
280 	if (!fops) {
281 		res = TEE_ERROR_ITEM_NOT_FOUND;
282 		goto exit;
283 	}
284 
285 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN) {
286 		res = TEE_ERROR_BAD_PARAMETERS;
287 		goto exit;
288 	}
289 
290 	res = vm_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_READ,
291 				     (uaddr_t)object_id, 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 = vm_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 = vm_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 	uint8_t *data = NULL;
521 	size_t len = 0;
522 
523 	res = tee_obj_get(utc, uref_to_vaddr(obj), &o);
524 	if (res != TEE_SUCCESS)
525 		return res;
526 
527 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE_META))
528 		return TEE_ERROR_ACCESS_CONFLICT;
529 
530 	if (o->pobj == NULL || o->pobj->obj_id == NULL)
531 		return TEE_ERROR_BAD_STATE;
532 
533 	if (IS_ENABLED(CFG_NXP_SE05X)) {
534 		len = o->info.dataSize;
535 		data = calloc(1, len);
536 		if (!data)
537 			return TEE_ERROR_OUT_OF_MEMORY;
538 
539 		res = o->pobj->fops->read(o->fh, o->info.dataPosition,
540 					  data, &len);
541 		if (res == TEE_SUCCESS)
542 			crypto_storage_obj_del(data, len);
543 		free(data);
544 	}
545 
546 	res = o->pobj->fops->remove(o->pobj);
547 	tee_obj_close(utc, o);
548 
549 	return res;
550 }
551 
552 TEE_Result syscall_storage_obj_rename(unsigned long obj, void *object_id,
553 				      size_t object_id_len)
554 {
555 	const struct tee_file_operations *fops = NULL;
556 	struct ts_session *sess = ts_get_current_session();
557 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
558 	TEE_Result res = TEE_SUCCESS;
559 	struct tee_pobj *po = NULL;
560 	struct tee_obj *o = NULL;
561 	char *new_file = NULL;
562 	char *old_file = NULL;
563 
564 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
565 		return TEE_ERROR_BAD_PARAMETERS;
566 
567 	res = tee_obj_get(utc, uref_to_vaddr(obj), &o);
568 	if (res != TEE_SUCCESS)
569 		return res;
570 
571 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
572 		res = TEE_ERROR_BAD_STATE;
573 		goto exit;
574 	}
575 
576 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE_META)) {
577 		res = TEE_ERROR_BAD_STATE;
578 		goto exit;
579 	}
580 
581 	if (o->pobj == NULL || o->pobj->obj_id == NULL) {
582 		res = TEE_ERROR_BAD_STATE;
583 		goto exit;
584 	}
585 
586 	res = vm_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_READ,
587 				     (uaddr_t)object_id, object_id_len);
588 	if (res != TEE_SUCCESS)
589 		goto exit;
590 
591 	/* reserve dest name */
592 	fops = o->pobj->fops;
593 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
594 			   object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META,
595 			   TEE_POBJ_USAGE_RENAME, fops, &po);
596 	if (res != TEE_SUCCESS)
597 		goto exit;
598 
599 	/* move */
600 	res = fops->rename(o->pobj, po, false /* no overwrite */);
601 	if (res)
602 		goto exit;
603 
604 	res = tee_pobj_rename(o->pobj, object_id, object_id_len);
605 
606 exit:
607 	tee_pobj_release(po);
608 
609 	free(new_file);
610 	free(old_file);
611 
612 	return res;
613 }
614 
615 TEE_Result syscall_storage_alloc_enum(uint32_t *obj_enum)
616 {
617 	struct ts_session *sess = ts_get_current_session();
618 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
619 	struct tee_storage_enum *e = NULL;
620 
621 	if (obj_enum == NULL)
622 		return TEE_ERROR_BAD_PARAMETERS;
623 
624 	e = malloc(sizeof(struct tee_storage_enum));
625 	if (e == NULL)
626 		return TEE_ERROR_OUT_OF_MEMORY;
627 
628 	e->dir = NULL;
629 	e->fops = NULL;
630 	TAILQ_INSERT_TAIL(&utc->storage_enums, e, link);
631 
632 	return copy_kaddr_to_uref(obj_enum, e);
633 }
634 
635 TEE_Result syscall_storage_free_enum(unsigned long obj_enum)
636 {
637 	struct ts_session *sess = ts_get_current_session();
638 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
639 	struct tee_storage_enum *e = NULL;
640 	TEE_Result res = TEE_SUCCESS;
641 
642 	res = tee_svc_storage_get_enum(utc,
643 			uref_to_vaddr(obj_enum), &e);
644 	if (res != TEE_SUCCESS)
645 		return res;
646 
647 	return tee_svc_close_enum(utc, e);
648 }
649 
650 TEE_Result syscall_storage_reset_enum(unsigned long obj_enum)
651 {
652 	struct ts_session *sess = ts_get_current_session();
653 	struct tee_storage_enum *e = NULL;
654 	TEE_Result res = TEE_SUCCESS;
655 
656 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
657 				       uref_to_vaddr(obj_enum), &e);
658 	if (res != TEE_SUCCESS)
659 		return res;
660 
661 	if (e->fops) {
662 		e->fops->closedir(e->dir);
663 		e->fops = NULL;
664 		e->dir = NULL;
665 	}
666 	assert(!e->dir);
667 
668 	return TEE_SUCCESS;
669 }
670 
671 TEE_Result syscall_storage_start_enum(unsigned long obj_enum,
672 				      unsigned long storage_id)
673 {
674 	struct ts_session *sess = ts_get_current_session();
675 	struct tee_storage_enum *e = NULL;
676 	TEE_Result res = TEE_SUCCESS;
677 	const struct tee_file_operations *fops =
678 			tee_svc_storage_file_ops(storage_id);
679 
680 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
681 				       uref_to_vaddr(obj_enum), &e);
682 	if (res != TEE_SUCCESS)
683 		return res;
684 
685 	if (e->dir) {
686 		e->fops->closedir(e->dir);
687 		e->dir = NULL;
688 	}
689 
690 	if (!fops)
691 		return TEE_ERROR_ITEM_NOT_FOUND;
692 
693 	e->fops = fops;
694 
695 	return fops->opendir(&sess->ctx->uuid, &e->dir);
696 }
697 
698 TEE_Result syscall_storage_next_enum(unsigned long obj_enum,
699 			TEE_ObjectInfo *info, void *obj_id, uint64_t *len)
700 {
701 	struct ts_session *sess = ts_get_current_session();
702 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
703 	struct tee_storage_enum *e = NULL;
704 	struct tee_fs_dirent *d = NULL;
705 	TEE_Result res = TEE_SUCCESS;
706 	struct tee_obj *o = NULL;
707 	uint64_t l = 0;
708 
709 	res = tee_svc_storage_get_enum(utc, uref_to_vaddr(obj_enum), &e);
710 	if (res != TEE_SUCCESS)
711 		goto exit;
712 
713 	/* check rights of the provided buffers */
714 	res = vm_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_WRITE,
715 				     (uaddr_t)info, sizeof(TEE_ObjectInfo));
716 	if (res != TEE_SUCCESS)
717 		goto exit;
718 
719 	res = vm_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_WRITE,
720 				     (uaddr_t)obj_id, TEE_OBJECT_ID_MAX_LEN);
721 	if (res != TEE_SUCCESS)
722 		goto exit;
723 
724 	if (!e->fops) {
725 		res = TEE_ERROR_ITEM_NOT_FOUND;
726 		goto exit;
727 	}
728 
729 	res = e->fops->readdir(e->dir, &d);
730 	if (res != TEE_SUCCESS)
731 		goto exit;
732 
733 	o = tee_obj_alloc();
734 	if (o == NULL) {
735 		res = TEE_ERROR_OUT_OF_MEMORY;
736 		goto exit;
737 	}
738 
739 	res = tee_pobj_get(&sess->ctx->uuid, d->oid, d->oidlen, 0,
740 			   TEE_POBJ_USAGE_ENUM, e->fops, &o->pobj);
741 	if (res)
742 		goto exit;
743 
744 	o->info.handleFlags = o->pobj->flags | TEE_HANDLE_FLAG_PERSISTENT |
745 			      TEE_HANDLE_FLAG_INITIALIZED;
746 
747 	res = tee_svc_storage_read_head(o);
748 	if (res != TEE_SUCCESS)
749 		goto exit;
750 
751 	memcpy(info, &o->info, sizeof(TEE_ObjectInfo));
752 	memcpy(obj_id, o->pobj->obj_id, o->pobj->obj_id_len);
753 
754 	l = o->pobj->obj_id_len;
755 	res = copy_to_user_private(len, &l, sizeof(*len));
756 
757 exit:
758 	if (o) {
759 		if (o->pobj) {
760 			o->pobj->fops->close(&o->fh);
761 			tee_pobj_release(o->pobj);
762 		}
763 		tee_obj_free(o);
764 	}
765 
766 	return res;
767 }
768 
769 TEE_Result syscall_storage_obj_read(unsigned long obj, void *data, size_t len,
770 				    uint64_t *count)
771 {
772 	struct ts_session *sess = ts_get_current_session();
773 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
774 	TEE_Result res = TEE_SUCCESS;
775 	struct tee_obj *o = NULL;
776 	uint64_t u_count = 0;
777 	size_t pos_tmp = 0;
778 	size_t bytes = 0;
779 
780 	res = tee_obj_get(utc, uref_to_vaddr(obj), &o);
781 	if (res != TEE_SUCCESS)
782 		goto exit;
783 
784 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
785 		res = TEE_ERROR_BAD_STATE;
786 		goto exit;
787 	}
788 
789 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_READ)) {
790 		res = TEE_ERROR_ACCESS_CONFLICT;
791 		goto exit;
792 	}
793 
794 	/* Guard o->info.dataPosition += bytes below from overflowing */
795 	if (ADD_OVERFLOW(o->info.dataPosition, len, &pos_tmp)) {
796 		res = TEE_ERROR_OVERFLOW;
797 		goto exit;
798 	}
799 
800 	/* check rights of the provided buffer */
801 	res = vm_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_WRITE,
802 				     (uaddr_t)data, len);
803 	if (res != TEE_SUCCESS)
804 		goto exit;
805 
806 	bytes = len;
807 	if (ADD_OVERFLOW(o->ds_pos, o->info.dataPosition, &pos_tmp)) {
808 		res = TEE_ERROR_OVERFLOW;
809 		goto exit;
810 	}
811 	res = o->pobj->fops->read(o->fh, pos_tmp, data, &bytes);
812 	if (res != TEE_SUCCESS) {
813 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
814 			EMSG("Object corrupt");
815 			tee_svc_storage_remove_corrupt_obj(sess, o);
816 		}
817 		goto exit;
818 	}
819 
820 	o->info.dataPosition += bytes;
821 
822 	u_count = bytes;
823 	res = copy_to_user_private(count, &u_count, sizeof(*count));
824 exit:
825 	return res;
826 }
827 
828 TEE_Result syscall_storage_obj_write(unsigned long obj, void *data, size_t len)
829 {
830 	struct ts_session *sess = ts_get_current_session();
831 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
832 	TEE_Result res = TEE_SUCCESS;
833 	struct tee_obj *o = NULL;
834 	size_t pos_tmp = 0;
835 
836 	res = tee_obj_get(utc, uref_to_vaddr(obj), &o);
837 	if (res != TEE_SUCCESS)
838 		goto exit;
839 
840 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
841 		res = TEE_ERROR_BAD_STATE;
842 		goto exit;
843 	}
844 
845 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE)) {
846 		res = TEE_ERROR_ACCESS_CONFLICT;
847 		goto exit;
848 	}
849 
850 	/* Guard o->info.dataPosition += bytes below from overflowing */
851 	if (ADD_OVERFLOW(o->info.dataPosition, len, &pos_tmp)) {
852 		res = TEE_ERROR_OVERFLOW;
853 		goto exit;
854 	}
855 
856 	/* check rights of the provided buffer */
857 	res = vm_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_READ,
858 				     (uaddr_t)data, len);
859 	if (res != TEE_SUCCESS)
860 		goto exit;
861 
862 	if (ADD_OVERFLOW(o->ds_pos, o->info.dataPosition, &pos_tmp)) {
863 		res = TEE_ERROR_ACCESS_CONFLICT;
864 		goto exit;
865 	}
866 	res = o->pobj->fops->write(o->fh, pos_tmp, data, len);
867 	if (res != TEE_SUCCESS)
868 		goto exit;
869 
870 	o->info.dataPosition += len;
871 	if (o->info.dataPosition > o->info.dataSize)
872 		o->info.dataSize = o->info.dataPosition;
873 
874 exit:
875 	return res;
876 }
877 
878 TEE_Result syscall_storage_obj_trunc(unsigned long obj, size_t len)
879 {
880 	struct ts_session *sess = ts_get_current_session();
881 	TEE_Result res = TEE_SUCCESS;
882 	struct tee_obj *o = NULL;
883 	size_t off = 0;
884 	size_t attr_size = 0;
885 
886 	res = tee_obj_get(to_user_ta_ctx(sess->ctx), uref_to_vaddr(obj), &o);
887 	if (res != TEE_SUCCESS)
888 		goto exit;
889 
890 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
891 		res = TEE_ERROR_BAD_STATE;
892 		goto exit;
893 	}
894 
895 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE)) {
896 		res = TEE_ERROR_ACCESS_CONFLICT;
897 		goto exit;
898 	}
899 
900 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
901 	if (res != TEE_SUCCESS)
902 		goto exit;
903 
904 	if (ADD_OVERFLOW(sizeof(struct tee_svc_storage_head), attr_size,
905 				&off)) {
906 		res = TEE_ERROR_OVERFLOW;
907 		goto exit;
908 	}
909 	if (ADD_OVERFLOW(len, off, &off)) {
910 		res = TEE_ERROR_OVERFLOW;
911 		goto exit;
912 	}
913 	res = o->pobj->fops->truncate(o->fh, off);
914 	switch (res) {
915 	case TEE_SUCCESS:
916 		o->info.dataSize = len;
917 		break;
918 	case TEE_ERROR_CORRUPT_OBJECT:
919 		EMSG("Object corruption");
920 		(void)tee_svc_storage_remove_corrupt_obj(sess, o);
921 		break;
922 	default:
923 		res = TEE_ERROR_GENERIC;
924 		break;
925 	}
926 
927 exit:
928 	return res;
929 }
930 
931 TEE_Result syscall_storage_obj_seek(unsigned long obj, int32_t offset,
932 				    unsigned long whence)
933 {
934 	struct ts_session *sess = ts_get_current_session();
935 	TEE_Result res = TEE_SUCCESS;
936 	struct tee_obj *o = NULL;
937 	tee_fs_off_t new_pos = 0;
938 
939 	res = tee_obj_get(to_user_ta_ctx(sess->ctx), uref_to_vaddr(obj), &o);
940 	if (res != TEE_SUCCESS)
941 		return res;
942 
943 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT))
944 		return TEE_ERROR_BAD_STATE;
945 
946 	switch (whence) {
947 	case TEE_DATA_SEEK_SET:
948 		new_pos = offset;
949 		break;
950 	case TEE_DATA_SEEK_CUR:
951 		if (ADD_OVERFLOW(o->info.dataPosition, offset, &new_pos))
952 			return TEE_ERROR_OVERFLOW;
953 		break;
954 	case TEE_DATA_SEEK_END:
955 		if (ADD_OVERFLOW(o->info.dataSize, offset, &new_pos))
956 			return TEE_ERROR_OVERFLOW;
957 		break;
958 	default:
959 		return TEE_ERROR_BAD_PARAMETERS;
960 	}
961 
962 	if (new_pos < 0)
963 		new_pos = 0;
964 
965 	if (new_pos > TEE_DATA_MAX_POSITION) {
966 		EMSG("Position is beyond TEE_DATA_MAX_POSITION");
967 		return TEE_ERROR_BAD_PARAMETERS;
968 	}
969 
970 	o->info.dataPosition = new_pos;
971 
972 	return TEE_SUCCESS;
973 }
974 
975 void tee_svc_storage_close_all_enum(struct user_ta_ctx *utc)
976 {
977 	struct tee_storage_enum_head *eh = &utc->storage_enums;
978 
979 	/* disregard return value */
980 	while (!TAILQ_EMPTY(eh))
981 		tee_svc_close_enum(utc, TAILQ_FIRST(eh));
982 }
983