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