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