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