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