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