xref: /optee_os/core/tee/tee_svc_storage.c (revision 0dcfa5686d022738f9e6372b19e6b30851523dd0)
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/tee_fs_defs.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 #elif defined(CFG_SQL_FS)
59 		return &sql_fs_ops;
60 #else
61 #error At least one filesystem must be enabled.
62 #endif
63 #ifdef CFG_REE_FS
64 	case TEE_STORAGE_PRIVATE_REE:
65 		return &ree_fs_ops;
66 #endif
67 #ifdef CFG_RPMB_FS
68 	case TEE_STORAGE_PRIVATE_RPMB:
69 		return &rpmb_fs_ops;
70 #endif
71 #ifdef CFG_SQL_FS
72 	case TEE_STORAGE_PRIVATE_SQL:
73 		return &sql_fs_ops;
74 #endif
75 	default:
76 		return NULL;
77 	}
78 }
79 
80 /* SSF (Secure Storage File version 00 */
81 #define TEE_SVC_STORAGE_MAGIC 0x53534600
82 
83 /* Header of GP formated secure storage files */
84 struct tee_svc_storage_head {
85 	uint32_t magic;
86 	uint32_t head_size;
87 	uint32_t meta_size;
88 	uint32_t ds_size;
89 	uint32_t keySize;
90 	uint32_t maxKeySize;
91 	uint32_t objectUsage;
92 	uint32_t objectType;
93 	uint32_t have_attrs;
94 };
95 
96 struct tee_storage_enum {
97 	TAILQ_ENTRY(tee_storage_enum) link;
98 	struct tee_fs_dir *dir;
99 	const struct tee_file_operations *fops;
100 };
101 
102 /*
103  * Protect TA storage directory: avoid race conditions between (create
104  * directory + create file) and (remove directory)
105  */
106 static struct mutex ta_dir_mutex = MUTEX_INITIALIZER;
107 
108 static TEE_Result tee_svc_storage_get_enum(struct user_ta_ctx *utc,
109 					   uint32_t enum_id,
110 					   struct tee_storage_enum **e_out)
111 {
112 	struct tee_storage_enum *e;
113 
114 	TAILQ_FOREACH(e, &utc->storage_enums, link) {
115 		if (enum_id == (vaddr_t)e) {
116 			*e_out = e;
117 			return TEE_SUCCESS;
118 		}
119 	}
120 	return TEE_ERROR_BAD_PARAMETERS;
121 }
122 
123 static TEE_Result tee_svc_close_enum(struct user_ta_ctx *utc,
124 				     struct tee_storage_enum *e)
125 {
126 	if (e == NULL || utc == NULL)
127 		return TEE_ERROR_BAD_PARAMETERS;
128 
129 	TAILQ_REMOVE(&utc->storage_enums, e, link);
130 
131 	if (!e->fops)
132 		return TEE_ERROR_ITEM_NOT_FOUND;
133 
134 	e->fops->closedir(e->dir);
135 	e->dir = NULL;
136 	e->fops = NULL;
137 
138 	free(e);
139 
140 	return TEE_SUCCESS;
141 }
142 
143 /* "/TA_uuid/object_id" or "/TA_uuid/.object_id" */
144 char *tee_svc_storage_create_filename(struct tee_ta_session *sess,
145 				      void *object_id,
146 				      uint32_t object_id_len,
147 				      bool transient)
148 {
149 	uint8_t *file;
150 	uint32_t pos = 0;
151 	uint32_t hslen = 1 /* Leading slash */
152 			+ TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID) + object_id_len)
153 			+ 1; /* Intermediate slash */
154 
155 	/* +1 for the '.' (temporary persistent object) */
156 	if (transient)
157 		hslen++;
158 
159 	file = malloc(hslen);
160 	if (!file)
161 		return NULL;
162 
163 	file[pos++] = '/';
164 	pos += tee_b2hs((uint8_t *)&sess->ctx->uuid, &file[pos],
165 			sizeof(TEE_UUID), hslen);
166 	file[pos++] = '/';
167 
168 	if (transient)
169 		file[pos++] = '.';
170 
171 	tee_b2hs(object_id, file + pos, object_id_len, hslen - pos);
172 
173 	return (char *)file;
174 }
175 
176 /* "/TA_uuid" */
177 char *tee_svc_storage_create_dirname(struct tee_ta_session *sess)
178 {
179 	uint8_t *dir;
180 	uint32_t hslen = TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID)) + 1;
181 
182 	dir = malloc(hslen);
183 	if (!dir)
184 		return NULL;
185 
186 	dir[0] = '/';
187 	tee_b2hs((uint8_t *)&sess->ctx->uuid, dir + 1, sizeof(TEE_UUID),
188 		 hslen);
189 
190 	return (char *)dir;
191 }
192 
193 static TEE_Result tee_svc_storage_remove_corrupt_obj(
194 					struct tee_ta_session *sess,
195 					struct tee_obj *o)
196 {
197 	TEE_Result res;
198 	char *file = NULL;
199 	const struct tee_file_operations *fops = o->pobj->fops;
200 
201 	file = tee_svc_storage_create_filename(sess,
202 					       o->pobj->obj_id,
203 					       o->pobj->obj_id_len,
204 					       false);
205 	if (file == NULL) {
206 		res = TEE_ERROR_OUT_OF_MEMORY;
207 		goto exit;
208 	}
209 
210 	tee_obj_close(to_user_ta_ctx(sess->ctx), o);
211 	fops->remove(file);
212 	free(file);
213 
214 	res = TEE_SUCCESS;
215 
216 exit:
217 	return res;
218 }
219 
220 static TEE_Result tee_svc_storage_read_head(struct tee_ta_session *sess,
221 				     struct tee_obj *o)
222 {
223 	TEE_Result res = TEE_SUCCESS;
224 	size_t bytes;
225 	struct tee_svc_storage_head head;
226 	char *file = NULL;
227 	const struct tee_file_operations *fops;
228 	void *attr = NULL;
229 
230 	if (o == NULL || o->pobj == NULL)
231 		return TEE_ERROR_BAD_PARAMETERS;
232 
233 	fops = o->pobj->fops;
234 
235 	file = tee_svc_storage_create_filename(sess,
236 					       o->pobj->obj_id,
237 					       o->pobj->obj_id_len,
238 					       false);
239 	if (file == NULL) {
240 		res = TEE_ERROR_OUT_OF_MEMORY;
241 		goto exit;
242 	}
243 
244 	assert(!o->fh);
245 	res = fops->open(file, &o->fh);
246 	if (res != TEE_SUCCESS)
247 		goto exit;
248 
249 	/* read head */
250 	bytes = sizeof(struct tee_svc_storage_head);
251 	res = fops->read(o->fh, &head, &bytes);
252 	if (res != TEE_SUCCESS) {
253 		if (res == TEE_ERROR_CORRUPT_OBJECT)
254 			EMSG("Head corrupt\n");
255 		goto exit;
256 	}
257 
258 	if (bytes != sizeof(struct tee_svc_storage_head)) {
259 		res = TEE_ERROR_BAD_FORMAT;
260 		goto exit;
261 	}
262 
263 	res = tee_obj_set_type(o, head.objectType, head.maxKeySize);
264 	if (res != TEE_SUCCESS)
265 		goto exit;
266 
267 	if (head.meta_size) {
268 		attr = malloc(head.meta_size);
269 		if (!attr) {
270 			res = TEE_ERROR_OUT_OF_MEMORY;
271 			goto exit;
272 		}
273 
274 		/* read meta */
275 		bytes = head.meta_size;
276 		res = fops->read(o->fh, attr, &bytes);
277 		if (res != TEE_SUCCESS || bytes != head.meta_size) {
278 			res = TEE_ERROR_CORRUPT_OBJECT;
279 			goto exit;
280 		}
281 	}
282 
283 	res = tee_obj_attr_from_binary(o, attr, head.meta_size);
284 	if (res != TEE_SUCCESS)
285 		goto exit;
286 
287 	o->info.dataSize = head.ds_size;
288 	o->info.keySize = head.keySize;
289 	o->info.objectUsage = head.objectUsage;
290 	o->info.objectType = head.objectType;
291 	o->have_attrs = head.have_attrs;
292 
293 exit:
294 	free(attr);
295 	free(file);
296 
297 	return res;
298 }
299 
300 static TEE_Result tee_svc_storage_update_head(struct tee_obj *o,
301 					uint32_t ds_size)
302 {
303 	TEE_Result res;
304 	const struct tee_file_operations *fops;
305 	int32_t old_off;
306 
307 	fops = o->pobj->fops;
308 
309 	/* save original offset */
310 	res = fops->seek(o->fh, 0, TEE_DATA_SEEK_CUR, &old_off);
311 	if (res != TEE_SUCCESS)
312 		return res;
313 
314 	/* update head.ds_size */
315 	res = fops->seek(o->fh, offsetof(struct tee_svc_storage_head,
316 			ds_size), TEE_DATA_SEEK_SET, NULL);
317 	if (res != TEE_SUCCESS)
318 		return res;
319 
320 	res = fops->write(o->fh, &ds_size, sizeof(uint32_t));
321 	if (res != TEE_SUCCESS)
322 		return res;
323 
324 	/* restore original offset */
325 	res = fops->seek(o->fh, old_off, TEE_DATA_SEEK_SET, NULL);
326 	return res;
327 }
328 
329 static TEE_Result tee_svc_storage_init_file(struct tee_ta_session *sess,
330 					    struct tee_obj *o,
331 					    struct tee_obj *attr_o, void *data,
332 					    uint32_t len)
333 {
334 	TEE_Result res = TEE_SUCCESS;
335 	struct tee_svc_storage_head head;
336 	char *tmpfile = NULL;
337 	const struct tee_file_operations *fops;
338 	void *attr = NULL;
339 	size_t attr_size = 0;
340 
341 	if (o == NULL || o->pobj == NULL)
342 		return TEE_ERROR_BAD_PARAMETERS;
343 
344 	fops = o->pobj->fops;
345 
346 	/* create temporary persistent object filename */
347 	tmpfile = tee_svc_storage_create_filename(sess,
348 						   o->pobj->obj_id,
349 						   o->pobj->obj_id_len,
350 						   true);
351 
352 	if (tmpfile == NULL) {
353 		res = TEE_ERROR_OUT_OF_MEMORY;
354 		goto exit;
355 	}
356 
357 	mutex_lock(&ta_dir_mutex);
358 	res = fops->create(tmpfile, &o->fh);
359 	mutex_unlock(&ta_dir_mutex);
360 	if (res != TEE_SUCCESS)
361 		goto exit;
362 
363 	if (attr_o) {
364 		res = tee_obj_set_type(o, attr_o->info.objectType,
365 				       attr_o->info.maxKeySize);
366 		if (res != TEE_SUCCESS)
367 			goto exit;
368 		res = tee_obj_attr_copy_from(o, attr_o);
369 		if (res != TEE_SUCCESS)
370 			goto exit;
371 		o->have_attrs = attr_o->have_attrs;
372 		o->info.objectUsage = attr_o->info.objectUsage;
373 		o->info.keySize = attr_o->info.keySize;
374 		res = tee_obj_attr_to_binary(o, NULL, &attr_size);
375 		if (res != TEE_SUCCESS)
376 			goto exit;
377 		if (attr_size) {
378 			attr = malloc(attr_size);
379 			if (!attr) {
380 				res = TEE_ERROR_OUT_OF_MEMORY;
381 				goto exit;
382 			}
383 			res = tee_obj_attr_to_binary(o, attr, &attr_size);
384 			if (res != TEE_SUCCESS)
385 				goto exit;
386 		}
387 	} else {
388 		res = tee_obj_set_type(o, TEE_TYPE_DATA, 0);
389 		if (res != TEE_SUCCESS)
390 			goto exit;
391 	}
392 
393 	/* write head */
394 	head.magic = TEE_SVC_STORAGE_MAGIC;
395 	head.head_size = sizeof(struct tee_svc_storage_head);
396 	head.meta_size = attr_size;
397 	head.ds_size = len;
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 	/* write head */
405 	res = fops->write(o->fh, &head, sizeof(struct tee_svc_storage_head));
406 	if (res != TEE_SUCCESS)
407 		goto exit;
408 
409 	/* write meta */
410 	res = fops->write(o->fh, attr, attr_size);
411 	if (res != TEE_SUCCESS)
412 		goto exit;
413 
414 	/* write init data */
415 	o->info.dataSize = len;
416 
417 	/* write data to fs if needed */
418 	if (data && len)
419 		res = fops->write(o->fh, data, len);
420 
421 exit:
422 	free(attr);
423 	free(tmpfile);
424 	fops->close(&o->fh);
425 
426 	return res;
427 }
428 
429 TEE_Result syscall_storage_obj_open(unsigned long storage_id, void *object_id,
430 			size_t object_id_len, unsigned long flags,
431 			uint32_t *obj)
432 {
433 	TEE_Result res;
434 	struct tee_ta_session *sess;
435 	struct tee_obj *o = NULL;
436 	char *file = NULL;
437 	struct tee_pobj *po = NULL;
438 	struct user_ta_ctx *utc;
439 	const struct tee_file_operations *fops = file_ops(storage_id);
440 	size_t attr_size;
441 
442 	if (!fops) {
443 		res = TEE_ERROR_ITEM_NOT_FOUND;
444 		goto exit;
445 	}
446 
447 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN) {
448 		res = TEE_ERROR_BAD_PARAMETERS;
449 		goto exit;
450 	}
451 
452 	res = tee_ta_get_current_session(&sess);
453 	if (res != TEE_SUCCESS)
454 		goto err;
455 	utc = to_user_ta_ctx(sess->ctx);
456 
457 	res = tee_mmu_check_access_rights(utc,
458 					  TEE_MEMORY_ACCESS_READ |
459 					  TEE_MEMORY_ACCESS_ANY_OWNER,
460 					  (uaddr_t) object_id,
461 					  object_id_len);
462 	if (res != TEE_SUCCESS)
463 		goto err;
464 
465 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
466 			   object_id_len, flags, fops, &po);
467 	if (res != TEE_SUCCESS)
468 		goto err;
469 
470 	o = tee_obj_alloc();
471 	if (o == NULL) {
472 		tee_pobj_release(po);
473 		res = TEE_ERROR_OUT_OF_MEMORY;
474 		goto err;
475 	}
476 
477 	o->info.handleFlags =
478 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
479 	o->flags = flags;
480 	o->pobj = po;
481 	tee_obj_add(utc, o);
482 
483 	res = tee_svc_storage_read_head(sess, o);
484 	if (res != TEE_SUCCESS) {
485 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
486 			EMSG("Object corrupt");
487 			goto err;
488 		}
489 		goto oclose;
490 	}
491 
492 	res = tee_svc_copy_kaddr_to_uref(obj, o);
493 	if (res != TEE_SUCCESS)
494 		goto oclose;
495 
496 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
497 	if (res != TEE_SUCCESS)
498 		goto oclose;
499 
500 	res = fops->seek(o->fh, sizeof(struct tee_svc_storage_head) + attr_size,
501 			 TEE_DATA_SEEK_SET, NULL);
502 	if (res  != TEE_SUCCESS)
503 		goto err;
504 
505 	goto exit;
506 
507 oclose:
508 	tee_obj_close(utc, o);
509 	o = NULL;
510 
511 err:
512 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
513 		res = TEE_ERROR_CORRUPT_OBJECT;
514 	if (res == TEE_ERROR_CORRUPT_OBJECT && o)
515 		tee_svc_storage_remove_corrupt_obj(sess, o);
516 
517 exit:
518 	free(file);
519 	file = NULL;
520 	return res;
521 }
522 
523 TEE_Result syscall_storage_obj_create(unsigned long storage_id, void *object_id,
524 			size_t object_id_len, unsigned long flags,
525 			unsigned long attr, void *data, size_t len,
526 			uint32_t *obj)
527 {
528 	TEE_Result res;
529 	struct tee_ta_session *sess;
530 	struct tee_obj *o = NULL;
531 	struct tee_obj *attr_o = NULL;
532 	char *file = NULL;
533 	struct tee_pobj *po = NULL;
534 	char *tmpfile = NULL;
535 	struct user_ta_ctx *utc;
536 	const struct tee_file_operations *fops = file_ops(storage_id);
537 	size_t attr_size;
538 
539 	if (!fops)
540 		return TEE_ERROR_ITEM_NOT_FOUND;
541 
542 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
543 		return TEE_ERROR_BAD_PARAMETERS;
544 
545 	res = tee_ta_get_current_session(&sess);
546 	if (res != TEE_SUCCESS)
547 		return res;
548 	utc = to_user_ta_ctx(sess->ctx);
549 
550 	res = tee_mmu_check_access_rights(utc,
551 					  TEE_MEMORY_ACCESS_READ |
552 					  TEE_MEMORY_ACCESS_ANY_OWNER,
553 					  (uaddr_t) object_id,
554 					  object_id_len);
555 	if (res != TEE_SUCCESS)
556 		goto err;
557 
558 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
559 			   object_id_len, flags, fops, &po);
560 	if (res != TEE_SUCCESS)
561 		goto err;
562 
563 	/* check rights of the provided buffer */
564 	if (data && len) {
565 		res = tee_mmu_check_access_rights(utc,
566 						  TEE_MEMORY_ACCESS_READ |
567 						  TEE_MEMORY_ACCESS_ANY_OWNER,
568 						  (uaddr_t) data, len);
569 
570 		if (res != TEE_SUCCESS)
571 			goto err;
572 	}
573 
574 	o = tee_obj_alloc();
575 	if (o == NULL) {
576 		res = TEE_ERROR_OUT_OF_MEMORY;
577 		goto err;
578 	}
579 
580 	o->info.handleFlags =
581 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
582 	o->flags = flags;
583 	o->pobj = po;
584 
585 	if (attr != TEE_HANDLE_NULL) {
586 		res = tee_obj_get(utc, tee_svc_uref_to_vaddr(attr),
587 				  &attr_o);
588 		if (res != TEE_SUCCESS)
589 			goto err;
590 	}
591 
592 	res = tee_svc_storage_init_file(sess, o, attr_o, data, len);
593 	if (res != TEE_SUCCESS)
594 		goto err;
595 
596 	/* create persistent object filename */
597 	file = tee_svc_storage_create_filename(sess, object_id,
598 					       object_id_len, false);
599 	if (file == NULL) {
600 		res = TEE_ERROR_OUT_OF_MEMORY;
601 		goto err;
602 	}
603 
604 	/* create temporary persistent object filename */
605 	tmpfile = tee_svc_storage_create_filename(sess, object_id,
606 						  object_id_len,
607 						  true);
608 	if (tmpfile == NULL) {
609 		res = TEE_ERROR_OUT_OF_MEMORY;
610 		goto err;
611 	}
612 
613 	/* rename temporary persistent object filename */
614 	res = fops->rename(tmpfile, file, !!(flags & TEE_DATA_FLAG_OVERWRITE));
615 	if (res != TEE_SUCCESS)
616 		goto rmfile;
617 
618 	res = fops->open(file, &o->fh);
619 	if (res != TEE_SUCCESS)
620 		goto err;
621 
622 	tee_obj_add(utc, o);
623 
624 	res = tee_svc_copy_kaddr_to_uref(obj, o);
625 	if (res != TEE_SUCCESS)
626 		goto oclose;
627 
628 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
629 	if (res != TEE_SUCCESS)
630 		goto oclose;
631 
632 	res = fops->seek(o->fh, sizeof(struct tee_svc_storage_head) + attr_size,
633 			 TEE_DATA_SEEK_SET, NULL);
634 	if (res != TEE_SUCCESS)
635 		goto oclose;
636 
637 	goto exit;
638 
639 oclose:
640 	tee_obj_close(utc, o);
641 	goto exit;
642 
643 rmfile:
644 	fops->remove(tmpfile);
645 
646 err:
647 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
648 		res = TEE_ERROR_CORRUPT_OBJECT;
649 	if (res == TEE_ERROR_CORRUPT_OBJECT && file)
650 		fops->remove(file);
651 	if (o)
652 		fops->close(&o->fh);
653 	if (po)
654 		tee_pobj_release(po);
655 	free(o);
656 
657 exit:
658 	free(file);
659 	free(tmpfile);
660 
661 	return res;
662 }
663 
664 TEE_Result syscall_storage_obj_del(unsigned long obj)
665 {
666 	TEE_Result res;
667 	struct tee_ta_session *sess;
668 	struct tee_obj *o;
669 	char *file;
670 	struct user_ta_ctx *utc;
671 	const struct tee_file_operations *fops;
672 
673 	res = tee_ta_get_current_session(&sess);
674 	if (res != TEE_SUCCESS)
675 		return res;
676 	utc = to_user_ta_ctx(sess->ctx);
677 
678 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
679 	if (res != TEE_SUCCESS)
680 		return res;
681 
682 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META))
683 		return TEE_ERROR_ACCESS_CONFLICT;
684 
685 	if (o->pobj == NULL || o->pobj->obj_id == NULL)
686 		return TEE_ERROR_BAD_STATE;
687 
688 	file = tee_svc_storage_create_filename(sess, o->pobj->obj_id,
689 						o->pobj->obj_id_len, false);
690 	if (file == NULL)
691 		return TEE_ERROR_OUT_OF_MEMORY;
692 
693 	fops = o->pobj->fops;
694 	tee_obj_close(utc, o);
695 
696 	res = fops->remove(file);
697 	free(file);
698 	return res;
699 }
700 
701 TEE_Result syscall_storage_obj_rename(unsigned long obj, void *object_id,
702 			size_t object_id_len)
703 {
704 	TEE_Result res;
705 	struct tee_ta_session *sess;
706 	struct tee_obj *o;
707 	struct tee_pobj *po = NULL;
708 	char *new_file = NULL;
709 	char *old_file = NULL;
710 	struct user_ta_ctx *utc;
711 	const struct tee_file_operations *fops;
712 
713 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
714 		return TEE_ERROR_BAD_PARAMETERS;
715 
716 	res = tee_ta_get_current_session(&sess);
717 	if (res != TEE_SUCCESS)
718 		return res;
719 	utc = to_user_ta_ctx(sess->ctx);
720 
721 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
722 	if (res != TEE_SUCCESS)
723 		return res;
724 
725 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
726 		res = TEE_ERROR_BAD_STATE;
727 		goto exit;
728 	}
729 
730 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META)) {
731 		res = TEE_ERROR_BAD_STATE;
732 		goto exit;
733 	}
734 
735 	if (o->pobj == NULL || o->pobj->obj_id == NULL) {
736 		res = TEE_ERROR_BAD_STATE;
737 		goto exit;
738 	}
739 
740 	res = tee_mmu_check_access_rights(utc,
741 					TEE_MEMORY_ACCESS_READ |
742 					TEE_MEMORY_ACCESS_ANY_OWNER,
743 					(uaddr_t) object_id, object_id_len);
744 	if (res != TEE_SUCCESS)
745 		goto exit;
746 
747 	/* get new ds name */
748 	new_file = tee_svc_storage_create_filename(sess, object_id,
749 						   object_id_len, false);
750 	if (new_file == NULL) {
751 		res = TEE_ERROR_OUT_OF_MEMORY;
752 		goto exit;
753 	}
754 
755 	old_file = tee_svc_storage_create_filename(sess, o->pobj->obj_id,
756 						   o->pobj->obj_id_len, false);
757 	if (old_file == NULL) {
758 		res = TEE_ERROR_OUT_OF_MEMORY;
759 		goto exit;
760 	}
761 
762 	/* reserve dest name */
763 	fops = o->pobj->fops;
764 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
765 			   object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META,
766 			   fops, &po);
767 	if (res != TEE_SUCCESS)
768 		goto exit;
769 
770 	/* move */
771 	res = fops->rename(old_file, new_file, false /* no overwrite */);
772 	if (res == TEE_ERROR_GENERIC)
773 		goto exit;
774 
775 	res = tee_pobj_rename(o->pobj, object_id, object_id_len);
776 
777 exit:
778 	tee_pobj_release(po);
779 
780 	free(new_file);
781 	free(old_file);
782 
783 	return res;
784 }
785 
786 TEE_Result syscall_storage_alloc_enum(uint32_t *obj_enum)
787 {
788 	struct tee_storage_enum *e;
789 	struct tee_ta_session *sess;
790 	TEE_Result res;
791 	struct user_ta_ctx *utc;
792 
793 	if (obj_enum == NULL)
794 		return TEE_ERROR_BAD_PARAMETERS;
795 
796 	res = tee_ta_get_current_session(&sess);
797 	if (res != TEE_SUCCESS)
798 		return res;
799 	utc = to_user_ta_ctx(sess->ctx);
800 
801 	e = malloc(sizeof(struct tee_storage_enum));
802 	if (e == NULL)
803 		return TEE_ERROR_OUT_OF_MEMORY;
804 
805 	e->dir = NULL;
806 	e->fops = NULL;
807 	TAILQ_INSERT_TAIL(&utc->storage_enums, e, link);
808 
809 	return tee_svc_copy_kaddr_to_uref(obj_enum, e);
810 }
811 
812 TEE_Result syscall_storage_free_enum(unsigned long obj_enum)
813 {
814 	struct tee_storage_enum *e;
815 	TEE_Result res;
816 	struct tee_ta_session *sess;
817 	struct user_ta_ctx *utc;
818 
819 	res = tee_ta_get_current_session(&sess);
820 	if (res != TEE_SUCCESS)
821 		return res;
822 	utc = to_user_ta_ctx(sess->ctx);
823 
824 	res = tee_svc_storage_get_enum(utc,
825 			tee_svc_uref_to_vaddr(obj_enum), &e);
826 	if (res != TEE_SUCCESS)
827 		return res;
828 
829 	return tee_svc_close_enum(utc, e);
830 }
831 
832 TEE_Result syscall_storage_reset_enum(unsigned long obj_enum)
833 {
834 	struct tee_storage_enum *e;
835 	TEE_Result res;
836 	struct tee_ta_session *sess;
837 
838 	res = tee_ta_get_current_session(&sess);
839 	if (res != TEE_SUCCESS)
840 		return res;
841 
842 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
843 			tee_svc_uref_to_vaddr(obj_enum), &e);
844 	if (res != TEE_SUCCESS)
845 		return res;
846 
847 	e->fops->closedir(e->dir);
848 	e->dir = NULL;
849 
850 	return TEE_SUCCESS;
851 }
852 
853 static TEE_Result tee_svc_storage_set_enum(char *d_name,
854 			const struct tee_file_operations *fops,
855 			struct tee_obj *o)
856 {
857 	TEE_Result res;
858 	uint32_t blen;
859 	uint32_t hslen;
860 
861 	o->info.handleFlags =
862 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
863 	o->info.objectUsage = TEE_USAGE_DEFAULT;
864 
865 	hslen = strlen(d_name);
866 	blen = TEE_HS2B_BBUF_SIZE(hslen);
867 	o->pobj->obj_id = malloc(blen);
868 	if (!o->pobj->obj_id) {
869 		res = TEE_ERROR_OUT_OF_MEMORY;
870 		goto exit;
871 	}
872 	tee_hs2b((uint8_t *)d_name, o->pobj->obj_id, hslen, blen);
873 	o->pobj->obj_id_len = blen;
874 	o->pobj->fops = fops;
875 
876 	res = TEE_SUCCESS;
877 
878 exit:
879 	return res;
880 
881 }
882 
883 TEE_Result syscall_storage_start_enum(unsigned long obj_enum,
884 				      unsigned long storage_id)
885 {
886 	struct tee_storage_enum *e;
887 	char *dir;
888 	TEE_Result res;
889 	struct tee_ta_session *sess;
890 	const struct tee_file_operations *fops = file_ops(storage_id);
891 
892 	res = tee_ta_get_current_session(&sess);
893 	if (res != TEE_SUCCESS)
894 		return res;
895 
896 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
897 			tee_svc_uref_to_vaddr(obj_enum), &e);
898 	if (res != TEE_SUCCESS)
899 		return res;
900 
901 	if (!fops)
902 		return TEE_ERROR_ITEM_NOT_FOUND;
903 
904 	e->fops = fops;
905 	dir = tee_svc_storage_create_dirname(sess);
906 	if (dir == NULL) {
907 		res = TEE_ERROR_OUT_OF_MEMORY;
908 		goto exit;
909 	}
910 
911 	assert(!e->dir);
912 	res = fops->opendir(dir, &e->dir);
913 	free(dir);
914 exit:
915 	return res;
916 }
917 
918 TEE_Result syscall_storage_next_enum(unsigned long obj_enum,
919 			TEE_ObjectInfo *info, void *obj_id, uint64_t *len)
920 {
921 	struct tee_storage_enum *e;
922 	struct tee_fs_dirent *d;
923 	TEE_Result res = TEE_SUCCESS;
924 	struct tee_ta_session *sess;
925 	struct tee_obj *o = NULL;
926 	uint64_t l;
927 	struct user_ta_ctx *utc;
928 
929 	res = tee_ta_get_current_session(&sess);
930 	if (res != TEE_SUCCESS)
931 		goto exit;
932 	utc = to_user_ta_ctx(sess->ctx);
933 
934 	res = tee_svc_storage_get_enum(utc,
935 			tee_svc_uref_to_vaddr(obj_enum), &e);
936 	if (res != TEE_SUCCESS)
937 		goto exit;
938 
939 	/* check rights of the provided buffers */
940 	res = tee_mmu_check_access_rights(utc,
941 					TEE_MEMORY_ACCESS_WRITE |
942 					TEE_MEMORY_ACCESS_ANY_OWNER,
943 					(uaddr_t) info,
944 					sizeof(TEE_ObjectInfo));
945 	if (res != TEE_SUCCESS)
946 		goto exit;
947 
948 	res = tee_mmu_check_access_rights(utc,
949 					TEE_MEMORY_ACCESS_WRITE |
950 					TEE_MEMORY_ACCESS_ANY_OWNER,
951 					(uaddr_t) obj_id,
952 					TEE_OBJECT_ID_MAX_LEN);
953 	if (res != TEE_SUCCESS)
954 		goto exit;
955 
956 	if (!e->fops) {
957 		res = TEE_ERROR_ITEM_NOT_FOUND;
958 		goto exit;
959 	}
960 
961 	res = e->fops->readdir(e->dir, &d);
962 	if (res != TEE_SUCCESS)
963 		goto exit;
964 
965 	o = tee_obj_alloc();
966 	if (o == NULL) {
967 		res = TEE_ERROR_OUT_OF_MEMORY;
968 		goto exit;
969 	}
970 	o->flags = TEE_DATA_FLAG_SHARE_READ;
971 
972 	o->pobj = calloc(1, sizeof(struct tee_pobj));
973 	if (!o->pobj) {
974 		res = TEE_ERROR_OUT_OF_MEMORY;
975 		goto exit;
976 	}
977 
978 	res = tee_svc_storage_set_enum(d->d_name, e->fops, o);
979 	if (res != TEE_SUCCESS)
980 		goto exit;
981 
982 	res = tee_svc_storage_read_head(sess, o);
983 	if (res != TEE_SUCCESS)
984 		goto exit;
985 
986 	memcpy(info, &o->info, sizeof(TEE_ObjectInfo));
987 	memcpy(obj_id, o->pobj->obj_id, o->pobj->obj_id_len);
988 
989 	l = o->pobj->obj_id_len;
990 	res = tee_svc_copy_to_user(len, &l, sizeof(*len));
991 
992 exit:
993 	if (o) {
994 		if (o->pobj) {
995 			o->pobj->fops->close(&o->fh);
996 			free(o->pobj->obj_id);
997 		}
998 		free(o->pobj);
999 		tee_obj_free(o);
1000 	}
1001 
1002 	return res;
1003 }
1004 
1005 TEE_Result syscall_storage_obj_read(unsigned long obj, void *data, size_t len,
1006 			uint64_t *count)
1007 {
1008 	TEE_Result res;
1009 	struct tee_ta_session *sess;
1010 	struct tee_obj *o;
1011 	uint64_t u_count;
1012 	struct user_ta_ctx *utc;
1013 	size_t bytes;
1014 
1015 	res = tee_ta_get_current_session(&sess);
1016 	if (res != TEE_SUCCESS)
1017 		goto exit;
1018 	utc = to_user_ta_ctx(sess->ctx);
1019 
1020 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
1021 	if (res != TEE_SUCCESS)
1022 		goto exit;
1023 
1024 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1025 		res = TEE_ERROR_BAD_STATE;
1026 		goto exit;
1027 	}
1028 
1029 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_READ)) {
1030 		res = TEE_ERROR_ACCESS_CONFLICT;
1031 		goto exit;
1032 	}
1033 
1034 	/* check rights of the provided buffer */
1035 	res = tee_mmu_check_access_rights(utc,
1036 					TEE_MEMORY_ACCESS_WRITE |
1037 					TEE_MEMORY_ACCESS_ANY_OWNER,
1038 					(uaddr_t) data, len);
1039 	if (res != TEE_SUCCESS)
1040 		goto exit;
1041 
1042 	bytes = len;
1043 	res = o->pobj->fops->read(o->fh, data, &bytes);
1044 	if (res != TEE_SUCCESS) {
1045 		EMSG("Error code=%x\n", (uint32_t)res);
1046 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
1047 			EMSG("Object corrupt\n");
1048 			tee_svc_storage_remove_corrupt_obj(sess, o);
1049 		}
1050 		goto exit;
1051 	}
1052 
1053 	o->info.dataPosition += bytes;
1054 
1055 	u_count = bytes;
1056 	res = tee_svc_copy_to_user(count, &u_count, sizeof(*count));
1057 exit:
1058 	return res;
1059 }
1060 
1061 TEE_Result syscall_storage_obj_write(unsigned long obj, void *data, size_t len)
1062 {
1063 	TEE_Result res;
1064 	struct tee_ta_session *sess;
1065 	struct tee_obj *o;
1066 	struct user_ta_ctx *utc;
1067 
1068 	res = tee_ta_get_current_session(&sess);
1069 	if (res != TEE_SUCCESS)
1070 		goto exit;
1071 	utc = to_user_ta_ctx(sess->ctx);
1072 
1073 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
1074 	if (res != TEE_SUCCESS)
1075 		goto exit;
1076 
1077 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1078 		res = TEE_ERROR_BAD_STATE;
1079 		goto exit;
1080 	}
1081 
1082 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) {
1083 		res = TEE_ERROR_ACCESS_CONFLICT;
1084 		goto exit;
1085 	}
1086 
1087 	/* check rights of the provided buffer */
1088 	res = tee_mmu_check_access_rights(utc,
1089 					TEE_MEMORY_ACCESS_READ |
1090 					TEE_MEMORY_ACCESS_ANY_OWNER,
1091 					(uaddr_t) data, len);
1092 	if (res != TEE_SUCCESS)
1093 		goto exit;
1094 
1095 	res = o->pobj->fops->write(o->fh, data, len);
1096 	if (res != TEE_SUCCESS)
1097 		goto exit;
1098 
1099 	o->info.dataPosition += len;
1100 	if (o->info.dataPosition > o->info.dataSize) {
1101 		res = tee_svc_storage_update_head(o, o->info.dataPosition);
1102 		if (res != TEE_SUCCESS)
1103 			goto exit;
1104 		o->info.dataSize = o->info.dataPosition;
1105 	}
1106 
1107 exit:
1108 	return res;
1109 }
1110 
1111 TEE_Result syscall_storage_obj_trunc(unsigned long obj, size_t len)
1112 {
1113 	TEE_Result res;
1114 	struct tee_ta_session *sess;
1115 	struct tee_obj *o;
1116 	size_t off;
1117 	size_t attr_size;
1118 
1119 	res = tee_ta_get_current_session(&sess);
1120 	if (res != TEE_SUCCESS)
1121 		goto exit;
1122 
1123 	res = tee_obj_get(to_user_ta_ctx(sess->ctx),
1124 			  tee_svc_uref_to_vaddr(obj), &o);
1125 	if (res != TEE_SUCCESS)
1126 		goto exit;
1127 
1128 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1129 		res = TEE_ERROR_BAD_STATE;
1130 		goto exit;
1131 	}
1132 
1133 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) {
1134 		res = TEE_ERROR_ACCESS_CONFLICT;
1135 		goto exit;
1136 	}
1137 
1138 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
1139 	if (res != TEE_SUCCESS)
1140 		goto exit;
1141 
1142 	off = sizeof(struct tee_svc_storage_head) + attr_size;
1143 	res = o->pobj->fops->truncate(o->fh, len + off);
1144 	if (res != TEE_SUCCESS) {
1145 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
1146 			EMSG("Object corrupt\n");
1147 			res = tee_svc_storage_remove_corrupt_obj(sess, o);
1148 			if (res != TEE_SUCCESS)
1149 				goto exit;
1150 			res = TEE_ERROR_CORRUPT_OBJECT;
1151 			goto exit;
1152 		} else
1153 			res = TEE_ERROR_GENERIC;
1154 	}
1155 
1156 exit:
1157 	return res;
1158 }
1159 
1160 TEE_Result syscall_storage_obj_seek(unsigned long obj, int32_t offset,
1161 				    unsigned long whence)
1162 {
1163 	TEE_Result res;
1164 	struct tee_ta_session *sess;
1165 	struct tee_obj *o;
1166 	int32_t off;
1167 	size_t attr_size;
1168 
1169 	res = tee_ta_get_current_session(&sess);
1170 	if (res != TEE_SUCCESS)
1171 		goto exit;
1172 
1173 	res = tee_obj_get(to_user_ta_ctx(sess->ctx),
1174 			  tee_svc_uref_to_vaddr(obj), &o);
1175 	if (res != TEE_SUCCESS)
1176 		goto exit;
1177 
1178 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1179 		res = TEE_ERROR_BAD_STATE;
1180 		goto exit;
1181 	}
1182 
1183 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
1184 	if (res != TEE_SUCCESS)
1185 		goto exit;
1186 
1187 	off = offset;
1188 	if (whence == TEE_DATA_SEEK_SET)
1189 		off += sizeof(struct tee_svc_storage_head) + attr_size;
1190 
1191 	res = o->pobj->fops->seek(o->fh, off, whence, &off);
1192 	if (res != TEE_SUCCESS)
1193 		goto exit;
1194 	o->info.dataPosition = off - (sizeof(struct tee_svc_storage_head) +
1195 				      attr_size);
1196 
1197 exit:
1198 	return res;
1199 }
1200 
1201 void tee_svc_storage_close_all_enum(struct user_ta_ctx *utc)
1202 {
1203 	struct tee_storage_enum_head *eh = &utc->storage_enums;
1204 
1205 	/* disregard return value */
1206 	while (!TAILQ_EMPTY(eh))
1207 		tee_svc_close_enum(utc, TAILQ_FIRST(eh));
1208 }
1209