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