Update from upstream to 2.4.0 version
[platform/core/security/tef-optee_os.git] / core / tee / tee_svc_storage.c
1 /*
2  * Copyright (c) 2014, STMicroelectronics International N.V.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include <kernel/mutex.h>
29 #include <kernel/tee_misc.h>
30 #include <kernel/tee_ta_manager.h>
31 #include <mm/tee_mmu.h>
32 #include <string.h>
33 #include <tee_api_defines_extensions.h>
34 #include <tee_api_defines.h>
35 #include <tee/tee_fs.h>
36 #include <tee/tee_obj.h>
37 #include <tee/tee_pobj.h>
38 #include <tee/tee_svc_cryp.h>
39 #include <tee/tee_svc.h>
40 #include <tee/tee_svc_storage.h>
41 #include <trace.h>
42
43 /*
44  * Returns the appropriate tee_file_operations for the specified storage ID.
45  * The value TEE_STORAGE_PRIVATE will select the REE FS if available, otherwise
46  * RPMB.
47  */
48 static const struct tee_file_operations *file_ops(uint32_t storage_id)
49 {
50
51         switch (storage_id) {
52         case TEE_STORAGE_PRIVATE:
53 #if defined(CFG_REE_FS)
54                 return &ree_fs_ops;
55 #elif defined(CFG_RPMB_FS)
56                 return &rpmb_fs_ops;
57 #elif defined(CFG_SQL_FS)
58                 return &sql_fs_ops;
59 #else
60 #error At least one filesystem must be enabled.
61 #endif
62 #ifdef CFG_REE_FS
63         case TEE_STORAGE_PRIVATE_REE:
64                 return &ree_fs_ops;
65 #endif
66 #ifdef CFG_RPMB_FS
67         case TEE_STORAGE_PRIVATE_RPMB:
68                 return &rpmb_fs_ops;
69 #endif
70 #ifdef CFG_SQL_FS
71         case TEE_STORAGE_PRIVATE_SQL:
72                 return &sql_fs_ops;
73 #endif
74         default:
75                 return NULL;
76         }
77 }
78
79 /* SSF (Secure Storage File version 00 */
80 #define TEE_SVC_STORAGE_MAGIC 0x53534600
81
82 /* Header of GP formated secure storage files */
83 struct tee_svc_storage_head {
84         uint32_t magic;
85         uint32_t head_size;
86         uint32_t meta_size;
87         uint32_t ds_size;
88         uint32_t keySize;
89         uint32_t maxKeySize;
90         uint32_t objectUsage;
91         uint32_t objectType;
92         uint32_t have_attrs;
93 };
94
95 struct tee_storage_enum {
96         TAILQ_ENTRY(tee_storage_enum) link;
97         struct tee_fs_dir *dir;
98         const struct tee_file_operations *fops;
99 };
100
101 static TEE_Result tee_svc_storage_get_enum(struct user_ta_ctx *utc,
102                                            uint32_t enum_id,
103                                            struct tee_storage_enum **e_out)
104 {
105         struct tee_storage_enum *e;
106
107         TAILQ_FOREACH(e, &utc->storage_enums, link) {
108                 if (enum_id == (vaddr_t)e) {
109                         *e_out = e;
110                         return TEE_SUCCESS;
111                 }
112         }
113         return TEE_ERROR_BAD_PARAMETERS;
114 }
115
116 static TEE_Result tee_svc_close_enum(struct user_ta_ctx *utc,
117                                      struct tee_storage_enum *e)
118 {
119         if (e == NULL || utc == NULL)
120                 return TEE_ERROR_BAD_PARAMETERS;
121
122         TAILQ_REMOVE(&utc->storage_enums, e, link);
123
124         if (e->fops)
125                 e->fops->closedir(e->dir);
126
127         e->dir = NULL;
128         e->fops = NULL;
129
130         free(e);
131
132         return TEE_SUCCESS;
133 }
134
135 /* "/TA_uuid/object_id" or "/TA_uuid/.object_id" */
136 TEE_Result tee_svc_storage_create_filename(void *buf, size_t blen,
137                                            struct tee_pobj *po, bool transient)
138 {
139         uint8_t *file = buf;
140         uint32_t pos = 0;
141         uint32_t hslen = 1 /* Leading slash */
142                         + TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID) + po->obj_id_len)
143                         + 1; /* Intermediate slash */
144
145         /* +1 for the '.' (temporary persistent object) */
146         if (transient)
147                 hslen++;
148
149         if (blen < hslen)
150                 return TEE_ERROR_SHORT_BUFFER;
151
152         file[pos++] = '/';
153         pos += tee_b2hs((uint8_t *)&po->uuid, &file[pos],
154                         sizeof(TEE_UUID), hslen);
155         file[pos++] = '/';
156
157         if (transient)
158                 file[pos++] = '.';
159
160         tee_b2hs(po->obj_id, file + pos, po->obj_id_len, hslen - pos);
161
162         return TEE_SUCCESS;
163 }
164
165 /* "/TA_uuid" */
166 TEE_Result tee_svc_storage_create_dirname(void *buf, size_t blen,
167                                           const TEE_UUID *uuid)
168 {
169         uint8_t *dir = buf;
170         uint32_t hslen = TEE_B2HS_HSBUF_SIZE(sizeof(TEE_UUID)) + 1;
171
172         if (blen < hslen)
173                 return TEE_ERROR_SHORT_BUFFER;
174
175         dir[0] = '/';
176         tee_b2hs((uint8_t *)uuid, dir + 1, sizeof(TEE_UUID), hslen);
177
178         return TEE_SUCCESS;
179 }
180
181 static TEE_Result tee_svc_storage_remove_corrupt_obj(
182                                         struct tee_ta_session *sess,
183                                         struct tee_obj *o)
184 {
185         o->pobj->fops->remove(o->pobj);
186         tee_obj_close(to_user_ta_ctx(sess->ctx), o);
187
188         return TEE_SUCCESS;
189 }
190
191 static TEE_Result tee_svc_storage_read_head(struct tee_obj *o)
192 {
193         TEE_Result res = TEE_SUCCESS;
194         size_t bytes;
195         struct tee_svc_storage_head head;
196         const struct tee_file_operations *fops = o->pobj->fops;
197         void *attr = NULL;
198
199         assert(!o->fh);
200         res = fops->open(o->pobj, &o->fh);
201         if (res != TEE_SUCCESS)
202                 goto exit;
203
204         /* read head */
205         bytes = sizeof(struct tee_svc_storage_head);
206         res = fops->read(o->fh, 0, &head, &bytes);
207         if (res != TEE_SUCCESS) {
208                 if (res == TEE_ERROR_CORRUPT_OBJECT)
209                         EMSG("Head corrupt\n");
210                 goto exit;
211         }
212
213         if (bytes != sizeof(struct tee_svc_storage_head)) {
214                 res = TEE_ERROR_BAD_FORMAT;
215                 goto exit;
216         }
217
218         res = tee_obj_set_type(o, head.objectType, head.maxKeySize);
219         if (res != TEE_SUCCESS)
220                 goto exit;
221
222         o->ds_pos = sizeof(struct tee_svc_storage_head) + head.meta_size;
223         if (head.meta_size) {
224                 attr = malloc(head.meta_size);
225                 if (!attr) {
226                         res = TEE_ERROR_OUT_OF_MEMORY;
227                         goto exit;
228                 }
229
230                 /* read meta */
231                 bytes = head.meta_size;
232                 res = fops->read(o->fh, sizeof(struct tee_svc_storage_head),
233                                  attr, &bytes);
234                 if (res != TEE_SUCCESS || bytes != head.meta_size) {
235                         res = TEE_ERROR_CORRUPT_OBJECT;
236                         goto exit;
237                 }
238         }
239
240         res = tee_obj_attr_from_binary(o, attr, head.meta_size);
241         if (res != TEE_SUCCESS)
242                 goto exit;
243
244         o->info.dataSize = head.ds_size;
245         o->info.keySize = head.keySize;
246         o->info.objectUsage = head.objectUsage;
247         o->info.objectType = head.objectType;
248         o->have_attrs = head.have_attrs;
249
250 exit:
251         free(attr);
252
253         return res;
254 }
255
256 static TEE_Result tee_svc_storage_update_head(struct tee_obj *o,
257                                         uint32_t ds_size)
258 {
259         size_t pos = offsetof(struct tee_svc_storage_head, ds_size);
260
261         return o->pobj->fops->write(o->fh, pos, &ds_size, sizeof(uint32_t));
262 }
263
264 static TEE_Result tee_svc_storage_init_file(struct tee_obj *o,
265                                             struct tee_obj *attr_o, void *data,
266                                             uint32_t len)
267 {
268         TEE_Result res = TEE_SUCCESS;
269         struct tee_svc_storage_head head;
270         const struct tee_file_operations *fops = o->pobj->fops;
271         void *attr = NULL;
272         size_t attr_size = 0;
273
274         res = fops->create(o->pobj, &o->fh);
275         if (res != TEE_SUCCESS)
276                 goto exit;
277
278         if (attr_o) {
279                 res = tee_obj_set_type(o, attr_o->info.objectType,
280                                        attr_o->info.maxKeySize);
281                 if (res != TEE_SUCCESS)
282                         goto exit;
283                 res = tee_obj_attr_copy_from(o, attr_o);
284                 if (res != TEE_SUCCESS)
285                         goto exit;
286                 o->have_attrs = attr_o->have_attrs;
287                 o->info.objectUsage = attr_o->info.objectUsage;
288                 o->info.keySize = attr_o->info.keySize;
289                 res = tee_obj_attr_to_binary(o, NULL, &attr_size);
290                 if (res != TEE_SUCCESS)
291                         goto exit;
292                 if (attr_size) {
293                         attr = malloc(attr_size);
294                         if (!attr) {
295                                 res = TEE_ERROR_OUT_OF_MEMORY;
296                                 goto exit;
297                         }
298                         res = tee_obj_attr_to_binary(o, attr, &attr_size);
299                         if (res != TEE_SUCCESS)
300                                 goto exit;
301                 }
302         } else {
303                 res = tee_obj_set_type(o, TEE_TYPE_DATA, 0);
304                 if (res != TEE_SUCCESS)
305                         goto exit;
306         }
307
308         o->ds_pos = sizeof(struct tee_svc_storage_head) + attr_size;
309
310         /* write head */
311         head.magic = TEE_SVC_STORAGE_MAGIC;
312         head.head_size = sizeof(struct tee_svc_storage_head);
313         head.meta_size = attr_size;
314         head.ds_size = len;
315         head.keySize = o->info.keySize;
316         head.maxKeySize = o->info.maxKeySize;
317         head.objectUsage = o->info.objectUsage;
318         head.objectType = o->info.objectType;
319         head.have_attrs = o->have_attrs;
320
321         /* write head */
322         res = fops->write(o->fh, 0, &head, sizeof(struct tee_svc_storage_head));
323         if (res != TEE_SUCCESS)
324                 goto exit;
325
326         /* write meta */
327         res = fops->write(o->fh, sizeof(struct tee_svc_storage_head),
328                           attr, attr_size);
329         if (res != TEE_SUCCESS)
330                 goto exit;
331
332         /* write init data */
333         o->info.dataSize = len;
334
335         /* write data to fs if needed */
336         if (data && len)
337                 res = fops->write(o->fh, o->ds_pos, data, len);
338
339 exit:
340         free(attr);
341         fops->close(&o->fh);
342
343         return res;
344 }
345
346 TEE_Result syscall_storage_obj_open(unsigned long storage_id, void *object_id,
347                         size_t object_id_len, unsigned long flags,
348                         uint32_t *obj)
349 {
350         TEE_Result res;
351         struct tee_ta_session *sess;
352         struct tee_obj *o = NULL;
353         char *file = NULL;
354         struct tee_pobj *po = NULL;
355         struct user_ta_ctx *utc;
356         const struct tee_file_operations *fops = file_ops(storage_id);
357         size_t attr_size;
358
359         if (!fops) {
360                 res = TEE_ERROR_ITEM_NOT_FOUND;
361                 goto exit;
362         }
363
364         if (object_id_len > TEE_OBJECT_ID_MAX_LEN) {
365                 res = TEE_ERROR_BAD_PARAMETERS;
366                 goto exit;
367         }
368
369         res = tee_ta_get_current_session(&sess);
370         if (res != TEE_SUCCESS)
371                 goto err;
372         utc = to_user_ta_ctx(sess->ctx);
373
374         res = tee_mmu_check_access_rights(utc,
375                                           TEE_MEMORY_ACCESS_READ |
376                                           TEE_MEMORY_ACCESS_ANY_OWNER,
377                                           (uaddr_t) object_id,
378                                           object_id_len);
379         if (res != TEE_SUCCESS)
380                 goto err;
381
382         res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
383                            object_id_len, flags, false, fops, &po);
384         if (res != TEE_SUCCESS)
385                 goto err;
386
387         o = tee_obj_alloc();
388         if (o == NULL) {
389                 tee_pobj_release(po);
390                 res = TEE_ERROR_OUT_OF_MEMORY;
391                 goto err;
392         }
393
394         o->info.handleFlags =
395             TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
396         o->flags = flags;
397         o->pobj = po;
398         tee_obj_add(utc, o);
399
400         res = tee_svc_storage_read_head(o);
401         if (res != TEE_SUCCESS) {
402                 if (res == TEE_ERROR_CORRUPT_OBJECT) {
403                         EMSG("Object corrupt");
404                         goto err;
405                 }
406                 goto oclose;
407         }
408
409         res = tee_svc_copy_kaddr_to_uref(obj, o);
410         if (res != TEE_SUCCESS)
411                 goto oclose;
412
413         res = tee_obj_attr_to_binary(o, NULL, &attr_size);
414         if (res != TEE_SUCCESS)
415                 goto oclose;
416
417         goto exit;
418
419 oclose:
420         tee_obj_close(utc, o);
421         o = NULL;
422
423 err:
424         if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
425                 res = TEE_ERROR_CORRUPT_OBJECT;
426         if (res == TEE_ERROR_CORRUPT_OBJECT && o)
427                 tee_svc_storage_remove_corrupt_obj(sess, o);
428
429 exit:
430         free(file);
431         file = NULL;
432         return res;
433 }
434
435 TEE_Result syscall_storage_obj_create(unsigned long storage_id, void *object_id,
436                         size_t object_id_len, unsigned long flags,
437                         unsigned long attr, void *data, size_t len,
438                         uint32_t *obj)
439 {
440         TEE_Result res;
441         struct tee_ta_session *sess;
442         struct tee_obj *o = NULL;
443         struct tee_obj *attr_o = NULL;
444         struct tee_pobj *po = NULL;
445         struct user_ta_ctx *utc;
446         const struct tee_file_operations *fops = file_ops(storage_id);
447         size_t attr_size;
448
449         if (!fops)
450                 return TEE_ERROR_ITEM_NOT_FOUND;
451
452         if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
453                 return TEE_ERROR_BAD_PARAMETERS;
454
455         res = tee_ta_get_current_session(&sess);
456         if (res != TEE_SUCCESS)
457                 return res;
458         utc = to_user_ta_ctx(sess->ctx);
459
460         res = tee_mmu_check_access_rights(utc,
461                                           TEE_MEMORY_ACCESS_READ |
462                                           TEE_MEMORY_ACCESS_ANY_OWNER,
463                                           (uaddr_t) object_id,
464                                           object_id_len);
465         if (res != TEE_SUCCESS)
466                 goto err;
467
468         res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
469                            object_id_len, flags, true, fops, &po);
470         if (res != TEE_SUCCESS)
471                 goto err;
472
473         /* check rights of the provided buffer */
474         if (data && len) {
475                 res = tee_mmu_check_access_rights(utc,
476                                                   TEE_MEMORY_ACCESS_READ |
477                                                   TEE_MEMORY_ACCESS_ANY_OWNER,
478                                                   (uaddr_t) data, len);
479
480                 if (res != TEE_SUCCESS)
481                         goto err;
482         }
483
484         o = tee_obj_alloc();
485         if (o == NULL) {
486                 res = TEE_ERROR_OUT_OF_MEMORY;
487                 goto err;
488         }
489
490         o->info.handleFlags =
491             TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
492         o->flags = flags;
493         o->pobj = po;
494
495         if (attr != TEE_HANDLE_NULL) {
496                 res = tee_obj_get(utc, tee_svc_uref_to_vaddr(attr),
497                                   &attr_o);
498                 if (res != TEE_SUCCESS)
499                         goto err;
500         }
501
502         res = tee_svc_storage_init_file(o, attr_o, data, len);
503         if (res != TEE_SUCCESS)
504                 goto err;
505
506         /* rename temporary persistent object filename */
507         po->temporary = false;
508         res = fops->rename(po, NULL, !!(flags & TEE_DATA_FLAG_OVERWRITE));
509         if (res != TEE_SUCCESS)
510                 goto rmfile;
511
512         res = fops->open(po, &o->fh);
513         if (res != TEE_SUCCESS)
514                 goto err;
515
516         tee_obj_add(utc, o);
517
518         res = tee_svc_copy_kaddr_to_uref(obj, o);
519         if (res != TEE_SUCCESS)
520                 goto oclose;
521
522         res = tee_obj_attr_to_binary(o, NULL, &attr_size);
523         if (res != TEE_SUCCESS)
524                 goto oclose;
525
526         return TEE_SUCCESS;
527
528 oclose:
529         tee_obj_close(utc, o);
530         return res;
531
532 rmfile:
533         fops->remove(po);
534
535 err:
536         if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
537                 res = TEE_ERROR_CORRUPT_OBJECT;
538         if (res == TEE_ERROR_CORRUPT_OBJECT && po)
539                 fops->remove(po);
540         if (o)
541                 fops->close(&o->fh);
542         if (po)
543                 tee_pobj_release(po);
544         free(o);
545
546         return res;
547 }
548
549 TEE_Result syscall_storage_obj_del(unsigned long obj)
550 {
551         TEE_Result res;
552         struct tee_ta_session *sess;
553         struct tee_obj *o;
554         struct user_ta_ctx *utc;
555
556         res = tee_ta_get_current_session(&sess);
557         if (res != TEE_SUCCESS)
558                 return res;
559         utc = to_user_ta_ctx(sess->ctx);
560
561         res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
562         if (res != TEE_SUCCESS)
563                 return res;
564
565         if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META))
566                 return TEE_ERROR_ACCESS_CONFLICT;
567
568         if (o->pobj == NULL || o->pobj->obj_id == NULL)
569                 return TEE_ERROR_BAD_STATE;
570
571         res = o->pobj->fops->remove(o->pobj);
572         tee_obj_close(utc, o);
573
574         return res;
575 }
576
577 TEE_Result syscall_storage_obj_rename(unsigned long obj, void *object_id,
578                         size_t object_id_len)
579 {
580         TEE_Result res;
581         struct tee_ta_session *sess;
582         struct tee_obj *o;
583         struct tee_pobj *po = NULL;
584         char *new_file = NULL;
585         char *old_file = NULL;
586         struct user_ta_ctx *utc;
587         const struct tee_file_operations *fops;
588
589         if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
590                 return TEE_ERROR_BAD_PARAMETERS;
591
592         res = tee_ta_get_current_session(&sess);
593         if (res != TEE_SUCCESS)
594                 return res;
595         utc = to_user_ta_ctx(sess->ctx);
596
597         res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
598         if (res != TEE_SUCCESS)
599                 return res;
600
601         if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
602                 res = TEE_ERROR_BAD_STATE;
603                 goto exit;
604         }
605
606         if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE_META)) {
607                 res = TEE_ERROR_BAD_STATE;
608                 goto exit;
609         }
610
611         if (o->pobj == NULL || o->pobj->obj_id == NULL) {
612                 res = TEE_ERROR_BAD_STATE;
613                 goto exit;
614         }
615
616         res = tee_mmu_check_access_rights(utc,
617                                         TEE_MEMORY_ACCESS_READ |
618                                         TEE_MEMORY_ACCESS_ANY_OWNER,
619                                         (uaddr_t) object_id, object_id_len);
620         if (res != TEE_SUCCESS)
621                 goto exit;
622
623         /* reserve dest name */
624         fops = o->pobj->fops;
625         res = tee_pobj_get((void *)&sess->ctx->uuid, object_id,
626                            object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META,
627                            false, fops, &po);
628         if (res != TEE_SUCCESS)
629                 goto exit;
630
631         /* move */
632         res = fops->rename(o->pobj, po, false /* no overwrite */);
633         if (res == TEE_ERROR_GENERIC)
634                 goto exit;
635
636         res = tee_pobj_rename(o->pobj, object_id, object_id_len);
637
638 exit:
639         tee_pobj_release(po);
640
641         free(new_file);
642         free(old_file);
643
644         return res;
645 }
646
647 TEE_Result syscall_storage_alloc_enum(uint32_t *obj_enum)
648 {
649         struct tee_storage_enum *e;
650         struct tee_ta_session *sess;
651         TEE_Result res;
652         struct user_ta_ctx *utc;
653
654         if (obj_enum == NULL)
655                 return TEE_ERROR_BAD_PARAMETERS;
656
657         res = tee_ta_get_current_session(&sess);
658         if (res != TEE_SUCCESS)
659                 return res;
660         utc = to_user_ta_ctx(sess->ctx);
661
662         e = malloc(sizeof(struct tee_storage_enum));
663         if (e == NULL)
664                 return TEE_ERROR_OUT_OF_MEMORY;
665
666         e->dir = NULL;
667         e->fops = NULL;
668         TAILQ_INSERT_TAIL(&utc->storage_enums, e, link);
669
670         return tee_svc_copy_kaddr_to_uref(obj_enum, e);
671 }
672
673 TEE_Result syscall_storage_free_enum(unsigned long obj_enum)
674 {
675         struct tee_storage_enum *e;
676         TEE_Result res;
677         struct tee_ta_session *sess;
678         struct user_ta_ctx *utc;
679
680         res = tee_ta_get_current_session(&sess);
681         if (res != TEE_SUCCESS)
682                 return res;
683         utc = to_user_ta_ctx(sess->ctx);
684
685         res = tee_svc_storage_get_enum(utc,
686                         tee_svc_uref_to_vaddr(obj_enum), &e);
687         if (res != TEE_SUCCESS)
688                 return res;
689
690         return tee_svc_close_enum(utc, e);
691 }
692
693 TEE_Result syscall_storage_reset_enum(unsigned long obj_enum)
694 {
695         struct tee_storage_enum *e;
696         TEE_Result res;
697         struct tee_ta_session *sess;
698
699         res = tee_ta_get_current_session(&sess);
700         if (res != TEE_SUCCESS)
701                 return res;
702
703         res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
704                         tee_svc_uref_to_vaddr(obj_enum), &e);
705         if (res != TEE_SUCCESS)
706                 return res;
707
708         if (e->fops) {
709                 e->fops->closedir(e->dir);
710                 e->fops = NULL;
711                 e->dir = NULL;
712         }
713         assert(!e->dir);
714
715         return TEE_SUCCESS;
716 }
717
718 static TEE_Result tee_svc_storage_set_enum(struct tee_fs_dirent *d,
719                         const struct tee_file_operations *fops,
720                         struct tee_obj *o)
721 {
722         o->info.handleFlags =
723             TEE_HANDLE_FLAG_PERSISTENT | TEE_HANDLE_FLAG_INITIALIZED;
724         o->info.objectUsage = TEE_USAGE_DEFAULT;
725
726         o->pobj->obj_id = malloc(d->oidlen);
727         if (!o->pobj->obj_id)
728                 return TEE_ERROR_OUT_OF_MEMORY;
729
730         memcpy(o->pobj->obj_id, d->oid, d->oidlen);
731         o->pobj->obj_id_len = d->oidlen;
732         o->pobj->fops = fops;
733
734         return TEE_SUCCESS;
735 }
736
737 TEE_Result syscall_storage_start_enum(unsigned long obj_enum,
738                                       unsigned long storage_id)
739 {
740         struct tee_storage_enum *e;
741         TEE_Result res;
742         struct tee_ta_session *sess;
743         const struct tee_file_operations *fops = file_ops(storage_id);
744
745         res = tee_ta_get_current_session(&sess);
746         if (res != TEE_SUCCESS)
747                 return res;
748
749         res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
750                         tee_svc_uref_to_vaddr(obj_enum), &e);
751         if (res != TEE_SUCCESS)
752                 return res;
753
754         if (!fops)
755                 return TEE_ERROR_ITEM_NOT_FOUND;
756
757         e->fops = fops;
758         assert(!e->dir);
759         return fops->opendir(&sess->ctx->uuid, &e->dir);
760 }
761
762 TEE_Result syscall_storage_next_enum(unsigned long obj_enum,
763                         TEE_ObjectInfo *info, void *obj_id, uint64_t *len)
764 {
765         struct tee_storage_enum *e;
766         struct tee_fs_dirent *d;
767         TEE_Result res = TEE_SUCCESS;
768         struct tee_ta_session *sess;
769         struct tee_obj *o = NULL;
770         uint64_t l;
771         struct user_ta_ctx *utc;
772
773         res = tee_ta_get_current_session(&sess);
774         if (res != TEE_SUCCESS)
775                 goto exit;
776         utc = to_user_ta_ctx(sess->ctx);
777
778         res = tee_svc_storage_get_enum(utc,
779                         tee_svc_uref_to_vaddr(obj_enum), &e);
780         if (res != TEE_SUCCESS)
781                 goto exit;
782
783         /* check rights of the provided buffers */
784         res = tee_mmu_check_access_rights(utc,
785                                         TEE_MEMORY_ACCESS_WRITE |
786                                         TEE_MEMORY_ACCESS_ANY_OWNER,
787                                         (uaddr_t) info,
788                                         sizeof(TEE_ObjectInfo));
789         if (res != TEE_SUCCESS)
790                 goto exit;
791
792         res = tee_mmu_check_access_rights(utc,
793                                         TEE_MEMORY_ACCESS_WRITE |
794                                         TEE_MEMORY_ACCESS_ANY_OWNER,
795                                         (uaddr_t) obj_id,
796                                         TEE_OBJECT_ID_MAX_LEN);
797         if (res != TEE_SUCCESS)
798                 goto exit;
799
800         if (!e->fops) {
801                 res = TEE_ERROR_ITEM_NOT_FOUND;
802                 goto exit;
803         }
804
805         res = e->fops->readdir(e->dir, &d);
806         if (res != TEE_SUCCESS)
807                 goto exit;
808
809         o = tee_obj_alloc();
810         if (o == NULL) {
811                 res = TEE_ERROR_OUT_OF_MEMORY;
812                 goto exit;
813         }
814         o->flags = TEE_DATA_FLAG_SHARE_READ;
815
816         o->pobj = calloc(1, sizeof(struct tee_pobj));
817         if (!o->pobj) {
818                 res = TEE_ERROR_OUT_OF_MEMORY;
819                 goto exit;
820         }
821
822         o->pobj->uuid = sess->ctx->uuid;
823         res = tee_svc_storage_set_enum(d, e->fops, o);
824         if (res != TEE_SUCCESS)
825                 goto exit;
826
827         res = tee_svc_storage_read_head(o);
828         if (res != TEE_SUCCESS)
829                 goto exit;
830
831         memcpy(info, &o->info, sizeof(TEE_ObjectInfo));
832         memcpy(obj_id, o->pobj->obj_id, o->pobj->obj_id_len);
833
834         l = o->pobj->obj_id_len;
835         res = tee_svc_copy_to_user(len, &l, sizeof(*len));
836
837 exit:
838         if (o) {
839                 if (o->pobj) {
840                         o->pobj->fops->close(&o->fh);
841                         free(o->pobj->obj_id);
842                 }
843                 free(o->pobj);
844                 tee_obj_free(o);
845         }
846
847         return res;
848 }
849
850 TEE_Result syscall_storage_obj_read(unsigned long obj, void *data, size_t len,
851                         uint64_t *count)
852 {
853         TEE_Result res;
854         struct tee_ta_session *sess;
855         struct tee_obj *o;
856         uint64_t u_count;
857         struct user_ta_ctx *utc;
858         size_t bytes;
859
860         res = tee_ta_get_current_session(&sess);
861         if (res != TEE_SUCCESS)
862                 goto exit;
863         utc = to_user_ta_ctx(sess->ctx);
864
865         res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
866         if (res != TEE_SUCCESS)
867                 goto exit;
868
869         if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
870                 res = TEE_ERROR_BAD_STATE;
871                 goto exit;
872         }
873
874         if (!(o->flags & TEE_DATA_FLAG_ACCESS_READ)) {
875                 res = TEE_ERROR_ACCESS_CONFLICT;
876                 goto exit;
877         }
878
879         /* check rights of the provided buffer */
880         res = tee_mmu_check_access_rights(utc,
881                                         TEE_MEMORY_ACCESS_WRITE |
882                                         TEE_MEMORY_ACCESS_ANY_OWNER,
883                                         (uaddr_t) data, len);
884         if (res != TEE_SUCCESS)
885                 goto exit;
886
887         bytes = len;
888         res = o->pobj->fops->read(o->fh, o->ds_pos + o->info.dataPosition,
889                                   data, &bytes);
890         if (res != TEE_SUCCESS) {
891                 EMSG("Error code=%x\n", (uint32_t)res);
892                 if (res == TEE_ERROR_CORRUPT_OBJECT) {
893                         EMSG("Object corrupt\n");
894                         tee_svc_storage_remove_corrupt_obj(sess, o);
895                 }
896                 goto exit;
897         }
898
899         o->info.dataPosition += bytes;
900
901         u_count = bytes;
902         res = tee_svc_copy_to_user(count, &u_count, sizeof(*count));
903 exit:
904         return res;
905 }
906
907 TEE_Result syscall_storage_obj_write(unsigned long obj, void *data, size_t len)
908 {
909         TEE_Result res;
910         struct tee_ta_session *sess;
911         struct tee_obj *o;
912         struct user_ta_ctx *utc;
913
914         res = tee_ta_get_current_session(&sess);
915         if (res != TEE_SUCCESS)
916                 goto exit;
917         utc = to_user_ta_ctx(sess->ctx);
918
919         res = tee_obj_get(utc, tee_svc_uref_to_vaddr(obj), &o);
920         if (res != TEE_SUCCESS)
921                 goto exit;
922
923         if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
924                 res = TEE_ERROR_BAD_STATE;
925                 goto exit;
926         }
927
928         if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) {
929                 res = TEE_ERROR_ACCESS_CONFLICT;
930                 goto exit;
931         }
932
933         /* check rights of the provided buffer */
934         res = tee_mmu_check_access_rights(utc,
935                                         TEE_MEMORY_ACCESS_READ |
936                                         TEE_MEMORY_ACCESS_ANY_OWNER,
937                                         (uaddr_t) data, len);
938         if (res != TEE_SUCCESS)
939                 goto exit;
940
941         res = o->pobj->fops->write(o->fh, o->ds_pos + o->info.dataPosition,
942                                    data, len);
943         if (res != TEE_SUCCESS)
944                 goto exit;
945
946         o->info.dataPosition += len;
947         if (o->info.dataPosition > o->info.dataSize) {
948                 res = tee_svc_storage_update_head(o, o->info.dataPosition);
949                 if (res != TEE_SUCCESS)
950                         goto exit;
951                 o->info.dataSize = o->info.dataPosition;
952         }
953
954 exit:
955         return res;
956 }
957
958 TEE_Result syscall_storage_obj_trunc(unsigned long obj, size_t len)
959 {
960         TEE_Result res;
961         struct tee_ta_session *sess;
962         struct tee_obj *o;
963         size_t off;
964         size_t attr_size;
965
966         res = tee_ta_get_current_session(&sess);
967         if (res != TEE_SUCCESS)
968                 goto exit;
969
970         res = tee_obj_get(to_user_ta_ctx(sess->ctx),
971                           tee_svc_uref_to_vaddr(obj), &o);
972         if (res != TEE_SUCCESS)
973                 goto exit;
974
975         if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
976                 res = TEE_ERROR_BAD_STATE;
977                 goto exit;
978         }
979
980         if (!(o->flags & TEE_DATA_FLAG_ACCESS_WRITE)) {
981                 res = TEE_ERROR_ACCESS_CONFLICT;
982                 goto exit;
983         }
984
985         res = tee_obj_attr_to_binary(o, NULL, &attr_size);
986         if (res != TEE_SUCCESS)
987                 goto exit;
988
989         off = sizeof(struct tee_svc_storage_head) + attr_size;
990         res = o->pobj->fops->truncate(o->fh, len + off);
991         if (res != TEE_SUCCESS) {
992                 if (res == TEE_ERROR_CORRUPT_OBJECT) {
993                         EMSG("Object corrupt\n");
994                         res = tee_svc_storage_remove_corrupt_obj(sess, o);
995                         if (res != TEE_SUCCESS)
996                                 goto exit;
997                         res = TEE_ERROR_CORRUPT_OBJECT;
998                         goto exit;
999                 } else
1000                         res = TEE_ERROR_GENERIC;
1001         }
1002
1003 exit:
1004         return res;
1005 }
1006
1007 TEE_Result syscall_storage_obj_seek(unsigned long obj, int32_t offset,
1008                                     unsigned long whence)
1009 {
1010         TEE_Result res;
1011         struct tee_ta_session *sess;
1012         struct tee_obj *o;
1013         size_t attr_size;
1014         tee_fs_off_t new_pos;
1015
1016         res = tee_ta_get_current_session(&sess);
1017         if (res != TEE_SUCCESS)
1018                 return res;
1019
1020         res = tee_obj_get(to_user_ta_ctx(sess->ctx),
1021                           tee_svc_uref_to_vaddr(obj), &o);
1022         if (res != TEE_SUCCESS)
1023                 return res;
1024
1025         if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT))
1026                 return TEE_ERROR_BAD_STATE;
1027
1028         res = tee_obj_attr_to_binary(o, NULL, &attr_size);
1029         if (res != TEE_SUCCESS)
1030                 return res;
1031
1032         switch (whence) {
1033         case TEE_DATA_SEEK_SET:
1034                 new_pos = offset;
1035                 break;
1036         case TEE_DATA_SEEK_CUR:
1037                 new_pos = o->info.dataPosition + offset;
1038                 break;
1039         case TEE_DATA_SEEK_END:
1040                 new_pos = o->info.dataSize + offset;
1041                 break;
1042         default:
1043                 return TEE_ERROR_BAD_PARAMETERS;
1044         }
1045
1046         if (new_pos < 0)
1047                 new_pos = 0;
1048
1049         if (new_pos > TEE_DATA_MAX_POSITION) {
1050                 EMSG("Position is beyond TEE_DATA_MAX_POSITION");
1051                 return TEE_ERROR_BAD_PARAMETERS;
1052         }
1053
1054         o->info.dataPosition = new_pos;
1055
1056         return TEE_SUCCESS;
1057 }
1058
1059 void tee_svc_storage_close_all_enum(struct user_ta_ctx *utc)
1060 {
1061         struct tee_storage_enum_head *eh = &utc->storage_enums;
1062
1063         /* disregard return value */
1064         while (!TAILQ_EMPTY(eh))
1065                 tee_svc_close_enum(utc, TAILQ_FIRST(eh));
1066 }