xref: /optee_os/core/tee/tee_svc_storage.c (revision 71ecb9fa58ecef9e535f63b4d9d9e45dd4696e51)
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