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