xref: /optee_os/core/tee/tee_svc_storage.c (revision 983d02116743476904b68d52ca432d0f79c38c43)
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 	int ret;
126 
127 	if (e == NULL || utc == NULL)
128 		return TEE_ERROR_BAD_PARAMETERS;
129 
130 	TAILQ_REMOVE(&utc->storage_enums, e, link);
131 
132 	if (!e->fops)
133 		return TEE_ERROR_ITEM_NOT_FOUND;
134 
135 	ret = e->fops->closedir(e->dir);
136 	e->dir = NULL;
137 	e->fops = NULL;
138 
139 	free(e);
140 
141 	if (ret != 0)
142 		return TEE_ERROR_ITEM_NOT_FOUND;
143 
144 	return TEE_SUCCESS;
145 }
146 
147 /* "/TA_uuid/object_id" or "/TA_uuid/.object_id" */
148 char *tee_svc_storage_create_filename(struct tee_ta_session *sess,
149 				      void *object_id,
150 				      uint32_t object_id_len,
151 				      bool transient)
152 {
153 	uint8_t *file;
154 	uint32_t pos = 0;
155 	uint32_t hslen = 1 /* Leading slash */
156 			+ TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID) + object_id_len)
157 			+ 1; /* Intermediate slash */
158 
159 	/* +1 for the '.' (temporary persistent object) */
160 	if (transient)
161 		hslen++;
162 
163 	file = malloc(hslen);
164 	if (!file)
165 		return NULL;
166 
167 	file[pos++] = '/';
168 	pos += tee_b2hs((uint8_t *)&sess->ctx->uuid, &file[pos],
169 			sizeof(TEE_UUID), hslen);
170 	file[pos++] = '/';
171 
172 	if (transient)
173 		file[pos++] = '.';
174 
175 	tee_b2hs(object_id, file + pos, object_id_len, hslen - pos);
176 
177 	return (char *)file;
178 }
179 
180 /* "/TA_uuid" */
181 char *tee_svc_storage_create_dirname(struct tee_ta_session *sess)
182 {
183 	uint8_t *dir;
184 	uint32_t hslen = TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID)) + 1;
185 
186 	dir = malloc(hslen);
187 	if (!dir)
188 		return NULL;
189 
190 	dir[0] = '/';
191 	tee_b2hs((uint8_t *)&sess->ctx->uuid, dir + 1, sizeof(TEE_UUID),
192 		 hslen);
193 
194 	return (char *)dir;
195 }
196 
197 static TEE_Result tee_svc_storage_remove_corrupt_obj(
198 					struct tee_ta_session *sess,
199 					struct tee_obj *o)
200 {
201 	TEE_Result res;
202 	char *file = NULL;
203 	char *dir = NULL;
204 	const struct tee_file_operations *fops = o->pobj->fops;
205 
206 	file = tee_svc_storage_create_filename(sess,
207 					       o->pobj->obj_id,
208 					       o->pobj->obj_id_len,
209 					       false);
210 	if (file == NULL) {
211 		res = TEE_ERROR_OUT_OF_MEMORY;
212 		goto exit;
213 	}
214 
215 	tee_obj_close(to_user_ta_ctx(sess->ctx), o);
216 	fops->unlink(file);
217 	free(file);
218 	dir = tee_svc_storage_create_dirname(sess);
219 	if (dir != NULL) {
220 		mutex_lock(&ta_dir_mutex);
221 		fops->rmdir(dir);
222 		mutex_unlock(&ta_dir_mutex);
223 		free(dir);
224 	}
225 
226 	res = TEE_SUCCESS;
227 
228 exit:
229 	return res;
230 }
231 
232 static uint32_t tee_svc_storage_conv_oflags(uint32_t flags)
233 {
234 	uint32_t out = 0;
235 
236 	if (flags & (TEE_DATA_FLAG_ACCESS_READ | TEE_DATA_FLAG_SHARE_READ)) {
237 		if (flags & (TEE_DATA_FLAG_ACCESS_WRITE |
238 			     TEE_DATA_FLAG_ACCESS_WRITE_META |
239 			     TEE_DATA_FLAG_SHARE_WRITE))
240 			out |= TEE_FS_O_RDWR;
241 		else
242 			out |= TEE_FS_O_RDONLY;
243 	} else {
244 		if (flags & (TEE_DATA_FLAG_ACCESS_WRITE |
245 			     TEE_DATA_FLAG_ACCESS_WRITE_META |
246 			     TEE_DATA_FLAG_SHARE_WRITE))
247 			out |= TEE_FS_O_WRONLY;
248 	}
249 
250 	return out;
251 }
252 
253 static int tee_svc_storage_conv_whence(TEE_Whence whence)
254 {
255 	switch (whence) {
256 	case TEE_DATA_SEEK_SET:
257 		return TEE_FS_SEEK_SET;
258 	case TEE_DATA_SEEK_CUR:
259 		return TEE_FS_SEEK_CUR;
260 	case TEE_DATA_SEEK_END:
261 		return TEE_FS_SEEK_END;
262 	default:
263 		return -1;
264 	}
265 }
266 
267 static TEE_Result tee_svc_storage_create_file(struct tee_ta_session *sess,
268 			char *file,
269 			const struct tee_file_operations *fops,
270 			int *fd)
271 {
272 	TEE_Result res = TEE_SUCCESS;
273 	TEE_Result errno;
274 	char *dir = NULL;
275 	int tmp;
276 	int err;
277 	uint32_t cflags = TEE_FS_O_WRONLY |
278 			TEE_FS_O_CREATE | TEE_FS_O_TRUNC;
279 
280 	dir = tee_svc_storage_create_dirname(sess);
281 	if (dir == NULL) {
282 		res = TEE_ERROR_OUT_OF_MEMORY;
283 		goto exit;
284 	}
285 
286 	mutex_lock(&ta_dir_mutex);
287 
288 	/* try and make directory */
289 	err = fops->access(dir, TEE_FS_F_OK);
290 	if (err) {
291 		/* directory does not exists */
292 		tmp = fops->mkdir(dir, TEE_FS_S_IRUSR | TEE_FS_S_IWUSR |
293 				  TEE_FS_S_IXUSR);
294 
295 		if (tmp < 0) {
296 			/* error codes needs better granularity */
297 			res = TEE_ERROR_GENERIC;
298 			goto unlock;
299 		}
300 	}
301 
302 	/* try and open again */
303 	*fd = fops->open(&errno, file, cflags);
304 	if (*fd < 0)
305 		res = errno;
306 
307 unlock:
308 	mutex_unlock(&ta_dir_mutex);
309 exit:
310 	free(dir);
311 
312 	return res;
313 }
314 
315 static TEE_Result tee_svc_storage_read_head(struct tee_ta_session *sess,
316 				     struct tee_obj *o)
317 {
318 	TEE_Result res = TEE_SUCCESS;
319 	TEE_Result errno;
320 	int fd = -1;
321 	int err;
322 	struct tee_svc_storage_head head;
323 	char *file = NULL;
324 	const struct tee_file_operations *fops;
325 	void *attr = NULL;
326 
327 	if (o == NULL || o->pobj == NULL)
328 		return TEE_ERROR_BAD_PARAMETERS;
329 
330 	fops = o->pobj->fops;
331 
332 	file = tee_svc_storage_create_filename(sess,
333 					       o->pobj->obj_id,
334 					       o->pobj->obj_id_len,
335 					       false);
336 	if (file == NULL) {
337 		res = TEE_ERROR_OUT_OF_MEMORY;
338 		goto exit;
339 	}
340 
341 	fd = fops->open(&errno, file, TEE_FS_O_RDONLY);
342 	free(file);
343 	if (fd < 0) {
344 		res = errno;
345 		goto exit;
346 	}
347 
348 	/* read head */
349 	err = fops->read(&errno, fd, &head,
350 				sizeof(struct tee_svc_storage_head));
351 	if (err < 0) {
352 		res = errno;
353 		if (res == TEE_ERROR_CORRUPT_OBJECT)
354 			EMSG("Head corrupt\n");
355 		goto exit;
356 	}
357 
358 	if (err != sizeof(struct tee_svc_storage_head)) {
359 		res = TEE_ERROR_BAD_FORMAT;
360 		goto exit;
361 	}
362 
363 	res = tee_obj_set_type(o, head.objectType, head.maxKeySize);
364 	if (res != TEE_SUCCESS)
365 		goto exit;
366 
367 	if (head.meta_size) {
368 		attr = malloc(head.meta_size);
369 		if (!attr) {
370 			res = TEE_ERROR_OUT_OF_MEMORY;
371 			goto exit;
372 		}
373 
374 		/* read meta */
375 		err = fops->read(&errno, fd, attr, head.meta_size);
376 		if (err != (int)head.meta_size) {
377 			res = TEE_ERROR_CORRUPT_OBJECT;
378 			goto exit;
379 		}
380 	}
381 
382 	res = tee_obj_attr_from_binary(o, attr, head.meta_size);
383 	if (res != TEE_SUCCESS)
384 		goto exit;
385 
386 	o->info.dataSize = head.ds_size;
387 	o->info.keySize = head.keySize;
388 	o->info.objectUsage = head.objectUsage;
389 	o->info.objectType = head.objectType;
390 	o->have_attrs = head.have_attrs;
391 
392 exit:
393 	free(attr);
394 	if (fd >= 0)
395 		fops->close(fd);
396 
397 	return res;
398 }
399 
400 static TEE_Result tee_svc_storage_init_file(struct tee_ta_session *sess,
401 					    struct tee_obj *o,
402 					    struct tee_obj *attr_o, void *data,
403 					    uint32_t len)
404 {
405 	TEE_Result res = TEE_SUCCESS;
406 	TEE_Result errno;
407 	int fd = -1;
408 	int err = -1;
409 	struct tee_svc_storage_head head;
410 	char *tmpfile = NULL;
411 	const struct tee_file_operations *fops;
412 	void *attr = NULL;
413 	size_t attr_size = 0;
414 
415 	if (o == NULL || o->pobj == NULL)
416 		return TEE_ERROR_BAD_PARAMETERS;
417 
418 	fops = o->pobj->fops;
419 
420 	/* create temporary persistent object filename */
421 	tmpfile = tee_svc_storage_create_filename(sess,
422 						   o->pobj->obj_id,
423 						   o->pobj->obj_id_len,
424 						   true);
425 
426 	if (tmpfile == NULL) {
427 		res = TEE_ERROR_OUT_OF_MEMORY;
428 		goto exit;
429 	}
430 
431 	res = tee_svc_storage_create_file(sess, tmpfile, fops, &fd);
432 	if (res != TEE_SUCCESS)
433 		goto exit;
434 
435 	if (attr_o) {
436 		res = tee_obj_set_type(o, attr_o->info.objectType,
437 				       attr_o->info.maxKeySize);
438 		if (res != TEE_SUCCESS)
439 			goto exit;
440 		res = tee_obj_attr_copy_from(o, attr_o);
441 		if (res != TEE_SUCCESS)
442 			goto exit;
443 		o->have_attrs = attr_o->have_attrs;
444 		o->info.objectUsage = attr_o->info.objectUsage;
445 		o->info.keySize = attr_o->info.keySize;
446 		res = tee_obj_attr_to_binary(o, NULL, &attr_size);
447 		if (res != TEE_SUCCESS)
448 			goto exit;
449 		if (attr_size) {
450 			attr = malloc(attr_size);
451 			if (!attr) {
452 				res = TEE_ERROR_OUT_OF_MEMORY;
453 				goto exit;
454 			}
455 			res = tee_obj_attr_to_binary(o, attr, &attr_size);
456 			if (res != TEE_SUCCESS)
457 				goto exit;
458 		}
459 	} else {
460 		res = tee_obj_set_type(o, TEE_TYPE_DATA, 0);
461 		if (res != TEE_SUCCESS)
462 			goto exit;
463 	}
464 
465 	/* write head */
466 	head.magic = TEE_SVC_STORAGE_MAGIC;
467 	head.head_size = sizeof(struct tee_svc_storage_head);
468 	head.meta_size = attr_size;
469 	head.ds_size = len;
470 	head.keySize = o->info.keySize;
471 	head.maxKeySize = o->info.maxKeySize;
472 	head.objectUsage = o->info.objectUsage;
473 	head.objectType = o->info.objectType;
474 	head.have_attrs = o->have_attrs;
475 
476 	/* write head */
477 	err = fops->write(&errno, fd, &head,
478 			sizeof(struct tee_svc_storage_head));
479 	if (err < 0)
480 		res = errno;
481 	if (err != sizeof(struct tee_svc_storage_head))
482 		goto exit;
483 
484 	/* write meta */
485 	err = fops->write(&errno, fd, attr, attr_size);
486 	if (err < 0)
487 		res = errno;
488 	if (err != (int)attr_size)
489 		goto exit;
490 
491 	/* write init data */
492 	o->info.dataSize = len;
493 
494 	/* write data to fs if needed */
495 	if (data && len) {
496 		err = fops->write(&errno, fd, data, len);
497 		if (err < 0)
498 			res = errno;
499 		if (err != (int)len)
500 			goto exit;
501 	}
502 
503 exit:
504 	free(attr);
505 	free(tmpfile);
506 	tmpfile = NULL;
507 	if (fd != -1)
508 		fops->close(fd);
509 
510 	return res;
511 }
512 
513 TEE_Result syscall_storage_obj_open(unsigned long storage_id, void *object_id,
514 			size_t object_id_len, unsigned long flags,
515 			uint32_t *obj)
516 {
517 	TEE_Result res;
518 	TEE_Result errno;
519 	struct tee_ta_session *sess;
520 	struct tee_obj *o;
521 	char *file = NULL;
522 	int fs_flags;
523 	int fd = -1;
524 	tee_fs_off_t off;
525 	tee_fs_off_t e_off;
526 	struct tee_pobj *po = NULL;
527 	int err = -1;
528 	struct user_ta_ctx *utc;
529 	const struct tee_file_operations *fops = file_ops(storage_id);
530 	size_t attr_size;
531 
532 	if (!fops) {
533 		res = TEE_ERROR_ITEM_NOT_FOUND;
534 		goto exit;
535 	}
536 
537 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN) {
538 		res = TEE_ERROR_BAD_PARAMETERS;
539 		goto exit;
540 	}
541 
542 	res = tee_ta_get_current_session(&sess);
543 	if (res != TEE_SUCCESS)
544 		goto err;
545 	utc = to_user_ta_ctx(sess->ctx);
546 
547 	res = tee_mmu_check_access_rights(utc,
548 					  TEE_MEMORY_ACCESS_READ |
549 					  TEE_MEMORY_ACCESS_ANY_OWNER,
550 					  (tee_uaddr_t) object_id,
551 					  object_id_len);
552 	if (res != TEE_SUCCESS)
553 		goto err;
554 
555 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
556 			   object_id_len, flags, fops, &po);
557 	if (res != TEE_SUCCESS)
558 		goto err;
559 
560 	fs_flags = tee_svc_storage_conv_oflags(flags);
561 
562 	o = tee_obj_alloc();
563 	if (o == NULL) {
564 		res = TEE_ERROR_OUT_OF_MEMORY;
565 		goto err;
566 	}
567 
568 	o->info.handleFlags =
569 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
570 	o->flags = flags;
571 	o->pobj = po;
572 
573 	res = tee_svc_storage_read_head(sess, o);
574 	if (res != TEE_SUCCESS) {
575 		tee_obj_add(utc, o);
576 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
577 			EMSG("Object corrupt\n");
578 			res = tee_svc_storage_remove_corrupt_obj(sess, o);
579 			if (res != TEE_SUCCESS)
580 				goto exit;
581 			res = TEE_ERROR_CORRUPT_OBJECT;
582 			goto exit;
583 		}
584 		goto oclose;
585 	}
586 
587 	file = tee_svc_storage_create_filename(sess, object_id,
588 					       object_id_len, false);
589 	if (file == NULL) {
590 		res = TEE_ERROR_OUT_OF_MEMORY;
591 		goto err;
592 	}
593 
594 	err = fops->access(file, TEE_FS_F_OK);
595 	if (err) {
596 		/* file not found */
597 		res = TEE_ERROR_STORAGE_NOT_AVAILABLE;
598 		goto err;
599 	}
600 
601 	fd = fops->open(&errno, file, fs_flags);
602 	if (fd < 0) {
603 		res = errno;
604 		goto err;
605 	}
606 	o->fd = fd;
607 
608 	tee_obj_add(utc, o);
609 
610 	res = tee_svc_copy_kaddr_to_uref(obj, o);
611 	if (res != TEE_SUCCESS)
612 		goto oclose;
613 
614 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
615 	if (res != TEE_SUCCESS && res)
616 		goto oclose;
617 
618 	e_off = sizeof(struct tee_svc_storage_head) + attr_size;
619 	off = fops->lseek(&errno, fd, e_off, TEE_FS_SEEK_SET);
620 	if (off != e_off) {
621 		res = TEE_ERROR_NO_DATA;
622 		goto oclose;
623 	} else {
624 		res = TEE_SUCCESS;
625 	}
626 
627 	goto exit;
628 
629 oclose:
630 	tee_obj_close(utc, o);
631 
632 err:
633 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
634 		res = TEE_ERROR_CORRUPT_OBJECT;
635 	if (res == TEE_ERROR_CORRUPT_OBJECT)
636 		fops->unlink(file);
637 	if (fd >= 0)
638 		fops->close(fd);
639 	if (po)
640 		tee_pobj_release(po);
641 
642 exit:
643 	free(file);
644 	file = NULL;
645 	return res;
646 }
647 
648 TEE_Result syscall_storage_obj_create(unsigned long storage_id, void *object_id,
649 			size_t object_id_len, unsigned long flags,
650 			unsigned long attr, void *data, size_t len,
651 			uint32_t *obj)
652 {
653 	TEE_Result res;
654 	TEE_Result errno;
655 	struct tee_ta_session *sess;
656 	struct tee_obj *o = NULL;
657 	struct tee_obj *attr_o = NULL;
658 	char *file = NULL;
659 	int fd = -1;
660 	int fs_flags;
661 	tee_fs_off_t off;
662 	tee_fs_off_t e_off;
663 	struct tee_pobj *po = NULL;
664 	char *tmpfile = NULL;
665 	int err = -1;
666 	int filedoesnotexist;
667 	struct user_ta_ctx *utc;
668 	const struct tee_file_operations *fops = file_ops(storage_id);
669 	size_t attr_size;
670 
671 	if (!fops)
672 		return TEE_ERROR_ITEM_NOT_FOUND;
673 
674 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
675 		return TEE_ERROR_BAD_PARAMETERS;
676 
677 	res = tee_ta_get_current_session(&sess);
678 	if (res != TEE_SUCCESS)
679 		return res;
680 	utc = to_user_ta_ctx(sess->ctx);
681 
682 	res = tee_mmu_check_access_rights(utc,
683 					  TEE_MEMORY_ACCESS_READ |
684 					  TEE_MEMORY_ACCESS_ANY_OWNER,
685 					  (tee_uaddr_t) object_id,
686 					  object_id_len);
687 	if (res != TEE_SUCCESS)
688 		goto err;
689 
690 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
691 			   object_id_len, flags, fops, &po);
692 	if (res != TEE_SUCCESS)
693 		goto err;
694 
695 	/* check rights of the provided buffer */
696 	if (data && len) {
697 		res = tee_mmu_check_access_rights(utc,
698 						  TEE_MEMORY_ACCESS_READ |
699 						  TEE_MEMORY_ACCESS_ANY_OWNER,
700 						  (tee_uaddr_t) data, len);
701 
702 		if (res != TEE_SUCCESS)
703 			goto err;
704 	}
705 
706 	o = tee_obj_alloc();
707 	if (o == NULL) {
708 		res = TEE_ERROR_OUT_OF_MEMORY;
709 		goto err;
710 	}
711 
712 	o->info.handleFlags =
713 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
714 	o->flags = flags;
715 	o->pobj = po;
716 
717 	if (attr != TEE_HANDLE_NULL) {
718 		res = tee_obj_get(utc, tee_svc_uref_to_vaddr(attr),
719 				  &attr_o);
720 		if (res != TEE_SUCCESS)
721 			goto err;
722 	}
723 
724 	res = tee_svc_storage_init_file(sess, o, attr_o, data, len);
725 	if (res != TEE_SUCCESS)
726 		goto err;
727 
728 	/* create persistent object filename */
729 	file = tee_svc_storage_create_filename(sess, object_id,
730 					       object_id_len, false);
731 	if (file == NULL) {
732 		res = TEE_ERROR_OUT_OF_MEMORY;
733 		goto err;
734 	}
735 
736 	filedoesnotexist = fops->access(file, TEE_FS_F_OK);
737 	if (!filedoesnotexist) {
738 		/* file exists */
739 		if (!(flags & TEE_DATA_FLAG_OVERWRITE)) {
740 			res = TEE_ERROR_ACCESS_CONFLICT;
741 			goto err;
742 		}
743 	}
744 
745 	/* create temporary persistent object filename */
746 	tmpfile = tee_svc_storage_create_filename(sess, object_id,
747 						  object_id_len,
748 						  true);
749 	if (tmpfile == NULL) {
750 		res = TEE_ERROR_OUT_OF_MEMORY;
751 		goto err;
752 	}
753 
754 	/*
755 	 * remove the file if it exists, because rename does not perform
756 	 * this operation. Note that it delete and rename should be atomic,
757 	 * which is not the case currently.
758 	 * Fixme: unlink must be removed once rename() support prior deletion
759 	 * of the new file name when it already exists.
760 	 */
761 	if (!filedoesnotexist)
762 		fops->unlink(file);
763 	/* rename temporary persistent object filename */
764 	err = fops->rename(tmpfile, file);
765 	if (err) {
766 		/* error codes needs better granularity */
767 		res = TEE_ERROR_GENERIC;
768 		goto rmfile;
769 	}
770 
771 	fs_flags = tee_svc_storage_conv_oflags(flags);
772 
773 	fd = fops->open(&errno, file, fs_flags);
774 	if (fd < 0) {
775 		res = errno;
776 		goto err;
777 	}
778 	o->fd = fd;
779 
780 	tee_obj_add(utc, o);
781 
782 	res = tee_svc_copy_kaddr_to_uref(obj, o);
783 	if (res != TEE_SUCCESS)
784 		goto oclose;
785 
786 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
787 	if (res != TEE_SUCCESS)
788 		goto oclose;
789 
790 	e_off = sizeof(struct tee_svc_storage_head) + attr_size;
791 	off = fops->lseek(&errno, fd, e_off, TEE_FS_SEEK_SET);
792 	if (off != e_off) {
793 		res = TEE_ERROR_NO_DATA;
794 		goto oclose;
795 	} else {
796 		res = TEE_SUCCESS;
797 	}
798 
799 	goto exit;
800 
801 oclose:
802 	tee_obj_close(utc, o);
803 	goto exit;
804 
805 rmfile:
806 	fops->unlink(tmpfile);
807 
808 err:
809 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
810 		res = TEE_ERROR_CORRUPT_OBJECT;
811 	if (res == TEE_ERROR_CORRUPT_OBJECT && file)
812 		fops->unlink(file);
813 	if (fd >= 0)
814 		fops->close(fd);
815 	if (po)
816 		tee_pobj_release(po);
817 	if (o)
818 		free(o);
819 
820 exit:
821 	free(file);
822 	file = NULL;
823 	free(tmpfile);
824 	tmpfile = NULL;
825 
826 	return res;
827 }
828 
829 TEE_Result syscall_storage_obj_del(unsigned long obj)
830 {
831 	TEE_Result res;
832 	struct tee_ta_session *sess;
833 	struct tee_obj *o;
834 	int err;
835 	char *file;
836 	char *dir;
837 	struct user_ta_ctx *utc;
838 	const struct tee_file_operations *fops;
839 
840 	res = tee_ta_get_current_session(&sess);
841 	if (res != TEE_SUCCESS)
842 		return res;
843 	utc = to_user_ta_ctx(sess->ctx);
844 
845 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
846 	if (res != TEE_SUCCESS)
847 		return res;
848 
849 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META))
850 		return TEE_ERROR_ACCESS_CONFLICT;
851 
852 	if (o->pobj == NULL || o->pobj->obj_id == NULL)
853 		return TEE_ERROR_BAD_STATE;
854 
855 	file = tee_svc_storage_create_filename(sess, o->pobj->obj_id,
856 						o->pobj->obj_id_len, false);
857 	if (file == NULL)
858 		return TEE_ERROR_OUT_OF_MEMORY;
859 
860 	fops = o->pobj->fops;
861 	tee_obj_close(utc, o);
862 
863 	err = fops->access(file, TEE_FS_F_OK);
864 	if (err)
865 		/* file not found */
866 		return TEE_ERROR_STORAGE_NOT_AVAILABLE;
867 
868 	err = fops->unlink(file);
869 	free(file);
870 	if (err)
871 		/* error codes needs better granularity */
872 		return TEE_ERROR_GENERIC;
873 
874 	/* try and remove dir */
875 	dir = tee_svc_storage_create_dirname(sess);
876 	if (dir == NULL)
877 		return TEE_ERROR_OUT_OF_MEMORY;
878 	mutex_lock(&ta_dir_mutex);
879 	/* ignore result */
880 	fops->rmdir(dir);
881 	mutex_unlock(&ta_dir_mutex);
882 	free(dir);
883 
884 	return TEE_SUCCESS;
885 }
886 
887 TEE_Result syscall_storage_obj_rename(unsigned long obj, void *object_id,
888 			size_t object_id_len)
889 {
890 	TEE_Result res;
891 	struct tee_ta_session *sess;
892 	struct tee_obj *o;
893 	struct tee_pobj *po = NULL;
894 	char *new_file = NULL;
895 	char *old_file = NULL;
896 	int err = -1;
897 	struct user_ta_ctx *utc;
898 	const struct tee_file_operations *fops;
899 
900 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
901 		return TEE_ERROR_BAD_PARAMETERS;
902 
903 	res = tee_ta_get_current_session(&sess);
904 	if (res != TEE_SUCCESS)
905 		return res;
906 	utc = to_user_ta_ctx(sess->ctx);
907 
908 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
909 	if (res != TEE_SUCCESS)
910 		return res;
911 
912 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
913 		res = TEE_ERROR_BAD_STATE;
914 		goto exit;
915 	}
916 
917 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META)) {
918 		res = TEE_ERROR_BAD_STATE;
919 		goto exit;
920 	}
921 
922 	if (o->pobj == NULL || o->pobj->obj_id == NULL) {
923 		res = TEE_ERROR_BAD_STATE;
924 		goto exit;
925 	}
926 
927 	res = tee_mmu_check_access_rights(utc,
928 					TEE_MEMORY_ACCESS_READ |
929 					TEE_MEMORY_ACCESS_ANY_OWNER,
930 					(tee_uaddr_t) object_id, object_id_len);
931 	if (res != TEE_SUCCESS)
932 		goto exit;
933 
934 	res = tee_obj_verify(sess, o);
935 	if (res != TEE_SUCCESS)
936 		goto exit;
937 
938 	/* get new ds name */
939 	new_file = tee_svc_storage_create_filename(sess, object_id,
940 						   object_id_len, false);
941 	if (new_file == NULL) {
942 		res = TEE_ERROR_OUT_OF_MEMORY;
943 		goto exit;
944 	}
945 
946 	old_file = tee_svc_storage_create_filename(sess, o->pobj->obj_id,
947 						   o->pobj->obj_id_len, false);
948 	if (old_file == NULL) {
949 		res = TEE_ERROR_OUT_OF_MEMORY;
950 		goto exit;
951 	}
952 
953 	/* reserve dest name */
954 	fops = o->pobj->fops;
955 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
956 			   object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META,
957 			   fops, &po);
958 	if (res != TEE_SUCCESS)
959 		goto exit;
960 
961 	err = fops->access(new_file, TEE_FS_F_OK);
962 	if (err == 0) {
963 		/* file exists */
964 		res = TEE_ERROR_ACCESS_CONFLICT;
965 		goto exit;
966 	}
967 
968 	/* move */
969 	err = fops->rename(old_file, new_file);
970 	if (err) {
971 		/* error codes needs better granularity */
972 		res = TEE_ERROR_GENERIC;
973 		goto exit;
974 	}
975 
976 	res = tee_pobj_rename(o->pobj, object_id, object_id_len);
977 
978 exit:
979 	tee_pobj_release(po);
980 
981 	free(new_file);
982 	free(old_file);
983 
984 	return res;
985 }
986 
987 TEE_Result syscall_storage_alloc_enum(uint32_t *obj_enum)
988 {
989 	struct tee_storage_enum *e;
990 	struct tee_ta_session *sess;
991 	TEE_Result res;
992 	struct user_ta_ctx *utc;
993 
994 	if (obj_enum == NULL)
995 		return TEE_ERROR_BAD_PARAMETERS;
996 
997 	res = tee_ta_get_current_session(&sess);
998 	if (res != TEE_SUCCESS)
999 		return res;
1000 	utc = to_user_ta_ctx(sess->ctx);
1001 
1002 	e = malloc(sizeof(struct tee_storage_enum));
1003 	if (e == NULL)
1004 		return TEE_ERROR_OUT_OF_MEMORY;
1005 
1006 	e->dir = NULL;
1007 	e->fops = NULL;
1008 	TAILQ_INSERT_TAIL(&utc->storage_enums, e, link);
1009 
1010 	return tee_svc_copy_kaddr_to_uref(obj_enum, e);
1011 }
1012 
1013 TEE_Result syscall_storage_free_enum(unsigned long obj_enum)
1014 {
1015 	struct tee_storage_enum *e;
1016 	TEE_Result res;
1017 	struct tee_ta_session *sess;
1018 	struct user_ta_ctx *utc;
1019 
1020 	res = tee_ta_get_current_session(&sess);
1021 	if (res != TEE_SUCCESS)
1022 		return res;
1023 	utc = to_user_ta_ctx(sess->ctx);
1024 
1025 	res = tee_svc_storage_get_enum(utc,
1026 			tee_svc_uref_to_vaddr(obj_enum), &e);
1027 	if (res != TEE_SUCCESS)
1028 		return res;
1029 
1030 	return tee_svc_close_enum(utc, e);
1031 }
1032 
1033 TEE_Result syscall_storage_reset_enum(unsigned long obj_enum)
1034 {
1035 	struct tee_storage_enum *e;
1036 	TEE_Result res;
1037 	struct tee_ta_session *sess;
1038 
1039 	res = tee_ta_get_current_session(&sess);
1040 	if (res != TEE_SUCCESS)
1041 		return res;
1042 
1043 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
1044 			tee_svc_uref_to_vaddr(obj_enum), &e);
1045 	if (res != TEE_SUCCESS)
1046 		return res;
1047 
1048 	res = e->fops->closedir(e->dir);
1049 	e->dir = NULL;
1050 	if (res != 0)
1051 		return TEE_ERROR_GENERIC;
1052 
1053 	return TEE_SUCCESS;
1054 }
1055 
1056 static TEE_Result tee_svc_storage_set_enum(char *d_name,
1057 			const struct tee_file_operations *fops,
1058 			struct tee_obj *o)
1059 {
1060 	TEE_Result res;
1061 	uint32_t blen;
1062 	uint32_t hslen;
1063 
1064 	o->info.handleFlags =
1065 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
1066 	o->info.objectUsage = TEE_USAGE_DEFAULT;
1067 
1068 	hslen = strlen(d_name);
1069 	blen = TEE_HS2B_BBUF_SIZE(hslen);
1070 	o->pobj->obj_id = malloc(blen);
1071 	if (!o->pobj->obj_id) {
1072 		res = TEE_ERROR_OUT_OF_MEMORY;
1073 		goto exit;
1074 	}
1075 	tee_hs2b((uint8_t *)d_name, o->pobj->obj_id, hslen, blen);
1076 	o->pobj->obj_id_len = blen;
1077 	o->pobj->fops = fops;
1078 
1079 	res = TEE_SUCCESS;
1080 
1081 exit:
1082 	return res;
1083 
1084 }
1085 
1086 TEE_Result syscall_storage_start_enum(unsigned long obj_enum,
1087 				      unsigned long storage_id)
1088 {
1089 	struct tee_storage_enum *e;
1090 	char *dir;
1091 	TEE_Result res;
1092 	struct tee_ta_session *sess;
1093 	struct tee_fs_dirent *d = NULL;
1094 	struct tee_obj *o = NULL;
1095 	const struct tee_file_operations *fops = file_ops(storage_id);
1096 
1097 	res = tee_ta_get_current_session(&sess);
1098 	if (res != TEE_SUCCESS)
1099 		return res;
1100 
1101 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
1102 			tee_svc_uref_to_vaddr(obj_enum), &e);
1103 	if (res != TEE_SUCCESS)
1104 		return res;
1105 
1106 	if (!fops)
1107 		return TEE_ERROR_ITEM_NOT_FOUND;
1108 
1109 	dir = tee_svc_storage_create_dirname(sess);
1110 	if (dir == NULL)
1111 		return TEE_ERROR_OUT_OF_MEMORY;
1112 
1113 	e->fops = fops;
1114 	e->dir = fops->opendir(dir);
1115 	free(dir);
1116 	if (e->dir == NULL)
1117 		/* error codes needs better granularity */
1118 		return TEE_ERROR_ITEM_NOT_FOUND;
1119 
1120 	/* verify object */
1121 	o = tee_obj_alloc();
1122 	if (o == NULL) {
1123 		res = TEE_ERROR_OUT_OF_MEMORY;
1124 		goto exit;
1125 	}
1126 
1127 	o->pobj = calloc(1, sizeof(struct tee_pobj));
1128 	if (!o->pobj) {
1129 		res = TEE_ERROR_OUT_OF_MEMORY;
1130 		goto exit;
1131 	}
1132 
1133 	/* object enumeration loop */
1134 	do {
1135 		d = fops->readdir(e->dir);
1136 		if (d) {
1137 			/* allocate obj_id and set object */
1138 			res = tee_svc_storage_set_enum(d->d_name, fops, o);
1139 			if (res != TEE_SUCCESS)
1140 				goto exit;
1141 			res = tee_obj_verify(sess, o);
1142 			if (res != TEE_SUCCESS)
1143 				goto exit;
1144 			/* free obj_id for each iteration */
1145 			free(o->pobj->obj_id);
1146 			/* force obj_id to skip freeing at exit statement */
1147 			o->pobj->obj_id = NULL;
1148 		}
1149 	} while (d);
1150 
1151 	/* re-start */
1152 	res = fops->closedir(e->dir);
1153 	e->dir = NULL;
1154 	if (res != 0) {
1155 		res = TEE_ERROR_GENERIC;
1156 		goto exit;
1157 	}
1158 
1159 	dir = tee_svc_storage_create_dirname(sess);
1160 	if (dir == NULL) {
1161 		res = TEE_ERROR_OUT_OF_MEMORY;
1162 		goto exit;
1163 	}
1164 
1165 	e->dir = fops->opendir(dir);
1166 	free(dir);
1167 
1168 exit:
1169 	if (o) {
1170 		if (o->pobj)
1171 			free(o->pobj->obj_id);
1172 		free(o->pobj);
1173 		tee_obj_free(o);
1174 	}
1175 
1176 	return res;
1177 }
1178 
1179 TEE_Result syscall_storage_next_enum(unsigned long obj_enum,
1180 			TEE_ObjectInfo *info, void *obj_id, uint64_t *len)
1181 {
1182 	struct tee_storage_enum *e;
1183 	struct tee_fs_dirent *d;
1184 	TEE_Result res = TEE_SUCCESS;
1185 	struct tee_ta_session *sess;
1186 	struct tee_obj *o = NULL;
1187 	uint64_t l;
1188 	struct user_ta_ctx *utc;
1189 
1190 	res = tee_ta_get_current_session(&sess);
1191 	if (res != TEE_SUCCESS)
1192 		goto exit;
1193 	utc = to_user_ta_ctx(sess->ctx);
1194 
1195 	res = tee_svc_storage_get_enum(utc,
1196 			tee_svc_uref_to_vaddr(obj_enum), &e);
1197 	if (res != TEE_SUCCESS)
1198 		goto exit;
1199 
1200 	/* check rights of the provided buffers */
1201 	res = tee_mmu_check_access_rights(utc,
1202 					TEE_MEMORY_ACCESS_WRITE |
1203 					TEE_MEMORY_ACCESS_ANY_OWNER,
1204 					(tee_uaddr_t) info,
1205 					sizeof(TEE_ObjectInfo));
1206 	if (res != TEE_SUCCESS)
1207 		goto exit;
1208 
1209 	res = tee_mmu_check_access_rights(utc,
1210 					TEE_MEMORY_ACCESS_WRITE |
1211 					TEE_MEMORY_ACCESS_ANY_OWNER,
1212 					(tee_uaddr_t) obj_id,
1213 					TEE_OBJECT_ID_MAX_LEN);
1214 	if (res != TEE_SUCCESS)
1215 		goto exit;
1216 
1217 	if (!e->fops) {
1218 		res = TEE_ERROR_ITEM_NOT_FOUND;
1219 		goto exit;
1220 	}
1221 
1222 	d = e->fops->readdir(e->dir);
1223 	if (d == NULL) {
1224 		res = TEE_ERROR_ITEM_NOT_FOUND;
1225 		goto exit;
1226 	}
1227 
1228 	o = tee_obj_alloc();
1229 	if (o == NULL) {
1230 		res = TEE_ERROR_OUT_OF_MEMORY;
1231 		goto exit;
1232 	}
1233 
1234 	o->pobj = calloc(1, sizeof(struct tee_pobj));
1235 	if (!o->pobj) {
1236 		res = TEE_ERROR_OUT_OF_MEMORY;
1237 		goto exit;
1238 	}
1239 
1240 	res = tee_svc_storage_set_enum(d->d_name, e->fops, o);
1241 	if (res != TEE_SUCCESS)
1242 		goto exit;
1243 
1244 	res = tee_obj_verify(sess, o);
1245 	if (res != TEE_SUCCESS)
1246 		goto exit;
1247 
1248 	res = tee_svc_storage_read_head(sess, o);
1249 	if (res != TEE_SUCCESS)
1250 		goto exit;
1251 
1252 	memcpy(info, &o->info, sizeof(TEE_ObjectInfo));
1253 	memcpy(obj_id, o->pobj->obj_id, o->pobj->obj_id_len);
1254 
1255 	l = o->pobj->obj_id_len;
1256 	res = tee_svc_copy_to_user(len, &l, sizeof(*len));
1257 
1258 exit:
1259 	if (o) {
1260 		if (o->pobj)
1261 			free(o->pobj->obj_id);
1262 		free(o->pobj);
1263 		tee_obj_free(o);
1264 	}
1265 
1266 	return res;
1267 }
1268 
1269 TEE_Result syscall_storage_obj_read(unsigned long obj, void *data, size_t len,
1270 			uint64_t *count)
1271 {
1272 	TEE_Result res;
1273 	TEE_Result errno;
1274 	struct tee_ta_session *sess;
1275 	struct tee_obj *o;
1276 	int n_count;
1277 	uint64_t u_count;
1278 	struct user_ta_ctx *utc;
1279 
1280 	res = tee_ta_get_current_session(&sess);
1281 	if (res != TEE_SUCCESS)
1282 		goto exit;
1283 	utc = to_user_ta_ctx(sess->ctx);
1284 
1285 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
1286 	if (res != TEE_SUCCESS)
1287 		goto exit;
1288 
1289 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1290 		res = TEE_ERROR_BAD_STATE;
1291 		goto exit;
1292 	}
1293 
1294 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_READ)) {
1295 		res = TEE_ERROR_ACCESS_CONFLICT;
1296 		goto exit;
1297 	}
1298 
1299 	/* check rights of the provided buffer */
1300 	res = tee_mmu_check_access_rights(utc,
1301 					TEE_MEMORY_ACCESS_WRITE |
1302 					TEE_MEMORY_ACCESS_ANY_OWNER,
1303 					(tee_uaddr_t) data, len);
1304 	if (res != TEE_SUCCESS)
1305 		goto exit;
1306 
1307 	n_count = o->pobj->fops->read(&errno, o->fd, data, len);
1308 	if (n_count < 0) {
1309 		res = errno;
1310 		EMSG("Error code=%x\n", (uint32_t)res);
1311 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
1312 			EMSG("Object corrupt\n");
1313 			tee_svc_storage_remove_corrupt_obj(sess, o);
1314 		}
1315 		goto exit;
1316 	}
1317 	u_count = (uint64_t)((n_count < 0) ? 0 : n_count);
1318 
1319 	res = tee_svc_copy_to_user(count, &u_count, sizeof(*count));
1320 
1321 	o->info.dataPosition += u_count;
1322 
1323 exit:
1324 	return res;
1325 }
1326 
1327 TEE_Result syscall_storage_obj_write(unsigned long obj, void *data, size_t len)
1328 {
1329 	TEE_Result res;
1330 	TEE_Result errno;
1331 	struct tee_ta_session *sess;
1332 	struct tee_obj *o;
1333 	int err;
1334 	struct user_ta_ctx *utc;
1335 
1336 	res = tee_ta_get_current_session(&sess);
1337 	if (res != TEE_SUCCESS)
1338 		goto exit;
1339 	utc = to_user_ta_ctx(sess->ctx);
1340 
1341 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
1342 	if (res != TEE_SUCCESS)
1343 		goto exit;
1344 
1345 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1346 		res = TEE_ERROR_BAD_STATE;
1347 		goto exit;
1348 	}
1349 
1350 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) {
1351 		res = TEE_ERROR_ACCESS_CONFLICT;
1352 		goto exit;
1353 	}
1354 
1355 	/* check rights of the provided buffer */
1356 	res = tee_mmu_check_access_rights(utc,
1357 					TEE_MEMORY_ACCESS_READ |
1358 					TEE_MEMORY_ACCESS_ANY_OWNER,
1359 					(tee_uaddr_t) data, len);
1360 	if (res != TEE_SUCCESS)
1361 		goto exit;
1362 
1363 	err = o->pobj->fops->write(&errno, o->fd, data, len);
1364 	if (err < 0)
1365 		res = errno;
1366 	if (err != (int)len)
1367 		goto exit;
1368 
1369 	o->info.dataPosition += len;
1370 	if (o->info.dataPosition > o->info.dataSize)
1371 		o->info.dataSize = o->info.dataPosition;
1372 
1373 exit:
1374 	return res;
1375 }
1376 
1377 TEE_Result syscall_storage_obj_trunc(unsigned long obj, size_t len)
1378 {
1379 	TEE_Result res;
1380 	TEE_Result errno;
1381 	struct tee_ta_session *sess;
1382 	struct tee_obj *o;
1383 	int err;
1384 	tee_fs_off_t off;
1385 	size_t attr_size;
1386 
1387 	res = tee_ta_get_current_session(&sess);
1388 	if (res != TEE_SUCCESS)
1389 		goto exit;
1390 
1391 	res = tee_obj_get(to_user_ta_ctx(sess->ctx),
1392 			  tee_svc_uref_to_vaddr(obj), &o);
1393 	if (res != TEE_SUCCESS)
1394 		goto exit;
1395 
1396 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1397 		res = TEE_ERROR_BAD_STATE;
1398 		goto exit;
1399 	}
1400 
1401 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) {
1402 		res = TEE_ERROR_ACCESS_CONFLICT;
1403 		goto exit;
1404 	}
1405 
1406 	res = tee_obj_verify(sess, o);
1407 	if (res != TEE_SUCCESS)
1408 		goto exit;
1409 
1410 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
1411 	if (res != TEE_SUCCESS)
1412 		goto exit;
1413 
1414 	off = sizeof(struct tee_svc_storage_head) + attr_size;
1415 	err = o->pobj->fops->ftruncate(&errno, o->fd, len + off);
1416 	if (err < 0) {
1417 		res = errno;
1418 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
1419 			EMSG("Object corrupt\n");
1420 			res = tee_svc_storage_remove_corrupt_obj(sess, o);
1421 			if (res != TEE_SUCCESS)
1422 				goto exit;
1423 			res = TEE_ERROR_CORRUPT_OBJECT;
1424 			goto exit;
1425 		} else
1426 			res = TEE_ERROR_GENERIC;
1427 	}
1428 
1429 exit:
1430 	return res;
1431 }
1432 
1433 TEE_Result syscall_storage_obj_seek(unsigned long obj, long offset,
1434 				    unsigned long whence)
1435 {
1436 	TEE_Result res;
1437 	TEE_Result errno;
1438 	struct tee_ta_session *sess;
1439 	struct tee_obj *o;
1440 	int fw;
1441 	tee_fs_off_t off;
1442 	tee_fs_off_t e_off = 0;
1443 	size_t attr_size;
1444 
1445 	res = tee_ta_get_current_session(&sess);
1446 	if (res != TEE_SUCCESS)
1447 		goto exit;
1448 
1449 	res = tee_obj_get(to_user_ta_ctx(sess->ctx),
1450 			  tee_svc_uref_to_vaddr(obj), &o);
1451 	if (res != TEE_SUCCESS)
1452 		goto exit;
1453 
1454 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1455 		res = TEE_ERROR_BAD_STATE;
1456 		goto exit;
1457 	}
1458 
1459 	res = tee_obj_verify(sess, o);
1460 	if (res != TEE_SUCCESS)
1461 		goto exit;
1462 
1463 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
1464 	if (res != TEE_SUCCESS)
1465 		goto exit;
1466 
1467 	fw = tee_svc_storage_conv_whence(whence);
1468 
1469 	if (whence == TEE_DATA_SEEK_SET)
1470 		e_off = sizeof(struct tee_svc_storage_head) + attr_size;
1471 
1472 	off = o->pobj->fops->lseek(&errno, o->fd, e_off + offset, fw);
1473 	if (off > -1 && off >= e_off) {
1474 		res = TEE_SUCCESS;
1475 		o->info.dataPosition = off -
1476 			(sizeof(struct tee_svc_storage_head) + attr_size);
1477 	} else {
1478 		res = TEE_ERROR_GENERIC;
1479 		goto exit;
1480 	}
1481 
1482 exit:
1483 	return res;
1484 }
1485 
1486 void tee_svc_storage_close_all_enum(struct user_ta_ctx *utc)
1487 {
1488 	struct tee_storage_enum_head *eh = &utc->storage_enums;
1489 
1490 	/* disregard return value */
1491 	while (!TAILQ_EMPTY(eh))
1492 		tee_svc_close_enum(utc, TAILQ_FIRST(eh));
1493 }
1494