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