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