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