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