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