xref: /optee_os/core/tee/tee_svc_storage.c (revision c3b3c4de602ccd7690bcbd65181d43d622b017e4)
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 	res = tee_obj_verify(sess, o);
902 	if (res != TEE_SUCCESS)
903 		goto exit;
904 
905 	/* get new ds name */
906 	new_file = tee_svc_storage_create_filename(sess, object_id,
907 						   object_id_len, false);
908 	if (new_file == NULL) {
909 		res = TEE_ERROR_OUT_OF_MEMORY;
910 		goto exit;
911 	}
912 
913 	old_file = tee_svc_storage_create_filename(sess, o->pobj->obj_id,
914 						   o->pobj->obj_id_len, false);
915 	if (old_file == NULL) {
916 		res = TEE_ERROR_OUT_OF_MEMORY;
917 		goto exit;
918 	}
919 
920 	/* reserve dest name */
921 	fops = o->pobj->fops;
922 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
923 			   object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META,
924 			   fops, &po);
925 	if (res != TEE_SUCCESS)
926 		goto exit;
927 
928 	err = fops->access(new_file, TEE_FS_F_OK);
929 	if (err == 0) {
930 		/* file exists */
931 		res = TEE_ERROR_ACCESS_CONFLICT;
932 		goto exit;
933 	}
934 
935 	/* move */
936 	err = fops->rename(old_file, new_file);
937 	if (err) {
938 		/* error codes needs better granularity */
939 		res = TEE_ERROR_GENERIC;
940 		goto exit;
941 	}
942 
943 	res = tee_pobj_rename(o->pobj, object_id, object_id_len);
944 
945 exit:
946 	tee_pobj_release(po);
947 
948 	free(new_file);
949 	free(old_file);
950 
951 	return res;
952 }
953 
954 TEE_Result syscall_storage_alloc_enum(uint32_t *obj_enum)
955 {
956 	struct tee_storage_enum *e;
957 	struct tee_ta_session *sess;
958 	TEE_Result res;
959 	struct user_ta_ctx *utc;
960 
961 	if (obj_enum == NULL)
962 		return TEE_ERROR_BAD_PARAMETERS;
963 
964 	res = tee_ta_get_current_session(&sess);
965 	if (res != TEE_SUCCESS)
966 		return res;
967 	utc = to_user_ta_ctx(sess->ctx);
968 
969 	e = malloc(sizeof(struct tee_storage_enum));
970 	if (e == NULL)
971 		return TEE_ERROR_OUT_OF_MEMORY;
972 
973 	e->dir = NULL;
974 	e->fops = NULL;
975 	TAILQ_INSERT_TAIL(&utc->storage_enums, e, link);
976 
977 	return tee_svc_copy_kaddr_to_uref(obj_enum, e);
978 }
979 
980 TEE_Result syscall_storage_free_enum(unsigned long obj_enum)
981 {
982 	struct tee_storage_enum *e;
983 	TEE_Result res;
984 	struct tee_ta_session *sess;
985 	struct user_ta_ctx *utc;
986 
987 	res = tee_ta_get_current_session(&sess);
988 	if (res != TEE_SUCCESS)
989 		return res;
990 	utc = to_user_ta_ctx(sess->ctx);
991 
992 	res = tee_svc_storage_get_enum(utc,
993 			tee_svc_uref_to_vaddr(obj_enum), &e);
994 	if (res != TEE_SUCCESS)
995 		return res;
996 
997 	return tee_svc_close_enum(utc, e);
998 }
999 
1000 TEE_Result syscall_storage_reset_enum(unsigned long obj_enum)
1001 {
1002 	struct tee_storage_enum *e;
1003 	TEE_Result res;
1004 	struct tee_ta_session *sess;
1005 
1006 	res = tee_ta_get_current_session(&sess);
1007 	if (res != TEE_SUCCESS)
1008 		return res;
1009 
1010 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
1011 			tee_svc_uref_to_vaddr(obj_enum), &e);
1012 	if (res != TEE_SUCCESS)
1013 		return res;
1014 
1015 	res = e->fops->closedir(e->dir);
1016 	e->dir = NULL;
1017 	if (res != 0)
1018 		return TEE_ERROR_GENERIC;
1019 
1020 	return TEE_SUCCESS;
1021 }
1022 
1023 static TEE_Result tee_svc_storage_set_enum(char *d_name,
1024 			const struct tee_file_operations *fops,
1025 			struct tee_obj *o)
1026 {
1027 	TEE_Result res;
1028 	uint32_t blen;
1029 	uint32_t hslen;
1030 
1031 	o->info.handleFlags =
1032 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
1033 	o->info.objectUsage = TEE_USAGE_DEFAULT;
1034 
1035 	hslen = strlen(d_name);
1036 	blen = TEE_HS2B_BBUF_SIZE(hslen);
1037 	o->pobj->obj_id = malloc(blen);
1038 	if (!o->pobj->obj_id) {
1039 		res = TEE_ERROR_OUT_OF_MEMORY;
1040 		goto exit;
1041 	}
1042 	tee_hs2b((uint8_t *)d_name, o->pobj->obj_id, hslen, blen);
1043 	o->pobj->obj_id_len = blen;
1044 	o->pobj->fops = fops;
1045 
1046 	res = TEE_SUCCESS;
1047 
1048 exit:
1049 	return res;
1050 
1051 }
1052 
1053 TEE_Result syscall_storage_start_enum(unsigned long obj_enum,
1054 				      unsigned long storage_id)
1055 {
1056 	struct tee_storage_enum *e;
1057 	char *dir;
1058 	TEE_Result res;
1059 	struct tee_ta_session *sess;
1060 	struct tee_fs_dirent *d = NULL;
1061 	struct tee_obj *o = NULL;
1062 	const struct tee_file_operations *fops = file_ops(storage_id);
1063 
1064 	res = tee_ta_get_current_session(&sess);
1065 	if (res != TEE_SUCCESS)
1066 		return res;
1067 
1068 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
1069 			tee_svc_uref_to_vaddr(obj_enum), &e);
1070 	if (res != TEE_SUCCESS)
1071 		return res;
1072 
1073 	if (!fops)
1074 		return TEE_ERROR_ITEM_NOT_FOUND;
1075 
1076 	dir = tee_svc_storage_create_dirname(sess);
1077 	if (dir == NULL)
1078 		return TEE_ERROR_OUT_OF_MEMORY;
1079 
1080 	e->fops = fops;
1081 	e->dir = fops->opendir(dir);
1082 	free(dir);
1083 	if (e->dir == NULL)
1084 		/* error codes needs better granularity */
1085 		return TEE_ERROR_ITEM_NOT_FOUND;
1086 
1087 	/* verify object */
1088 	o = tee_obj_alloc();
1089 	if (o == NULL) {
1090 		res = TEE_ERROR_OUT_OF_MEMORY;
1091 		goto exit;
1092 	}
1093 
1094 	o->pobj = calloc(1, sizeof(struct tee_pobj));
1095 	if (!o->pobj) {
1096 		res = TEE_ERROR_OUT_OF_MEMORY;
1097 		goto exit;
1098 	}
1099 
1100 	/* object enumeration loop */
1101 	do {
1102 		d = fops->readdir(e->dir);
1103 		if (d) {
1104 			/* allocate obj_id and set object */
1105 			res = tee_svc_storage_set_enum(d->d_name, fops, o);
1106 			if (res != TEE_SUCCESS)
1107 				goto exit;
1108 			res = tee_obj_verify(sess, o);
1109 			if (res != TEE_SUCCESS)
1110 				goto exit;
1111 			/* free obj_id for each iteration */
1112 			free(o->pobj->obj_id);
1113 			/* force obj_id to skip freeing at exit statement */
1114 			o->pobj->obj_id = NULL;
1115 		}
1116 	} while (d);
1117 
1118 	/* re-start */
1119 	res = fops->closedir(e->dir);
1120 	e->dir = NULL;
1121 	if (res != 0) {
1122 		res = TEE_ERROR_GENERIC;
1123 		goto exit;
1124 	}
1125 
1126 	dir = tee_svc_storage_create_dirname(sess);
1127 	if (dir == NULL) {
1128 		res = TEE_ERROR_OUT_OF_MEMORY;
1129 		goto exit;
1130 	}
1131 
1132 	e->dir = fops->opendir(dir);
1133 	free(dir);
1134 
1135 exit:
1136 	if (o) {
1137 		if (o->pobj)
1138 			free(o->pobj->obj_id);
1139 		free(o->pobj);
1140 		tee_obj_free(o);
1141 	}
1142 
1143 	return res;
1144 }
1145 
1146 TEE_Result syscall_storage_next_enum(unsigned long obj_enum,
1147 			TEE_ObjectInfo *info, void *obj_id, uint64_t *len)
1148 {
1149 	struct tee_storage_enum *e;
1150 	struct tee_fs_dirent *d;
1151 	TEE_Result res = TEE_SUCCESS;
1152 	struct tee_ta_session *sess;
1153 	struct tee_obj *o = NULL;
1154 	uint64_t l;
1155 	struct user_ta_ctx *utc;
1156 
1157 	res = tee_ta_get_current_session(&sess);
1158 	if (res != TEE_SUCCESS)
1159 		goto exit;
1160 	utc = to_user_ta_ctx(sess->ctx);
1161 
1162 	res = tee_svc_storage_get_enum(utc,
1163 			tee_svc_uref_to_vaddr(obj_enum), &e);
1164 	if (res != TEE_SUCCESS)
1165 		goto exit;
1166 
1167 	/* check rights of the provided buffers */
1168 	res = tee_mmu_check_access_rights(utc,
1169 					TEE_MEMORY_ACCESS_WRITE |
1170 					TEE_MEMORY_ACCESS_ANY_OWNER,
1171 					(tee_uaddr_t) info,
1172 					sizeof(TEE_ObjectInfo));
1173 	if (res != TEE_SUCCESS)
1174 		goto exit;
1175 
1176 	res = tee_mmu_check_access_rights(utc,
1177 					TEE_MEMORY_ACCESS_WRITE |
1178 					TEE_MEMORY_ACCESS_ANY_OWNER,
1179 					(tee_uaddr_t) obj_id,
1180 					TEE_OBJECT_ID_MAX_LEN);
1181 	if (res != TEE_SUCCESS)
1182 		goto exit;
1183 
1184 	if (!e->fops) {
1185 		res = TEE_ERROR_ITEM_NOT_FOUND;
1186 		goto exit;
1187 	}
1188 
1189 	d = e->fops->readdir(e->dir);
1190 	if (d == NULL) {
1191 		res = TEE_ERROR_ITEM_NOT_FOUND;
1192 		goto exit;
1193 	}
1194 
1195 	o = tee_obj_alloc();
1196 	if (o == NULL) {
1197 		res = TEE_ERROR_OUT_OF_MEMORY;
1198 		goto exit;
1199 	}
1200 	o->flags = TEE_DATA_FLAG_SHARE_READ;
1201 
1202 	o->pobj = calloc(1, sizeof(struct tee_pobj));
1203 	if (!o->pobj) {
1204 		res = TEE_ERROR_OUT_OF_MEMORY;
1205 		goto exit;
1206 	}
1207 
1208 	res = tee_svc_storage_set_enum(d->d_name, e->fops, o);
1209 	if (res != TEE_SUCCESS)
1210 		goto exit;
1211 
1212 	res = tee_svc_storage_read_head(sess, o);
1213 	if (res != TEE_SUCCESS)
1214 		goto exit;
1215 
1216 	memcpy(info, &o->info, sizeof(TEE_ObjectInfo));
1217 	memcpy(obj_id, o->pobj->obj_id, o->pobj->obj_id_len);
1218 
1219 	l = o->pobj->obj_id_len;
1220 	res = tee_svc_copy_to_user(len, &l, sizeof(*len));
1221 
1222 exit:
1223 	if (o) {
1224 		if (o->pobj) {
1225 			if (o->fd >= 0)
1226 				o->pobj->fops->close(o->fd);
1227 			free(o->pobj->obj_id);
1228 		}
1229 		free(o->pobj);
1230 		tee_obj_free(o);
1231 	}
1232 
1233 	return res;
1234 }
1235 
1236 TEE_Result syscall_storage_obj_read(unsigned long obj, void *data, size_t len,
1237 			uint64_t *count)
1238 {
1239 	TEE_Result res;
1240 	TEE_Result errno;
1241 	struct tee_ta_session *sess;
1242 	struct tee_obj *o;
1243 	int n_count;
1244 	uint64_t u_count;
1245 	struct user_ta_ctx *utc;
1246 
1247 	res = tee_ta_get_current_session(&sess);
1248 	if (res != TEE_SUCCESS)
1249 		goto exit;
1250 	utc = to_user_ta_ctx(sess->ctx);
1251 
1252 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
1253 	if (res != TEE_SUCCESS)
1254 		goto exit;
1255 
1256 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1257 		res = TEE_ERROR_BAD_STATE;
1258 		goto exit;
1259 	}
1260 
1261 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_READ)) {
1262 		res = TEE_ERROR_ACCESS_CONFLICT;
1263 		goto exit;
1264 	}
1265 
1266 	/* check rights of the provided buffer */
1267 	res = tee_mmu_check_access_rights(utc,
1268 					TEE_MEMORY_ACCESS_WRITE |
1269 					TEE_MEMORY_ACCESS_ANY_OWNER,
1270 					(tee_uaddr_t) data, len);
1271 	if (res != TEE_SUCCESS)
1272 		goto exit;
1273 
1274 	n_count = o->pobj->fops->read(&errno, o->fd, data, len);
1275 	if (n_count < 0) {
1276 		res = errno;
1277 		EMSG("Error code=%x\n", (uint32_t)res);
1278 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
1279 			EMSG("Object corrupt\n");
1280 			tee_svc_storage_remove_corrupt_obj(sess, o);
1281 		}
1282 		goto exit;
1283 	}
1284 	u_count = (uint64_t)((n_count < 0) ? 0 : n_count);
1285 
1286 	res = tee_svc_copy_to_user(count, &u_count, sizeof(*count));
1287 
1288 	o->info.dataPosition += u_count;
1289 
1290 exit:
1291 	return res;
1292 }
1293 
1294 TEE_Result syscall_storage_obj_write(unsigned long obj, void *data, size_t len)
1295 {
1296 	TEE_Result res;
1297 	TEE_Result errno;
1298 	struct tee_ta_session *sess;
1299 	struct tee_obj *o;
1300 	int err;
1301 	struct user_ta_ctx *utc;
1302 
1303 	res = tee_ta_get_current_session(&sess);
1304 	if (res != TEE_SUCCESS)
1305 		goto exit;
1306 	utc = to_user_ta_ctx(sess->ctx);
1307 
1308 	res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
1309 	if (res != TEE_SUCCESS)
1310 		goto exit;
1311 
1312 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1313 		res = TEE_ERROR_BAD_STATE;
1314 		goto exit;
1315 	}
1316 
1317 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) {
1318 		res = TEE_ERROR_ACCESS_CONFLICT;
1319 		goto exit;
1320 	}
1321 
1322 	/* check rights of the provided buffer */
1323 	res = tee_mmu_check_access_rights(utc,
1324 					TEE_MEMORY_ACCESS_READ |
1325 					TEE_MEMORY_ACCESS_ANY_OWNER,
1326 					(tee_uaddr_t) data, len);
1327 	if (res != TEE_SUCCESS)
1328 		goto exit;
1329 
1330 	err = o->pobj->fops->write(&errno, o->fd, data, len);
1331 	if (err < 0)
1332 		res = errno;
1333 	if (err != (int)len)
1334 		goto exit;
1335 
1336 	o->info.dataPosition += len;
1337 	if (o->info.dataPosition > o->info.dataSize)
1338 		o->info.dataSize = o->info.dataPosition;
1339 
1340 exit:
1341 	return res;
1342 }
1343 
1344 TEE_Result syscall_storage_obj_trunc(unsigned long obj, size_t len)
1345 {
1346 	TEE_Result res;
1347 	TEE_Result errno;
1348 	struct tee_ta_session *sess;
1349 	struct tee_obj *o;
1350 	int err;
1351 	tee_fs_off_t off;
1352 	size_t attr_size;
1353 
1354 	res = tee_ta_get_current_session(&sess);
1355 	if (res != TEE_SUCCESS)
1356 		goto exit;
1357 
1358 	res = tee_obj_get(to_user_ta_ctx(sess->ctx),
1359 			  tee_svc_uref_to_vaddr(obj), &o);
1360 	if (res != TEE_SUCCESS)
1361 		goto exit;
1362 
1363 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1364 		res = TEE_ERROR_BAD_STATE;
1365 		goto exit;
1366 	}
1367 
1368 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) {
1369 		res = TEE_ERROR_ACCESS_CONFLICT;
1370 		goto exit;
1371 	}
1372 
1373 	res = tee_obj_verify(sess, o);
1374 	if (res != TEE_SUCCESS)
1375 		goto exit;
1376 
1377 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
1378 	if (res != TEE_SUCCESS)
1379 		goto exit;
1380 
1381 	off = sizeof(struct tee_svc_storage_head) + attr_size;
1382 	err = o->pobj->fops->ftruncate(&errno, o->fd, len + off);
1383 	if (err < 0) {
1384 		res = errno;
1385 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
1386 			EMSG("Object corrupt\n");
1387 			res = tee_svc_storage_remove_corrupt_obj(sess, o);
1388 			if (res != TEE_SUCCESS)
1389 				goto exit;
1390 			res = TEE_ERROR_CORRUPT_OBJECT;
1391 			goto exit;
1392 		} else
1393 			res = TEE_ERROR_GENERIC;
1394 	}
1395 
1396 exit:
1397 	return res;
1398 }
1399 
1400 TEE_Result syscall_storage_obj_seek(unsigned long obj, int32_t offset,
1401 				    unsigned long whence)
1402 {
1403 	TEE_Result res;
1404 	TEE_Result errno;
1405 	struct tee_ta_session *sess;
1406 	struct tee_obj *o;
1407 	int fw;
1408 	tee_fs_off_t off;
1409 	tee_fs_off_t e_off = 0;
1410 	size_t attr_size;
1411 
1412 	res = tee_ta_get_current_session(&sess);
1413 	if (res != TEE_SUCCESS)
1414 		goto exit;
1415 
1416 	res = tee_obj_get(to_user_ta_ctx(sess->ctx),
1417 			  tee_svc_uref_to_vaddr(obj), &o);
1418 	if (res != TEE_SUCCESS)
1419 		goto exit;
1420 
1421 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
1422 		res = TEE_ERROR_BAD_STATE;
1423 		goto exit;
1424 	}
1425 
1426 	res = tee_obj_verify(sess, o);
1427 	if (res != TEE_SUCCESS)
1428 		goto exit;
1429 
1430 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
1431 	if (res != TEE_SUCCESS)
1432 		goto exit;
1433 
1434 	fw = tee_svc_storage_conv_whence(whence);
1435 
1436 	if (whence == TEE_DATA_SEEK_SET)
1437 		e_off = sizeof(struct tee_svc_storage_head) + attr_size;
1438 
1439 	off = o->pobj->fops->lseek(&errno, o->fd, e_off + offset, fw);
1440 	if (off > -1 && off >= e_off) {
1441 		res = TEE_SUCCESS;
1442 		o->info.dataPosition = off -
1443 			(sizeof(struct tee_svc_storage_head) + attr_size);
1444 	} else {
1445 		res = TEE_ERROR_GENERIC;
1446 		goto exit;
1447 	}
1448 
1449 exit:
1450 	return res;
1451 }
1452 
1453 void tee_svc_storage_close_all_enum(struct user_ta_ctx *utc)
1454 {
1455 	struct tee_storage_enum_head *eh = &utc->storage_enums;
1456 
1457 	/* disregard return value */
1458 	while (!TAILQ_EMPTY(eh))
1459 		tee_svc_close_enum(utc, TAILQ_FIRST(eh));
1460 }
1461