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