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