xref: /optee_os/core/kernel/ldelf_syscalls.c (revision ef44161f847bb1f17e6c803e70047d749e7b394e)
1cbe7e1b8SBalint Dobszay // SPDX-License-Identifier: BSD-2-Clause
2cbe7e1b8SBalint Dobszay /*
36105aa86SJens Wiklander  * Copyright (c) 2018-2019, 2022 Linaro Limited
4c185655eSJelle Sels  * Copyright (c) 2020-2021, Arm Limited
5cbe7e1b8SBalint Dobszay  */
6cbe7e1b8SBalint Dobszay 
7cbe7e1b8SBalint Dobszay #include <assert.h>
8baa5161dSBalint Dobszay #include <crypto/crypto.h>
9cbe7e1b8SBalint Dobszay #include <kernel/ldelf_syscalls.h>
10cbe7e1b8SBalint Dobszay #include <kernel/user_mode_ctx.h>
11cbe7e1b8SBalint Dobszay #include <ldelf.h>
12cbe7e1b8SBalint Dobszay #include <mm/file.h>
13cbe7e1b8SBalint Dobszay #include <mm/fobj.h>
14cbe7e1b8SBalint Dobszay #include <mm/mobj.h>
15cbe7e1b8SBalint Dobszay #include <mm/vm.h>
16cbe7e1b8SBalint Dobszay #include <stdlib.h>
17cbe7e1b8SBalint Dobszay #include <string.h>
18cbe7e1b8SBalint Dobszay #include <trace.h>
19cbe7e1b8SBalint Dobszay #include <util.h>
20cbe7e1b8SBalint Dobszay 
21cbe7e1b8SBalint Dobszay struct bin_handle {
22cbe7e1b8SBalint Dobszay 	const struct ts_store_ops *op;
23cbe7e1b8SBalint Dobszay 	struct ts_store_handle *h;
24cbe7e1b8SBalint Dobszay 	struct file *f;
25cbe7e1b8SBalint Dobszay 	size_t offs_bytes;
26cbe7e1b8SBalint Dobszay 	size_t size_bytes;
27cbe7e1b8SBalint Dobszay };
28cbe7e1b8SBalint Dobszay 
29baa5161dSBalint Dobszay TEE_Result ldelf_syscall_map_zi(vaddr_t *va, size_t num_bytes, size_t pad_begin,
30baa5161dSBalint Dobszay 				size_t pad_end, unsigned long flags)
31baa5161dSBalint Dobszay {
32baa5161dSBalint Dobszay 	TEE_Result res = TEE_SUCCESS;
33baa5161dSBalint Dobszay 	struct ts_session *sess = ts_get_current_session();
34baa5161dSBalint Dobszay 	struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx);
35baa5161dSBalint Dobszay 	struct fobj *f = NULL;
36baa5161dSBalint Dobszay 	struct mobj *mobj = NULL;
37baa5161dSBalint Dobszay 	uint32_t prot = TEE_MATTR_URW | TEE_MATTR_PRW;
38baa5161dSBalint Dobszay 	uint32_t vm_flags = 0;
39baa5161dSBalint Dobszay 
40baa5161dSBalint Dobszay 	if (flags & ~LDELF_MAP_FLAG_SHAREABLE)
41baa5161dSBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
42baa5161dSBalint Dobszay 
43baa5161dSBalint Dobszay 	if (flags & LDELF_MAP_FLAG_SHAREABLE)
44baa5161dSBalint Dobszay 		vm_flags |= VM_FLAG_SHAREABLE;
45baa5161dSBalint Dobszay 
46baa5161dSBalint Dobszay 	f = fobj_ta_mem_alloc(ROUNDUP_DIV(num_bytes, SMALL_PAGE_SIZE));
47baa5161dSBalint Dobszay 	if (!f)
48baa5161dSBalint Dobszay 		return TEE_ERROR_OUT_OF_MEMORY;
496105aa86SJens Wiklander 	mobj = mobj_with_fobj_alloc(f, NULL, TEE_MATTR_MEM_TYPE_TAGGED);
50baa5161dSBalint Dobszay 	fobj_put(f);
51baa5161dSBalint Dobszay 	if (!mobj)
52baa5161dSBalint Dobszay 		return TEE_ERROR_OUT_OF_MEMORY;
53baa5161dSBalint Dobszay 	res = vm_map_pad(uctx, va, num_bytes, prot, vm_flags,
54baa5161dSBalint Dobszay 			 mobj, 0, pad_begin, pad_end, 0);
55baa5161dSBalint Dobszay 	mobj_put(mobj);
56baa5161dSBalint Dobszay 
57baa5161dSBalint Dobszay 	return res;
58baa5161dSBalint Dobszay }
59baa5161dSBalint Dobszay 
60baa5161dSBalint Dobszay TEE_Result ldelf_syscall_unmap(vaddr_t va, size_t num_bytes)
61baa5161dSBalint Dobszay {
62baa5161dSBalint Dobszay 	TEE_Result res = TEE_SUCCESS;
63baa5161dSBalint Dobszay 	struct ts_session *sess = ts_get_current_session();
64baa5161dSBalint Dobszay 	struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx);
65baa5161dSBalint Dobszay 	size_t sz = ROUNDUP(num_bytes, SMALL_PAGE_SIZE);
66baa5161dSBalint Dobszay 	uint32_t vm_flags = 0;
67baa5161dSBalint Dobszay 	vaddr_t end_va = 0;
68baa5161dSBalint Dobszay 
69baa5161dSBalint Dobszay 	/*
70baa5161dSBalint Dobszay 	 * The vm_get_flags() and vm_unmap() are supposed to detect or handle
71baa5161dSBalint Dobszay 	 * overflow directly or indirectly. However, since this function is an
72baa5161dSBalint Dobszay 	 * API function it's worth having an extra guard here. If nothing else,
73baa5161dSBalint Dobszay 	 * to increase code clarity.
74baa5161dSBalint Dobszay 	 */
75baa5161dSBalint Dobszay 	if (ADD_OVERFLOW(va, sz, &end_va))
76baa5161dSBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
77baa5161dSBalint Dobszay 
78baa5161dSBalint Dobszay 	res = vm_get_flags(uctx, va, sz, &vm_flags);
79baa5161dSBalint Dobszay 	if (res)
80baa5161dSBalint Dobszay 		return res;
81baa5161dSBalint Dobszay 	if (vm_flags & VM_FLAG_PERMANENT)
82baa5161dSBalint Dobszay 		return TEE_ERROR_ACCESS_DENIED;
83baa5161dSBalint Dobszay 
84baa5161dSBalint Dobszay 	return vm_unmap(uctx, va, sz);
85baa5161dSBalint Dobszay }
86baa5161dSBalint Dobszay 
87baa5161dSBalint Dobszay static void bin_close(void *ptr)
88cbe7e1b8SBalint Dobszay {
89cbe7e1b8SBalint Dobszay 	struct bin_handle *binh = ptr;
90cbe7e1b8SBalint Dobszay 
91cbe7e1b8SBalint Dobszay 	if (binh) {
92cbe7e1b8SBalint Dobszay 		if (binh->op && binh->h)
93cbe7e1b8SBalint Dobszay 			binh->op->close(binh->h);
94cbe7e1b8SBalint Dobszay 		file_put(binh->f);
95cbe7e1b8SBalint Dobszay 	}
96cbe7e1b8SBalint Dobszay 	free(binh);
97cbe7e1b8SBalint Dobszay }
98cbe7e1b8SBalint Dobszay 
99baa5161dSBalint Dobszay TEE_Result ldelf_syscall_open_bin(const TEE_UUID *uuid, size_t uuid_size,
100baa5161dSBalint Dobszay 				  uint32_t *handle)
101cbe7e1b8SBalint Dobszay {
102cbe7e1b8SBalint Dobszay 	TEE_Result res = TEE_SUCCESS;
103baa5161dSBalint Dobszay 	struct ts_session *sess = ts_get_current_session();
104baa5161dSBalint Dobszay 	struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx);
105baa5161dSBalint Dobszay 	struct system_ctx *sys_ctx = sess->user_ctx;
106cbe7e1b8SBalint Dobszay 	struct bin_handle *binh = NULL;
107cbe7e1b8SBalint Dobszay 	uint8_t tag[FILE_TAG_SIZE] = { 0 };
108cbe7e1b8SBalint Dobszay 	unsigned int tag_len = sizeof(tag);
109baa5161dSBalint Dobszay 	int h = 0;
110cbe7e1b8SBalint Dobszay 
111baa5161dSBalint Dobszay 	res = vm_check_access_rights(uctx,
112baa5161dSBalint Dobszay 				     TEE_MEMORY_ACCESS_READ |
113baa5161dSBalint Dobszay 				     TEE_MEMORY_ACCESS_ANY_OWNER,
114baa5161dSBalint Dobszay 				     (uaddr_t)uuid, sizeof(TEE_UUID));
115baa5161dSBalint Dobszay 	if (res)
116baa5161dSBalint Dobszay 		return res;
117baa5161dSBalint Dobszay 
118baa5161dSBalint Dobszay 	res = vm_check_access_rights(uctx,
119baa5161dSBalint Dobszay 				     TEE_MEMORY_ACCESS_WRITE |
120baa5161dSBalint Dobszay 				     TEE_MEMORY_ACCESS_ANY_OWNER,
121baa5161dSBalint Dobszay 				     (uaddr_t)handle, sizeof(uint32_t));
122baa5161dSBalint Dobszay 	if (res)
123baa5161dSBalint Dobszay 		return res;
124baa5161dSBalint Dobszay 
125baa5161dSBalint Dobszay 	if (uuid_size != sizeof(*uuid))
126cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
127cbe7e1b8SBalint Dobszay 
128baa5161dSBalint Dobszay 	if (!sys_ctx) {
129baa5161dSBalint Dobszay 		sys_ctx = calloc(1, sizeof(*sys_ctx));
130baa5161dSBalint Dobszay 		if (!sys_ctx)
131baa5161dSBalint Dobszay 			return TEE_ERROR_OUT_OF_MEMORY;
132baa5161dSBalint Dobszay 		sess->user_ctx = sys_ctx;
133baa5161dSBalint Dobszay 	}
134cbe7e1b8SBalint Dobszay 
135cbe7e1b8SBalint Dobszay 	binh = calloc(1, sizeof(*binh));
136cbe7e1b8SBalint Dobszay 	if (!binh)
137cbe7e1b8SBalint Dobszay 		return TEE_ERROR_OUT_OF_MEMORY;
138cbe7e1b8SBalint Dobszay 
139c185655eSJelle Sels 	if (is_user_ta_ctx(sess->ctx) || is_stmm_ctx(sess->ctx)) {
140c185655eSJelle Sels 		SCATTERED_ARRAY_FOREACH(binh->op, ta_stores,
141c185655eSJelle Sels 					struct ts_store_ops) {
142cbe7e1b8SBalint Dobszay 			DMSG("Lookup user TA ELF %pUl (%s)",
143cbe7e1b8SBalint Dobszay 			     (void *)uuid, binh->op->description);
144cbe7e1b8SBalint Dobszay 
145cbe7e1b8SBalint Dobszay 			res = binh->op->open(uuid, &binh->h);
146baa5161dSBalint Dobszay 			DMSG("res=%#"PRIx32, res);
147cbe7e1b8SBalint Dobszay 			if (res != TEE_ERROR_ITEM_NOT_FOUND &&
148cbe7e1b8SBalint Dobszay 			    res != TEE_ERROR_STORAGE_NOT_AVAILABLE)
149cbe7e1b8SBalint Dobszay 				break;
150cbe7e1b8SBalint Dobszay 		}
151c185655eSJelle Sels 	} else if (is_sp_ctx(sess->ctx)) {
152c185655eSJelle Sels 		SCATTERED_ARRAY_FOREACH(binh->op, sp_stores,
153c185655eSJelle Sels 					struct ts_store_ops) {
154c185655eSJelle Sels 			DMSG("Lookup user SP ELF %pUl (%s)",
155c185655eSJelle Sels 			     (void *)uuid, binh->op->description);
156c185655eSJelle Sels 
157c185655eSJelle Sels 			res = binh->op->open(uuid, &binh->h);
158c185655eSJelle Sels 			DMSG("res=%#"PRIx32, res);
159c185655eSJelle Sels 			if (res != TEE_ERROR_ITEM_NOT_FOUND &&
160c185655eSJelle Sels 			    res != TEE_ERROR_STORAGE_NOT_AVAILABLE)
161c185655eSJelle Sels 				break;
162c185655eSJelle Sels 		}
163c185655eSJelle Sels 	} else {
164c185655eSJelle Sels 		res = TEE_ERROR_ITEM_NOT_FOUND;
165c185655eSJelle Sels 	}
166c185655eSJelle Sels 
167cbe7e1b8SBalint Dobszay 	if (res)
168cbe7e1b8SBalint Dobszay 		goto err;
169cbe7e1b8SBalint Dobszay 
170cbe7e1b8SBalint Dobszay 	res = binh->op->get_size(binh->h, &binh->size_bytes);
171cbe7e1b8SBalint Dobszay 	if (res)
172cbe7e1b8SBalint Dobszay 		goto err;
173cbe7e1b8SBalint Dobszay 	res = binh->op->get_tag(binh->h, tag, &tag_len);
174cbe7e1b8SBalint Dobszay 	if (res)
175cbe7e1b8SBalint Dobszay 		goto err;
176cbe7e1b8SBalint Dobszay 	binh->f = file_get_by_tag(tag, tag_len);
177cbe7e1b8SBalint Dobszay 	if (!binh->f)
178cbe7e1b8SBalint Dobszay 		goto err_oom;
179cbe7e1b8SBalint Dobszay 
180baa5161dSBalint Dobszay 	h = handle_get(&sys_ctx->db, binh);
181cbe7e1b8SBalint Dobszay 	if (h < 0)
182cbe7e1b8SBalint Dobszay 		goto err_oom;
183baa5161dSBalint Dobszay 	*handle = h;
184cbe7e1b8SBalint Dobszay 
185cbe7e1b8SBalint Dobszay 	return TEE_SUCCESS;
186baa5161dSBalint Dobszay 
187cbe7e1b8SBalint Dobszay err_oom:
188cbe7e1b8SBalint Dobszay 	res = TEE_ERROR_OUT_OF_MEMORY;
189cbe7e1b8SBalint Dobszay err:
190baa5161dSBalint Dobszay 	bin_close(binh);
191cbe7e1b8SBalint Dobszay 	return res;
192cbe7e1b8SBalint Dobszay }
193cbe7e1b8SBalint Dobszay 
194baa5161dSBalint Dobszay TEE_Result ldelf_syscall_close_bin(unsigned long handle)
195cbe7e1b8SBalint Dobszay {
196cbe7e1b8SBalint Dobszay 	TEE_Result res = TEE_SUCCESS;
197baa5161dSBalint Dobszay 	struct ts_session *sess = ts_get_current_session();
198baa5161dSBalint Dobszay 	struct system_ctx *sys_ctx = sess->user_ctx;
199cbe7e1b8SBalint Dobszay 	struct bin_handle *binh = NULL;
200cbe7e1b8SBalint Dobszay 
201baa5161dSBalint Dobszay 	if (!sys_ctx)
202cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
203cbe7e1b8SBalint Dobszay 
204baa5161dSBalint Dobszay 	binh = handle_put(&sys_ctx->db, handle);
205cbe7e1b8SBalint Dobszay 	if (!binh)
206cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
207cbe7e1b8SBalint Dobszay 
208cbe7e1b8SBalint Dobszay 	if (binh->offs_bytes < binh->size_bytes)
209*ef44161fSJens Wiklander 		res = binh->op->read(binh->h, NULL, NULL,
210cbe7e1b8SBalint Dobszay 				     binh->size_bytes - binh->offs_bytes);
211cbe7e1b8SBalint Dobszay 
212baa5161dSBalint Dobszay 	bin_close(binh);
213baa5161dSBalint Dobszay 	if (handle_db_is_empty(&sys_ctx->db)) {
214baa5161dSBalint Dobszay 		handle_db_destroy(&sys_ctx->db, bin_close);
215baa5161dSBalint Dobszay 		free(sys_ctx);
216baa5161dSBalint Dobszay 		sess->user_ctx = NULL;
217baa5161dSBalint Dobszay 	}
218cbe7e1b8SBalint Dobszay 
219cbe7e1b8SBalint Dobszay 	return res;
220cbe7e1b8SBalint Dobszay }
221cbe7e1b8SBalint Dobszay 
222*ef44161fSJens Wiklander static TEE_Result binh_copy_to(struct bin_handle *binh, vaddr_t va_core,
223*ef44161fSJens Wiklander 			       vaddr_t va_user, size_t offs_bytes,
224*ef44161fSJens Wiklander 			       size_t num_bytes)
225cbe7e1b8SBalint Dobszay {
226cbe7e1b8SBalint Dobszay 	TEE_Result res = TEE_SUCCESS;
227cbe7e1b8SBalint Dobszay 	size_t next_offs = 0;
228cbe7e1b8SBalint Dobszay 
229cbe7e1b8SBalint Dobszay 	if (offs_bytes < binh->offs_bytes)
230cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_STATE;
231cbe7e1b8SBalint Dobszay 
232cbe7e1b8SBalint Dobszay 	if (ADD_OVERFLOW(offs_bytes, num_bytes, &next_offs))
233cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
234cbe7e1b8SBalint Dobszay 
235cbe7e1b8SBalint Dobszay 	if (offs_bytes > binh->offs_bytes) {
236*ef44161fSJens Wiklander 		res = binh->op->read(binh->h, NULL, NULL,
237cbe7e1b8SBalint Dobszay 				     offs_bytes - binh->offs_bytes);
238cbe7e1b8SBalint Dobszay 		if (res)
239cbe7e1b8SBalint Dobszay 			return res;
240cbe7e1b8SBalint Dobszay 		binh->offs_bytes = offs_bytes;
241cbe7e1b8SBalint Dobszay 	}
242cbe7e1b8SBalint Dobszay 
243cbe7e1b8SBalint Dobszay 	if (next_offs > binh->size_bytes) {
244cbe7e1b8SBalint Dobszay 		size_t rb = binh->size_bytes - binh->offs_bytes;
245cbe7e1b8SBalint Dobszay 
246*ef44161fSJens Wiklander 		res = binh->op->read(binh->h, (void *)va_core,
247*ef44161fSJens Wiklander 				     (void *)va_user, rb);
248cbe7e1b8SBalint Dobszay 		if (res)
249cbe7e1b8SBalint Dobszay 			return res;
250*ef44161fSJens Wiklander 		if (va_core)
251*ef44161fSJens Wiklander 			memset((uint8_t *)va_core + rb, 0, num_bytes - rb);
252*ef44161fSJens Wiklander 		if (va_user) {
253*ef44161fSJens Wiklander 			res = clear_user((uint8_t *)va_user + rb,
254*ef44161fSJens Wiklander 					 num_bytes - rb);
255*ef44161fSJens Wiklander 			if (res)
256*ef44161fSJens Wiklander 				return res;
257*ef44161fSJens Wiklander 		}
258cbe7e1b8SBalint Dobszay 		binh->offs_bytes = binh->size_bytes;
259cbe7e1b8SBalint Dobszay 	} else {
260*ef44161fSJens Wiklander 		res = binh->op->read(binh->h, (void *)va_core,
261*ef44161fSJens Wiklander 				     (void *)va_user, num_bytes);
262cbe7e1b8SBalint Dobszay 		if (res)
263cbe7e1b8SBalint Dobszay 			return res;
264cbe7e1b8SBalint Dobszay 		binh->offs_bytes = next_offs;
265cbe7e1b8SBalint Dobszay 	}
266cbe7e1b8SBalint Dobszay 
267cbe7e1b8SBalint Dobszay 	return TEE_SUCCESS;
268cbe7e1b8SBalint Dobszay }
269cbe7e1b8SBalint Dobszay 
270baa5161dSBalint Dobszay TEE_Result ldelf_syscall_map_bin(vaddr_t *va, size_t num_bytes,
271baa5161dSBalint Dobszay 				 unsigned long handle, size_t offs_bytes,
272baa5161dSBalint Dobszay 				 size_t pad_begin, size_t pad_end,
273baa5161dSBalint Dobszay 				 unsigned long flags)
274cbe7e1b8SBalint Dobszay {
275baa5161dSBalint Dobszay 	TEE_Result res = TEE_SUCCESS;
276baa5161dSBalint Dobszay 	struct ts_session *sess = ts_get_current_session();
277baa5161dSBalint Dobszay 	struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx);
278baa5161dSBalint Dobszay 	struct system_ctx *sys_ctx = sess->user_ctx;
279cbe7e1b8SBalint Dobszay 	struct bin_handle *binh = NULL;
280cbe7e1b8SBalint Dobszay 	uint32_t num_rounded_bytes = 0;
281cbe7e1b8SBalint Dobszay 	struct file_slice *fs = NULL;
282cbe7e1b8SBalint Dobszay 	bool file_is_locked = false;
283cbe7e1b8SBalint Dobszay 	struct mobj *mobj = NULL;
284cbe7e1b8SBalint Dobszay 	uint32_t offs_pages = 0;
285cbe7e1b8SBalint Dobszay 	size_t num_pages = 0;
286cbe7e1b8SBalint Dobszay 	uint32_t prot = 0;
287baa5161dSBalint Dobszay 	const uint32_t accept_flags = LDELF_MAP_FLAG_SHAREABLE |
288baa5161dSBalint Dobszay 				      LDELF_MAP_FLAG_WRITEABLE |
2890d482f82SRuchika Gupta 				      LDELF_MAP_FLAG_BTI |
290baa5161dSBalint Dobszay 				      LDELF_MAP_FLAG_EXECUTABLE;
291cbe7e1b8SBalint Dobszay 
292baa5161dSBalint Dobszay 	if (!sys_ctx)
293cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
294cbe7e1b8SBalint Dobszay 
295baa5161dSBalint Dobszay 	binh = handle_lookup(&sys_ctx->db, handle);
296cbe7e1b8SBalint Dobszay 	if (!binh)
297cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
298cbe7e1b8SBalint Dobszay 
299cbe7e1b8SBalint Dobszay 	if ((flags & accept_flags) != flags)
300cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
301cbe7e1b8SBalint Dobszay 
302baa5161dSBalint Dobszay 	if ((flags & LDELF_MAP_FLAG_SHAREABLE) &&
303baa5161dSBalint Dobszay 	    (flags & LDELF_MAP_FLAG_WRITEABLE))
304cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
305cbe7e1b8SBalint Dobszay 
306baa5161dSBalint Dobszay 	if ((flags & LDELF_MAP_FLAG_EXECUTABLE) &&
307baa5161dSBalint Dobszay 	    (flags & LDELF_MAP_FLAG_WRITEABLE))
308cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
309cbe7e1b8SBalint Dobszay 
310cbe7e1b8SBalint Dobszay 	if (offs_bytes & SMALL_PAGE_MASK)
311cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
312cbe7e1b8SBalint Dobszay 
313cbe7e1b8SBalint Dobszay 	prot = TEE_MATTR_UR | TEE_MATTR_PR;
314baa5161dSBalint Dobszay 	if (flags & LDELF_MAP_FLAG_WRITEABLE)
315cbe7e1b8SBalint Dobszay 		prot |= TEE_MATTR_UW | TEE_MATTR_PW;
316baa5161dSBalint Dobszay 	if (flags & LDELF_MAP_FLAG_EXECUTABLE)
317cbe7e1b8SBalint Dobszay 		prot |= TEE_MATTR_UX;
3180d482f82SRuchika Gupta 	if (flags & LDELF_MAP_FLAG_BTI)
3190d482f82SRuchika Gupta 		prot |= TEE_MATTR_GUARDED;
320cbe7e1b8SBalint Dobszay 
321cbe7e1b8SBalint Dobszay 	offs_pages = offs_bytes >> SMALL_PAGE_SHIFT;
322cbe7e1b8SBalint Dobszay 	if (ROUNDUP_OVERFLOW(num_bytes, SMALL_PAGE_SIZE, &num_rounded_bytes))
323cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
324cbe7e1b8SBalint Dobszay 	num_pages = num_rounded_bytes / SMALL_PAGE_SIZE;
325cbe7e1b8SBalint Dobszay 
326cbe7e1b8SBalint Dobszay 	if (!file_trylock(binh->f)) {
327cbe7e1b8SBalint Dobszay 		/*
328cbe7e1b8SBalint Dobszay 		 * Before we can block on the file lock we must make all
329cbe7e1b8SBalint Dobszay 		 * our page tables available for reclaiming in order to
330cbe7e1b8SBalint Dobszay 		 * avoid a dead-lock with the other thread (which already
331cbe7e1b8SBalint Dobszay 		 * is holding the file lock) mapping lots of memory below.
332cbe7e1b8SBalint Dobszay 		 */
333cbe7e1b8SBalint Dobszay 		vm_set_ctx(NULL);
334cbe7e1b8SBalint Dobszay 		file_lock(binh->f);
335cbe7e1b8SBalint Dobszay 		vm_set_ctx(uctx->ts_ctx);
336cbe7e1b8SBalint Dobszay 	}
337cbe7e1b8SBalint Dobszay 	file_is_locked = true;
338cbe7e1b8SBalint Dobszay 	fs = file_find_slice(binh->f, offs_pages);
339cbe7e1b8SBalint Dobszay 	if (fs) {
340cbe7e1b8SBalint Dobszay 		/* If there's registered slice it has to match */
341cbe7e1b8SBalint Dobszay 		if (fs->page_offset != offs_pages ||
342cbe7e1b8SBalint Dobszay 		    num_pages > fs->fobj->num_pages) {
343cbe7e1b8SBalint Dobszay 			res = TEE_ERROR_BAD_PARAMETERS;
344cbe7e1b8SBalint Dobszay 			goto err;
345cbe7e1b8SBalint Dobszay 		}
346cbe7e1b8SBalint Dobszay 
347cbe7e1b8SBalint Dobszay 		/* If there's a slice we must be mapping shareable */
348baa5161dSBalint Dobszay 		if (!(flags & LDELF_MAP_FLAG_SHAREABLE)) {
349cbe7e1b8SBalint Dobszay 			res = TEE_ERROR_BAD_PARAMETERS;
350cbe7e1b8SBalint Dobszay 			goto err;
351cbe7e1b8SBalint Dobszay 		}
352cbe7e1b8SBalint Dobszay 
3536105aa86SJens Wiklander 		mobj = mobj_with_fobj_alloc(fs->fobj, binh->f,
3546105aa86SJens Wiklander 					    TEE_MATTR_MEM_TYPE_TAGGED);
355cbe7e1b8SBalint Dobszay 		if (!mobj) {
356cbe7e1b8SBalint Dobszay 			res = TEE_ERROR_OUT_OF_MEMORY;
357cbe7e1b8SBalint Dobszay 			goto err;
358cbe7e1b8SBalint Dobszay 		}
359baa5161dSBalint Dobszay 		res = vm_map_pad(uctx, va, num_rounded_bytes,
360cbe7e1b8SBalint Dobszay 				 prot, VM_FLAG_READONLY,
361cbe7e1b8SBalint Dobszay 				 mobj, 0, pad_begin, pad_end, 0);
362cbe7e1b8SBalint Dobszay 		mobj_put(mobj);
363cbe7e1b8SBalint Dobszay 		if (res)
364cbe7e1b8SBalint Dobszay 			goto err;
365cbe7e1b8SBalint Dobszay 	} else {
366cbe7e1b8SBalint Dobszay 		struct fobj *f = fobj_ta_mem_alloc(num_pages);
367cbe7e1b8SBalint Dobszay 		struct file *file = NULL;
368cbe7e1b8SBalint Dobszay 		uint32_t vm_flags = 0;
369cbe7e1b8SBalint Dobszay 
370cbe7e1b8SBalint Dobszay 		if (!f) {
371cbe7e1b8SBalint Dobszay 			res = TEE_ERROR_OUT_OF_MEMORY;
372cbe7e1b8SBalint Dobszay 			goto err;
373cbe7e1b8SBalint Dobszay 		}
374baa5161dSBalint Dobszay 		if (!(flags & LDELF_MAP_FLAG_WRITEABLE)) {
375cbe7e1b8SBalint Dobszay 			file = binh->f;
376cbe7e1b8SBalint Dobszay 			vm_flags |= VM_FLAG_READONLY;
377cbe7e1b8SBalint Dobszay 		}
378cbe7e1b8SBalint Dobszay 
3796105aa86SJens Wiklander 		mobj = mobj_with_fobj_alloc(f, file, TEE_MATTR_MEM_TYPE_TAGGED);
380cbe7e1b8SBalint Dobszay 		fobj_put(f);
381cbe7e1b8SBalint Dobszay 		if (!mobj) {
382cbe7e1b8SBalint Dobszay 			res = TEE_ERROR_OUT_OF_MEMORY;
383cbe7e1b8SBalint Dobszay 			goto err;
384cbe7e1b8SBalint Dobszay 		}
385baa5161dSBalint Dobszay 		res = vm_map_pad(uctx, va, num_rounded_bytes,
386cbe7e1b8SBalint Dobszay 				 TEE_MATTR_PRW, vm_flags, mobj, 0,
387cbe7e1b8SBalint Dobszay 				 pad_begin, pad_end, 0);
388cbe7e1b8SBalint Dobszay 		mobj_put(mobj);
389cbe7e1b8SBalint Dobszay 		if (res)
390cbe7e1b8SBalint Dobszay 			goto err;
391*ef44161fSJens Wiklander 		res = binh_copy_to(binh, *va, 0, offs_bytes, num_bytes);
392cbe7e1b8SBalint Dobszay 		if (res)
393cbe7e1b8SBalint Dobszay 			goto err_unmap_va;
394baa5161dSBalint Dobszay 		res = vm_set_prot(uctx, *va, num_rounded_bytes,
395cbe7e1b8SBalint Dobszay 				  prot);
396cbe7e1b8SBalint Dobszay 		if (res)
397cbe7e1b8SBalint Dobszay 			goto err_unmap_va;
398cbe7e1b8SBalint Dobszay 
399cbe7e1b8SBalint Dobszay 		/*
400cbe7e1b8SBalint Dobszay 		 * The context currently is active set it again to update
401cbe7e1b8SBalint Dobszay 		 * the mapping.
402cbe7e1b8SBalint Dobszay 		 */
403cbe7e1b8SBalint Dobszay 		vm_set_ctx(uctx->ts_ctx);
404cbe7e1b8SBalint Dobszay 
405baa5161dSBalint Dobszay 		if (!(flags & LDELF_MAP_FLAG_WRITEABLE)) {
406cbe7e1b8SBalint Dobszay 			res = file_add_slice(binh->f, f, offs_pages);
407cbe7e1b8SBalint Dobszay 			if (res)
408cbe7e1b8SBalint Dobszay 				goto err_unmap_va;
409cbe7e1b8SBalint Dobszay 		}
410cbe7e1b8SBalint Dobszay 	}
411cbe7e1b8SBalint Dobszay 
412cbe7e1b8SBalint Dobszay 	file_unlock(binh->f);
413cbe7e1b8SBalint Dobszay 
414cbe7e1b8SBalint Dobszay 	return TEE_SUCCESS;
415cbe7e1b8SBalint Dobszay 
416cbe7e1b8SBalint Dobszay err_unmap_va:
417baa5161dSBalint Dobszay 	if (vm_unmap(uctx, *va, num_rounded_bytes))
418cbe7e1b8SBalint Dobszay 		panic();
419cbe7e1b8SBalint Dobszay 
420cbe7e1b8SBalint Dobszay 	/*
421cbe7e1b8SBalint Dobszay 	 * The context currently is active set it again to update
422cbe7e1b8SBalint Dobszay 	 * the mapping.
423cbe7e1b8SBalint Dobszay 	 */
424cbe7e1b8SBalint Dobszay 	vm_set_ctx(uctx->ts_ctx);
425cbe7e1b8SBalint Dobszay 
426cbe7e1b8SBalint Dobszay err:
427cbe7e1b8SBalint Dobszay 	if (file_is_locked)
428cbe7e1b8SBalint Dobszay 		file_unlock(binh->f);
429cbe7e1b8SBalint Dobszay 
430cbe7e1b8SBalint Dobszay 	return res;
431cbe7e1b8SBalint Dobszay }
432cbe7e1b8SBalint Dobszay 
433baa5161dSBalint Dobszay TEE_Result ldelf_syscall_copy_from_bin(void *dst, size_t offs, size_t num_bytes,
434baa5161dSBalint Dobszay 				       unsigned long handle)
435cbe7e1b8SBalint Dobszay {
436baa5161dSBalint Dobszay 	TEE_Result res = TEE_SUCCESS;
437baa5161dSBalint Dobszay 	struct ts_session *sess = ts_get_current_session();
438baa5161dSBalint Dobszay 	struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx);
439baa5161dSBalint Dobszay 	struct system_ctx *sys_ctx = sess->user_ctx;
440cbe7e1b8SBalint Dobszay 	struct bin_handle *binh = NULL;
441cbe7e1b8SBalint Dobszay 
442baa5161dSBalint Dobszay 	res = vm_check_access_rights(uctx,
443baa5161dSBalint Dobszay 				     TEE_MEMORY_ACCESS_WRITE |
444baa5161dSBalint Dobszay 				     TEE_MEMORY_ACCESS_ANY_OWNER,
445baa5161dSBalint Dobszay 				     (uaddr_t)dst, num_bytes);
446baa5161dSBalint Dobszay 	if (res)
447baa5161dSBalint Dobszay 		return res;
448baa5161dSBalint Dobszay 
449baa5161dSBalint Dobszay 	if (!sys_ctx)
450cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
451cbe7e1b8SBalint Dobszay 
452baa5161dSBalint Dobszay 	binh = handle_lookup(&sys_ctx->db, handle);
453cbe7e1b8SBalint Dobszay 	if (!binh)
454cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
455cbe7e1b8SBalint Dobszay 
456*ef44161fSJens Wiklander 	return binh_copy_to(binh, 0, (vaddr_t)dst, offs, num_bytes);
457cbe7e1b8SBalint Dobszay }
458cbe7e1b8SBalint Dobszay 
459baa5161dSBalint Dobszay TEE_Result ldelf_syscall_set_prot(unsigned long va, size_t num_bytes,
460baa5161dSBalint Dobszay 				  unsigned long flags)
461cbe7e1b8SBalint Dobszay {
462cbe7e1b8SBalint Dobszay 	TEE_Result res = TEE_SUCCESS;
463baa5161dSBalint Dobszay 	struct ts_session *sess = ts_get_current_session();
464baa5161dSBalint Dobszay 	struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx);
465baa5161dSBalint Dobszay 	size_t sz = ROUNDUP(num_bytes, SMALL_PAGE_SIZE);
466baa5161dSBalint Dobszay 	uint32_t prot = TEE_MATTR_UR | TEE_MATTR_PR;
467cbe7e1b8SBalint Dobszay 	uint32_t vm_flags = 0;
468cbe7e1b8SBalint Dobszay 	vaddr_t end_va = 0;
469baa5161dSBalint Dobszay 	const uint32_t accept_flags = LDELF_MAP_FLAG_WRITEABLE |
4700d482f82SRuchika Gupta 				      LDELF_MAP_FLAG_BTI |
471baa5161dSBalint Dobszay 				      LDELF_MAP_FLAG_EXECUTABLE;
472cbe7e1b8SBalint Dobszay 
473cbe7e1b8SBalint Dobszay 	if ((flags & accept_flags) != flags)
474cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
475baa5161dSBalint Dobszay 	if (flags & LDELF_MAP_FLAG_WRITEABLE)
476cbe7e1b8SBalint Dobszay 		prot |= TEE_MATTR_UW | TEE_MATTR_PW;
477baa5161dSBalint Dobszay 	if (flags & LDELF_MAP_FLAG_EXECUTABLE)
478cbe7e1b8SBalint Dobszay 		prot |= TEE_MATTR_UX;
4790d482f82SRuchika Gupta 	if (flags & LDELF_MAP_FLAG_BTI)
4800d482f82SRuchika Gupta 		prot |= TEE_MATTR_GUARDED;
481cbe7e1b8SBalint Dobszay 
482cbe7e1b8SBalint Dobszay 	/*
483baa5161dSBalint Dobszay 	 * The vm_get_flags() and vm_unmap() are supposed to detect or handle
484baa5161dSBalint Dobszay 	 * overflow directly or indirectly. However, since this function is an
485baa5161dSBalint Dobszay 	 * API function it's worth having an extra guard here. If nothing else,
486baa5161dSBalint Dobszay 	 * to increase code clarity.
487cbe7e1b8SBalint Dobszay 	 */
488cbe7e1b8SBalint Dobszay 	if (ADD_OVERFLOW(va, sz, &end_va))
489cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
490cbe7e1b8SBalint Dobszay 
491cbe7e1b8SBalint Dobszay 	res = vm_get_flags(uctx, va, sz, &vm_flags);
492cbe7e1b8SBalint Dobszay 	if (res)
493cbe7e1b8SBalint Dobszay 		return res;
494cbe7e1b8SBalint Dobszay 	if (vm_flags & VM_FLAG_PERMANENT)
495cbe7e1b8SBalint Dobszay 		return TEE_ERROR_ACCESS_DENIED;
496cbe7e1b8SBalint Dobszay 
497cbe7e1b8SBalint Dobszay 	/*
498cbe7e1b8SBalint Dobszay 	 * If the segment is a mapping of a part of a file (vm_flags &
499cbe7e1b8SBalint Dobszay 	 * VM_FLAG_READONLY) it cannot be made writeable as all mapped
500cbe7e1b8SBalint Dobszay 	 * files are mapped read-only.
501cbe7e1b8SBalint Dobszay 	 */
502cbe7e1b8SBalint Dobszay 	if ((vm_flags & VM_FLAG_READONLY) &&
503cbe7e1b8SBalint Dobszay 	    (prot & (TEE_MATTR_UW | TEE_MATTR_PW)))
504cbe7e1b8SBalint Dobszay 		return TEE_ERROR_ACCESS_DENIED;
505cbe7e1b8SBalint Dobszay 
506cbe7e1b8SBalint Dobszay 	return vm_set_prot(uctx, va, sz, prot);
507cbe7e1b8SBalint Dobszay }
508cbe7e1b8SBalint Dobszay 
509baa5161dSBalint Dobszay TEE_Result ldelf_syscall_remap(unsigned long old_va, vaddr_t *new_va,
510baa5161dSBalint Dobszay 			       size_t num_bytes, size_t pad_begin,
511baa5161dSBalint Dobszay 			       size_t pad_end)
512cbe7e1b8SBalint Dobszay {
513cbe7e1b8SBalint Dobszay 	TEE_Result res = TEE_SUCCESS;
514baa5161dSBalint Dobszay 	struct ts_session *sess = ts_get_current_session();
515baa5161dSBalint Dobszay 	struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx);
516cbe7e1b8SBalint Dobszay 	uint32_t vm_flags = 0;
517cbe7e1b8SBalint Dobszay 
518cbe7e1b8SBalint Dobszay 	res = vm_get_flags(uctx, old_va, num_bytes, &vm_flags);
519cbe7e1b8SBalint Dobszay 	if (res)
520cbe7e1b8SBalint Dobszay 		return res;
521cbe7e1b8SBalint Dobszay 	if (vm_flags & VM_FLAG_PERMANENT)
522cbe7e1b8SBalint Dobszay 		return TEE_ERROR_ACCESS_DENIED;
523cbe7e1b8SBalint Dobszay 
524baa5161dSBalint Dobszay 	res = vm_remap(uctx, new_va, old_va, num_bytes, pad_begin, pad_end);
525cbe7e1b8SBalint Dobszay 
526cbe7e1b8SBalint Dobszay 	return res;
527cbe7e1b8SBalint Dobszay }
528baa5161dSBalint Dobszay 
529baa5161dSBalint Dobszay TEE_Result ldelf_syscall_gen_rnd_num(void *buf, size_t num_bytes)
530baa5161dSBalint Dobszay {
531baa5161dSBalint Dobszay 	TEE_Result res = TEE_SUCCESS;
532baa5161dSBalint Dobszay 	struct ts_session *sess = ts_get_current_session();
533baa5161dSBalint Dobszay 	struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx);
534baa5161dSBalint Dobszay 
535baa5161dSBalint Dobszay 	res = vm_check_access_rights(uctx,
536baa5161dSBalint Dobszay 				     TEE_MEMORY_ACCESS_WRITE |
537baa5161dSBalint Dobszay 				     TEE_MEMORY_ACCESS_ANY_OWNER,
538baa5161dSBalint Dobszay 				     (uaddr_t)buf, num_bytes);
539baa5161dSBalint Dobszay 	if (res)
540baa5161dSBalint Dobszay 		return res;
541baa5161dSBalint Dobszay 
542baa5161dSBalint Dobszay 	return crypto_rng_read(buf, num_bytes);
543baa5161dSBalint Dobszay }
544baa5161dSBalint Dobszay 
545baa5161dSBalint Dobszay /*
546baa5161dSBalint Dobszay  * Should be called after returning from ldelf. If user_ctx is not NULL means
547baa5161dSBalint Dobszay  * that ldelf crashed or otherwise didn't complete properly. This function will
548baa5161dSBalint Dobszay  * close the remaining handles and free the context structs allocated by ldelf.
549baa5161dSBalint Dobszay  */
550baa5161dSBalint Dobszay void ldelf_sess_cleanup(struct ts_session *sess)
551baa5161dSBalint Dobszay {
552baa5161dSBalint Dobszay 	struct system_ctx *sys_ctx = sess->user_ctx;
553baa5161dSBalint Dobszay 
554baa5161dSBalint Dobszay 	if (sys_ctx) {
555baa5161dSBalint Dobszay 		handle_db_destroy(&sys_ctx->db, bin_close);
556baa5161dSBalint Dobszay 		free(sys_ctx);
557baa5161dSBalint Dobszay 		sess->user_ctx = NULL;
558baa5161dSBalint Dobszay 	}
559baa5161dSBalint Dobszay }
560