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