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