xref: /optee_os/core/tee/tee_svc_storage.c (revision e231582fca25178ed521995577f537580ed47a41)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2014, STMicroelectronics International N.V.
4  * Copyright (c) 2020, Linaro Limited
5  */
6 
7 #include <config.h>
8 #include <crypto/crypto.h>
9 #include <kernel/mutex.h>
10 #include <kernel/tee_misc.h>
11 #include <kernel/tee_ta_manager.h>
12 #include <kernel/ts_manager.h>
13 #include <kernel/user_access.h>
14 #include <mm/vm.h>
15 #include <string.h>
16 #include <tee_api_defines_extensions.h>
17 #include <tee_api_defines.h>
18 #include <tee/tee_fs.h>
19 #include <tee/tee_obj.h>
20 #include <tee/tee_pobj.h>
21 #include <tee/tee_svc_cryp.h>
22 #include <tee/tee_svc.h>
23 #include <tee/tee_svc_storage.h>
24 #include <trace.h>
25 
26 /* Header of GP formated secure storage files */
27 struct tee_svc_storage_head {
28 	uint32_t attr_size;
29 	uint32_t keySize;
30 	uint32_t maxKeySize;
31 	uint32_t objectUsage;
32 	uint32_t objectType;
33 	uint32_t have_attrs;
34 };
35 
36 struct tee_storage_enum {
37 	TAILQ_ENTRY(tee_storage_enum) link;
38 	struct tee_fs_dir *dir;
39 	const struct tee_file_operations *fops;
40 };
41 
42 static TEE_Result tee_svc_storage_get_enum(struct user_ta_ctx *utc,
43 					   vaddr_t enum_id,
44 					   struct tee_storage_enum **e_out)
45 {
46 	struct tee_storage_enum *e;
47 
48 	TAILQ_FOREACH(e, &utc->storage_enums, link) {
49 		if (enum_id == (vaddr_t)e) {
50 			*e_out = e;
51 			return TEE_SUCCESS;
52 		}
53 	}
54 	return TEE_ERROR_BAD_PARAMETERS;
55 }
56 
57 static TEE_Result tee_svc_close_enum(struct user_ta_ctx *utc,
58 				     struct tee_storage_enum *e)
59 {
60 	if (e == NULL || utc == NULL)
61 		return TEE_ERROR_BAD_PARAMETERS;
62 
63 	TAILQ_REMOVE(&utc->storage_enums, e, link);
64 
65 	if (e->fops)
66 		e->fops->closedir(e->dir);
67 
68 	e->dir = NULL;
69 	e->fops = NULL;
70 
71 	free(e);
72 
73 	return TEE_SUCCESS;
74 }
75 
76 static TEE_Result tee_svc_storage_remove_corrupt_obj(struct ts_session *sess,
77 						     struct tee_obj *o)
78 {
79 	o->pobj->fops->remove(o->pobj);
80 	tee_obj_close(to_user_ta_ctx(sess->ctx), o);
81 
82 	return TEE_SUCCESS;
83 }
84 
85 static TEE_Result tee_svc_storage_read_head(struct tee_obj *o)
86 {
87 	TEE_Result res = TEE_SUCCESS;
88 	size_t bytes;
89 	struct tee_svc_storage_head head;
90 	const struct tee_file_operations *fops = o->pobj->fops;
91 	void *attr = NULL;
92 	size_t size;
93 	size_t tmp = 0;
94 
95 	assert(!o->fh);
96 	res = fops->open(o->pobj, &size, &o->fh);
97 	if (res != TEE_SUCCESS)
98 		goto exit;
99 
100 	/* read head */
101 	bytes = sizeof(struct tee_svc_storage_head);
102 	res = fops->read(o->fh, 0, &head, &bytes);
103 	if (res != TEE_SUCCESS) {
104 		if (res == TEE_ERROR_CORRUPT_OBJECT)
105 			EMSG("Head corrupt");
106 		goto exit;
107 	}
108 
109 	if (ADD_OVERFLOW(sizeof(head), head.attr_size, &tmp)) {
110 		res = TEE_ERROR_OVERFLOW;
111 		goto exit;
112 	}
113 	if (tmp > size) {
114 		res = TEE_ERROR_CORRUPT_OBJECT;
115 		goto exit;
116 	}
117 
118 	if (bytes != sizeof(struct tee_svc_storage_head)) {
119 		res = TEE_ERROR_BAD_FORMAT;
120 		goto exit;
121 	}
122 
123 	res = tee_obj_set_type(o, head.objectType, head.maxKeySize);
124 	if (res != TEE_SUCCESS)
125 		goto exit;
126 
127 	o->ds_pos = tmp;
128 
129 	if (head.attr_size) {
130 		attr = malloc(head.attr_size);
131 		if (!attr) {
132 			res = TEE_ERROR_OUT_OF_MEMORY;
133 			goto exit;
134 		}
135 
136 		/* read meta */
137 		bytes = head.attr_size;
138 		res = fops->read(o->fh, sizeof(struct tee_svc_storage_head),
139 				 attr, &bytes);
140 		if (res == TEE_ERROR_OUT_OF_MEMORY)
141 			goto exit;
142 		if (res != TEE_SUCCESS || bytes != head.attr_size)
143 			res = TEE_ERROR_CORRUPT_OBJECT;
144 		if (res)
145 			goto exit;
146 	}
147 
148 	res = tee_obj_attr_from_binary(o, attr, head.attr_size);
149 	if (res != TEE_SUCCESS)
150 		goto exit;
151 
152 	o->info.dataSize = size - sizeof(head) - head.attr_size;
153 	o->info.keySize = head.keySize;
154 	o->info.objectUsage = head.objectUsage;
155 	o->info.objectType = head.objectType;
156 	o->have_attrs = head.have_attrs;
157 
158 exit:
159 	free(attr);
160 
161 	return res;
162 }
163 
164 TEE_Result syscall_storage_obj_open(unsigned long storage_id, void *object_id,
165 				    size_t object_id_len, unsigned long flags,
166 				    uint32_t *obj)
167 {
168 	const unsigned long valid_flags = TEE_DATA_FLAG_ACCESS_READ |
169 					  TEE_DATA_FLAG_ACCESS_WRITE |
170 					  TEE_DATA_FLAG_ACCESS_WRITE_META |
171 					  TEE_DATA_FLAG_SHARE_READ |
172 					  TEE_DATA_FLAG_SHARE_WRITE;
173 	const struct tee_file_operations *fops =
174 			tee_svc_storage_file_ops(storage_id);
175 	struct ts_session *sess = ts_get_current_session();
176 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
177 	TEE_Result res = TEE_SUCCESS;
178 	struct tee_pobj *po = NULL;
179 	struct tee_obj *o = NULL;
180 	char *file = NULL;
181 
182 	if (flags & ~valid_flags)
183 		return TEE_ERROR_BAD_PARAMETERS;
184 
185 	if (!fops) {
186 		res = TEE_ERROR_ITEM_NOT_FOUND;
187 		goto exit;
188 	}
189 
190 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN) {
191 		res = TEE_ERROR_BAD_PARAMETERS;
192 		goto exit;
193 	}
194 
195 	if (object_id_len) {
196 		res = vm_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_READ,
197 					     (uaddr_t)object_id, object_id_len);
198 		if (res != TEE_SUCCESS)
199 			goto err;
200 	}
201 
202 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
203 			   object_id_len, flags, TEE_POBJ_USAGE_OPEN, fops,
204 			   &po);
205 	if (res != TEE_SUCCESS)
206 		goto err;
207 
208 	o = tee_obj_alloc();
209 	if (o == NULL) {
210 		tee_pobj_release(po);
211 		res = TEE_ERROR_OUT_OF_MEMORY;
212 		goto err;
213 	}
214 
215 	o->info.handleFlags = TEE_HANDLE_FLAG_PERSISTENT |
216 			      TEE_HANDLE_FLAG_INITIALIZED | flags;
217 	o->pobj = po;
218 	tee_obj_add(utc, o);
219 
220 	res = tee_svc_storage_read_head(o);
221 	if (res != TEE_SUCCESS) {
222 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
223 			EMSG("Object corrupt");
224 			goto err;
225 		}
226 		goto oclose;
227 	}
228 
229 	res = copy_kaddr_to_uref(obj, o);
230 	if (res != TEE_SUCCESS)
231 		goto oclose;
232 
233 	goto exit;
234 
235 oclose:
236 	tee_obj_close(utc, o);
237 	o = NULL;
238 
239 err:
240 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
241 		res = TEE_ERROR_CORRUPT_OBJECT;
242 	if (res == TEE_ERROR_CORRUPT_OBJECT && o)
243 		tee_svc_storage_remove_corrupt_obj(sess, o);
244 
245 exit:
246 	free(file);
247 	file = NULL;
248 	return res;
249 }
250 
251 static TEE_Result tee_svc_storage_init_file(struct tee_obj *o, bool overwrite,
252 					    struct tee_obj *attr_o, void *data,
253 					    uint32_t len)
254 {
255 	TEE_Result res = TEE_SUCCESS;
256 	struct tee_svc_storage_head head;
257 	const struct tee_file_operations *fops = o->pobj->fops;
258 	void *attr = NULL;
259 	size_t attr_size = 0;
260 
261 	if (attr_o) {
262 		res = tee_obj_set_type(o, attr_o->info.objectType,
263 				       attr_o->info.maxKeySize);
264 		if (res)
265 			return res;
266 		res = tee_obj_attr_copy_from(o, attr_o);
267 		if (res)
268 			return res;
269 		o->have_attrs = attr_o->have_attrs;
270 		o->info.objectUsage = attr_o->info.objectUsage;
271 		o->info.keySize = attr_o->info.keySize;
272 		res = tee_obj_attr_to_binary(o, NULL, &attr_size);
273 		if (res)
274 			return res;
275 		if (attr_size) {
276 			attr = malloc(attr_size);
277 			if (!attr)
278 				return TEE_ERROR_OUT_OF_MEMORY;
279 			res = tee_obj_attr_to_binary(o, attr, &attr_size);
280 			if (res != TEE_SUCCESS)
281 				goto exit;
282 		}
283 	} else {
284 		res = tee_obj_set_type(o, TEE_TYPE_DATA, 0);
285 		if (res != TEE_SUCCESS)
286 			goto exit;
287 	}
288 
289 	o->ds_pos = sizeof(struct tee_svc_storage_head) + attr_size;
290 
291 	/* write head */
292 	head.attr_size = attr_size;
293 	head.keySize = o->info.keySize;
294 	head.maxKeySize = o->info.maxKeySize;
295 	head.objectUsage = o->info.objectUsage;
296 	head.objectType = o->info.objectType;
297 	head.have_attrs = o->have_attrs;
298 
299 	res = fops->create(o->pobj, overwrite, &head, sizeof(head), attr,
300 			   attr_size, data, len, &o->fh);
301 
302 	if (!res)
303 		o->info.dataSize = len;
304 exit:
305 	free(attr);
306 	return res;
307 }
308 
309 TEE_Result syscall_storage_obj_create(unsigned long storage_id, void *object_id,
310 			size_t object_id_len, unsigned long flags,
311 			unsigned long attr, void *data, size_t len,
312 			uint32_t *obj)
313 {
314 	const unsigned long valid_flags = TEE_DATA_FLAG_ACCESS_READ |
315 					  TEE_DATA_FLAG_ACCESS_WRITE |
316 					  TEE_DATA_FLAG_ACCESS_WRITE_META |
317 					  TEE_DATA_FLAG_SHARE_READ |
318 					  TEE_DATA_FLAG_SHARE_WRITE |
319 					  TEE_DATA_FLAG_OVERWRITE;
320 	const struct tee_file_operations *fops =
321 			tee_svc_storage_file_ops(storage_id);
322 	struct ts_session *sess = ts_get_current_session();
323 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
324 	struct tee_obj *attr_o = NULL;
325 	TEE_Result res = TEE_SUCCESS;
326 	struct tee_pobj *po = NULL;
327 	struct tee_obj *o = NULL;
328 
329 	if (flags & ~valid_flags)
330 		return TEE_ERROR_BAD_PARAMETERS;
331 
332 	if (!fops)
333 		return TEE_ERROR_ITEM_NOT_FOUND;
334 
335 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
336 		return TEE_ERROR_BAD_PARAMETERS;
337 
338 	if (object_id_len) {
339 		res = vm_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_READ,
340 					     (uaddr_t)object_id, object_id_len);
341 		if (res != TEE_SUCCESS)
342 			goto err;
343 	}
344 
345 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
346 			   object_id_len, flags, TEE_POBJ_USAGE_CREATE,
347 			   fops, &po);
348 	if (res != TEE_SUCCESS)
349 		goto err;
350 
351 	/* check rights of the provided buffer */
352 	if (len) {
353 		if (data) {
354 			uint32_t f = TEE_MEMORY_ACCESS_READ |
355 				     TEE_MEMORY_ACCESS_ANY_OWNER;
356 
357 			res = vm_check_access_rights(&utc->uctx, f,
358 						     (uaddr_t)data, len);
359 
360 			if (res != TEE_SUCCESS)
361 				goto err;
362 		} else {
363 			res = TEE_ERROR_BAD_PARAMETERS;
364 			goto err;
365 		}
366 	}
367 
368 	o = tee_obj_alloc();
369 	if (o == NULL) {
370 		res = TEE_ERROR_OUT_OF_MEMORY;
371 		goto err;
372 	}
373 
374 	o->info.handleFlags = TEE_HANDLE_FLAG_PERSISTENT |
375 			      TEE_HANDLE_FLAG_INITIALIZED | flags;
376 	o->pobj = po;
377 
378 	if (attr != TEE_HANDLE_NULL) {
379 		res = tee_obj_get(utc, uref_to_vaddr(attr), &attr_o);
380 		if (res != TEE_SUCCESS)
381 			goto err;
382 		/* The supplied handle must be one of an initialized object */
383 		if (!(attr_o->info.handleFlags & TEE_HANDLE_FLAG_INITIALIZED)) {
384 			res = TEE_ERROR_BAD_PARAMETERS;
385 			goto err;
386 		}
387 	}
388 
389 	res = tee_svc_storage_init_file(o, flags & TEE_DATA_FLAG_OVERWRITE,
390 					attr_o, data, len);
391 	if (res != TEE_SUCCESS)
392 		goto err;
393 
394 	po = NULL; /* o owns it from now on */
395 	tee_obj_add(utc, o);
396 
397 	res = copy_kaddr_to_uref(obj, o);
398 	if (res != TEE_SUCCESS)
399 		goto oclose;
400 
401 	tee_pobj_create_final(o->pobj);
402 	return TEE_SUCCESS;
403 
404 oclose:
405 	tee_obj_close(utc, o);
406 	return res;
407 
408 err:
409 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
410 		res = TEE_ERROR_CORRUPT_OBJECT;
411 	if (res == TEE_ERROR_CORRUPT_OBJECT && po)
412 		fops->remove(po);
413 	if (o) {
414 		fops->close(&o->fh);
415 		tee_obj_free(o);
416 	}
417 	if (po)
418 		tee_pobj_release(po);
419 
420 	return res;
421 }
422 
423 TEE_Result syscall_storage_obj_del(unsigned long obj)
424 {
425 	struct ts_session *sess = ts_get_current_session();
426 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
427 	TEE_Result res = TEE_SUCCESS;
428 	struct tee_obj *o = NULL;
429 	uint8_t *data = NULL;
430 	size_t len = 0;
431 
432 	res = tee_obj_get(utc, uref_to_vaddr(obj), &o);
433 	if (res != TEE_SUCCESS)
434 		return res;
435 
436 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE_META))
437 		return TEE_ERROR_ACCESS_CONFLICT;
438 
439 	if (o->pobj == NULL || o->pobj->obj_id == NULL)
440 		return TEE_ERROR_BAD_STATE;
441 
442 	if (IS_ENABLED(CFG_NXP_SE05X)) {
443 		len = o->info.dataSize;
444 		data = calloc(1, len);
445 		if (!data)
446 			return TEE_ERROR_OUT_OF_MEMORY;
447 
448 		res = o->pobj->fops->read(o->fh, o->info.dataPosition,
449 					  data, &len);
450 		if (res == TEE_SUCCESS)
451 			crypto_storage_obj_del(data, len);
452 		free(data);
453 	}
454 
455 	res = o->pobj->fops->remove(o->pobj);
456 	tee_obj_close(utc, o);
457 
458 	return res;
459 }
460 
461 TEE_Result syscall_storage_obj_rename(unsigned long obj, void *object_id,
462 				      size_t object_id_len)
463 {
464 	const struct tee_file_operations *fops = NULL;
465 	struct ts_session *sess = ts_get_current_session();
466 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
467 	TEE_Result res = TEE_SUCCESS;
468 	struct tee_pobj *po = NULL;
469 	struct tee_obj *o = NULL;
470 	char *new_file = NULL;
471 	char *old_file = NULL;
472 
473 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
474 		return TEE_ERROR_BAD_PARAMETERS;
475 
476 	res = tee_obj_get(utc, uref_to_vaddr(obj), &o);
477 	if (res != TEE_SUCCESS)
478 		return res;
479 
480 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
481 		res = TEE_ERROR_BAD_STATE;
482 		goto exit;
483 	}
484 
485 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE_META)) {
486 		res = TEE_ERROR_BAD_STATE;
487 		goto exit;
488 	}
489 
490 	if (o->pobj == NULL || o->pobj->obj_id == NULL) {
491 		res = TEE_ERROR_BAD_STATE;
492 		goto exit;
493 	}
494 
495 	if (object_id_len) {
496 		res = vm_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_READ,
497 					     (uaddr_t)object_id, object_id_len);
498 		if (res != TEE_SUCCESS)
499 			goto exit;
500 	}
501 
502 	/* reserve dest name */
503 	fops = o->pobj->fops;
504 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
505 			   object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META,
506 			   TEE_POBJ_USAGE_RENAME, fops, &po);
507 	if (res != TEE_SUCCESS)
508 		goto exit;
509 
510 	/* move */
511 	res = fops->rename(o->pobj, po, false /* no overwrite */);
512 	if (res)
513 		goto exit;
514 
515 	res = tee_pobj_rename(o->pobj, object_id, object_id_len);
516 
517 exit:
518 	tee_pobj_release(po);
519 
520 	free(new_file);
521 	free(old_file);
522 
523 	return res;
524 }
525 
526 TEE_Result syscall_storage_alloc_enum(uint32_t *obj_enum)
527 {
528 	struct ts_session *sess = ts_get_current_session();
529 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
530 	struct tee_storage_enum *e = NULL;
531 
532 	if (obj_enum == NULL)
533 		return TEE_ERROR_BAD_PARAMETERS;
534 
535 	e = malloc(sizeof(struct tee_storage_enum));
536 	if (e == NULL)
537 		return TEE_ERROR_OUT_OF_MEMORY;
538 
539 	e->dir = NULL;
540 	e->fops = NULL;
541 	TAILQ_INSERT_TAIL(&utc->storage_enums, e, link);
542 
543 	return copy_kaddr_to_uref(obj_enum, e);
544 }
545 
546 TEE_Result syscall_storage_free_enum(unsigned long obj_enum)
547 {
548 	struct ts_session *sess = ts_get_current_session();
549 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
550 	struct tee_storage_enum *e = NULL;
551 	TEE_Result res = TEE_SUCCESS;
552 
553 	res = tee_svc_storage_get_enum(utc,
554 			uref_to_vaddr(obj_enum), &e);
555 	if (res != TEE_SUCCESS)
556 		return res;
557 
558 	return tee_svc_close_enum(utc, e);
559 }
560 
561 TEE_Result syscall_storage_reset_enum(unsigned long obj_enum)
562 {
563 	struct ts_session *sess = ts_get_current_session();
564 	struct tee_storage_enum *e = NULL;
565 	TEE_Result res = TEE_SUCCESS;
566 
567 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
568 				       uref_to_vaddr(obj_enum), &e);
569 	if (res != TEE_SUCCESS)
570 		return res;
571 
572 	if (e->fops) {
573 		e->fops->closedir(e->dir);
574 		e->fops = NULL;
575 		e->dir = NULL;
576 	}
577 	assert(!e->dir);
578 
579 	return TEE_SUCCESS;
580 }
581 
582 TEE_Result syscall_storage_start_enum(unsigned long obj_enum,
583 				      unsigned long storage_id)
584 {
585 	struct ts_session *sess = ts_get_current_session();
586 	struct tee_storage_enum *e = NULL;
587 	TEE_Result res = TEE_SUCCESS;
588 	const struct tee_file_operations *fops =
589 			tee_svc_storage_file_ops(storage_id);
590 
591 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
592 				       uref_to_vaddr(obj_enum), &e);
593 	if (res != TEE_SUCCESS)
594 		return res;
595 
596 	if (e->dir) {
597 		e->fops->closedir(e->dir);
598 		e->dir = NULL;
599 	}
600 
601 	if (!fops)
602 		return TEE_ERROR_ITEM_NOT_FOUND;
603 
604 	e->fops = fops;
605 
606 	return fops->opendir(&sess->ctx->uuid, &e->dir);
607 }
608 
609 TEE_Result syscall_storage_next_enum(unsigned long obj_enum,
610 			TEE_ObjectInfo *info, void *obj_id, uint64_t *len)
611 {
612 	struct ts_session *sess = ts_get_current_session();
613 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
614 	struct tee_storage_enum *e = NULL;
615 	struct tee_fs_dirent *d = NULL;
616 	TEE_Result res = TEE_SUCCESS;
617 	struct tee_obj *o = NULL;
618 	uint64_t l = 0;
619 
620 	res = tee_svc_storage_get_enum(utc, uref_to_vaddr(obj_enum), &e);
621 	if (res != TEE_SUCCESS)
622 		goto exit;
623 
624 	/* check rights of the provided buffers */
625 	res = vm_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_WRITE,
626 				     (uaddr_t)info, sizeof(TEE_ObjectInfo));
627 	if (res != TEE_SUCCESS)
628 		goto exit;
629 
630 	res = vm_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_WRITE,
631 				     (uaddr_t)obj_id, TEE_OBJECT_ID_MAX_LEN);
632 	if (res != TEE_SUCCESS)
633 		goto exit;
634 
635 	if (!e->fops) {
636 		res = TEE_ERROR_ITEM_NOT_FOUND;
637 		goto exit;
638 	}
639 
640 	res = e->fops->readdir(e->dir, &d);
641 	if (res != TEE_SUCCESS)
642 		goto exit;
643 
644 	o = tee_obj_alloc();
645 	if (o == NULL) {
646 		res = TEE_ERROR_OUT_OF_MEMORY;
647 		goto exit;
648 	}
649 
650 	res = tee_pobj_get(&sess->ctx->uuid, d->oid, d->oidlen, 0,
651 			   TEE_POBJ_USAGE_ENUM, e->fops, &o->pobj);
652 	if (res)
653 		goto exit;
654 
655 	o->info.handleFlags = o->pobj->flags | TEE_HANDLE_FLAG_PERSISTENT |
656 			      TEE_HANDLE_FLAG_INITIALIZED;
657 
658 	res = tee_svc_storage_read_head(o);
659 	if (res != TEE_SUCCESS)
660 		goto exit;
661 
662 	memcpy(info, &o->info, sizeof(TEE_ObjectInfo));
663 	memcpy(obj_id, o->pobj->obj_id, o->pobj->obj_id_len);
664 
665 	l = o->pobj->obj_id_len;
666 	res = copy_to_user_private(len, &l, sizeof(*len));
667 
668 exit:
669 	if (o) {
670 		if (o->pobj) {
671 			o->pobj->fops->close(&o->fh);
672 			tee_pobj_release(o->pobj);
673 		}
674 		tee_obj_free(o);
675 	}
676 
677 	return res;
678 }
679 
680 TEE_Result syscall_storage_obj_read(unsigned long obj, void *data, size_t len,
681 				    uint64_t *count)
682 {
683 	struct ts_session *sess = ts_get_current_session();
684 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
685 	TEE_Result res = TEE_SUCCESS;
686 	struct tee_obj *o = NULL;
687 	uint64_t u_count = 0;
688 	size_t pos_tmp = 0;
689 	size_t bytes = 0;
690 
691 	res = tee_obj_get(utc, uref_to_vaddr(obj), &o);
692 	if (res != TEE_SUCCESS)
693 		goto exit;
694 
695 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
696 		res = TEE_ERROR_BAD_STATE;
697 		goto exit;
698 	}
699 
700 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_READ)) {
701 		res = TEE_ERROR_ACCESS_CONFLICT;
702 		goto exit;
703 	}
704 
705 	/* Guard o->info.dataPosition += bytes below from overflowing */
706 	if (ADD_OVERFLOW(o->info.dataPosition, len, &pos_tmp)) {
707 		res = TEE_ERROR_OVERFLOW;
708 		goto exit;
709 	}
710 
711 	/* check rights of the provided buffer */
712 	res = vm_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_WRITE,
713 				     (uaddr_t)data, len);
714 	if (res != TEE_SUCCESS)
715 		goto exit;
716 
717 	bytes = len;
718 	if (ADD_OVERFLOW(o->ds_pos, o->info.dataPosition, &pos_tmp)) {
719 		res = TEE_ERROR_OVERFLOW;
720 		goto exit;
721 	}
722 	res = o->pobj->fops->read(o->fh, pos_tmp, data, &bytes);
723 	if (res != TEE_SUCCESS) {
724 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
725 			EMSG("Object corrupt");
726 			tee_svc_storage_remove_corrupt_obj(sess, o);
727 		}
728 		goto exit;
729 	}
730 
731 	o->info.dataPosition += bytes;
732 
733 	u_count = bytes;
734 	res = copy_to_user_private(count, &u_count, sizeof(*count));
735 exit:
736 	return res;
737 }
738 
739 TEE_Result syscall_storage_obj_write(unsigned long obj, void *data, size_t len)
740 {
741 	struct ts_session *sess = ts_get_current_session();
742 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
743 	TEE_Result res = TEE_SUCCESS;
744 	struct tee_obj *o = NULL;
745 	size_t pos_tmp = 0;
746 
747 	res = tee_obj_get(utc, uref_to_vaddr(obj), &o);
748 	if (res != TEE_SUCCESS)
749 		goto exit;
750 
751 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
752 		res = TEE_ERROR_BAD_STATE;
753 		goto exit;
754 	}
755 
756 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE)) {
757 		res = TEE_ERROR_ACCESS_CONFLICT;
758 		goto exit;
759 	}
760 
761 	/* Guard o->info.dataPosition += bytes below from overflowing */
762 	if (ADD_OVERFLOW(o->info.dataPosition, len, &pos_tmp)) {
763 		res = TEE_ERROR_OVERFLOW;
764 		goto exit;
765 	}
766 
767 	/* check rights of the provided buffer */
768 	res = vm_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_READ,
769 				     (uaddr_t)data, len);
770 	if (res != TEE_SUCCESS)
771 		goto exit;
772 
773 	if (ADD_OVERFLOW(o->ds_pos, o->info.dataPosition, &pos_tmp)) {
774 		res = TEE_ERROR_ACCESS_CONFLICT;
775 		goto exit;
776 	}
777 	res = o->pobj->fops->write(o->fh, pos_tmp, data, len);
778 	if (res != TEE_SUCCESS)
779 		goto exit;
780 
781 	o->info.dataPosition += len;
782 	if (o->info.dataPosition > o->info.dataSize)
783 		o->info.dataSize = o->info.dataPosition;
784 
785 exit:
786 	return res;
787 }
788 
789 TEE_Result syscall_storage_obj_trunc(unsigned long obj, size_t len)
790 {
791 	struct ts_session *sess = ts_get_current_session();
792 	TEE_Result res = TEE_SUCCESS;
793 	struct tee_obj *o = NULL;
794 	size_t off = 0;
795 	size_t attr_size = 0;
796 
797 	res = tee_obj_get(to_user_ta_ctx(sess->ctx), uref_to_vaddr(obj), &o);
798 	if (res != TEE_SUCCESS)
799 		goto exit;
800 
801 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
802 		res = TEE_ERROR_BAD_STATE;
803 		goto exit;
804 	}
805 
806 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE)) {
807 		res = TEE_ERROR_ACCESS_CONFLICT;
808 		goto exit;
809 	}
810 
811 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
812 	if (res != TEE_SUCCESS)
813 		goto exit;
814 
815 	if (ADD_OVERFLOW(sizeof(struct tee_svc_storage_head), attr_size,
816 				&off)) {
817 		res = TEE_ERROR_OVERFLOW;
818 		goto exit;
819 	}
820 	if (ADD_OVERFLOW(len, off, &off)) {
821 		res = TEE_ERROR_OVERFLOW;
822 		goto exit;
823 	}
824 	res = o->pobj->fops->truncate(o->fh, off);
825 	switch (res) {
826 	case TEE_SUCCESS:
827 		o->info.dataSize = len;
828 		break;
829 	case TEE_ERROR_CORRUPT_OBJECT:
830 		EMSG("Object corruption");
831 		(void)tee_svc_storage_remove_corrupt_obj(sess, o);
832 		break;
833 	default:
834 		res = TEE_ERROR_GENERIC;
835 		break;
836 	}
837 
838 exit:
839 	return res;
840 }
841 
842 TEE_Result syscall_storage_obj_seek(unsigned long obj, int32_t offset,
843 				    unsigned long whence)
844 {
845 	struct ts_session *sess = ts_get_current_session();
846 	TEE_Result res = TEE_SUCCESS;
847 	struct tee_obj *o = NULL;
848 	tee_fs_off_t new_pos = 0;
849 
850 	res = tee_obj_get(to_user_ta_ctx(sess->ctx), uref_to_vaddr(obj), &o);
851 	if (res != TEE_SUCCESS)
852 		return res;
853 
854 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT))
855 		return TEE_ERROR_BAD_STATE;
856 
857 	switch (whence) {
858 	case TEE_DATA_SEEK_SET:
859 		new_pos = offset;
860 		break;
861 	case TEE_DATA_SEEK_CUR:
862 		if (ADD_OVERFLOW(o->info.dataPosition, offset, &new_pos))
863 			return TEE_ERROR_OVERFLOW;
864 		break;
865 	case TEE_DATA_SEEK_END:
866 		if (ADD_OVERFLOW(o->info.dataSize, offset, &new_pos))
867 			return TEE_ERROR_OVERFLOW;
868 		break;
869 	default:
870 		return TEE_ERROR_BAD_PARAMETERS;
871 	}
872 
873 	if (new_pos < 0)
874 		new_pos = 0;
875 
876 	if (new_pos > TEE_DATA_MAX_POSITION) {
877 		EMSG("Position is beyond TEE_DATA_MAX_POSITION");
878 		return TEE_ERROR_BAD_PARAMETERS;
879 	}
880 
881 	o->info.dataPosition = new_pos;
882 
883 	return TEE_SUCCESS;
884 }
885 
886 void tee_svc_storage_close_all_enum(struct user_ta_ctx *utc)
887 {
888 	struct tee_storage_enum_head *eh = &utc->storage_enums;
889 
890 	/* disregard return value */
891 	while (!TAILQ_EMPTY(eh))
892 		tee_svc_close_enum(utc, TAILQ_FIRST(eh));
893 }
894