11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
2b0104773SPascal Brand /*
3b0104773SPascal Brand * Copyright (c) 2014, STMicroelectronics International N.V.
40f50ba5aSJens Wiklander * Copyright (c) 2020, 2022-2023 Linaro Limited
5b0104773SPascal Brand */
6b0104773SPascal Brand
75dfe86d0SJorge Ramirez-Ortiz #include <config.h>
85dfe86d0SJorge Ramirez-Ortiz #include <crypto/crypto.h>
9b81882b2SJerome Forissier #include <kernel/mutex.h>
10b0104773SPascal Brand #include <kernel/tee_misc.h>
112ffdd194SJens Wiklander #include <kernel/tee_ta_manager.h>
1200b3b9a2SJens Wiklander #include <kernel/ts_manager.h>
13c40a6505SJens Wiklander #include <kernel/user_access.h>
14ef142203SJens Wiklander #include <memtag.h>
1589c9728dSJens Wiklander #include <mm/vm.h>
162ffdd194SJens Wiklander #include <string.h>
17b44708c1SJerome Forissier #include <tee_api_defines_extensions.h>
182ffdd194SJens Wiklander #include <tee_api_defines.h>
192ffdd194SJens Wiklander #include <tee/tee_fs.h>
202ffdd194SJens Wiklander #include <tee/tee_obj.h>
212ffdd194SJens Wiklander #include <tee/tee_pobj.h>
222ffdd194SJens Wiklander #include <tee/tee_svc_cryp.h>
232ffdd194SJens Wiklander #include <tee/tee_svc_storage.h>
244de4bebcSJens Wiklander #include <trace.h>
25b0104773SPascal Brand
26b0104773SPascal Brand /* Header of GP formated secure storage files */
27b0104773SPascal Brand struct tee_svc_storage_head {
28d5fe340fSJens Wiklander uint32_t attr_size;
29181f0998SJens Wiklander uint32_t objectSize;
30181f0998SJens Wiklander uint32_t maxObjectSize;
3150ffad36SPascal Brand uint32_t objectUsage;
3250ffad36SPascal Brand uint32_t objectType;
3350ffad36SPascal Brand uint32_t have_attrs;
34b0104773SPascal Brand };
35b0104773SPascal Brand
36b0104773SPascal Brand struct tee_storage_enum {
37b0104773SPascal Brand TAILQ_ENTRY(tee_storage_enum) link;
3851493045SJerome Forissier struct tee_fs_dir *dir;
39b44708c1SJerome Forissier const struct tee_file_operations *fops;
40b0104773SPascal Brand };
41b0104773SPascal Brand
tee_svc_storage_get_enum(struct user_ta_ctx * utc,vaddr_t enum_id,struct tee_storage_enum ** e_out)428684fde8SJens Wiklander static TEE_Result tee_svc_storage_get_enum(struct user_ta_ctx *utc,
43589a4941SJerome Forissier vaddr_t enum_id,
44b0104773SPascal Brand struct tee_storage_enum **e_out)
45b0104773SPascal Brand {
46b0104773SPascal Brand struct tee_storage_enum *e;
47b0104773SPascal Brand
488684fde8SJens Wiklander TAILQ_FOREACH(e, &utc->storage_enums, link) {
4961ea19fdSJens Wiklander if (enum_id == (vaddr_t)e) {
50b0104773SPascal Brand *e_out = e;
51b0104773SPascal Brand return TEE_SUCCESS;
52b0104773SPascal Brand }
53b0104773SPascal Brand }
54b0104773SPascal Brand return TEE_ERROR_BAD_PARAMETERS;
55b0104773SPascal Brand }
56b0104773SPascal Brand
tee_svc_close_enum(struct user_ta_ctx * utc,struct tee_storage_enum * e)578684fde8SJens Wiklander static TEE_Result tee_svc_close_enum(struct user_ta_ctx *utc,
58b0104773SPascal Brand struct tee_storage_enum *e)
59b0104773SPascal Brand {
608684fde8SJens Wiklander if (e == NULL || utc == NULL)
61b0104773SPascal Brand return TEE_ERROR_BAD_PARAMETERS;
62b0104773SPascal Brand
638684fde8SJens Wiklander TAILQ_REMOVE(&utc->storage_enums, e, link);
64b0104773SPascal Brand
65928468cbSJerome Forissier if (e->fops)
66b0311ad8SJens Wiklander e->fops->closedir(e->dir);
67928468cbSJerome Forissier
68b0104773SPascal Brand e->dir = NULL;
69b44708c1SJerome Forissier e->fops = NULL;
70b0104773SPascal Brand
71b0104773SPascal Brand free(e);
72b0104773SPascal Brand
73b0104773SPascal Brand return TEE_SUCCESS;
74b0104773SPascal Brand }
75b0104773SPascal Brand
remove_corrupt_obj(struct user_ta_ctx * utc,struct tee_obj * o)76138c5102SJens Wiklander static void remove_corrupt_obj(struct user_ta_ctx *utc, struct tee_obj *o)
77a2e9a830SCedric Chaumont {
78b2215adfSJens Wiklander o->pobj->fops->remove(o->pobj);
79138c5102SJens Wiklander if (!(utc->ta_ctx.flags & TA_FLAG_DONT_CLOSE_HANDLE_ON_CORRUPT_OBJECT))
80138c5102SJens Wiklander tee_obj_close(utc, o);
81a2e9a830SCedric Chaumont }
82a2e9a830SCedric Chaumont
tee_svc_storage_read_head(struct tee_obj * o)83b2215adfSJens Wiklander static TEE_Result tee_svc_storage_read_head(struct tee_obj *o)
84b0104773SPascal Brand {
85b0104773SPascal Brand TEE_Result res = TEE_SUCCESS;
86b0311ad8SJens Wiklander size_t bytes;
87b0104773SPascal Brand struct tee_svc_storage_head head;
88b2215adfSJens Wiklander const struct tee_file_operations *fops = o->pobj->fops;
8940a4fd66SJens Wiklander void *attr = NULL;
90d5fe340fSJens Wiklander size_t size;
91ced8449aSBastien Simondi size_t tmp = 0;
92b0104773SPascal Brand
93b0311ad8SJens Wiklander assert(!o->fh);
94d5fe340fSJens Wiklander res = fops->open(o->pobj, &size, &o->fh);
95b0311ad8SJens Wiklander if (res != TEE_SUCCESS)
96a2e9a830SCedric Chaumont goto exit;
97b0104773SPascal Brand
98b0104773SPascal Brand /* read head */
99b0311ad8SJens Wiklander bytes = sizeof(struct tee_svc_storage_head);
100b2284b11SJens Wiklander res = fops->read(o->fh, 0, &head, NULL, &bytes);
101b0311ad8SJens Wiklander if (res != TEE_SUCCESS) {
102a2e9a830SCedric Chaumont if (res == TEE_ERROR_CORRUPT_OBJECT)
10365fe41dbSEtienne Carriere EMSG("Head corrupt");
104a2e9a830SCedric Chaumont goto exit;
105a2e9a830SCedric Chaumont }
106a2e9a830SCedric Chaumont
107ced8449aSBastien Simondi if (ADD_OVERFLOW(sizeof(head), head.attr_size, &tmp)) {
108ced8449aSBastien Simondi res = TEE_ERROR_OVERFLOW;
109ced8449aSBastien Simondi goto exit;
110ced8449aSBastien Simondi }
111ced8449aSBastien Simondi if (tmp > size) {
112ced8449aSBastien Simondi res = TEE_ERROR_CORRUPT_OBJECT;
113ced8449aSBastien Simondi goto exit;
114ced8449aSBastien Simondi }
115ced8449aSBastien Simondi
116b0311ad8SJens Wiklander if (bytes != sizeof(struct tee_svc_storage_head)) {
117b0104773SPascal Brand res = TEE_ERROR_BAD_FORMAT;
118b0104773SPascal Brand goto exit;
119b0104773SPascal Brand }
120b0104773SPascal Brand
121181f0998SJens Wiklander res = tee_obj_set_type(o, head.objectType, head.maxObjectSize);
12240a4fd66SJens Wiklander if (res != TEE_SUCCESS)
12340a4fd66SJens Wiklander goto exit;
124b0104773SPascal Brand
125ced8449aSBastien Simondi o->ds_pos = tmp;
126ced8449aSBastien Simondi
127d5fe340fSJens Wiklander if (head.attr_size) {
128d5fe340fSJens Wiklander attr = malloc(head.attr_size);
12940a4fd66SJens Wiklander if (!attr) {
130b0104773SPascal Brand res = TEE_ERROR_OUT_OF_MEMORY;
131b0104773SPascal Brand goto exit;
132b0104773SPascal Brand }
133b0104773SPascal Brand
134b0104773SPascal Brand /* read meta */
135d5fe340fSJens Wiklander bytes = head.attr_size;
136879237aeSJens Wiklander res = fops->read(o->fh, sizeof(struct tee_svc_storage_head),
137b2284b11SJens Wiklander attr, NULL, &bytes);
138*71ecb9faSPengguang Zhu if (res != TEE_SUCCESS)
13940a4fd66SJens Wiklander goto exit;
140*71ecb9faSPengguang Zhu if (bytes != head.attr_size) {
141f678d2cdSJens Wiklander res = TEE_ERROR_CORRUPT_OBJECT;
142f678d2cdSJens Wiklander goto exit;
143b0104773SPascal Brand }
144*71ecb9faSPengguang Zhu }
145b0104773SPascal Brand
146d5fe340fSJens Wiklander res = tee_obj_attr_from_binary(o, attr, head.attr_size);
14740a4fd66SJens Wiklander if (res != TEE_SUCCESS)
14840a4fd66SJens Wiklander goto exit;
14940a4fd66SJens Wiklander
150d5fe340fSJens Wiklander o->info.dataSize = size - sizeof(head) - head.attr_size;
151181f0998SJens Wiklander o->info.objectSize = head.objectSize;
1520f50ba5aSJens Wiklander o->pobj->obj_info_usage = head.objectUsage;
15340a4fd66SJens Wiklander o->info.objectType = head.objectType;
15440a4fd66SJens Wiklander o->have_attrs = head.have_attrs;
15540a4fd66SJens Wiklander
156b0104773SPascal Brand exit:
15740a4fd66SJens Wiklander free(attr);
158b0104773SPascal Brand
159b0104773SPascal Brand return res;
160b0104773SPascal Brand }
161b0104773SPascal Brand
syscall_storage_obj_open(unsigned long storage_id,void * object_id,size_t object_id_len,unsigned long flags,uint32_t * obj)162e86f1266SJens Wiklander TEE_Result syscall_storage_obj_open(unsigned long storage_id, void *object_id,
163e86f1266SJens Wiklander size_t object_id_len, unsigned long flags,
164b0104773SPascal Brand uint32_t *obj)
165b0104773SPascal Brand {
16606b0fe08SJens Wiklander const unsigned long valid_flags = TEE_DATA_FLAG_ACCESS_READ |
16706b0fe08SJens Wiklander TEE_DATA_FLAG_ACCESS_WRITE |
16806b0fe08SJens Wiklander TEE_DATA_FLAG_ACCESS_WRITE_META |
16906b0fe08SJens Wiklander TEE_DATA_FLAG_SHARE_READ |
17006b0fe08SJens Wiklander TEE_DATA_FLAG_SHARE_WRITE;
171e98e3c87SJens Wiklander const struct tee_file_operations *fops =
172e98e3c87SJens Wiklander tee_svc_storage_file_ops(storage_id);
17300b3b9a2SJens Wiklander struct ts_session *sess = ts_get_current_session();
17400b3b9a2SJens Wiklander struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
1751936dfc7SJens Wiklander TEE_Result res = TEE_SUCCESS;
1761936dfc7SJens Wiklander struct tee_pobj *po = NULL;
1771936dfc7SJens Wiklander struct tee_obj *o = NULL;
17884f78978SSeonghyun Park void *oid_bbuf = NULL;
179b0104773SPascal Brand
18006b0fe08SJens Wiklander if (flags & ~valid_flags)
18106b0fe08SJens Wiklander return TEE_ERROR_BAD_PARAMETERS;
18206b0fe08SJens Wiklander
183b44708c1SJerome Forissier if (!fops) {
18438916b4bSJerome Forissier res = TEE_ERROR_ITEM_NOT_FOUND;
185a2e9a830SCedric Chaumont goto exit;
186a2e9a830SCedric Chaumont }
187b0104773SPascal Brand
188a2e9a830SCedric Chaumont if (object_id_len > TEE_OBJECT_ID_MAX_LEN) {
189a2e9a830SCedric Chaumont res = TEE_ERROR_BAD_PARAMETERS;
190a2e9a830SCedric Chaumont goto exit;
191a2e9a830SCedric Chaumont }
192b0104773SPascal Brand
1937be18e1bSJens Wiklander res = bb_memdup_user_private(object_id, object_id_len, &oid_bbuf);
19484f78978SSeonghyun Park if (res)
19584f78978SSeonghyun Park goto exit;
196b0104773SPascal Brand
19784f78978SSeonghyun Park res = tee_pobj_get((void *)&sess->ctx->uuid, oid_bbuf,
1986885abf2SJens Wiklander object_id_len, flags, TEE_POBJ_USAGE_OPEN, fops,
1996885abf2SJens Wiklander &po);
20084f78978SSeonghyun Park bb_free(oid_bbuf, object_id_len);
201b0104773SPascal Brand if (res != TEE_SUCCESS)
202a2e9a830SCedric Chaumont goto err;
203b0104773SPascal Brand
20440a4fd66SJens Wiklander o = tee_obj_alloc();
205b0104773SPascal Brand if (o == NULL) {
2066d2f7cf2SJens Wiklander tee_pobj_release(po);
207b0104773SPascal Brand res = TEE_ERROR_OUT_OF_MEMORY;
208a2e9a830SCedric Chaumont goto err;
209b0104773SPascal Brand }
210b0104773SPascal Brand
21106b0fe08SJens Wiklander o->info.handleFlags = TEE_HANDLE_FLAG_PERSISTENT |
21206b0fe08SJens Wiklander TEE_HANDLE_FLAG_INITIALIZED | flags;
213b0104773SPascal Brand o->pobj = po;
2146d2f7cf2SJens Wiklander tee_obj_add(utc, o);
215b0104773SPascal Brand
2160f50ba5aSJens Wiklander tee_pobj_lock_usage(o->pobj);
217b2215adfSJens Wiklander res = tee_svc_storage_read_head(o);
2180f50ba5aSJens Wiklander tee_pobj_unlock_usage(o->pobj);
219b0104773SPascal Brand if (res != TEE_SUCCESS) {
220a2e9a830SCedric Chaumont if (res == TEE_ERROR_CORRUPT_OBJECT) {
2216d2f7cf2SJens Wiklander EMSG("Object corrupt");
2226d2f7cf2SJens Wiklander goto err;
223a2e9a830SCedric Chaumont }
224a2e9a830SCedric Chaumont goto oclose;
225b0104773SPascal Brand }
226b0104773SPascal Brand
227c40a6505SJens Wiklander res = copy_kaddr_to_uref(obj, o);
228b0104773SPascal Brand if (res != TEE_SUCCESS)
229a2e9a830SCedric Chaumont goto oclose;
230b0104773SPascal Brand
231b0104773SPascal Brand goto exit;
232b0104773SPascal Brand
233a2e9a830SCedric Chaumont oclose:
2348684fde8SJens Wiklander tee_obj_close(utc, o);
2356d2f7cf2SJens Wiklander o = NULL;
236b0104773SPascal Brand
237a2e9a830SCedric Chaumont err:
238a2e9a830SCedric Chaumont if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
239a2e9a830SCedric Chaumont res = TEE_ERROR_CORRUPT_OBJECT;
2406d2f7cf2SJens Wiklander if (res == TEE_ERROR_CORRUPT_OBJECT && o)
241138c5102SJens Wiklander remove_corrupt_obj(utc, o);
242b0104773SPascal Brand
243a2e9a830SCedric Chaumont exit:
244b0104773SPascal Brand return res;
245b0104773SPascal Brand }
246b0104773SPascal Brand
tee_svc_storage_init_file(struct tee_obj * o,bool overwrite,struct tee_obj * attr_o,void * data,uint32_t len)24706b0fe08SJens Wiklander static TEE_Result tee_svc_storage_init_file(struct tee_obj *o, bool overwrite,
248b2284b11SJens Wiklander struct tee_obj *attr_o,
249b2284b11SJens Wiklander void *data, uint32_t len)
25073ea1cdeSJens Wiklander {
25173ea1cdeSJens Wiklander TEE_Result res = TEE_SUCCESS;
252f22e1655SJens Wiklander struct tee_svc_storage_head head = { };
25373ea1cdeSJens Wiklander const struct tee_file_operations *fops = o->pobj->fops;
25473ea1cdeSJens Wiklander void *attr = NULL;
25573ea1cdeSJens Wiklander size_t attr_size = 0;
25673ea1cdeSJens Wiklander
25773ea1cdeSJens Wiklander if (attr_o) {
258f22e1655SJens Wiklander if (o != attr_o) {
25973ea1cdeSJens Wiklander res = tee_obj_set_type(o, attr_o->info.objectType,
260181f0998SJens Wiklander attr_o->info.maxObjectSize);
26173ea1cdeSJens Wiklander if (res)
26273ea1cdeSJens Wiklander return res;
26373ea1cdeSJens Wiklander res = tee_obj_attr_copy_from(o, attr_o);
26473ea1cdeSJens Wiklander if (res)
26573ea1cdeSJens Wiklander return res;
26673ea1cdeSJens Wiklander o->have_attrs = attr_o->have_attrs;
2670f50ba5aSJens Wiklander o->pobj->obj_info_usage = attr_o->info.objectUsage;
268181f0998SJens Wiklander o->info.objectSize = attr_o->info.objectSize;
269f22e1655SJens Wiklander }
27073ea1cdeSJens Wiklander res = tee_obj_attr_to_binary(o, NULL, &attr_size);
27173ea1cdeSJens Wiklander if (res)
27273ea1cdeSJens Wiklander return res;
27373ea1cdeSJens Wiklander if (attr_size) {
27473ea1cdeSJens Wiklander attr = malloc(attr_size);
27573ea1cdeSJens Wiklander if (!attr)
27673ea1cdeSJens Wiklander return TEE_ERROR_OUT_OF_MEMORY;
27773ea1cdeSJens Wiklander res = tee_obj_attr_to_binary(o, attr, &attr_size);
27873ea1cdeSJens Wiklander if (res != TEE_SUCCESS)
27973ea1cdeSJens Wiklander goto exit;
28073ea1cdeSJens Wiklander }
28173ea1cdeSJens Wiklander } else {
28273ea1cdeSJens Wiklander res = tee_obj_set_type(o, TEE_TYPE_DATA, 0);
28373ea1cdeSJens Wiklander if (res != TEE_SUCCESS)
28473ea1cdeSJens Wiklander goto exit;
28573ea1cdeSJens Wiklander }
28673ea1cdeSJens Wiklander
28773ea1cdeSJens Wiklander o->ds_pos = sizeof(struct tee_svc_storage_head) + attr_size;
28873ea1cdeSJens Wiklander
28973ea1cdeSJens Wiklander /* write head */
290d5fe340fSJens Wiklander head.attr_size = attr_size;
291181f0998SJens Wiklander head.objectSize = o->info.objectSize;
292181f0998SJens Wiklander head.maxObjectSize = o->info.maxObjectSize;
2930f50ba5aSJens Wiklander head.objectUsage = o->pobj->obj_info_usage;
29473ea1cdeSJens Wiklander head.objectType = o->info.objectType;
29573ea1cdeSJens Wiklander head.have_attrs = o->have_attrs;
29673ea1cdeSJens Wiklander
29706b0fe08SJens Wiklander res = fops->create(o->pobj, overwrite, &head, sizeof(head), attr,
298b2284b11SJens Wiklander attr_size, NULL, data, len, &o->fh);
29973ea1cdeSJens Wiklander
300f22e1655SJens Wiklander if (res)
301f22e1655SJens Wiklander o->ds_pos = 0;
302f22e1655SJens Wiklander else
30373ea1cdeSJens Wiklander o->info.dataSize = len;
30473ea1cdeSJens Wiklander exit:
30573ea1cdeSJens Wiklander free(attr);
30673ea1cdeSJens Wiklander return res;
30773ea1cdeSJens Wiklander }
30873ea1cdeSJens Wiklander
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)309e86f1266SJens Wiklander TEE_Result syscall_storage_obj_create(unsigned long storage_id, void *object_id,
310e86f1266SJens Wiklander size_t object_id_len, unsigned long flags,
311e86f1266SJens Wiklander unsigned long attr, void *data, size_t len,
312b0104773SPascal Brand uint32_t *obj)
313b0104773SPascal Brand {
31406b0fe08SJens Wiklander const unsigned long valid_flags = TEE_DATA_FLAG_ACCESS_READ |
31506b0fe08SJens Wiklander TEE_DATA_FLAG_ACCESS_WRITE |
31606b0fe08SJens Wiklander TEE_DATA_FLAG_ACCESS_WRITE_META |
31706b0fe08SJens Wiklander TEE_DATA_FLAG_SHARE_READ |
31806b0fe08SJens Wiklander TEE_DATA_FLAG_SHARE_WRITE |
31906b0fe08SJens Wiklander TEE_DATA_FLAG_OVERWRITE;
320e98e3c87SJens Wiklander const struct tee_file_operations *fops =
321e98e3c87SJens Wiklander tee_svc_storage_file_ops(storage_id);
32200b3b9a2SJens Wiklander struct ts_session *sess = ts_get_current_session();
32300b3b9a2SJens Wiklander struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
3241936dfc7SJens Wiklander struct tee_obj *attr_o = NULL;
3251936dfc7SJens Wiklander TEE_Result res = TEE_SUCCESS;
3261936dfc7SJens Wiklander struct tee_pobj *po = NULL;
3271936dfc7SJens Wiklander struct tee_obj *o = NULL;
32884f78978SSeonghyun Park void *oid_bbuf = NULL;
329b0104773SPascal Brand
33006b0fe08SJens Wiklander if (flags & ~valid_flags)
33106b0fe08SJens Wiklander return TEE_ERROR_BAD_PARAMETERS;
33206b0fe08SJens Wiklander
333b44708c1SJerome Forissier if (!fops)
33438916b4bSJerome Forissier return TEE_ERROR_ITEM_NOT_FOUND;
335b0104773SPascal Brand
336b0104773SPascal Brand if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
337b0104773SPascal Brand return TEE_ERROR_BAD_PARAMETERS;
338b0104773SPascal Brand
339ef142203SJens Wiklander object_id = memtag_strip_tag(object_id);
340ef142203SJens Wiklander data = memtag_strip_tag(data);
341ef142203SJens Wiklander
342b2284b11SJens Wiklander /* Check presence of optional buffer */
343b2284b11SJens Wiklander if (len && !data)
344b2284b11SJens Wiklander return TEE_ERROR_BAD_PARAMETERS;
345b2284b11SJens Wiklander
3467be18e1bSJens Wiklander res = bb_memdup_user_private(object_id, object_id_len, &oid_bbuf);
34784f78978SSeonghyun Park if (res)
34884f78978SSeonghyun Park return res;
349b0104773SPascal Brand
35084f78978SSeonghyun Park res = tee_pobj_get((void *)&sess->ctx->uuid, oid_bbuf,
3516885abf2SJens Wiklander object_id_len, flags, TEE_POBJ_USAGE_CREATE,
3526885abf2SJens Wiklander fops, &po);
35384f78978SSeonghyun Park bb_free(oid_bbuf, object_id_len);
354b0104773SPascal Brand if (res != TEE_SUCCESS)
35584431ae3SCedric Chaumont goto err;
356b0104773SPascal Brand
35784431ae3SCedric Chaumont if (attr != TEE_HANDLE_NULL) {
358c40a6505SJens Wiklander res = tee_obj_get(utc, uref_to_vaddr(attr), &attr_o);
35984431ae3SCedric Chaumont if (res != TEE_SUCCESS)
36084431ae3SCedric Chaumont goto err;
3615e817523SJens Wiklander /* The supplied handle must be one of an initialized object */
3625e817523SJens Wiklander if (!(attr_o->info.handleFlags & TEE_HANDLE_FLAG_INITIALIZED)) {
3635e817523SJens Wiklander res = TEE_ERROR_BAD_PARAMETERS;
3645e817523SJens Wiklander goto err;
3655e817523SJens Wiklander }
36684431ae3SCedric Chaumont }
36784431ae3SCedric Chaumont
368f22e1655SJens Wiklander if (!obj && attr_o &&
369f22e1655SJens Wiklander !(attr_o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
370f22e1655SJens Wiklander /*
371f22e1655SJens Wiklander * The caller expects the supplied attributes handle to be
372f22e1655SJens Wiklander * transformed into a persistent object.
3730f50ba5aSJens Wiklander *
3740f50ba5aSJens Wiklander * Persistent object keeps the objectUsage field in the
3750f50ba5aSJens Wiklander * pobj so move the field below.
376f22e1655SJens Wiklander */
377f22e1655SJens Wiklander uint32_t saved_flags = attr_o->info.handleFlags;
378f22e1655SJens Wiklander
379f22e1655SJens Wiklander attr_o->info.handleFlags = TEE_HANDLE_FLAG_PERSISTENT |
380f22e1655SJens Wiklander TEE_HANDLE_FLAG_INITIALIZED | flags;
381f22e1655SJens Wiklander attr_o->pobj = po;
3820f50ba5aSJens Wiklander po->obj_info_usage = attr_o->info.objectUsage;
383f22e1655SJens Wiklander res = tee_svc_storage_init_file(attr_o,
384f22e1655SJens Wiklander flags & TEE_DATA_FLAG_OVERWRITE,
385f22e1655SJens Wiklander attr_o, data, len);
386f22e1655SJens Wiklander if (res) {
387f22e1655SJens Wiklander attr_o->info.handleFlags = saved_flags;
388f22e1655SJens Wiklander attr_o->pobj = NULL;
389f22e1655SJens Wiklander goto err;
390f22e1655SJens Wiklander }
3910f50ba5aSJens Wiklander attr_o->info.objectUsage = 0;
392f22e1655SJens Wiklander } else {
393f22e1655SJens Wiklander o = tee_obj_alloc();
394f22e1655SJens Wiklander if (!o) {
395f22e1655SJens Wiklander res = TEE_ERROR_OUT_OF_MEMORY;
396f22e1655SJens Wiklander goto err;
397f22e1655SJens Wiklander }
398f22e1655SJens Wiklander
399f22e1655SJens Wiklander o->info.handleFlags = TEE_HANDLE_FLAG_PERSISTENT |
400f22e1655SJens Wiklander TEE_HANDLE_FLAG_INITIALIZED | flags;
401f22e1655SJens Wiklander o->pobj = po;
402f22e1655SJens Wiklander
403f22e1655SJens Wiklander res = tee_svc_storage_init_file(o,
404f22e1655SJens Wiklander flags & TEE_DATA_FLAG_OVERWRITE,
40506b0fe08SJens Wiklander attr_o, data, len);
40684431ae3SCedric Chaumont if (res != TEE_SUCCESS)
40784431ae3SCedric Chaumont goto err;
40884431ae3SCedric Chaumont
409a7337d86SEtienne Carriere po = NULL; /* o owns it from now on */
4108684fde8SJens Wiklander tee_obj_add(utc, o);
411b0104773SPascal Brand
412f22e1655SJens Wiklander if (obj) {
413c40a6505SJens Wiklander res = copy_kaddr_to_uref(obj, o);
414b0104773SPascal Brand if (res != TEE_SUCCESS)
41584431ae3SCedric Chaumont goto oclose;
416f22e1655SJens Wiklander }
417b0104773SPascal Brand
41863146177SJens Wiklander tee_pobj_create_final(o->pobj);
419f22e1655SJens Wiklander
420f22e1655SJens Wiklander if (!obj)
421f22e1655SJens Wiklander tee_obj_close(utc, o);
422f22e1655SJens Wiklander }
423f22e1655SJens Wiklander
424b2215adfSJens Wiklander return TEE_SUCCESS;
42584431ae3SCedric Chaumont
42684431ae3SCedric Chaumont oclose:
4278684fde8SJens Wiklander tee_obj_close(utc, o);
428b2215adfSJens Wiklander return res;
42984431ae3SCedric Chaumont
43084431ae3SCedric Chaumont err:
431a2e9a830SCedric Chaumont if (res == TEE_ERROR_NO_DATA || res == TEE_ERROR_BAD_FORMAT)
432a2e9a830SCedric Chaumont res = TEE_ERROR_CORRUPT_OBJECT;
433b2215adfSJens Wiklander if (res == TEE_ERROR_CORRUPT_OBJECT && po)
434b2215adfSJens Wiklander fops->remove(po);
43541b29406SOliver Chiang if (o) {
436b0311ad8SJens Wiklander fops->close(&o->fh);
43741b29406SOliver Chiang tee_obj_free(o);
43841b29406SOliver Chiang }
439b0104773SPascal Brand if (po)
440b0104773SPascal Brand tee_pobj_release(po);
44184431ae3SCedric Chaumont
442b0104773SPascal Brand return res;
443b0104773SPascal Brand }
444b0104773SPascal Brand
syscall_storage_obj_del(unsigned long obj)445e86f1266SJens Wiklander TEE_Result syscall_storage_obj_del(unsigned long obj)
446b0104773SPascal Brand {
44700b3b9a2SJens Wiklander struct ts_session *sess = ts_get_current_session();
44800b3b9a2SJens Wiklander struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
44900b3b9a2SJens Wiklander TEE_Result res = TEE_SUCCESS;
45000b3b9a2SJens Wiklander struct tee_obj *o = NULL;
451b0104773SPascal Brand
452c40a6505SJens Wiklander res = tee_obj_get(utc, uref_to_vaddr(obj), &o);
453b0104773SPascal Brand if (res != TEE_SUCCESS)
454b0104773SPascal Brand return res;
455b0104773SPascal Brand
45606b0fe08SJens Wiklander if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE_META))
457b0104773SPascal Brand return TEE_ERROR_ACCESS_CONFLICT;
458b0104773SPascal Brand
459b0104773SPascal Brand if (o->pobj == NULL || o->pobj->obj_id == NULL)
460b0104773SPascal Brand return TEE_ERROR_BAD_STATE;
461b0104773SPascal Brand
4625dfe86d0SJorge Ramirez-Ortiz if (IS_ENABLED(CFG_NXP_SE05X)) {
4636301ca1cSJorge Ramirez-Ortiz /* Cryptographic layer house-keeping */
4646301ca1cSJorge Ramirez-Ortiz res = crypto_storage_obj_del(o);
4656301ca1cSJorge Ramirez-Ortiz if (res)
4666301ca1cSJorge Ramirez-Ortiz return res;
4675dfe86d0SJorge Ramirez-Ortiz }
4685dfe86d0SJorge Ramirez-Ortiz
469b2215adfSJens Wiklander res = o->pobj->fops->remove(o->pobj);
4708684fde8SJens Wiklander tee_obj_close(utc, o);
471b0104773SPascal Brand
472b0311ad8SJens Wiklander return res;
473b0104773SPascal Brand }
474b0104773SPascal Brand
syscall_storage_obj_rename(unsigned long obj,void * object_id,size_t object_id_len)475e86f1266SJens Wiklander TEE_Result syscall_storage_obj_rename(unsigned long obj, void *object_id,
476e86f1266SJens Wiklander size_t object_id_len)
477b0104773SPascal Brand {
4781936dfc7SJens Wiklander const struct tee_file_operations *fops = NULL;
47900b3b9a2SJens Wiklander struct ts_session *sess = ts_get_current_session();
48000b3b9a2SJens Wiklander struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
4811936dfc7SJens Wiklander TEE_Result res = TEE_SUCCESS;
482b0104773SPascal Brand struct tee_pobj *po = NULL;
4831936dfc7SJens Wiklander struct tee_obj *o = NULL;
484b0104773SPascal Brand char *new_file = NULL;
485b0104773SPascal Brand char *old_file = NULL;
48684f78978SSeonghyun Park void *oid_bbuf = NULL;
487b0104773SPascal Brand
488b0104773SPascal Brand if (object_id_len > TEE_OBJECT_ID_MAX_LEN)
489b0104773SPascal Brand return TEE_ERROR_BAD_PARAMETERS;
490b0104773SPascal Brand
491c40a6505SJens Wiklander res = tee_obj_get(utc, uref_to_vaddr(obj), &o);
492b0104773SPascal Brand if (res != TEE_SUCCESS)
493b0104773SPascal Brand return res;
494b0104773SPascal Brand
495a2e9a830SCedric Chaumont if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
496a2e9a830SCedric Chaumont res = TEE_ERROR_BAD_STATE;
497a2e9a830SCedric Chaumont goto exit;
498a2e9a830SCedric Chaumont }
499a2e9a830SCedric Chaumont
50006b0fe08SJens Wiklander if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE_META)) {
501b0104773SPascal Brand res = TEE_ERROR_BAD_STATE;
502b0104773SPascal Brand goto exit;
503b0104773SPascal Brand }
504b0104773SPascal Brand
505a2e9a830SCedric Chaumont if (o->pobj == NULL || o->pobj->obj_id == NULL) {
506a2e9a830SCedric Chaumont res = TEE_ERROR_BAD_STATE;
507a2e9a830SCedric Chaumont goto exit;
508a2e9a830SCedric Chaumont }
509b0104773SPascal Brand
5107be18e1bSJens Wiklander res = bb_memdup_user_private(object_id, object_id_len, &oid_bbuf);
51184f78978SSeonghyun Park if (res)
512b0104773SPascal Brand goto exit;
513b0104773SPascal Brand
514b0104773SPascal Brand /* reserve dest name */
515b44708c1SJerome Forissier fops = o->pobj->fops;
51684f78978SSeonghyun Park res = tee_pobj_get((void *)&sess->ctx->uuid, oid_bbuf,
517b44708c1SJerome Forissier object_id_len, TEE_DATA_FLAG_ACCESS_WRITE_META,
5186885abf2SJens Wiklander TEE_POBJ_USAGE_RENAME, fops, &po);
51984f78978SSeonghyun Park bb_free(oid_bbuf, object_id_len);
520b0104773SPascal Brand if (res != TEE_SUCCESS)
521b0104773SPascal Brand goto exit;
522b0104773SPascal Brand
523b0104773SPascal Brand /* move */
524b2215adfSJens Wiklander res = fops->rename(o->pobj, po, false /* no overwrite */);
525b1183340SJerome Forissier if (res)
526b0104773SPascal Brand goto exit;
527b0104773SPascal Brand
5286d628a81SJens Wiklander res = tee_pobj_rename(o->pobj, po->obj_id, po->obj_id_len);
529b0104773SPascal Brand
530b0104773SPascal Brand exit:
531b0104773SPascal Brand tee_pobj_release(po);
532b0104773SPascal Brand
533b0104773SPascal Brand free(new_file);
534b0104773SPascal Brand free(old_file);
535b0104773SPascal Brand
536b0104773SPascal Brand return res;
537b0104773SPascal Brand }
538b0104773SPascal Brand
syscall_storage_alloc_enum(uint32_t * obj_enum)539453a5030SJerome Forissier TEE_Result syscall_storage_alloc_enum(uint32_t *obj_enum)
540b0104773SPascal Brand {
54100b3b9a2SJens Wiklander struct ts_session *sess = ts_get_current_session();
54200b3b9a2SJens Wiklander struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
54300b3b9a2SJens Wiklander struct tee_storage_enum *e = NULL;
544b0104773SPascal Brand
545b0104773SPascal Brand if (obj_enum == NULL)
546b0104773SPascal Brand return TEE_ERROR_BAD_PARAMETERS;
547b0104773SPascal Brand
548b0104773SPascal Brand e = malloc(sizeof(struct tee_storage_enum));
549b0104773SPascal Brand if (e == NULL)
550b0104773SPascal Brand return TEE_ERROR_OUT_OF_MEMORY;
551b0104773SPascal Brand
552b0104773SPascal Brand e->dir = NULL;
553b44708c1SJerome Forissier e->fops = NULL;
5548684fde8SJens Wiklander TAILQ_INSERT_TAIL(&utc->storage_enums, e, link);
555b0104773SPascal Brand
556c40a6505SJens Wiklander return copy_kaddr_to_uref(obj_enum, e);
557b0104773SPascal Brand }
558b0104773SPascal Brand
syscall_storage_free_enum(unsigned long obj_enum)559e86f1266SJens Wiklander TEE_Result syscall_storage_free_enum(unsigned long obj_enum)
560b0104773SPascal Brand {
56100b3b9a2SJens Wiklander struct ts_session *sess = ts_get_current_session();
56200b3b9a2SJens Wiklander struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
56300b3b9a2SJens Wiklander struct tee_storage_enum *e = NULL;
56400b3b9a2SJens Wiklander TEE_Result res = TEE_SUCCESS;
565b0104773SPascal Brand
5668684fde8SJens Wiklander res = tee_svc_storage_get_enum(utc,
567c40a6505SJens Wiklander uref_to_vaddr(obj_enum), &e);
568b0104773SPascal Brand if (res != TEE_SUCCESS)
569b0104773SPascal Brand return res;
570b0104773SPascal Brand
5718684fde8SJens Wiklander return tee_svc_close_enum(utc, e);
572b0104773SPascal Brand }
573b0104773SPascal Brand
syscall_storage_reset_enum(unsigned long obj_enum)574e86f1266SJens Wiklander TEE_Result syscall_storage_reset_enum(unsigned long obj_enum)
575b0104773SPascal Brand {
57600b3b9a2SJens Wiklander struct ts_session *sess = ts_get_current_session();
57700b3b9a2SJens Wiklander struct tee_storage_enum *e = NULL;
57800b3b9a2SJens Wiklander TEE_Result res = TEE_SUCCESS;
579b0104773SPascal Brand
5808684fde8SJens Wiklander res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
581c40a6505SJens Wiklander uref_to_vaddr(obj_enum), &e);
582b0104773SPascal Brand if (res != TEE_SUCCESS)
583b0104773SPascal Brand return res;
584b0104773SPascal Brand
58528ad73f9SJerome Forissier if (e->fops) {
586b0311ad8SJens Wiklander e->fops->closedir(e->dir);
587928468cbSJerome Forissier e->fops = NULL;
588b0104773SPascal Brand e->dir = NULL;
58928ad73f9SJerome Forissier }
59028ad73f9SJerome Forissier assert(!e->dir);
591b0104773SPascal Brand
592b0104773SPascal Brand return TEE_SUCCESS;
593b0104773SPascal Brand }
594b0104773SPascal Brand
syscall_storage_start_enum(unsigned long obj_enum,unsigned long storage_id)595e86f1266SJens Wiklander TEE_Result syscall_storage_start_enum(unsigned long obj_enum,
596e86f1266SJens Wiklander unsigned long storage_id)
597b0104773SPascal Brand {
59800b3b9a2SJens Wiklander struct ts_session *sess = ts_get_current_session();
59900b3b9a2SJens Wiklander struct tee_storage_enum *e = NULL;
60000b3b9a2SJens Wiklander TEE_Result res = TEE_SUCCESS;
601e98e3c87SJens Wiklander const struct tee_file_operations *fops =
602e98e3c87SJens Wiklander tee_svc_storage_file_ops(storage_id);
603b0104773SPascal Brand
6048684fde8SJens Wiklander res = tee_svc_storage_get_enum(to_user_ta_ctx(sess->ctx),
605c40a6505SJens Wiklander uref_to_vaddr(obj_enum), &e);
606b0104773SPascal Brand if (res != TEE_SUCCESS)
607b0104773SPascal Brand return res;
608b0104773SPascal Brand
609be847addSJoakim Bech if (e->dir) {
610be847addSJoakim Bech e->fops->closedir(e->dir);
611be847addSJoakim Bech e->dir = NULL;
612be847addSJoakim Bech }
613be847addSJoakim Bech
614b44708c1SJerome Forissier if (!fops)
61538916b4bSJerome Forissier return TEE_ERROR_ITEM_NOT_FOUND;
616b0104773SPascal Brand
617b44708c1SJerome Forissier e->fops = fops;
618be847addSJoakim Bech
619b2215adfSJens Wiklander return fops->opendir(&sess->ctx->uuid, &e->dir);
620b0104773SPascal Brand }
621b0104773SPascal Brand
syscall_storage_next_enum(unsigned long obj_enum,struct utee_object_info * info,void * obj_id,uint64_t * len)622e86f1266SJens Wiklander TEE_Result syscall_storage_next_enum(unsigned long obj_enum,
62375d6a373SJens Wiklander struct utee_object_info *info,
62475d6a373SJens Wiklander void *obj_id, uint64_t *len)
625b0104773SPascal Brand {
62600b3b9a2SJens Wiklander struct ts_session *sess = ts_get_current_session();
62700b3b9a2SJens Wiklander struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
6281936dfc7SJens Wiklander struct tee_storage_enum *e = NULL;
6291936dfc7SJens Wiklander struct tee_fs_dirent *d = NULL;
630b0104773SPascal Brand TEE_Result res = TEE_SUCCESS;
631b0104773SPascal Brand struct tee_obj *o = NULL;
6321936dfc7SJens Wiklander uint64_t l = 0;
63384f78978SSeonghyun Park struct utee_object_info bbuf = { };
634b0104773SPascal Brand
635c40a6505SJens Wiklander res = tee_svc_storage_get_enum(utc, uref_to_vaddr(obj_enum), &e);
636b0104773SPascal Brand if (res != TEE_SUCCESS)
637a2e9a830SCedric Chaumont goto exit;
638b0104773SPascal Brand
639ef142203SJens Wiklander info = memtag_strip_tag(info);
640ef142203SJens Wiklander obj_id = memtag_strip_tag(obj_id);
641ef142203SJens Wiklander
642b0104773SPascal Brand /* check rights of the provided buffers */
64389c9728dSJens Wiklander res = vm_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_WRITE,
64475d6a373SJens Wiklander (uaddr_t)info, sizeof(*info));
645b0104773SPascal Brand if (res != TEE_SUCCESS)
646a2e9a830SCedric Chaumont goto exit;
647b0104773SPascal Brand
64889c9728dSJens Wiklander res = vm_check_access_rights(&utc->uctx, TEE_MEMORY_ACCESS_WRITE,
64989c9728dSJens Wiklander (uaddr_t)obj_id, TEE_OBJECT_ID_MAX_LEN);
650b0104773SPascal Brand if (res != TEE_SUCCESS)
651a2e9a830SCedric Chaumont goto exit;
652b0104773SPascal Brand
653b44708c1SJerome Forissier if (!e->fops) {
654b44708c1SJerome Forissier res = TEE_ERROR_ITEM_NOT_FOUND;
655b44708c1SJerome Forissier goto exit;
656b44708c1SJerome Forissier }
657b44708c1SJerome Forissier
658b0311ad8SJens Wiklander res = e->fops->readdir(e->dir, &d);
659b0311ad8SJens Wiklander if (res != TEE_SUCCESS)
660a2e9a830SCedric Chaumont goto exit;
661b0104773SPascal Brand
66240a4fd66SJens Wiklander o = tee_obj_alloc();
663b0104773SPascal Brand if (o == NULL) {
664b0104773SPascal Brand res = TEE_ERROR_OUT_OF_MEMORY;
665b0104773SPascal Brand goto exit;
666b0104773SPascal Brand }
667b0104773SPascal Brand
668928efd06SJens Wiklander res = tee_pobj_get(&sess->ctx->uuid, d->oid, d->oidlen, 0,
669928efd06SJens Wiklander TEE_POBJ_USAGE_ENUM, e->fops, &o->pobj);
670928efd06SJens Wiklander if (res)
671b0104773SPascal Brand goto exit;
672b0104773SPascal Brand
673928efd06SJens Wiklander o->info.handleFlags = o->pobj->flags | TEE_HANDLE_FLAG_PERSISTENT |
674928efd06SJens Wiklander TEE_HANDLE_FLAG_INITIALIZED;
675a2e9a830SCedric Chaumont
6760f50ba5aSJens Wiklander tee_pobj_lock_usage(o->pobj);
677b2215adfSJens Wiklander res = tee_svc_storage_read_head(o);
67884f78978SSeonghyun Park bbuf = (struct utee_object_info){
67975d6a373SJens Wiklander .obj_type = o->info.objectType,
68075d6a373SJens Wiklander .obj_size = o->info.objectSize,
68175d6a373SJens Wiklander .max_obj_size = o->info.maxObjectSize,
6820f50ba5aSJens Wiklander .obj_usage = o->pobj->obj_info_usage,
68375d6a373SJens Wiklander .data_size = o->info.dataSize,
68475d6a373SJens Wiklander .data_pos = o->info.dataPosition,
68575d6a373SJens Wiklander .handle_flags = o->info.handleFlags,
68675d6a373SJens Wiklander };
6870f50ba5aSJens Wiklander tee_pobj_unlock_usage(o->pobj);
6880f50ba5aSJens Wiklander if (res != TEE_SUCCESS)
6890f50ba5aSJens Wiklander goto exit;
6900f50ba5aSJens Wiklander
69184f78978SSeonghyun Park res = copy_to_user(info, &bbuf, sizeof(bbuf));
69284f78978SSeonghyun Park if (res)
69384f78978SSeonghyun Park goto exit;
69484f78978SSeonghyun Park
69584f78978SSeonghyun Park res = copy_to_user(obj_id, o->pobj->obj_id, o->pobj->obj_id_len);
69684f78978SSeonghyun Park if (res)
69784f78978SSeonghyun Park goto exit;
698b0104773SPascal Brand
699e86f1266SJens Wiklander l = o->pobj->obj_id_len;
700e12c9f67SJens Wiklander res = copy_to_user_private(len, &l, sizeof(*len));
701b0104773SPascal Brand
702b0104773SPascal Brand exit:
703b0104773SPascal Brand if (o) {
70419cb73ddSJens Wiklander if (o->pobj) {
70519cb73ddSJens Wiklander o->pobj->fops->close(&o->fh);
706928efd06SJens Wiklander tee_pobj_release(o->pobj);
70719cb73ddSJens Wiklander }
70840a4fd66SJens Wiklander tee_obj_free(o);
709b0104773SPascal Brand }
710b0104773SPascal Brand
711b0104773SPascal Brand return res;
712b0104773SPascal Brand }
713b0104773SPascal Brand
syscall_storage_obj_read(unsigned long obj,void * data,size_t len,uint64_t * count)714e86f1266SJens Wiklander TEE_Result syscall_storage_obj_read(unsigned long obj, void *data, size_t len,
715e86f1266SJens Wiklander uint64_t *count)
716b0104773SPascal Brand {
71700b3b9a2SJens Wiklander struct ts_session *sess = ts_get_current_session();
71800b3b9a2SJens Wiklander struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
7191936dfc7SJens Wiklander TEE_Result res = TEE_SUCCESS;
7201936dfc7SJens Wiklander struct tee_obj *o = NULL;
7211936dfc7SJens Wiklander uint64_t u_count = 0;
722ced8449aSBastien Simondi size_t pos_tmp = 0;
7231936dfc7SJens Wiklander size_t bytes = 0;
724b0104773SPascal Brand
725c40a6505SJens Wiklander res = tee_obj_get(utc, uref_to_vaddr(obj), &o);
726b0104773SPascal Brand if (res != TEE_SUCCESS)
727a2e9a830SCedric Chaumont goto exit;
728b0104773SPascal Brand
729a2e9a830SCedric Chaumont if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
730a2e9a830SCedric Chaumont res = TEE_ERROR_BAD_STATE;
731a2e9a830SCedric Chaumont goto exit;
732a2e9a830SCedric Chaumont }
733a2e9a830SCedric Chaumont
73406b0fe08SJens Wiklander if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_READ)) {
735a2e9a830SCedric Chaumont res = TEE_ERROR_ACCESS_CONFLICT;
736a2e9a830SCedric Chaumont goto exit;
737a2e9a830SCedric Chaumont }
738b0104773SPascal Brand
739ced8449aSBastien Simondi /* Guard o->info.dataPosition += bytes below from overflowing */
740ced8449aSBastien Simondi if (ADD_OVERFLOW(o->info.dataPosition, len, &pos_tmp)) {
741ced8449aSBastien Simondi res = TEE_ERROR_OVERFLOW;
742ced8449aSBastien Simondi goto exit;
743ced8449aSBastien Simondi }
744ced8449aSBastien Simondi
745ef142203SJens Wiklander data = memtag_strip_tag(data);
746b0104773SPascal Brand
747b0311ad8SJens Wiklander bytes = len;
748ced8449aSBastien Simondi if (ADD_OVERFLOW(o->ds_pos, o->info.dataPosition, &pos_tmp)) {
749ced8449aSBastien Simondi res = TEE_ERROR_OVERFLOW;
750ced8449aSBastien Simondi goto exit;
751ced8449aSBastien Simondi }
752b2284b11SJens Wiklander res = o->pobj->fops->read(o->fh, pos_tmp, NULL, data, &bytes);
753b0311ad8SJens Wiklander if (res != TEE_SUCCESS) {
754a2e9a830SCedric Chaumont if (res == TEE_ERROR_CORRUPT_OBJECT) {
75565fe41dbSEtienne Carriere EMSG("Object corrupt");
756138c5102SJens Wiklander remove_corrupt_obj(utc, o);
757a2e9a830SCedric Chaumont }
758a2e9a830SCedric Chaumont goto exit;
759a2e9a830SCedric Chaumont }
760b0104773SPascal Brand
761b0311ad8SJens Wiklander o->info.dataPosition += bytes;
762b0311ad8SJens Wiklander
763b0311ad8SJens Wiklander u_count = bytes;
764e12c9f67SJens Wiklander res = copy_to_user_private(count, &u_count, sizeof(*count));
765a2e9a830SCedric Chaumont exit:
766a2e9a830SCedric Chaumont return res;
767b0104773SPascal Brand }
768b0104773SPascal Brand
syscall_storage_obj_write(unsigned long obj,void * data,size_t len)769e86f1266SJens Wiklander TEE_Result syscall_storage_obj_write(unsigned long obj, void *data, size_t len)
770b0104773SPascal Brand {
77100b3b9a2SJens Wiklander struct ts_session *sess = ts_get_current_session();
77200b3b9a2SJens Wiklander struct user_ta_ctx *utc = to_user_ta_ctx(sess->ctx);
7731936dfc7SJens Wiklander TEE_Result res = TEE_SUCCESS;
7741936dfc7SJens Wiklander struct tee_obj *o = NULL;
775ced8449aSBastien Simondi size_t pos_tmp = 0;
776b0104773SPascal Brand
777c40a6505SJens Wiklander res = tee_obj_get(utc, uref_to_vaddr(obj), &o);
778b0104773SPascal Brand if (res != TEE_SUCCESS)
779a2e9a830SCedric Chaumont goto exit;
780b0104773SPascal Brand
781a2e9a830SCedric Chaumont if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
782a2e9a830SCedric Chaumont res = TEE_ERROR_BAD_STATE;
783a2e9a830SCedric Chaumont goto exit;
784a2e9a830SCedric Chaumont }
785a2e9a830SCedric Chaumont
78606b0fe08SJens Wiklander if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE)) {
787a2e9a830SCedric Chaumont res = TEE_ERROR_ACCESS_CONFLICT;
788a2e9a830SCedric Chaumont goto exit;
789a2e9a830SCedric Chaumont }
790b0104773SPascal Brand
791ced8449aSBastien Simondi /* Guard o->info.dataPosition += bytes below from overflowing */
792ced8449aSBastien Simondi if (ADD_OVERFLOW(o->info.dataPosition, len, &pos_tmp)) {
793ced8449aSBastien Simondi res = TEE_ERROR_OVERFLOW;
794ced8449aSBastien Simondi goto exit;
795ced8449aSBastien Simondi }
796ced8449aSBastien Simondi
797ef142203SJens Wiklander data = memtag_strip_tag(data);
798b0104773SPascal Brand
799ced8449aSBastien Simondi if (ADD_OVERFLOW(o->ds_pos, o->info.dataPosition, &pos_tmp)) {
800ced8449aSBastien Simondi res = TEE_ERROR_ACCESS_CONFLICT;
801ced8449aSBastien Simondi goto exit;
802ced8449aSBastien Simondi }
803b2284b11SJens Wiklander res = o->pobj->fops->write(o->fh, pos_tmp, NULL, data, len);
804de1cd722SJens Wiklander if (res != TEE_SUCCESS) {
805de1cd722SJens Wiklander if (res == TEE_ERROR_CORRUPT_OBJECT) {
806de1cd722SJens Wiklander EMSG("Object corrupt");
807138c5102SJens Wiklander remove_corrupt_obj(utc, o);
808de1cd722SJens Wiklander }
809a2e9a830SCedric Chaumont goto exit;
810de1cd722SJens Wiklander }
811b0104773SPascal Brand
812b0104773SPascal Brand o->info.dataPosition += len;
813d5fe340fSJens Wiklander if (o->info.dataPosition > o->info.dataSize)
814b0104773SPascal Brand o->info.dataSize = o->info.dataPosition;
815b0104773SPascal Brand
816a2e9a830SCedric Chaumont exit:
817a2e9a830SCedric Chaumont return res;
818b0104773SPascal Brand }
819b0104773SPascal Brand
tee_svc_storage_write_usage(struct tee_obj * o,uint32_t usage)8200f50ba5aSJens Wiklander TEE_Result tee_svc_storage_write_usage(struct tee_obj *o, uint32_t usage)
8210f50ba5aSJens Wiklander {
8220f50ba5aSJens Wiklander const size_t pos = offsetof(struct tee_svc_storage_head, objectUsage);
8230f50ba5aSJens Wiklander
8240f50ba5aSJens Wiklander return o->pobj->fops->write(o->fh, pos, &usage, NULL, sizeof(usage));
8250f50ba5aSJens Wiklander }
8260f50ba5aSJens Wiklander
syscall_storage_obj_trunc(unsigned long obj,size_t len)827e86f1266SJens Wiklander TEE_Result syscall_storage_obj_trunc(unsigned long obj, size_t len)
828b0104773SPascal Brand {
82900b3b9a2SJens Wiklander struct ts_session *sess = ts_get_current_session();
83000b3b9a2SJens Wiklander TEE_Result res = TEE_SUCCESS;
83100b3b9a2SJens Wiklander struct tee_obj *o = NULL;
83200b3b9a2SJens Wiklander size_t off = 0;
83300b3b9a2SJens Wiklander size_t attr_size = 0;
834b0104773SPascal Brand
835c40a6505SJens Wiklander res = tee_obj_get(to_user_ta_ctx(sess->ctx), uref_to_vaddr(obj), &o);
836b0104773SPascal Brand if (res != TEE_SUCCESS)
837a2e9a830SCedric Chaumont goto exit;
838b0104773SPascal Brand
839a2e9a830SCedric Chaumont if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT)) {
840a2e9a830SCedric Chaumont res = TEE_ERROR_BAD_STATE;
841a2e9a830SCedric Chaumont goto exit;
842a2e9a830SCedric Chaumont }
843a2e9a830SCedric Chaumont
84406b0fe08SJens Wiklander if (!(o->info.handleFlags & TEE_DATA_FLAG_ACCESS_WRITE)) {
845a2e9a830SCedric Chaumont res = TEE_ERROR_ACCESS_CONFLICT;
846a2e9a830SCedric Chaumont goto exit;
847a2e9a830SCedric Chaumont }
848a2e9a830SCedric Chaumont
84940a4fd66SJens Wiklander res = tee_obj_attr_to_binary(o, NULL, &attr_size);
85053620831SJerome Forissier if (res != TEE_SUCCESS)
85140a4fd66SJens Wiklander goto exit;
85240a4fd66SJens Wiklander
853ced8449aSBastien Simondi if (ADD_OVERFLOW(sizeof(struct tee_svc_storage_head), attr_size,
854ced8449aSBastien Simondi &off)) {
855ced8449aSBastien Simondi res = TEE_ERROR_OVERFLOW;
856ced8449aSBastien Simondi goto exit;
857ced8449aSBastien Simondi }
858ced8449aSBastien Simondi if (ADD_OVERFLOW(len, off, &off)) {
859ced8449aSBastien Simondi res = TEE_ERROR_OVERFLOW;
860ced8449aSBastien Simondi goto exit;
861ced8449aSBastien Simondi }
862ced8449aSBastien Simondi res = o->pobj->fops->truncate(o->fh, off);
86313e224aaSChristopher Tam switch (res) {
86413e224aaSChristopher Tam case TEE_SUCCESS:
86513e224aaSChristopher Tam o->info.dataSize = len;
86613e224aaSChristopher Tam break;
86713e224aaSChristopher Tam case TEE_ERROR_CORRUPT_OBJECT:
86813e224aaSChristopher Tam EMSG("Object corruption");
869138c5102SJens Wiklander remove_corrupt_obj(to_user_ta_ctx(sess->ctx), o);
87013e224aaSChristopher Tam break;
87113e224aaSChristopher Tam default:
872a2e9a830SCedric Chaumont res = TEE_ERROR_GENERIC;
87313e224aaSChristopher Tam break;
874a2e9a830SCedric Chaumont }
875b0104773SPascal Brand
876a2e9a830SCedric Chaumont exit:
877a2e9a830SCedric Chaumont return res;
878b0104773SPascal Brand }
879b0104773SPascal Brand
syscall_storage_obj_seek(unsigned long obj,int32_t offset,unsigned long whence)8809102ce21SJens Wiklander TEE_Result syscall_storage_obj_seek(unsigned long obj, int32_t offset,
881e86f1266SJens Wiklander unsigned long whence)
882b0104773SPascal Brand {
88300b3b9a2SJens Wiklander struct ts_session *sess = ts_get_current_session();
88400b3b9a2SJens Wiklander TEE_Result res = TEE_SUCCESS;
88500b3b9a2SJens Wiklander struct tee_obj *o = NULL;
88600b3b9a2SJens Wiklander tee_fs_off_t new_pos = 0;
887b0104773SPascal Brand
888c40a6505SJens Wiklander res = tee_obj_get(to_user_ta_ctx(sess->ctx), uref_to_vaddr(obj), &o);
889b0104773SPascal Brand if (res != TEE_SUCCESS)
890879237aeSJens Wiklander return res;
891b0104773SPascal Brand
892879237aeSJens Wiklander if (!(o->info.handleFlags & TEE_HANDLE_FLAG_PERSISTENT))
893879237aeSJens Wiklander return TEE_ERROR_BAD_STATE;
894a2e9a830SCedric Chaumont
895879237aeSJens Wiklander switch (whence) {
896879237aeSJens Wiklander case TEE_DATA_SEEK_SET:
897879237aeSJens Wiklander new_pos = offset;
898879237aeSJens Wiklander break;
899879237aeSJens Wiklander case TEE_DATA_SEEK_CUR:
900ced8449aSBastien Simondi if (ADD_OVERFLOW(o->info.dataPosition, offset, &new_pos))
901ced8449aSBastien Simondi return TEE_ERROR_OVERFLOW;
902879237aeSJens Wiklander break;
903879237aeSJens Wiklander case TEE_DATA_SEEK_END:
904ced8449aSBastien Simondi if (ADD_OVERFLOW(o->info.dataSize, offset, &new_pos))
905ced8449aSBastien Simondi return TEE_ERROR_OVERFLOW;
906879237aeSJens Wiklander break;
907879237aeSJens Wiklander default:
908879237aeSJens Wiklander return TEE_ERROR_BAD_PARAMETERS;
909879237aeSJens Wiklander }
910879237aeSJens Wiklander
911879237aeSJens Wiklander if (new_pos < 0)
912879237aeSJens Wiklander new_pos = 0;
913879237aeSJens Wiklander
914879237aeSJens Wiklander if (new_pos > TEE_DATA_MAX_POSITION) {
915879237aeSJens Wiklander EMSG("Position is beyond TEE_DATA_MAX_POSITION");
916879237aeSJens Wiklander return TEE_ERROR_BAD_PARAMETERS;
917879237aeSJens Wiklander }
918879237aeSJens Wiklander
919879237aeSJens Wiklander o->info.dataPosition = new_pos;
920879237aeSJens Wiklander
921879237aeSJens Wiklander return TEE_SUCCESS;
922b0104773SPascal Brand }
923b0104773SPascal Brand
tee_svc_storage_close_all_enum(struct user_ta_ctx * utc)9248684fde8SJens Wiklander void tee_svc_storage_close_all_enum(struct user_ta_ctx *utc)
925b0104773SPascal Brand {
9268684fde8SJens Wiklander struct tee_storage_enum_head *eh = &utc->storage_enums;
927b0104773SPascal Brand
928b0104773SPascal Brand /* disregard return value */
929b0104773SPascal Brand while (!TAILQ_EMPTY(eh))
9308684fde8SJens Wiklander tee_svc_close_enum(utc, TAILQ_FIRST(eh));
931b0104773SPascal Brand }
932