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 
tee_svc_storage_get_enum(struct user_ta_ctx * utc,vaddr_t enum_id,struct tee_storage_enum ** e_out)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 
tee_svc_close_enum(struct user_ta_ctx * utc,struct tee_storage_enum * e)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 
tee_svc_storage_remove_corrupt_obj(struct ts_session * sess,struct tee_obj * o)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 
tee_svc_storage_read_head(struct tee_obj * o)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 
syscall_storage_obj_open(unsigned long storage_id,void * object_id,size_t object_id_len,unsigned long flags,uint32_t * obj)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 	res = vm_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_READ,
196 				     (uaddr_t)object_id, object_id_len);
197 	if (res != TEE_SUCCESS)
198 		goto err;
199 
200 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
201 			   object_id_len, flags, TEE_POBJ_USAGE_OPEN, fops,
202 			   &po);
203 	if (res != TEE_SUCCESS)
204 		goto err;
205 
206 	o = tee_obj_alloc();
207 	if (o == NULL) {
208 		tee_pobj_release(po);
209 		res = TEE_ERROR_OUT_OF_MEMORY;
210 		goto err;
211 	}
212 
213 	o->info.handleFlags = TEE_HANDLE_FLAG_PERSISTENT |
214 			      TEE_HANDLE_FLAG_INITIALIZED | flags;
215 	o->pobj = po;
216 	tee_obj_add(utc, o);
217 
218 	res = tee_svc_storage_read_head(o);
219 	if (res != TEE_SUCCESS) {
220 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
221 			EMSG("Object corrupt");
222 			goto err;
223 		}
224 		goto oclose;
225 	}
226 
227 	res = copy_kaddr_to_uref(obj, o);
228 	if (res != TEE_SUCCESS)
229 		goto oclose;
230 
231 	goto exit;
232 
233 oclose:
234 	tee_obj_close(utc, o);
235 	o = NULL;
236 
237 err:
238 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
239 		res = TEE_ERROR_CORRUPT_OBJECT;
240 	if (res == TEE_ERROR_CORRUPT_OBJECT && o)
241 		tee_svc_storage_remove_corrupt_obj(sess, o);
242 
243 exit:
244 	free(file);
245 	file = NULL;
246 	return res;
247 }
248 
tee_svc_storage_init_file(struct tee_obj * o,bool overwrite,struct tee_obj * attr_o,void * data,uint32_t len)249 static TEE_Result tee_svc_storage_init_file(struct tee_obj *o, bool overwrite,
250 					    struct tee_obj *attr_o, void *data,
251 					    uint32_t len)
252 {
253 	TEE_Result res = TEE_SUCCESS;
254 	struct tee_svc_storage_head head;
255 	const struct tee_file_operations *fops = o->pobj->fops;
256 	void *attr = NULL;
257 	size_t attr_size = 0;
258 
259 	if (attr_o) {
260 		res = tee_obj_set_type(o, attr_o->info.objectType,
261 				       attr_o->info.maxKeySize);
262 		if (res)
263 			return res;
264 		res = tee_obj_attr_copy_from(o, attr_o);
265 		if (res)
266 			return res;
267 		o->have_attrs = attr_o->have_attrs;
268 		o->info.objectUsage = attr_o->info.objectUsage;
269 		o->info.keySize = attr_o->info.keySize;
270 		res = tee_obj_attr_to_binary(o, NULL, &attr_size);
271 		if (res)
272 			return res;
273 		if (attr_size) {
274 			attr = malloc(attr_size);
275 			if (!attr)
276 				return TEE_ERROR_OUT_OF_MEMORY;
277 			res = tee_obj_attr_to_binary(o, attr, &attr_size);
278 			if (res != TEE_SUCCESS)
279 				goto exit;
280 		}
281 	} else {
282 		res = tee_obj_set_type(o, TEE_TYPE_DATA, 0);
283 		if (res != TEE_SUCCESS)
284 			goto exit;
285 	}
286 
287 	o->ds_pos = sizeof(struct tee_svc_storage_head) + attr_size;
288 
289 	/* write head */
290 	head.attr_size = attr_size;
291 	head.keySize = o->info.keySize;
292 	head.maxKeySize = o->info.maxKeySize;
293 	head.objectUsage = o->info.objectUsage;
294 	head.objectType = o->info.objectType;
295 	head.have_attrs = o->have_attrs;
296 
297 	res = fops->create(o->pobj, overwrite, &head, sizeof(head), attr,
298 			   attr_size, data, len, &o->fh);
299 
300 	if (!res)
301 		o->info.dataSize = len;
302 exit:
303 	free(attr);
304 	return res;
305 }
306 
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)307 TEE_Result syscall_storage_obj_create(unsigned long storage_id, void *object_id,
308 			size_t object_id_len, unsigned long flags,
309 			unsigned long attr, void *data, size_t len,
310 			uint32_t *obj)
311 {
312 	const unsigned long valid_flags = TEE_DATA_FLAG_ACCESS_READ |
313 					  TEE_DATA_FLAG_ACCESS_WRITE |
314 					  TEE_DATA_FLAG_ACCESS_WRITE_META |
315 					  TEE_DATA_FLAG_SHARE_READ |
316 					  TEE_DATA_FLAG_SHARE_WRITE |
317 					  TEE_DATA_FLAG_OVERWRITE;
318 	const struct tee_file_operations *fops =
319 			tee_svc_storage_file_ops(storage_id);
320 	struct ts_session *sess = ts_get_current_session();
321 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
322 	struct tee_obj *attr_o = NULL;
323 	TEE_Result res = TEE_SUCCESS;
324 	struct tee_pobj *po = NULL;
325 	struct tee_obj *o = NULL;
326 
327 	if (flags & ~valid_flags)
328 		return TEE_ERROR_BAD_PARAMETERS;
329 
330 	if (!fops)
331 		return TEE_ERROR_ITEM_NOT_FOUND;
332 
333 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
334 		return TEE_ERROR_BAD_PARAMETERS;
335 
336 	res = vm_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_READ,
337 				     (uaddr_t)object_id, object_id_len);
338 	if (res != TEE_SUCCESS)
339 		goto err;
340 
341 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
342 			   object_id_len, flags, TEE_POBJ_USAGE_CREATE,
343 			   fops, &po);
344 	if (res != TEE_SUCCESS)
345 		goto err;
346 
347 	/* check rights of the provided buffer */
348 	if (len) {
349 		if (data) {
350 			uint32_t f = TEE_MEMORY_ACCESS_READ |
351 				     TEE_MEMORY_ACCESS_ANY_OWNER;
352 
353 			res = vm_check_access_rights(&utc->uctx, f,
354 						     (uaddr_t)data, len);
355 
356 			if (res != TEE_SUCCESS)
357 				goto err;
358 		} else {
359 			res = TEE_ERROR_BAD_PARAMETERS;
360 			goto err;
361 		}
362 	}
363 
364 	o = tee_obj_alloc();
365 	if (o == NULL) {
366 		res = TEE_ERROR_OUT_OF_MEMORY;
367 		goto err;
368 	}
369 
370 	o->info.handleFlags = TEE_HANDLE_FLAG_PERSISTENT |
371 			      TEE_HANDLE_FLAG_INITIALIZED | flags;
372 	o->pobj = po;
373 
374 	if (attr != TEE_HANDLE_NULL) {
375 		res = tee_obj_get(utc, uref_to_vaddr(attr), &attr_o);
376 		if (res != TEE_SUCCESS)
377 			goto err;
378 		/* The supplied handle must be one of an initialized object */
379 		if (!(attr_o->info.handleFlags & TEE_HANDLE_FLAG_INITIALIZED)) {
380 			res = TEE_ERROR_BAD_PARAMETERS;
381 			goto err;
382 		}
383 	}
384 
385 	res = tee_svc_storage_init_file(o, flags & TEE_DATA_FLAG_OVERWRITE,
386 					attr_o, data, len);
387 	if (res != TEE_SUCCESS)
388 		goto err;
389 
390 	po = NULL; /* o owns it from now on */
391 	tee_obj_add(utc, o);
392 
393 	res = copy_kaddr_to_uref(obj, o);
394 	if (res != TEE_SUCCESS)
395 		goto oclose;
396 
397 	tee_pobj_create_final(o->pobj);
398 	return TEE_SUCCESS;
399 
400 oclose:
401 	tee_obj_close(utc, o);
402 	return res;
403 
404 err:
405 	if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
406 		res = TEE_ERROR_CORRUPT_OBJECT;
407 	if (res == TEE_ERROR_CORRUPT_OBJECT && po)
408 		fops->remove(po);
409 	if (o) {
410 		fops->close(&o->fh);
411 		tee_obj_free(o);
412 	}
413 	if (po)
414 		tee_pobj_release(po);
415 
416 	return res;
417 }
418 
syscall_storage_obj_del(unsigned long obj)419 TEE_Result syscall_storage_obj_del(unsigned long obj)
420 {
421 	struct ts_session *sess = ts_get_current_session();
422 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
423 	TEE_Result res = TEE_SUCCESS;
424 	struct tee_obj *o = NULL;
425 	uint8_t *data = NULL;
426 	size_t len = 0;
427 
428 	res = tee_obj_get(utc, uref_to_vaddr(obj), &o);
429 	if (res != TEE_SUCCESS)
430 		return res;
431 
432 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE_META))
433 		return TEE_ERROR_ACCESS_CONFLICT;
434 
435 	if (o->pobj == NULL || o->pobj->obj_id == NULL)
436 		return TEE_ERROR_BAD_STATE;
437 
438 	if (IS_ENABLED(CFG_NXP_SE05X)) {
439 		len = o->info.dataSize;
440 		data = calloc(1, len);
441 		if (!data)
442 			return TEE_ERROR_OUT_OF_MEMORY;
443 
444 		res = o->pobj->fops->read(o->fh, o->info.dataPosition,
445 					  data, &len);
446 		if (res == TEE_SUCCESS)
447 			crypto_storage_obj_del(data, len);
448 		free(data);
449 	}
450 
451 	res = o->pobj->fops->remove(o->pobj);
452 	tee_obj_close(utc, o);
453 
454 	return res;
455 }
456 
syscall_storage_obj_rename(unsigned long obj,void * object_id,size_t object_id_len)457 TEE_Result syscall_storage_obj_rename(unsigned long obj, void *object_id,
458 				      size_t object_id_len)
459 {
460 	const struct tee_file_operations *fops = NULL;
461 	struct ts_session *sess = ts_get_current_session();
462 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
463 	TEE_Result res = TEE_SUCCESS;
464 	struct tee_pobj *po = NULL;
465 	struct tee_obj *o = NULL;
466 	char *new_file = NULL;
467 	char *old_file = NULL;
468 
469 	if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
470 		return TEE_ERROR_BAD_PARAMETERS;
471 
472 	res = tee_obj_get(utc, uref_to_vaddr(obj), &o);
473 	if (res != TEE_SUCCESS)
474 		return res;
475 
476 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
477 		res = TEE_ERROR_BAD_STATE;
478 		goto exit;
479 	}
480 
481 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE_META)) {
482 		res = TEE_ERROR_BAD_STATE;
483 		goto exit;
484 	}
485 
486 	if (o->pobj == NULL || o->pobj->obj_id == NULL) {
487 		res = TEE_ERROR_BAD_STATE;
488 		goto exit;
489 	}
490 
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 	/* reserve dest name */
497 	fops = o->pobj->fops;
498 	res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
499 			   object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META,
500 			   TEE_POBJ_USAGE_RENAME, fops, &po);
501 	if (res != TEE_SUCCESS)
502 		goto exit;
503 
504 	/* move */
505 	res = fops->rename(o->pobj, po, false /* no overwrite */);
506 	if (res)
507 		goto exit;
508 
509 	res = tee_pobj_rename(o->pobj, object_id, object_id_len);
510 
511 exit:
512 	tee_pobj_release(po);
513 
514 	free(new_file);
515 	free(old_file);
516 
517 	return res;
518 }
519 
syscall_storage_alloc_enum(uint32_t * obj_enum)520 TEE_Result syscall_storage_alloc_enum(uint32_t *obj_enum)
521 {
522 	struct ts_session *sess = ts_get_current_session();
523 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
524 	struct tee_storage_enum *e = NULL;
525 
526 	if (obj_enum == NULL)
527 		return TEE_ERROR_BAD_PARAMETERS;
528 
529 	e = malloc(sizeof(struct tee_storage_enum));
530 	if (e == NULL)
531 		return TEE_ERROR_OUT_OF_MEMORY;
532 
533 	e->dir = NULL;
534 	e->fops = NULL;
535 	TAILQ_INSERT_TAIL(&utc->storage_enums, e, link);
536 
537 	return copy_kaddr_to_uref(obj_enum, e);
538 }
539 
syscall_storage_free_enum(unsigned long obj_enum)540 TEE_Result syscall_storage_free_enum(unsigned long obj_enum)
541 {
542 	struct ts_session *sess = ts_get_current_session();
543 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
544 	struct tee_storage_enum *e = NULL;
545 	TEE_Result res = TEE_SUCCESS;
546 
547 	res = tee_svc_storage_get_enum(utc,
548 			uref_to_vaddr(obj_enum), &e);
549 	if (res != TEE_SUCCESS)
550 		return res;
551 
552 	return tee_svc_close_enum(utc, e);
553 }
554 
syscall_storage_reset_enum(unsigned long obj_enum)555 TEE_Result syscall_storage_reset_enum(unsigned long obj_enum)
556 {
557 	struct ts_session *sess = ts_get_current_session();
558 	struct tee_storage_enum *e = NULL;
559 	TEE_Result res = TEE_SUCCESS;
560 
561 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
562 				       uref_to_vaddr(obj_enum), &e);
563 	if (res != TEE_SUCCESS)
564 		return res;
565 
566 	if (e->fops) {
567 		e->fops->closedir(e->dir);
568 		e->fops = NULL;
569 		e->dir = NULL;
570 	}
571 	assert(!e->dir);
572 
573 	return TEE_SUCCESS;
574 }
575 
syscall_storage_start_enum(unsigned long obj_enum,unsigned long storage_id)576 TEE_Result syscall_storage_start_enum(unsigned long obj_enum,
577 				      unsigned long storage_id)
578 {
579 	struct ts_session *sess = ts_get_current_session();
580 	struct tee_storage_enum *e = NULL;
581 	TEE_Result res = TEE_SUCCESS;
582 	const struct tee_file_operations *fops =
583 			tee_svc_storage_file_ops(storage_id);
584 
585 	res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
586 				       uref_to_vaddr(obj_enum), &e);
587 	if (res != TEE_SUCCESS)
588 		return res;
589 
590 	if (e->dir) {
591 		e->fops->closedir(e->dir);
592 		e->dir = NULL;
593 	}
594 
595 	if (!fops)
596 		return TEE_ERROR_ITEM_NOT_FOUND;
597 
598 	e->fops = fops;
599 
600 	return fops->opendir(&sess->ctx->uuid, &e->dir);
601 }
602 
syscall_storage_next_enum(unsigned long obj_enum,TEE_ObjectInfo * info,void * obj_id,uint64_t * len)603 TEE_Result syscall_storage_next_enum(unsigned long obj_enum,
604 			TEE_ObjectInfo *info, void *obj_id, uint64_t *len)
605 {
606 	struct ts_session *sess = ts_get_current_session();
607 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
608 	struct tee_storage_enum *e = NULL;
609 	struct tee_fs_dirent *d = NULL;
610 	TEE_Result res = TEE_SUCCESS;
611 	struct tee_obj *o = NULL;
612 	uint64_t l = 0;
613 
614 	res = tee_svc_storage_get_enum(utc, uref_to_vaddr(obj_enum), &e);
615 	if (res != TEE_SUCCESS)
616 		goto exit;
617 
618 	/* check rights of the provided buffers */
619 	res = vm_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_WRITE,
620 				     (uaddr_t)info, sizeof(TEE_ObjectInfo));
621 	if (res != TEE_SUCCESS)
622 		goto exit;
623 
624 	res = vm_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_WRITE,
625 				     (uaddr_t)obj_id, TEE_OBJECT_ID_MAX_LEN);
626 	if (res != TEE_SUCCESS)
627 		goto exit;
628 
629 	if (!e->fops) {
630 		res = TEE_ERROR_ITEM_NOT_FOUND;
631 		goto exit;
632 	}
633 
634 	res = e->fops->readdir(e->dir, &d);
635 	if (res != TEE_SUCCESS)
636 		goto exit;
637 
638 	o = tee_obj_alloc();
639 	if (o == NULL) {
640 		res = TEE_ERROR_OUT_OF_MEMORY;
641 		goto exit;
642 	}
643 
644 	res = tee_pobj_get(&sess->ctx->uuid, d->oid, d->oidlen, 0,
645 			   TEE_POBJ_USAGE_ENUM, e->fops, &o->pobj);
646 	if (res)
647 		goto exit;
648 
649 	o->info.handleFlags = o->pobj->flags | TEE_HANDLE_FLAG_PERSISTENT |
650 			      TEE_HANDLE_FLAG_INITIALIZED;
651 
652 	res = tee_svc_storage_read_head(o);
653 	if (res != TEE_SUCCESS)
654 		goto exit;
655 
656 	memcpy(info, &o->info, sizeof(TEE_ObjectInfo));
657 	memcpy(obj_id, o->pobj->obj_id, o->pobj->obj_id_len);
658 
659 	l = o->pobj->obj_id_len;
660 	res = copy_to_user_private(len, &l, sizeof(*len));
661 
662 exit:
663 	if (o) {
664 		if (o->pobj) {
665 			o->pobj->fops->close(&o->fh);
666 			tee_pobj_release(o->pobj);
667 		}
668 		tee_obj_free(o);
669 	}
670 
671 	return res;
672 }
673 
syscall_storage_obj_read(unsigned long obj,void * data,size_t len,uint64_t * count)674 TEE_Result syscall_storage_obj_read(unsigned long obj, void *data, size_t len,
675 				    uint64_t *count)
676 {
677 	struct ts_session *sess = ts_get_current_session();
678 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
679 	TEE_Result res = TEE_SUCCESS;
680 	struct tee_obj *o = NULL;
681 	uint64_t u_count = 0;
682 	size_t pos_tmp = 0;
683 	size_t bytes = 0;
684 
685 	res = tee_obj_get(utc, uref_to_vaddr(obj), &o);
686 	if (res != TEE_SUCCESS)
687 		goto exit;
688 
689 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
690 		res = TEE_ERROR_BAD_STATE;
691 		goto exit;
692 	}
693 
694 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_READ)) {
695 		res = TEE_ERROR_ACCESS_CONFLICT;
696 		goto exit;
697 	}
698 
699 	/* Guard o->info.dataPosition += bytes below from overflowing */
700 	if (ADD_OVERFLOW(o->info.dataPosition, len, &pos_tmp)) {
701 		res = TEE_ERROR_OVERFLOW;
702 		goto exit;
703 	}
704 
705 	/* check rights of the provided buffer */
706 	res = vm_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_WRITE,
707 				     (uaddr_t)data, len);
708 	if (res != TEE_SUCCESS)
709 		goto exit;
710 
711 	bytes = len;
712 	if (ADD_OVERFLOW(o->ds_pos, o->info.dataPosition, &pos_tmp)) {
713 		res = TEE_ERROR_OVERFLOW;
714 		goto exit;
715 	}
716 	res = o->pobj->fops->read(o->fh, pos_tmp, data, &bytes);
717 	if (res != TEE_SUCCESS) {
718 		if (res == TEE_ERROR_CORRUPT_OBJECT) {
719 			EMSG("Object corrupt");
720 			tee_svc_storage_remove_corrupt_obj(sess, o);
721 		}
722 		goto exit;
723 	}
724 
725 	o->info.dataPosition += bytes;
726 
727 	u_count = bytes;
728 	res = copy_to_user_private(count, &u_count, sizeof(*count));
729 exit:
730 	return res;
731 }
732 
syscall_storage_obj_write(unsigned long obj,void * data,size_t len)733 TEE_Result syscall_storage_obj_write(unsigned long obj, void *data, size_t len)
734 {
735 	struct ts_session *sess = ts_get_current_session();
736 	struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
737 	TEE_Result res = TEE_SUCCESS;
738 	struct tee_obj *o = NULL;
739 	size_t pos_tmp = 0;
740 
741 	res = tee_obj_get(utc, uref_to_vaddr(obj), &o);
742 	if (res != TEE_SUCCESS)
743 		goto exit;
744 
745 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
746 		res = TEE_ERROR_BAD_STATE;
747 		goto exit;
748 	}
749 
750 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE)) {
751 		res = TEE_ERROR_ACCESS_CONFLICT;
752 		goto exit;
753 	}
754 
755 	/* Guard o->info.dataPosition += bytes below from overflowing */
756 	if (ADD_OVERFLOW(o->info.dataPosition, len, &pos_tmp)) {
757 		res = TEE_ERROR_OVERFLOW;
758 		goto exit;
759 	}
760 
761 	/* check rights of the provided buffer */
762 	res = vm_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_READ,
763 				     (uaddr_t)data, len);
764 	if (res != TEE_SUCCESS)
765 		goto exit;
766 
767 	if (ADD_OVERFLOW(o->ds_pos, o->info.dataPosition, &pos_tmp)) {
768 		res = TEE_ERROR_ACCESS_CONFLICT;
769 		goto exit;
770 	}
771 	res = o->pobj->fops->write(o->fh, pos_tmp, data, len);
772 	if (res != TEE_SUCCESS)
773 		goto exit;
774 
775 	o->info.dataPosition += len;
776 	if (o->info.dataPosition > o->info.dataSize)
777 		o->info.dataSize = o->info.dataPosition;
778 
779 exit:
780 	return res;
781 }
782 
syscall_storage_obj_trunc(unsigned long obj,size_t len)783 TEE_Result syscall_storage_obj_trunc(unsigned long obj, size_t len)
784 {
785 	struct ts_session *sess = ts_get_current_session();
786 	TEE_Result res = TEE_SUCCESS;
787 	struct tee_obj *o = NULL;
788 	size_t off = 0;
789 	size_t attr_size = 0;
790 
791 	res = tee_obj_get(to_user_ta_ctx(sess->ctx), uref_to_vaddr(obj), &o);
792 	if (res != TEE_SUCCESS)
793 		goto exit;
794 
795 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
796 		res = TEE_ERROR_BAD_STATE;
797 		goto exit;
798 	}
799 
800 	if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE)) {
801 		res = TEE_ERROR_ACCESS_CONFLICT;
802 		goto exit;
803 	}
804 
805 	res = tee_obj_attr_to_binary(o, NULL, &attr_size);
806 	if (res != TEE_SUCCESS)
807 		goto exit;
808 
809 	if (ADD_OVERFLOW(sizeof(struct tee_svc_storage_head), attr_size,
810 				&off)) {
811 		res = TEE_ERROR_OVERFLOW;
812 		goto exit;
813 	}
814 	if (ADD_OVERFLOW(len, off, &off)) {
815 		res = TEE_ERROR_OVERFLOW;
816 		goto exit;
817 	}
818 	res = o->pobj->fops->truncate(o->fh, off);
819 	switch (res) {
820 	case TEE_SUCCESS:
821 		o->info.dataSize = len;
822 		break;
823 	case TEE_ERROR_CORRUPT_OBJECT:
824 		EMSG("Object corruption");
825 		(void)tee_svc_storage_remove_corrupt_obj(sess, o);
826 		break;
827 	default:
828 		res = TEE_ERROR_GENERIC;
829 		break;
830 	}
831 
832 exit:
833 	return res;
834 }
835 
syscall_storage_obj_seek(unsigned long obj,int32_t offset,unsigned long whence)836 TEE_Result syscall_storage_obj_seek(unsigned long obj, int32_t offset,
837 				    unsigned long whence)
838 {
839 	struct ts_session *sess = ts_get_current_session();
840 	TEE_Result res = TEE_SUCCESS;
841 	struct tee_obj *o = NULL;
842 	tee_fs_off_t new_pos = 0;
843 
844 	res = tee_obj_get(to_user_ta_ctx(sess->ctx), uref_to_vaddr(obj), &o);
845 	if (res != TEE_SUCCESS)
846 		return res;
847 
848 	if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT))
849 		return TEE_ERROR_BAD_STATE;
850 
851 	switch (whence) {
852 	case TEE_DATA_SEEK_SET:
853 		new_pos = offset;
854 		break;
855 	case TEE_DATA_SEEK_CUR:
856 		if (ADD_OVERFLOW(o->info.dataPosition, offset, &new_pos))
857 			return TEE_ERROR_OVERFLOW;
858 		break;
859 	case TEE_DATA_SEEK_END:
860 		if (ADD_OVERFLOW(o->info.dataSize, offset, &new_pos))
861 			return TEE_ERROR_OVERFLOW;
862 		break;
863 	default:
864 		return TEE_ERROR_BAD_PARAMETERS;
865 	}
866 
867 	if (new_pos < 0)
868 		new_pos = 0;
869 
870 	if (new_pos > TEE_DATA_MAX_POSITION) {
871 		EMSG("Position is beyond TEE_DATA_MAX_POSITION");
872 		return TEE_ERROR_BAD_PARAMETERS;
873 	}
874 
875 	o->info.dataPosition = new_pos;
876 
877 	return TEE_SUCCESS;
878 }
879 
tee_svc_storage_close_all_enum(struct user_ta_ctx * utc)880 void tee_svc_storage_close_all_enum(struct user_ta_ctx *utc)
881 {
882 	struct tee_storage_enum_head *eh = &utc->storage_enums;
883 
884 	/* disregard return value */
885 	while (!TAILQ_EMPTY(eh))
886 		tee_svc_close_enum(utc, TAILQ_FIRST(eh));
887 }
888