xref: /optee_os/core/tee/tee_svc_storage.c (revision b01047730e77127c23a36591643eeb8bb0487d68)
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 <tee/tee_svc_storage.h>
29 
30 #include <kernel/tee_ta_manager.h>
31 #include <tee_api_defines.h>
32 #include <kernel/tee_misc.h>
33 #include <tee/tee_fs.h>
34 #include <tee/tee_fs_defs.h>
35 #include <tee/tee_obj.h>
36 #include <tee/tee_svc.h>
37 #include <mm/tee_mmu.h>
38 #include <tee/tee_pobj.h>
39 
40 /* SSF (Secure Storage File version 00 */
41 #define TEE_SVC_STORAGE_MAGIC 0x53534600;
42 
43 /* Header of GP formated secure storage files */
44 struct tee_svc_storage_head {
45 	uint32_t magic;
46 	uint32_t head_size;
47 	uint32_t meta_size;
48 	uint32_t ds_size;
49 };
50 
51 struct tee_storage_enum {
52 	TAILQ_ENTRY(tee_storage_enum) link;
53 	tee_fs_dir *dir;
54 };
55 
56 static TEE_Result tee_svc_storage_get_enum(struct tee_ta_ctx *ctx,
57 					   uint32_t enum_id,
58 					   struct tee_storage_enum **e_out)
59 {
60 	struct tee_storage_enum *e;
61 
62 	TAILQ_FOREACH(e, &ctx->storage_enums, link) {
63 		if (enum_id == (uint32_t) e) {
64 			*e_out = e;
65 			return TEE_SUCCESS;
66 		}
67 	}
68 	return TEE_ERROR_BAD_PARAMETERS;
69 }
70 
71 static TEE_Result tee_svc_close_enum(struct tee_ta_ctx *ctx,
72 				     struct tee_storage_enum *e)
73 {
74 	int ret;
75 
76 	if (e == NULL || ctx == NULL)
77 		return TEE_ERROR_BAD_PARAMETERS;
78 
79 	TAILQ_REMOVE(&ctx->storage_enums, e, link);
80 
81 	ret = tee_fs_closedir(e->dir);
82 	e->dir = NULL;
83 
84 	free(e);
85 
86 	if (ret != 0)
87 		return TEE_ERROR_ITEM_NOT_FOUND;
88 
89 	return TEE_SUCCESS;
90 }
91 
92 static char *tee_svc_storage_create_filename(struct tee_ta_session *sess,
93 					     void *object_id,
94 					     uint32_t object_id_len)
95 {
96 	uint8_t *file = NULL;
97 	/* +1 for the '/' */
98 	uint32_t hslen =
99 	    TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID) + object_id_len) + 1;
100 	uint32_t pos;
101 
102 	file = malloc(hslen);
103 
104 	if (file == NULL)
105 		return NULL;
106 
107 	pos = tee_b2hs((uint8_t *)&sess->ctx->head->uuid, file,
108 		       sizeof(TEE_UUID), hslen);
109 	file[pos] = '/';
110 	pos++;
111 	tee_b2hs(object_id, file + pos, object_id_len, hslen - pos);
112 
113 	return (char *)file;
114 }
115 
116 static char *tee_svc_storage_create_dirname(struct tee_ta_session *sess)
117 {
118 	uint8_t *dir = NULL;
119 	uint32_t hslen = TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID));
120 
121 	dir = malloc(hslen);
122 
123 	if (dir == NULL)
124 		return NULL;
125 
126 	tee_b2hs((uint8_t *)&sess->ctx->head->uuid, dir, sizeof(TEE_UUID),
127 		 hslen);
128 
129 	return (char *)dir;
130 }
131 
132 static uint32_t tee_svc_storage_conv_oflags(uint32_t flags)
133 {
134 	uint32_t out = 0;
135 
136 	if (flags & (TEE_DATA_FLAG_ACCESS_READ | TEE_DATA_FLAG_SHARE_READ)) {
137 		if (flags & (TEE_DATA_FLAG_ACCESS_WRITE |
138 			     TEE_DATA_FLAG_ACCESS_WRITE_META |
139 			     TEE_DATA_FLAG_SHARE_WRITE))
140 			out |= TEE_FS_O_RDWR;
141 		else
142 			out |= TEE_FS_O_RDONLY;
143 	} else {
144 		if (flags & (TEE_DATA_FLAG_ACCESS_WRITE |
145 			     TEE_DATA_FLAG_ACCESS_WRITE_META |
146 			     TEE_DATA_FLAG_SHARE_WRITE))
147 			out |= TEE_FS_O_WRONLY;
148 	}
149 
150 	if (flags & TEE_DATA_FLAG_EXCLUSIVE)
151 		out |= TEE_FS_O_EXCL;
152 
153 	return out;
154 }
155 
156 static int tee_svc_storage_conv_whence(TEE_Whence whence)
157 {
158 	switch (whence) {
159 	case TEE_DATA_SEEK_SET:
160 		return TEE_FS_SEEK_SET;
161 	case TEE_DATA_SEEK_CUR:
162 		return TEE_FS_SEEK_CUR;
163 	case TEE_DATA_SEEK_END:
164 		return TEE_FS_SEEK_END;
165 	default:
166 		return -1;
167 	}
168 }
169 
170 static TEE_Result tee_svc_storage_create_file(struct tee_ta_session *sess,
171 					      char *file, int *fd,
172 					      uint32_t flags)
173 {
174 	TEE_Result res = TEE_SUCCESS;
175 	char *dir = NULL;
176 	int tmp;
177 	uint32_t cflags = TEE_FS_O_WRONLY | TEE_FS_O_CREATE;
178 
179 	if (flags & TEE_DATA_FLAG_EXCLUSIVE)
180 		cflags |= TEE_FS_O_EXCL;
181 
182 	*fd = tee_fs_open(file, cflags);
183 
184 	if (*fd < 0) {
185 		/* try and make directory */
186 		dir = tee_svc_storage_create_dirname(sess);
187 		if (dir == NULL) {
188 			res = TEE_ERROR_OUT_OF_MEMORY;
189 			goto exit;
190 		}
191 
192 		tmp = tee_fs_mkdir(dir, TEE_FS_S_IRUSR | TEE_FS_S_IWUSR);
193 		free(dir);
194 
195 		if (tmp < 0) {
196 			/* error codes needs better granularity */
197 			res = TEE_ERROR_GENERIC;
198 			goto exit;
199 		}
200 
201 		/* try and open again */
202 		*fd = tee_fs_open(file, cflags);
203 
204 		if (*fd < 0) {
205 			/* error codes needs better granularity */
206 			res = TEE_ERROR_GENERIC;
207 			goto exit;
208 		}
209 	}
210 
211 exit:
212 	return res;
213 }
214 
215 static TEE_Result tee_svc_storage_read_head(struct tee_ta_session *sess,
216 					    struct tee_obj *o)
217 {
218 	TEE_Result res = TEE_SUCCESS;
219 	int fd = -1;
220 	int err;
221 	struct tee_svc_storage_head head;
222 	char *file = NULL;
223 
224 	if (o == NULL || o->pobj == NULL)
225 		return TEE_ERROR_BAD_PARAMETERS;
226 
227 	file =
228 	    tee_svc_storage_create_filename(sess, o->pobj->obj_id,
229 					    o->pobj->obj_id_len);
230 	if (file == NULL) {
231 		res = TEE_ERROR_OUT_OF_MEMORY;
232 		goto exit;
233 	}
234 
235 	fd = tee_fs_open(file, TEE_FS_O_RDONLY);
236 	free(file);
237 
238 	/* error codes needs better granularity */
239 	if (fd < 0)
240 		return TEE_ERROR_ITEM_NOT_FOUND;
241 
242 	/* read head */
243 	err = tee_fs_read(fd, &head, sizeof(struct tee_svc_storage_head));
244 	if (err != sizeof(struct tee_svc_storage_head)) {
245 		res = TEE_ERROR_BAD_FORMAT;
246 		goto exit;
247 	}
248 
249 	o->data_size = head.meta_size;
250 	o->info.dataSize = head.ds_size;
251 
252 	o->data = malloc(o->data_size);
253 	if (o->data == NULL) {
254 		res = TEE_ERROR_OUT_OF_MEMORY;
255 		goto exit;
256 	}
257 
258 	/* read meta */
259 	err = tee_fs_read(fd, o->data, o->data_size);
260 	if (err != (int)o->data_size) {
261 		free(o->data);
262 		o->data = NULL;
263 		res = TEE_ERROR_NO_DATA;
264 	}
265 
266 exit:
267 	tee_fs_close(fd);
268 
269 	return res;
270 }
271 
272 static TEE_Result tee_svc_storage_init_file(struct tee_ta_session *sess,
273 					    struct tee_obj *o,
274 					    struct tee_obj *attr_o, void *data,
275 					    uint32_t len, uint32_t flags)
276 {
277 	TEE_Result res = TEE_SUCCESS;
278 	int fd;
279 	int err;
280 	struct tee_svc_storage_head head;
281 	char *file = NULL;
282 
283 	if (o == NULL || o->pobj == NULL)
284 		return TEE_ERROR_BAD_PARAMETERS;
285 
286 	free(o->data);
287 
288 	if (attr_o && attr_o->data_size) {
289 		o->data_size = attr_o->data_size;
290 		o->data = malloc(attr_o->data_size);
291 		if (o->data == NULL)
292 			return TEE_ERROR_OUT_OF_MEMORY;
293 
294 		memcpy(o->data, attr_o->data, attr_o->data_size);
295 		o->have_attrs = attr_o->have_attrs;
296 		o->info.objectUsage = attr_o->info.objectUsage;
297 		o->info.objectType = attr_o->info.objectType;
298 	} else {
299 		o->data = NULL;
300 		o->data_size = 0;
301 		o->have_attrs = 0;
302 		o->info.objectUsage = TEE_USAGE_DEFAULT;
303 		o->info.objectType = 0;
304 	}
305 
306 	/* write head */
307 	head.magic = TEE_SVC_STORAGE_MAGIC;
308 	head.head_size = sizeof(struct tee_svc_storage_head);
309 	head.meta_size = o->data_size;
310 	head.ds_size = len;
311 
312 	file =
313 	    tee_svc_storage_create_filename(sess, o->pobj->obj_id,
314 					    o->pobj->obj_id_len);
315 	if (file == NULL)
316 		return TEE_ERROR_OUT_OF_MEMORY;
317 
318 	res = tee_svc_storage_create_file(sess, file, &fd, flags);
319 	free(file);
320 	if (res != TEE_SUCCESS)
321 		return res;
322 
323 	/* error codes needs better granularity */
324 	if (fd < 0)
325 		return TEE_ERROR_GENERIC;
326 
327 	/* write head */
328 	err = tee_fs_write(fd, &head, sizeof(struct tee_svc_storage_head));
329 	/* error codes needs better granularity */
330 	if (err != sizeof(struct tee_svc_storage_head)) {
331 		res = TEE_ERROR_GENERIC;
332 		goto exit;
333 	}
334 
335 	/* write meta */
336 	err = tee_fs_write(fd, o->data, o->data_size);
337 	/* error codes needs better granularity */
338 	if (err != (int)o->data_size) {
339 		res = TEE_ERROR_GENERIC;
340 		goto exit;
341 	}
342 
343 	/* write init data */
344 	o->info.dataSize = len;
345 
346 	/* write data to fs if needed */
347 	if (data && len) {
348 		err = tee_fs_write(fd, data, len);
349 
350 		if (err != (int)len) {
351 			/* error codes needs better granularity */
352 			res = TEE_ERROR_GENERIC;
353 			return res;
354 		}
355 	}
356 
357 exit:
358 	tee_fs_close(fd);
359 
360 	return TEE_SUCCESS;
361 }
362 
363 static TEE_Result tee_svc_storage_remove(struct tee_ta_session *sess,
364 					 uint32_t storage_id, void *object_id,
365 					 uint32_t object_id_len)
366 {
367 	TEE_Result res = TEE_SUCCESS;
368 	char *file = NULL;
369 	int err;
370 
371 	if (sess == NULL)
372 		return TEE_ERROR_BAD_PARAMETERS;
373 
374 	if (storage_id != TEE_STORAGE_PRIVATE)
375 		return TEE_ERROR_ITEM_NOT_FOUND;
376 
377 	file = tee_svc_storage_create_filename(sess, object_id, object_id_len);
378 	if (file == NULL)
379 		return TEE_ERROR_OUT_OF_MEMORY;
380 
381 	err = tee_fs_unlink(file);
382 	free(file);
383 	if (err != 0)
384 		/* error codes needs better granularity */
385 		res = TEE_ERROR_GENERIC;
386 
387 	return res;
388 }
389 
390 TEE_Result tee_svc_storage_obj_open(uint32_t storage_id, void *object_id,
391 				    uint32_t object_id_len, uint32_t flags,
392 				    uint32_t *obj)
393 {
394 	TEE_Result res;
395 	struct tee_ta_session *sess;
396 	struct tee_obj *o;
397 	char *file = NULL;
398 	int fs_flags;
399 	int fd = -1;
400 	tee_fs_off_t off;
401 	tee_fs_off_t e_off;
402 	struct tee_pobj *po = NULL;
403 
404 	if (storage_id != TEE_STORAGE_PRIVATE)
405 		return TEE_ERROR_ITEM_NOT_FOUND;
406 
407 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
408 		return TEE_ERROR_BAD_PARAMETERS;
409 
410 	res = tee_ta_get_current_session(&sess);
411 	if (res != TEE_SUCCESS)
412 		goto exit;
413 
414 	res =
415 	    tee_mmu_check_access_rights(sess->ctx,
416 					TEE_MEMORY_ACCESS_READ |
417 					TEE_MEMORY_ACCESS_ANY_OWNER,
418 					(tee_uaddr_t) object_id, object_id_len);
419 	if (res != TEE_SUCCESS)
420 		goto exit;
421 
422 	res = tee_pobj_get((void *)&sess->ctx->head->uuid, object_id,
423 			   object_id_len, flags, &po);
424 	if (res != TEE_SUCCESS)
425 		goto exit;
426 
427 	fs_flags = tee_svc_storage_conv_oflags(flags);
428 
429 	o = calloc(1, sizeof(*o));
430 	if (o == NULL) {
431 		res = TEE_ERROR_OUT_OF_MEMORY;
432 		goto exit;
433 	}
434 
435 	o->info.handleFlags =
436 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
437 	o->info.objectUsage = TEE_USAGE_DEFAULT;
438 	o->flags = flags;
439 	o->pobj = po;
440 
441 	res = tee_svc_storage_read_head(sess, o);
442 	if (res != TEE_SUCCESS) {
443 		free(o);
444 		goto exit;
445 	}
446 
447 	file = tee_svc_storage_create_filename(sess, object_id, object_id_len);
448 	if (file == NULL) {
449 		res = TEE_ERROR_OUT_OF_MEMORY;
450 		goto exit;
451 	}
452 
453 	fd = tee_fs_open(file, fs_flags);
454 	free(file);
455 	if (fd < 0) {
456 		res = TEE_ERROR_ITEM_NOT_FOUND;
457 		goto exit;
458 	}
459 	o->fd = fd;
460 
461 	tee_obj_add(sess->ctx, o);
462 
463 	res = tee_svc_copy_to_user(sess, obj, &o, sizeof(o));
464 	if (res != TEE_SUCCESS)
465 		tee_obj_close(sess->ctx, o);
466 
467 	e_off = sizeof(struct tee_svc_storage_head) + o->data_size;
468 	off = tee_fs_lseek(fd, e_off, TEE_FS_SEEK_SET);
469 	if (off != e_off) {
470 		res = TEE_ERROR_NO_DATA;
471 		goto exit;
472 	}
473 
474 exit:
475 	if (res != TEE_SUCCESS) {
476 		if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT) {
477 			/* the file is corrupt, delete */
478 			tee_svc_storage_remove(sess, storage_id, object_id,
479 					       object_id_len);
480 
481 			/* "greaceful" return */
482 			res = TEE_ERROR_ITEM_NOT_FOUND;
483 		}
484 
485 		if (fd >= 0)
486 			tee_fs_close(fd);
487 		if (po)
488 			tee_pobj_release(po);
489 	}
490 
491 	return res;
492 }
493 
494 TEE_Result tee_svc_storage_obj_create(uint32_t storage_id, void *object_id,
495 				      uint32_t object_id_len, uint32_t flags,
496 				      uint32_t attr, void *data, uint32_t len,
497 				      uint32_t *obj)
498 {
499 	TEE_Result res;
500 	struct tee_ta_session *sess;
501 	struct tee_obj *o = NULL;
502 	struct tee_obj *attr_o = NULL;
503 	char *file = NULL;
504 	int fd = -1;
505 	int fs_flags;
506 	tee_fs_off_t off;
507 	tee_fs_off_t e_off;
508 	struct tee_pobj *po = NULL;
509 
510 	if (storage_id != TEE_STORAGE_PRIVATE)
511 		return TEE_ERROR_ITEM_NOT_FOUND;
512 
513 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
514 		return TEE_ERROR_BAD_PARAMETERS;
515 
516 	res = tee_ta_get_current_session(&sess);
517 	if (res != TEE_SUCCESS)
518 		return res;
519 
520 	res =
521 	    tee_mmu_check_access_rights(sess->ctx,
522 					TEE_MEMORY_ACCESS_READ |
523 					TEE_MEMORY_ACCESS_ANY_OWNER,
524 					(tee_uaddr_t) object_id, object_id_len);
525 	if (res != TEE_SUCCESS)
526 		goto exit;
527 
528 	res = tee_pobj_get((void *)&sess->ctx->head->uuid, object_id,
529 			   object_id_len, flags, &po);
530 	if (res != TEE_SUCCESS)
531 		goto exit;
532 
533 	/* Init attributes if attibutes are provided */
534 	if (attr != TEE_HANDLE_NULL) {
535 		res = tee_obj_get(sess->ctx, attr, &attr_o);
536 		if (res != TEE_SUCCESS)
537 			goto exit;
538 	}
539 
540 	/* check rights of the provided buffer */
541 	if (data && len) {
542 		res =
543 		    tee_mmu_check_access_rights(sess->ctx,
544 						TEE_MEMORY_ACCESS_READ |
545 						TEE_MEMORY_ACCESS_ANY_OWNER,
546 						(tee_uaddr_t) data, len);
547 
548 		if (res != TEE_SUCCESS)
549 			goto exit;
550 	}
551 
552 	o = calloc(1, sizeof(*o));
553 	if (o == NULL) {
554 		res = TEE_ERROR_OUT_OF_MEMORY;
555 		goto exit;
556 	}
557 
558 	o->info.handleFlags =
559 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
560 	o->flags = flags;
561 	o->pobj = po;
562 
563 	res = tee_svc_storage_init_file(sess, o, attr_o, data, len, flags);
564 	if (res != TEE_SUCCESS) {
565 		free(o);
566 		goto exit;
567 	}
568 
569 	fs_flags = tee_svc_storage_conv_oflags(flags);
570 
571 	file = tee_svc_storage_create_filename(sess, object_id, object_id_len);
572 	if (file == NULL) {
573 		res = TEE_ERROR_OUT_OF_MEMORY;
574 		goto exit;
575 	}
576 
577 	fd = tee_fs_open(file, fs_flags);
578 	free(file);
579 	file = NULL;
580 	if (fd < 0) {
581 		res = TEE_ERROR_ITEM_NOT_FOUND;
582 		goto exit;
583 	}
584 	o->fd = fd;
585 
586 	tee_obj_add(sess->ctx, o);
587 
588 	res = tee_svc_copy_to_user(sess, obj, &o, sizeof(o));
589 	if (res != TEE_SUCCESS)
590 		tee_obj_close(sess->ctx, o);
591 
592 	e_off = sizeof(struct tee_svc_storage_head) + o->data_size;
593 	off = tee_fs_lseek(fd, e_off, TEE_FS_SEEK_SET);
594 	if (off != e_off) {
595 		res = TEE_ERROR_NO_DATA;
596 		goto exit;
597 	}
598 
599 exit:
600 	if (res != TEE_SUCCESS) {
601 		if (fd >= 0)
602 			tee_fs_close(fd);
603 		if (po)
604 			tee_pobj_release(po);
605 	}
606 
607 	return res;
608 }
609 
610 TEE_Result tee_svc_storage_obj_del(uint32_t obj)
611 {
612 	TEE_Result res;
613 	struct tee_ta_session *sess;
614 	struct tee_obj *o;
615 	int err;
616 	char *file;
617 	char *dir;
618 
619 	res = tee_ta_get_current_session(&sess);
620 	if (res != TEE_SUCCESS)
621 		return res;
622 
623 	res = tee_obj_get(sess->ctx, obj, &o);
624 	if (res != TEE_SUCCESS)
625 		return res;
626 
627 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META))
628 		return TEE_ERROR_ACCESS_CONFLICT;
629 
630 	if (o->pobj == NULL || o->pobj->obj_id == NULL)
631 		return TEE_ERROR_BAD_STATE;
632 
633 	file =
634 	    tee_svc_storage_create_filename(sess, o->pobj->obj_id,
635 					    o->pobj->obj_id_len);
636 	if (file == NULL)
637 		return TEE_ERROR_OUT_OF_MEMORY;
638 
639 	tee_obj_close(sess->ctx, o);
640 
641 	err = tee_fs_unlink(file);
642 	free(file);
643 	if (err != 0)
644 		/* error codes needs better granularity */
645 		return TEE_ERROR_GENERIC;
646 
647 	/* try and remove dir */
648 	dir = tee_svc_storage_create_dirname(sess);
649 	if (dir == NULL)
650 		return TEE_ERROR_OUT_OF_MEMORY;
651 	/* ignore result */
652 	tee_fs_rmdir(dir);
653 	free(dir);
654 
655 	return TEE_SUCCESS;
656 }
657 
658 TEE_Result tee_svc_storage_obj_rename(uint32_t obj, void *object_id,
659 				      uint32_t object_id_len)
660 {
661 	TEE_Result res;
662 	struct tee_ta_session *sess;
663 	struct tee_obj *o;
664 	struct tee_pobj *po = NULL;
665 	char *new_file = NULL;
666 	char *old_file = NULL;
667 	int err = -1;
668 
669 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
670 		return TEE_ERROR_BAD_PARAMETERS;
671 
672 	res = tee_ta_get_current_session(&sess);
673 	if (res != TEE_SUCCESS)
674 		return res;
675 
676 	res = tee_obj_get(sess->ctx, obj, &o);
677 	if (res != TEE_SUCCESS)
678 		return res;
679 
680 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META)) {
681 		res = TEE_ERROR_BAD_STATE;
682 		goto exit;
683 	}
684 
685 	if (o->pobj == NULL || o->pobj->obj_id == NULL)
686 		return TEE_ERROR_BAD_STATE;
687 
688 	res =
689 	    tee_mmu_check_access_rights(sess->ctx,
690 					TEE_MEMORY_ACCESS_READ |
691 					TEE_MEMORY_ACCESS_ANY_OWNER,
692 					(tee_uaddr_t) object_id, object_id_len);
693 	if (res != TEE_SUCCESS)
694 		goto exit;
695 
696 	/* get new ds name */
697 	new_file =
698 	    tee_svc_storage_create_filename(sess, object_id, object_id_len);
699 	if (new_file == NULL) {
700 		res = TEE_ERROR_OUT_OF_MEMORY;
701 		goto exit;
702 	}
703 
704 	old_file =
705 	    tee_svc_storage_create_filename(sess, o->pobj->obj_id,
706 					    o->pobj->obj_id_len);
707 	if (old_file == NULL) {
708 		res = TEE_ERROR_OUT_OF_MEMORY;
709 		goto exit;
710 	}
711 
712 	/* reserve dest name */
713 	res = tee_pobj_get((void *)&sess->ctx->head->uuid, object_id,
714 			   object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META, &po);
715 	if (res != TEE_SUCCESS)
716 		goto exit;
717 
718 	err = tee_fs_access(new_file, TEE_FS_F_OK);
719 	if (err == 0) {
720 		/* file exists */
721 		res = TEE_ERROR_ACCESS_CONFLICT;
722 		goto exit;
723 	}
724 
725 	/* move */
726 	err = tee_fs_rename(old_file, new_file);
727 	if (err) {
728 		/* error codes needs better granularity */
729 		res = TEE_ERROR_GENERIC;
730 		goto exit;
731 	}
732 
733 	res = tee_pobj_rename(o->pobj, object_id, object_id_len);
734 
735 exit:
736 	tee_pobj_release(po);
737 
738 	free(new_file);
739 	free(old_file);
740 
741 	return res;
742 }
743 
744 TEE_Result tee_svc_storage_alloc_enum(uint32_t *obj_enum)
745 {
746 	struct tee_storage_enum *e;
747 	struct tee_ta_session *sess;
748 	TEE_Result res;
749 
750 	if (obj_enum == NULL)
751 		return TEE_ERROR_BAD_PARAMETERS;
752 
753 	res = tee_ta_get_current_session(&sess);
754 	if (res != TEE_SUCCESS)
755 		return res;
756 
757 	e = malloc(sizeof(struct tee_storage_enum));
758 
759 	if (e == NULL)
760 		return TEE_ERROR_OUT_OF_MEMORY;
761 
762 	e->dir = NULL;
763 	TAILQ_INSERT_TAIL(&sess->ctx->storage_enums, e, link);
764 
765 	return tee_svc_copy_to_user(sess, obj_enum, &e,
766 				    sizeof(TEE_ObjectEnumHandle *));
767 }
768 
769 TEE_Result tee_svc_storage_free_enum(uint32_t obj_enum)
770 {
771 	struct tee_storage_enum *e;
772 	TEE_Result res;
773 	struct tee_ta_session *sess;
774 
775 	if (obj_enum == TEE_HANDLE_NULL)
776 		return TEE_SUCCESS;
777 
778 	res = tee_ta_get_current_session(&sess);
779 	if (res != TEE_SUCCESS)
780 		return res;
781 
782 	res = tee_svc_storage_get_enum(sess->ctx, obj_enum, &e);
783 	if (res != TEE_SUCCESS)
784 		return res;
785 
786 	return tee_svc_close_enum(sess->ctx, e);
787 }
788 
789 TEE_Result tee_svc_storage_reset_enum(uint32_t obj_enum)
790 {
791 	struct tee_storage_enum *e;
792 	int res;
793 	struct tee_ta_session *sess;
794 
795 	res = tee_ta_get_current_session(&sess);
796 	if (res != TEE_SUCCESS)
797 		return res;
798 
799 	if (obj_enum == TEE_HANDLE_NULL)
800 		return TEE_SUCCESS;
801 
802 	res = tee_svc_storage_get_enum(sess->ctx, obj_enum, &e);
803 	if (res != TEE_SUCCESS)
804 		return res;
805 
806 	res = tee_fs_closedir(e->dir);
807 	e->dir = NULL;
808 	if (res != 0)
809 		return TEE_ERROR_GENERIC;
810 
811 	return TEE_SUCCESS;
812 }
813 
814 TEE_Result tee_svc_storage_start_enum(uint32_t obj_enum, uint32_t storage_id)
815 {
816 	struct tee_storage_enum *e;
817 	char *dir;
818 	TEE_Result res;
819 	struct tee_ta_session *sess;
820 
821 	if (obj_enum == TEE_HANDLE_NULL)
822 		return TEE_ERROR_BAD_PARAMETERS;
823 
824 	res = tee_ta_get_current_session(&sess);
825 	if (res != TEE_SUCCESS)
826 		return res;
827 
828 	res = tee_svc_storage_get_enum(sess->ctx, obj_enum, &e);
829 	if (res != TEE_SUCCESS)
830 		return res;
831 
832 	if (storage_id != TEE_STORAGE_PRIVATE)
833 		return TEE_ERROR_ITEM_NOT_FOUND;
834 
835 	dir = tee_svc_storage_create_dirname(sess);
836 	if (dir == NULL)
837 		return TEE_ERROR_OUT_OF_MEMORY;
838 
839 	e->dir = tee_fs_opendir(dir);
840 	free(dir);
841 
842 	if (e->dir == NULL)
843 		/* error codes needs better granularity */
844 		return TEE_ERROR_ITEM_NOT_FOUND;
845 
846 	return TEE_SUCCESS;
847 }
848 
849 TEE_Result tee_svc_storage_next_enum(uint32_t obj_enum, TEE_ObjectInfo *info,
850 				     void *obj_id, size_t *len)
851 {
852 	struct tee_storage_enum *e;
853 	struct tee_fs_dirent *d;
854 	TEE_Result res = TEE_SUCCESS;
855 	struct tee_ta_session *sess;
856 	struct tee_obj *o = NULL;
857 	uint32_t blen;
858 	uint32_t hslen;
859 
860 	res = tee_ta_get_current_session(&sess);
861 	if (res != TEE_SUCCESS)
862 		return res;
863 
864 	if (obj_enum == TEE_HANDLE_NULL)
865 		return TEE_ERROR_BAD_PARAMETERS;
866 
867 	res = tee_svc_storage_get_enum(sess->ctx, obj_enum, &e);
868 	if (res != TEE_SUCCESS)
869 		return res;
870 
871 	/* check rights of the provided buffers */
872 	res =
873 	    tee_mmu_check_access_rights(sess->ctx,
874 					TEE_MEMORY_ACCESS_WRITE |
875 					TEE_MEMORY_ACCESS_ANY_OWNER,
876 					(tee_uaddr_t) info,
877 					sizeof(TEE_ObjectInfo));
878 	if (res != TEE_SUCCESS)
879 		return res;
880 
881 	res =
882 	    tee_mmu_check_access_rights(sess->ctx,
883 					TEE_MEMORY_ACCESS_WRITE |
884 					TEE_MEMORY_ACCESS_ANY_OWNER,
885 					(tee_uaddr_t) obj_id,
886 					TEE_OBJECT_ID_MAX_LEN);
887 	if (res != TEE_SUCCESS)
888 		return res;
889 
890 	d = tee_fs_readdir(e->dir);
891 	if (d == NULL)
892 		return TEE_ERROR_ITEM_NOT_FOUND;
893 
894 	o = calloc(1, sizeof(struct tee_obj));
895 	if (o == NULL) {
896 		res = TEE_ERROR_OUT_OF_MEMORY;
897 		goto exit;
898 	}
899 
900 	o->pobj = calloc(1, sizeof(struct tee_pobj));
901 	if (!o->pobj) {
902 		res = TEE_ERROR_OUT_OF_MEMORY;
903 		goto exit;
904 	}
905 
906 	o->info.handleFlags =
907 	    TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
908 	o->info.objectUsage = TEE_USAGE_DEFAULT;
909 
910 	/*
911 	 * NOTE: Special usage of pobj due to not ref cnt should be inc
912 	 */
913 	hslen = strlen(d->d_name);
914 	blen = TEE_HS2B_BBUF_SIZE(hslen);
915 	o->pobj->obj_id = malloc(blen);
916 	if (o->pobj->obj_id == NULL) {
917 		res = TEE_ERROR_OUT_OF_MEMORY;
918 		goto exit;
919 	}
920 	tee_hs2b((uint8_t *)d->d_name, o->pobj->obj_id, hslen, blen);
921 	o->pobj->obj_id_len = blen;
922 
923 	res = tee_svc_storage_read_head(sess, o);
924 	if (res != TEE_SUCCESS) {
925 		/* TODO: handle corrupt files in a greaceful way */
926 		goto exit;
927 	}
928 	memcpy(info, &o->info, sizeof(TEE_ObjectInfo));
929 	memcpy(obj_id, o->pobj->obj_id, o->pobj->obj_id_len);
930 
931 	res =
932 	    tee_svc_copy_to_user(sess, len, &o->pobj->obj_id_len,
933 				 sizeof(uint32_t));
934 
935 exit:
936 	if (o) {
937 		if (o->pobj)
938 			free(o->pobj->obj_id);
939 		free(o->pobj);
940 		free(o->data);
941 	}
942 	free(o);
943 
944 	return res;
945 }
946 
947 TEE_Result tee_svc_storage_obj_read(uint32_t obj, void *data, size_t len,
948 				    uint32_t *count)
949 {
950 	TEE_Result res;
951 	struct tee_ta_session *sess;
952 	struct tee_obj *o;
953 	int n_count;
954 	uint32_t u_count;
955 
956 	res = tee_ta_get_current_session(&sess);
957 	if (res != TEE_SUCCESS)
958 		return res;
959 
960 	res = tee_obj_get(sess->ctx, obj, &o);
961 	if (res != TEE_SUCCESS)
962 		return res;
963 
964 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_READ))
965 		return TEE_ERROR_ACCESS_CONFLICT;
966 
967 	/* check rights of the provided buffer */
968 	res =
969 	    tee_mmu_check_access_rights(sess->ctx,
970 					TEE_MEMORY_ACCESS_WRITE |
971 					TEE_MEMORY_ACCESS_ANY_OWNER,
972 					(tee_uaddr_t) data, len);
973 	if (res != TEE_SUCCESS)
974 		return res;
975 
976 	n_count = tee_fs_read(o->fd, data, len);
977 	u_count = (uint32_t) ((n_count < 0) ? 0 : n_count);
978 
979 	res = tee_svc_copy_to_user(sess, count, &u_count, sizeof(uint32_t));
980 
981 	o->info.dataPosition += u_count;
982 
983 	return TEE_SUCCESS;
984 }
985 
986 TEE_Result tee_svc_storage_obj_write(uint32_t obj, void *data, size_t len)
987 {
988 	TEE_Result res;
989 	struct tee_ta_session *sess;
990 	struct tee_obj *o;
991 	int err;
992 
993 	res = tee_ta_get_current_session(&sess);
994 	if (res != TEE_SUCCESS)
995 		return res;
996 
997 	res = tee_obj_get(sess->ctx, obj, &o);
998 	if (res != TEE_SUCCESS)
999 		return res;
1000 
1001 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE))
1002 		return TEE_ERROR_ACCESS_CONFLICT;
1003 
1004 	/* check rights of the provided buffer */
1005 	res =
1006 	    tee_mmu_check_access_rights(sess->ctx,
1007 					TEE_MEMORY_ACCESS_READ |
1008 					TEE_MEMORY_ACCESS_ANY_OWNER,
1009 					(tee_uaddr_t) data, len);
1010 
1011 	err = tee_fs_write(o->fd, data, len);
1012 
1013 	if (err != (int)len) {
1014 		/* error codes needs better granularity */
1015 		res = TEE_ERROR_GENERIC;
1016 		return res;
1017 	}
1018 
1019 	o->info.dataPosition += len;
1020 	if (o->info.dataPosition > o->info.dataSize)
1021 		o->info.dataSize = o->info.dataPosition;
1022 
1023 	return TEE_SUCCESS;
1024 }
1025 
1026 TEE_Result tee_svc_storage_obj_trunc(uint32_t obj, size_t len)
1027 {
1028 	TEE_Result res;
1029 	struct tee_ta_session *sess;
1030 	struct tee_obj *o;
1031 	int err;
1032 	tee_fs_off_t off;
1033 
1034 	res = tee_ta_get_current_session(&sess);
1035 	if (res != TEE_SUCCESS)
1036 		return res;
1037 
1038 	res = tee_obj_get(sess->ctx, obj, &o);
1039 	if (res != TEE_SUCCESS)
1040 		return res;
1041 
1042 	if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE))
1043 		return TEE_ERROR_ACCESS_CONFLICT;
1044 
1045 	off = sizeof(struct tee_svc_storage_head) + o->data_size;
1046 	err = tee_fs_ftruncate(o->fd, len + off);
1047 
1048 	if (err != 0)
1049 		/* error codes needs better granularity */
1050 		return TEE_ERROR_GENERIC;
1051 
1052 	return TEE_SUCCESS;
1053 }
1054 
1055 TEE_Result tee_svc_storage_obj_seek(uint32_t obj, int32_t offset,
1056 				    TEE_Whence whence)
1057 {
1058 	TEE_Result res;
1059 	struct tee_ta_session *sess;
1060 	struct tee_obj *o;
1061 	int fw;
1062 	tee_fs_off_t off;
1063 	tee_fs_off_t e_off = 0;
1064 
1065 	res = tee_ta_get_current_session(&sess);
1066 	if (res != TEE_SUCCESS)
1067 		return res;
1068 
1069 	res = tee_obj_get(sess->ctx, obj, &o);
1070 	if (res != TEE_SUCCESS)
1071 		return res;
1072 
1073 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT))
1074 		return TEE_ERROR_BAD_STATE;
1075 
1076 	fw = tee_svc_storage_conv_whence(whence);
1077 
1078 	if (whence == TEE_DATA_SEEK_SET)
1079 		e_off = sizeof(struct tee_svc_storage_head) + o->data_size;
1080 
1081 	off = tee_fs_lseek(o->fd, e_off + offset, fw);
1082 	if (off > -1 && off >= e_off)
1083 		o->info.dataPosition =
1084 		    off - sizeof(struct tee_svc_storage_head) + o->data_size;
1085 	else
1086 		return TEE_ERROR_GENERIC;
1087 
1088 	return TEE_SUCCESS;
1089 }
1090 
1091 void tee_svc_storage_close_all_enum(struct tee_ta_ctx *ctx)
1092 {
1093 	struct tee_storage_enum_head *eh = &ctx->storage_enums;
1094 
1095 	/* disregard return value */
1096 	while (!TAILQ_EMPTY(eh))
1097 		tee_svc_close_enum(ctx, TAILQ_FIRST(eh));
1098 }
1099