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