xref: /optee_os/core/kernel/ldelf_syscalls.c (revision cbe7e1b87977e7dff91e859f5ff0c839b9387c4a)
1*cbe7e1b8SBalint Dobszay // SPDX-License-Identifier: BSD-2-Clause
2*cbe7e1b8SBalint Dobszay /*
3*cbe7e1b8SBalint Dobszay  * Copyright (c) 2018-2019, Linaro Limited
4*cbe7e1b8SBalint Dobszay  * Copyright (c) 2020, Arm Limited
5*cbe7e1b8SBalint Dobszay  */
6*cbe7e1b8SBalint Dobszay 
7*cbe7e1b8SBalint Dobszay #include <assert.h>
8*cbe7e1b8SBalint Dobszay #include <kernel/ldelf_syscalls.h>
9*cbe7e1b8SBalint Dobszay #include <kernel/user_mode_ctx.h>
10*cbe7e1b8SBalint Dobszay #include <ldelf.h>
11*cbe7e1b8SBalint Dobszay #include <mm/file.h>
12*cbe7e1b8SBalint Dobszay #include <mm/fobj.h>
13*cbe7e1b8SBalint Dobszay #include <mm/mobj.h>
14*cbe7e1b8SBalint Dobszay #include <mm/vm.h>
15*cbe7e1b8SBalint Dobszay #include <pta_system.h>
16*cbe7e1b8SBalint Dobszay #include <stdlib.h>
17*cbe7e1b8SBalint Dobszay #include <string.h>
18*cbe7e1b8SBalint Dobszay #include <trace.h>
19*cbe7e1b8SBalint Dobszay #include <util.h>
20*cbe7e1b8SBalint Dobszay 
21*cbe7e1b8SBalint Dobszay struct bin_handle {
22*cbe7e1b8SBalint Dobszay 	const struct ts_store_ops *op;
23*cbe7e1b8SBalint Dobszay 	struct ts_store_handle *h;
24*cbe7e1b8SBalint Dobszay 	struct file *f;
25*cbe7e1b8SBalint Dobszay 	size_t offs_bytes;
26*cbe7e1b8SBalint Dobszay 	size_t size_bytes;
27*cbe7e1b8SBalint Dobszay };
28*cbe7e1b8SBalint Dobszay 
29*cbe7e1b8SBalint Dobszay void ta_bin_close(void *ptr)
30*cbe7e1b8SBalint Dobszay {
31*cbe7e1b8SBalint Dobszay 	struct bin_handle *binh = ptr;
32*cbe7e1b8SBalint Dobszay 
33*cbe7e1b8SBalint Dobszay 	if (binh) {
34*cbe7e1b8SBalint Dobszay 		if (binh->op && binh->h)
35*cbe7e1b8SBalint Dobszay 			binh->op->close(binh->h);
36*cbe7e1b8SBalint Dobszay 		file_put(binh->f);
37*cbe7e1b8SBalint Dobszay 	}
38*cbe7e1b8SBalint Dobszay 	free(binh);
39*cbe7e1b8SBalint Dobszay }
40*cbe7e1b8SBalint Dobszay 
41*cbe7e1b8SBalint Dobszay TEE_Result ldelf_open_ta_binary(struct system_ctx *ctx, uint32_t param_types,
42*cbe7e1b8SBalint Dobszay 				TEE_Param params[TEE_NUM_PARAMS])
43*cbe7e1b8SBalint Dobszay {
44*cbe7e1b8SBalint Dobszay 	TEE_Result res = TEE_SUCCESS;
45*cbe7e1b8SBalint Dobszay 	struct bin_handle *binh = NULL;
46*cbe7e1b8SBalint Dobszay 	int h = 0;
47*cbe7e1b8SBalint Dobszay 	TEE_UUID *uuid = NULL;
48*cbe7e1b8SBalint Dobszay 	uint8_t tag[FILE_TAG_SIZE] = { 0 };
49*cbe7e1b8SBalint Dobszay 	unsigned int tag_len = sizeof(tag);
50*cbe7e1b8SBalint Dobszay 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
51*cbe7e1b8SBalint Dobszay 					  TEE_PARAM_TYPE_VALUE_OUTPUT,
52*cbe7e1b8SBalint Dobszay 					  TEE_PARAM_TYPE_NONE,
53*cbe7e1b8SBalint Dobszay 					  TEE_PARAM_TYPE_NONE);
54*cbe7e1b8SBalint Dobszay 
55*cbe7e1b8SBalint Dobszay 	if (exp_pt != param_types)
56*cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
57*cbe7e1b8SBalint Dobszay 	if (params[0].memref.size != sizeof(*uuid))
58*cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
59*cbe7e1b8SBalint Dobszay 
60*cbe7e1b8SBalint Dobszay 	uuid = params[0].memref.buffer;
61*cbe7e1b8SBalint Dobszay 
62*cbe7e1b8SBalint Dobszay 	binh = calloc(1, sizeof(*binh));
63*cbe7e1b8SBalint Dobszay 	if (!binh)
64*cbe7e1b8SBalint Dobszay 		return TEE_ERROR_OUT_OF_MEMORY;
65*cbe7e1b8SBalint Dobszay 
66*cbe7e1b8SBalint Dobszay 	SCATTERED_ARRAY_FOREACH(binh->op, ta_stores, struct ts_store_ops) {
67*cbe7e1b8SBalint Dobszay 		DMSG("Lookup user TA ELF %pUl (%s)",
68*cbe7e1b8SBalint Dobszay 		     (void *)uuid, binh->op->description);
69*cbe7e1b8SBalint Dobszay 
70*cbe7e1b8SBalint Dobszay 		res = binh->op->open(uuid, &binh->h);
71*cbe7e1b8SBalint Dobszay 		DMSG("res=0x%x", res);
72*cbe7e1b8SBalint Dobszay 		if (res != TEE_ERROR_ITEM_NOT_FOUND &&
73*cbe7e1b8SBalint Dobszay 		    res != TEE_ERROR_STORAGE_NOT_AVAILABLE)
74*cbe7e1b8SBalint Dobszay 			break;
75*cbe7e1b8SBalint Dobszay 	}
76*cbe7e1b8SBalint Dobszay 	if (res)
77*cbe7e1b8SBalint Dobszay 		goto err;
78*cbe7e1b8SBalint Dobszay 
79*cbe7e1b8SBalint Dobszay 	res = binh->op->get_size(binh->h, &binh->size_bytes);
80*cbe7e1b8SBalint Dobszay 	if (res)
81*cbe7e1b8SBalint Dobszay 		goto err;
82*cbe7e1b8SBalint Dobszay 	res = binh->op->get_tag(binh->h, tag, &tag_len);
83*cbe7e1b8SBalint Dobszay 	if (res)
84*cbe7e1b8SBalint Dobszay 		goto err;
85*cbe7e1b8SBalint Dobszay 	binh->f = file_get_by_tag(tag, tag_len);
86*cbe7e1b8SBalint Dobszay 	if (!binh->f)
87*cbe7e1b8SBalint Dobszay 		goto err_oom;
88*cbe7e1b8SBalint Dobszay 
89*cbe7e1b8SBalint Dobszay 	h = handle_get(&ctx->db, binh);
90*cbe7e1b8SBalint Dobszay 	if (h < 0)
91*cbe7e1b8SBalint Dobszay 		goto err_oom;
92*cbe7e1b8SBalint Dobszay 	params[0].value.a = h;
93*cbe7e1b8SBalint Dobszay 
94*cbe7e1b8SBalint Dobszay 	return TEE_SUCCESS;
95*cbe7e1b8SBalint Dobszay err_oom:
96*cbe7e1b8SBalint Dobszay 	res = TEE_ERROR_OUT_OF_MEMORY;
97*cbe7e1b8SBalint Dobszay err:
98*cbe7e1b8SBalint Dobszay 	ta_bin_close(binh);
99*cbe7e1b8SBalint Dobszay 	return res;
100*cbe7e1b8SBalint Dobszay }
101*cbe7e1b8SBalint Dobszay 
102*cbe7e1b8SBalint Dobszay TEE_Result ldelf_close_ta_binary(struct system_ctx *ctx, uint32_t param_types,
103*cbe7e1b8SBalint Dobszay 				 TEE_Param params[TEE_NUM_PARAMS])
104*cbe7e1b8SBalint Dobszay {
105*cbe7e1b8SBalint Dobszay 	TEE_Result res = TEE_SUCCESS;
106*cbe7e1b8SBalint Dobszay 	struct bin_handle *binh = NULL;
107*cbe7e1b8SBalint Dobszay 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
108*cbe7e1b8SBalint Dobszay 					  TEE_PARAM_TYPE_NONE,
109*cbe7e1b8SBalint Dobszay 					  TEE_PARAM_TYPE_NONE,
110*cbe7e1b8SBalint Dobszay 					  TEE_PARAM_TYPE_NONE);
111*cbe7e1b8SBalint Dobszay 
112*cbe7e1b8SBalint Dobszay 	if (exp_pt != param_types)
113*cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
114*cbe7e1b8SBalint Dobszay 
115*cbe7e1b8SBalint Dobszay 	if (params[0].value.b)
116*cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
117*cbe7e1b8SBalint Dobszay 
118*cbe7e1b8SBalint Dobszay 	binh = handle_put(&ctx->db, params[0].value.a);
119*cbe7e1b8SBalint Dobszay 	if (!binh)
120*cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
121*cbe7e1b8SBalint Dobszay 
122*cbe7e1b8SBalint Dobszay 	if (binh->offs_bytes < binh->size_bytes)
123*cbe7e1b8SBalint Dobszay 		res = binh->op->read(binh->h, NULL,
124*cbe7e1b8SBalint Dobszay 				     binh->size_bytes - binh->offs_bytes);
125*cbe7e1b8SBalint Dobszay 
126*cbe7e1b8SBalint Dobszay 	ta_bin_close(binh);
127*cbe7e1b8SBalint Dobszay 
128*cbe7e1b8SBalint Dobszay 	return res;
129*cbe7e1b8SBalint Dobszay }
130*cbe7e1b8SBalint Dobszay 
131*cbe7e1b8SBalint Dobszay static TEE_Result binh_copy_to(struct bin_handle *binh, vaddr_t va,
132*cbe7e1b8SBalint Dobszay 			       size_t offs_bytes, size_t num_bytes)
133*cbe7e1b8SBalint Dobszay {
134*cbe7e1b8SBalint Dobszay 	TEE_Result res = TEE_SUCCESS;
135*cbe7e1b8SBalint Dobszay 	size_t next_offs = 0;
136*cbe7e1b8SBalint Dobszay 
137*cbe7e1b8SBalint Dobszay 	if (offs_bytes < binh->offs_bytes)
138*cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_STATE;
139*cbe7e1b8SBalint Dobszay 
140*cbe7e1b8SBalint Dobszay 	if (ADD_OVERFLOW(offs_bytes, num_bytes, &next_offs))
141*cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
142*cbe7e1b8SBalint Dobszay 
143*cbe7e1b8SBalint Dobszay 	if (offs_bytes > binh->offs_bytes) {
144*cbe7e1b8SBalint Dobszay 		res = binh->op->read(binh->h, NULL,
145*cbe7e1b8SBalint Dobszay 				     offs_bytes - binh->offs_bytes);
146*cbe7e1b8SBalint Dobszay 		if (res)
147*cbe7e1b8SBalint Dobszay 			return res;
148*cbe7e1b8SBalint Dobszay 		binh->offs_bytes = offs_bytes;
149*cbe7e1b8SBalint Dobszay 	}
150*cbe7e1b8SBalint Dobszay 
151*cbe7e1b8SBalint Dobszay 	if (next_offs > binh->size_bytes) {
152*cbe7e1b8SBalint Dobszay 		size_t rb = binh->size_bytes - binh->offs_bytes;
153*cbe7e1b8SBalint Dobszay 
154*cbe7e1b8SBalint Dobszay 		res = binh->op->read(binh->h, (void *)va, rb);
155*cbe7e1b8SBalint Dobszay 		if (res)
156*cbe7e1b8SBalint Dobszay 			return res;
157*cbe7e1b8SBalint Dobszay 		memset((uint8_t *)va + rb, 0, num_bytes - rb);
158*cbe7e1b8SBalint Dobszay 		binh->offs_bytes = binh->size_bytes;
159*cbe7e1b8SBalint Dobszay 	} else {
160*cbe7e1b8SBalint Dobszay 		res = binh->op->read(binh->h, (void *)va, num_bytes);
161*cbe7e1b8SBalint Dobszay 		if (res)
162*cbe7e1b8SBalint Dobszay 			return res;
163*cbe7e1b8SBalint Dobszay 		binh->offs_bytes = next_offs;
164*cbe7e1b8SBalint Dobszay 	}
165*cbe7e1b8SBalint Dobszay 
166*cbe7e1b8SBalint Dobszay 	return TEE_SUCCESS;
167*cbe7e1b8SBalint Dobszay }
168*cbe7e1b8SBalint Dobszay 
169*cbe7e1b8SBalint Dobszay TEE_Result ldelf_map_ta_binary(struct system_ctx *ctx,
170*cbe7e1b8SBalint Dobszay 			       struct user_mode_ctx *uctx,
171*cbe7e1b8SBalint Dobszay 			       uint32_t param_types,
172*cbe7e1b8SBalint Dobszay 			       TEE_Param params[TEE_NUM_PARAMS])
173*cbe7e1b8SBalint Dobszay {
174*cbe7e1b8SBalint Dobszay 	const uint32_t accept_flags = PTA_SYSTEM_MAP_FLAG_SHAREABLE |
175*cbe7e1b8SBalint Dobszay 				      PTA_SYSTEM_MAP_FLAG_WRITEABLE |
176*cbe7e1b8SBalint Dobszay 				      PTA_SYSTEM_MAP_FLAG_EXECUTABLE;
177*cbe7e1b8SBalint Dobszay 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
178*cbe7e1b8SBalint Dobszay 					  TEE_PARAM_TYPE_VALUE_INPUT,
179*cbe7e1b8SBalint Dobszay 					  TEE_PARAM_TYPE_VALUE_INOUT,
180*cbe7e1b8SBalint Dobszay 					  TEE_PARAM_TYPE_VALUE_INPUT);
181*cbe7e1b8SBalint Dobszay 	struct bin_handle *binh = NULL;
182*cbe7e1b8SBalint Dobszay 	uint32_t num_rounded_bytes = 0;
183*cbe7e1b8SBalint Dobszay 	TEE_Result res = TEE_SUCCESS;
184*cbe7e1b8SBalint Dobszay 	struct file_slice *fs = NULL;
185*cbe7e1b8SBalint Dobszay 	bool file_is_locked = false;
186*cbe7e1b8SBalint Dobszay 	struct mobj *mobj = NULL;
187*cbe7e1b8SBalint Dobszay 	uint32_t offs_bytes = 0;
188*cbe7e1b8SBalint Dobszay 	uint32_t offs_pages = 0;
189*cbe7e1b8SBalint Dobszay 	uint32_t num_bytes = 0;
190*cbe7e1b8SBalint Dobszay 	uint32_t pad_begin = 0;
191*cbe7e1b8SBalint Dobszay 	uint32_t pad_end = 0;
192*cbe7e1b8SBalint Dobszay 	size_t num_pages = 0;
193*cbe7e1b8SBalint Dobszay 	uint32_t flags = 0;
194*cbe7e1b8SBalint Dobszay 	uint32_t prot = 0;
195*cbe7e1b8SBalint Dobszay 	vaddr_t va = 0;
196*cbe7e1b8SBalint Dobszay 
197*cbe7e1b8SBalint Dobszay 	if (exp_pt != param_types)
198*cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
199*cbe7e1b8SBalint Dobszay 
200*cbe7e1b8SBalint Dobszay 	binh = handle_lookup(&ctx->db, params[0].value.a);
201*cbe7e1b8SBalint Dobszay 	if (!binh)
202*cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
203*cbe7e1b8SBalint Dobszay 	flags = params[0].value.b;
204*cbe7e1b8SBalint Dobszay 	offs_bytes = params[1].value.a;
205*cbe7e1b8SBalint Dobszay 	num_bytes = params[1].value.b;
206*cbe7e1b8SBalint Dobszay 	va = reg_pair_to_64(params[2].value.a, params[2].value.b);
207*cbe7e1b8SBalint Dobszay 	pad_begin = params[3].value.a;
208*cbe7e1b8SBalint Dobszay 	pad_end = params[3].value.b;
209*cbe7e1b8SBalint Dobszay 
210*cbe7e1b8SBalint Dobszay 	if ((flags & accept_flags) != flags)
211*cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
212*cbe7e1b8SBalint Dobszay 
213*cbe7e1b8SBalint Dobszay 	if ((flags & PTA_SYSTEM_MAP_FLAG_SHAREABLE) &&
214*cbe7e1b8SBalint Dobszay 	    (flags & PTA_SYSTEM_MAP_FLAG_WRITEABLE))
215*cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
216*cbe7e1b8SBalint Dobszay 
217*cbe7e1b8SBalint Dobszay 	if ((flags & PTA_SYSTEM_MAP_FLAG_EXECUTABLE) &&
218*cbe7e1b8SBalint Dobszay 	    (flags & PTA_SYSTEM_MAP_FLAG_WRITEABLE))
219*cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
220*cbe7e1b8SBalint Dobszay 
221*cbe7e1b8SBalint Dobszay 	if (offs_bytes & SMALL_PAGE_MASK)
222*cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
223*cbe7e1b8SBalint Dobszay 
224*cbe7e1b8SBalint Dobszay 	prot = TEE_MATTR_UR | TEE_MATTR_PR;
225*cbe7e1b8SBalint Dobszay 	if (flags & PTA_SYSTEM_MAP_FLAG_WRITEABLE)
226*cbe7e1b8SBalint Dobszay 		prot |= TEE_MATTR_UW | TEE_MATTR_PW;
227*cbe7e1b8SBalint Dobszay 	if (flags & PTA_SYSTEM_MAP_FLAG_EXECUTABLE)
228*cbe7e1b8SBalint Dobszay 		prot |= TEE_MATTR_UX;
229*cbe7e1b8SBalint Dobszay 
230*cbe7e1b8SBalint Dobszay 	offs_pages = offs_bytes >> SMALL_PAGE_SHIFT;
231*cbe7e1b8SBalint Dobszay 	if (ROUNDUP_OVERFLOW(num_bytes, SMALL_PAGE_SIZE, &num_rounded_bytes))
232*cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
233*cbe7e1b8SBalint Dobszay 	num_pages = num_rounded_bytes / SMALL_PAGE_SIZE;
234*cbe7e1b8SBalint Dobszay 
235*cbe7e1b8SBalint Dobszay 	if (!file_trylock(binh->f)) {
236*cbe7e1b8SBalint Dobszay 		/*
237*cbe7e1b8SBalint Dobszay 		 * Before we can block on the file lock we must make all
238*cbe7e1b8SBalint Dobszay 		 * our page tables available for reclaiming in order to
239*cbe7e1b8SBalint Dobszay 		 * avoid a dead-lock with the other thread (which already
240*cbe7e1b8SBalint Dobszay 		 * is holding the file lock) mapping lots of memory below.
241*cbe7e1b8SBalint Dobszay 		 */
242*cbe7e1b8SBalint Dobszay 		vm_set_ctx(NULL);
243*cbe7e1b8SBalint Dobszay 		file_lock(binh->f);
244*cbe7e1b8SBalint Dobszay 		vm_set_ctx(uctx->ts_ctx);
245*cbe7e1b8SBalint Dobszay 	}
246*cbe7e1b8SBalint Dobszay 	file_is_locked = true;
247*cbe7e1b8SBalint Dobszay 	fs = file_find_slice(binh->f, offs_pages);
248*cbe7e1b8SBalint Dobszay 	if (fs) {
249*cbe7e1b8SBalint Dobszay 		/* If there's registered slice it has to match */
250*cbe7e1b8SBalint Dobszay 		if (fs->page_offset != offs_pages ||
251*cbe7e1b8SBalint Dobszay 		    num_pages > fs->fobj->num_pages) {
252*cbe7e1b8SBalint Dobszay 			res = TEE_ERROR_BAD_PARAMETERS;
253*cbe7e1b8SBalint Dobszay 			goto err;
254*cbe7e1b8SBalint Dobszay 		}
255*cbe7e1b8SBalint Dobszay 
256*cbe7e1b8SBalint Dobszay 		/* If there's a slice we must be mapping shareable */
257*cbe7e1b8SBalint Dobszay 		if (!(flags & PTA_SYSTEM_MAP_FLAG_SHAREABLE)) {
258*cbe7e1b8SBalint Dobszay 			res = TEE_ERROR_BAD_PARAMETERS;
259*cbe7e1b8SBalint Dobszay 			goto err;
260*cbe7e1b8SBalint Dobszay 		}
261*cbe7e1b8SBalint Dobszay 
262*cbe7e1b8SBalint Dobszay 		mobj = mobj_with_fobj_alloc(fs->fobj, binh->f);
263*cbe7e1b8SBalint Dobszay 		if (!mobj) {
264*cbe7e1b8SBalint Dobszay 			res = TEE_ERROR_OUT_OF_MEMORY;
265*cbe7e1b8SBalint Dobszay 			goto err;
266*cbe7e1b8SBalint Dobszay 		}
267*cbe7e1b8SBalint Dobszay 		res = vm_map_pad(uctx, &va, num_rounded_bytes,
268*cbe7e1b8SBalint Dobszay 				 prot, VM_FLAG_READONLY,
269*cbe7e1b8SBalint Dobszay 				 mobj, 0, pad_begin, pad_end, 0);
270*cbe7e1b8SBalint Dobszay 		mobj_put(mobj);
271*cbe7e1b8SBalint Dobszay 		if (res)
272*cbe7e1b8SBalint Dobszay 			goto err;
273*cbe7e1b8SBalint Dobszay 	} else {
274*cbe7e1b8SBalint Dobszay 		struct fobj *f = fobj_ta_mem_alloc(num_pages);
275*cbe7e1b8SBalint Dobszay 		struct file *file = NULL;
276*cbe7e1b8SBalint Dobszay 		uint32_t vm_flags = 0;
277*cbe7e1b8SBalint Dobszay 
278*cbe7e1b8SBalint Dobszay 		if (!f) {
279*cbe7e1b8SBalint Dobszay 			res = TEE_ERROR_OUT_OF_MEMORY;
280*cbe7e1b8SBalint Dobszay 			goto err;
281*cbe7e1b8SBalint Dobszay 		}
282*cbe7e1b8SBalint Dobszay 		if (!(flags & PTA_SYSTEM_MAP_FLAG_WRITEABLE)) {
283*cbe7e1b8SBalint Dobszay 			file = binh->f;
284*cbe7e1b8SBalint Dobszay 			vm_flags |= VM_FLAG_READONLY;
285*cbe7e1b8SBalint Dobszay 		}
286*cbe7e1b8SBalint Dobszay 
287*cbe7e1b8SBalint Dobszay 		mobj = mobj_with_fobj_alloc(f, file);
288*cbe7e1b8SBalint Dobszay 		fobj_put(f);
289*cbe7e1b8SBalint Dobszay 		if (!mobj) {
290*cbe7e1b8SBalint Dobszay 			res = TEE_ERROR_OUT_OF_MEMORY;
291*cbe7e1b8SBalint Dobszay 			goto err;
292*cbe7e1b8SBalint Dobszay 		}
293*cbe7e1b8SBalint Dobszay 		res = vm_map_pad(uctx, &va, num_rounded_bytes,
294*cbe7e1b8SBalint Dobszay 				 TEE_MATTR_PRW, vm_flags, mobj, 0,
295*cbe7e1b8SBalint Dobszay 				 pad_begin, pad_end, 0);
296*cbe7e1b8SBalint Dobszay 		mobj_put(mobj);
297*cbe7e1b8SBalint Dobszay 		if (res)
298*cbe7e1b8SBalint Dobszay 			goto err;
299*cbe7e1b8SBalint Dobszay 		res = binh_copy_to(binh, va, offs_bytes, num_bytes);
300*cbe7e1b8SBalint Dobszay 		if (res)
301*cbe7e1b8SBalint Dobszay 			goto err_unmap_va;
302*cbe7e1b8SBalint Dobszay 		res = vm_set_prot(uctx, va, num_rounded_bytes,
303*cbe7e1b8SBalint Dobszay 				  prot);
304*cbe7e1b8SBalint Dobszay 		if (res)
305*cbe7e1b8SBalint Dobszay 			goto err_unmap_va;
306*cbe7e1b8SBalint Dobszay 
307*cbe7e1b8SBalint Dobszay 		/*
308*cbe7e1b8SBalint Dobszay 		 * The context currently is active set it again to update
309*cbe7e1b8SBalint Dobszay 		 * the mapping.
310*cbe7e1b8SBalint Dobszay 		 */
311*cbe7e1b8SBalint Dobszay 		vm_set_ctx(uctx->ts_ctx);
312*cbe7e1b8SBalint Dobszay 
313*cbe7e1b8SBalint Dobszay 		if (!(flags & PTA_SYSTEM_MAP_FLAG_WRITEABLE)) {
314*cbe7e1b8SBalint Dobszay 			res = file_add_slice(binh->f, f, offs_pages);
315*cbe7e1b8SBalint Dobszay 			if (res)
316*cbe7e1b8SBalint Dobszay 				goto err_unmap_va;
317*cbe7e1b8SBalint Dobszay 		}
318*cbe7e1b8SBalint Dobszay 	}
319*cbe7e1b8SBalint Dobszay 
320*cbe7e1b8SBalint Dobszay 	file_unlock(binh->f);
321*cbe7e1b8SBalint Dobszay 
322*cbe7e1b8SBalint Dobszay 	reg_pair_from_64(va, &params[2].value.a, &params[2].value.b);
323*cbe7e1b8SBalint Dobszay 	return TEE_SUCCESS;
324*cbe7e1b8SBalint Dobszay 
325*cbe7e1b8SBalint Dobszay err_unmap_va:
326*cbe7e1b8SBalint Dobszay 	if (vm_unmap(uctx, va, num_rounded_bytes))
327*cbe7e1b8SBalint Dobszay 		panic();
328*cbe7e1b8SBalint Dobszay 
329*cbe7e1b8SBalint Dobszay 	/*
330*cbe7e1b8SBalint Dobszay 	 * The context currently is active set it again to update
331*cbe7e1b8SBalint Dobszay 	 * the mapping.
332*cbe7e1b8SBalint Dobszay 	 */
333*cbe7e1b8SBalint Dobszay 	vm_set_ctx(uctx->ts_ctx);
334*cbe7e1b8SBalint Dobszay 
335*cbe7e1b8SBalint Dobszay err:
336*cbe7e1b8SBalint Dobszay 	if (file_is_locked)
337*cbe7e1b8SBalint Dobszay 		file_unlock(binh->f);
338*cbe7e1b8SBalint Dobszay 
339*cbe7e1b8SBalint Dobszay 	return res;
340*cbe7e1b8SBalint Dobszay }
341*cbe7e1b8SBalint Dobszay 
342*cbe7e1b8SBalint Dobszay TEE_Result ldelf_copy_from_ta_binary(struct system_ctx *ctx,
343*cbe7e1b8SBalint Dobszay 				     uint32_t param_types,
344*cbe7e1b8SBalint Dobszay 				     TEE_Param params[TEE_NUM_PARAMS])
345*cbe7e1b8SBalint Dobszay {
346*cbe7e1b8SBalint Dobszay 	struct bin_handle *binh = NULL;
347*cbe7e1b8SBalint Dobszay 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
348*cbe7e1b8SBalint Dobszay 					  TEE_PARAM_TYPE_MEMREF_OUTPUT,
349*cbe7e1b8SBalint Dobszay 					  TEE_PARAM_TYPE_NONE,
350*cbe7e1b8SBalint Dobszay 					  TEE_PARAM_TYPE_NONE);
351*cbe7e1b8SBalint Dobszay 
352*cbe7e1b8SBalint Dobszay 	if (exp_pt != param_types)
353*cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
354*cbe7e1b8SBalint Dobszay 
355*cbe7e1b8SBalint Dobszay 	binh = handle_lookup(&ctx->db, params[0].value.a);
356*cbe7e1b8SBalint Dobszay 	if (!binh)
357*cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
358*cbe7e1b8SBalint Dobszay 
359*cbe7e1b8SBalint Dobszay 	return binh_copy_to(binh, (vaddr_t)params[1].memref.buffer,
360*cbe7e1b8SBalint Dobszay 			    params[0].value.b, params[1].memref.size);
361*cbe7e1b8SBalint Dobszay }
362*cbe7e1b8SBalint Dobszay 
363*cbe7e1b8SBalint Dobszay TEE_Result ldelf_set_prot(struct user_mode_ctx *uctx, uint32_t param_types,
364*cbe7e1b8SBalint Dobszay 			  TEE_Param params[TEE_NUM_PARAMS])
365*cbe7e1b8SBalint Dobszay {
366*cbe7e1b8SBalint Dobszay 	const uint32_t accept_flags = PTA_SYSTEM_MAP_FLAG_WRITEABLE |
367*cbe7e1b8SBalint Dobszay 				      PTA_SYSTEM_MAP_FLAG_EXECUTABLE;
368*cbe7e1b8SBalint Dobszay 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
369*cbe7e1b8SBalint Dobszay 					  TEE_PARAM_TYPE_VALUE_INPUT,
370*cbe7e1b8SBalint Dobszay 					  TEE_PARAM_TYPE_NONE,
371*cbe7e1b8SBalint Dobszay 					  TEE_PARAM_TYPE_NONE);
372*cbe7e1b8SBalint Dobszay 	uint32_t prot = TEE_MATTR_UR | TEE_MATTR_PR;
373*cbe7e1b8SBalint Dobszay 	TEE_Result res = TEE_SUCCESS;
374*cbe7e1b8SBalint Dobszay 	uint32_t vm_flags = 0;
375*cbe7e1b8SBalint Dobszay 	uint32_t flags = 0;
376*cbe7e1b8SBalint Dobszay 	vaddr_t end_va = 0;
377*cbe7e1b8SBalint Dobszay 	vaddr_t va = 0;
378*cbe7e1b8SBalint Dobszay 	size_t sz = 0;
379*cbe7e1b8SBalint Dobszay 
380*cbe7e1b8SBalint Dobszay 	if (exp_pt != param_types)
381*cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
382*cbe7e1b8SBalint Dobszay 
383*cbe7e1b8SBalint Dobszay 	flags = params[0].value.b;
384*cbe7e1b8SBalint Dobszay 
385*cbe7e1b8SBalint Dobszay 	if ((flags & accept_flags) != flags)
386*cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
387*cbe7e1b8SBalint Dobszay 	if (flags & PTA_SYSTEM_MAP_FLAG_WRITEABLE)
388*cbe7e1b8SBalint Dobszay 		prot |= TEE_MATTR_UW | TEE_MATTR_PW;
389*cbe7e1b8SBalint Dobszay 	if (flags & PTA_SYSTEM_MAP_FLAG_EXECUTABLE)
390*cbe7e1b8SBalint Dobszay 		prot |= TEE_MATTR_UX;
391*cbe7e1b8SBalint Dobszay 
392*cbe7e1b8SBalint Dobszay 	va = reg_pair_to_64(params[1].value.a, params[1].value.b);
393*cbe7e1b8SBalint Dobszay 	sz = ROUNDUP(params[0].value.a, SMALL_PAGE_SIZE);
394*cbe7e1b8SBalint Dobszay 
395*cbe7e1b8SBalint Dobszay 	/*
396*cbe7e1b8SBalint Dobszay 	 * The vm_get_flags() and vm_set_prot() are supposed to detect or
397*cbe7e1b8SBalint Dobszay 	 * handle overflow directly or indirectly. However, this function
398*cbe7e1b8SBalint Dobszay 	 * an API function so an extra guard here is in order. If nothing
399*cbe7e1b8SBalint Dobszay 	 * else to make it easier to review the code.
400*cbe7e1b8SBalint Dobszay 	 */
401*cbe7e1b8SBalint Dobszay 	if (ADD_OVERFLOW(va, sz, &end_va))
402*cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
403*cbe7e1b8SBalint Dobszay 
404*cbe7e1b8SBalint Dobszay 	res = vm_get_flags(uctx, va, sz, &vm_flags);
405*cbe7e1b8SBalint Dobszay 	if (res)
406*cbe7e1b8SBalint Dobszay 		return res;
407*cbe7e1b8SBalint Dobszay 	if (vm_flags & VM_FLAG_PERMANENT)
408*cbe7e1b8SBalint Dobszay 		return TEE_ERROR_ACCESS_DENIED;
409*cbe7e1b8SBalint Dobszay 
410*cbe7e1b8SBalint Dobszay 	/*
411*cbe7e1b8SBalint Dobszay 	 * If the segment is a mapping of a part of a file (vm_flags &
412*cbe7e1b8SBalint Dobszay 	 * VM_FLAG_READONLY) it cannot be made writeable as all mapped
413*cbe7e1b8SBalint Dobszay 	 * files are mapped read-only.
414*cbe7e1b8SBalint Dobszay 	 */
415*cbe7e1b8SBalint Dobszay 	if ((vm_flags & VM_FLAG_READONLY) &&
416*cbe7e1b8SBalint Dobszay 	    (prot & (TEE_MATTR_UW | TEE_MATTR_PW)))
417*cbe7e1b8SBalint Dobszay 		return TEE_ERROR_ACCESS_DENIED;
418*cbe7e1b8SBalint Dobszay 
419*cbe7e1b8SBalint Dobszay 	return vm_set_prot(uctx, va, sz, prot);
420*cbe7e1b8SBalint Dobszay }
421*cbe7e1b8SBalint Dobszay 
422*cbe7e1b8SBalint Dobszay TEE_Result ldelf_remap(struct user_mode_ctx *uctx, uint32_t param_types,
423*cbe7e1b8SBalint Dobszay 		       TEE_Param params[TEE_NUM_PARAMS])
424*cbe7e1b8SBalint Dobszay {
425*cbe7e1b8SBalint Dobszay 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
426*cbe7e1b8SBalint Dobszay 					  TEE_PARAM_TYPE_VALUE_INPUT,
427*cbe7e1b8SBalint Dobszay 					  TEE_PARAM_TYPE_VALUE_INOUT,
428*cbe7e1b8SBalint Dobszay 					  TEE_PARAM_TYPE_VALUE_INPUT);
429*cbe7e1b8SBalint Dobszay 	TEE_Result res = TEE_SUCCESS;
430*cbe7e1b8SBalint Dobszay 	uint32_t num_bytes = 0;
431*cbe7e1b8SBalint Dobszay 	uint32_t pad_begin = 0;
432*cbe7e1b8SBalint Dobszay 	uint32_t vm_flags = 0;
433*cbe7e1b8SBalint Dobszay 	uint32_t pad_end = 0;
434*cbe7e1b8SBalint Dobszay 	vaddr_t old_va = 0;
435*cbe7e1b8SBalint Dobszay 	vaddr_t new_va = 0;
436*cbe7e1b8SBalint Dobszay 
437*cbe7e1b8SBalint Dobszay 	if (exp_pt != param_types)
438*cbe7e1b8SBalint Dobszay 		return TEE_ERROR_BAD_PARAMETERS;
439*cbe7e1b8SBalint Dobszay 
440*cbe7e1b8SBalint Dobszay 	num_bytes = params[0].value.a;
441*cbe7e1b8SBalint Dobszay 	old_va = reg_pair_to_64(params[1].value.a, params[1].value.b);
442*cbe7e1b8SBalint Dobszay 	new_va = reg_pair_to_64(params[2].value.a, params[2].value.b);
443*cbe7e1b8SBalint Dobszay 	pad_begin = params[3].value.a;
444*cbe7e1b8SBalint Dobszay 	pad_end = params[3].value.b;
445*cbe7e1b8SBalint Dobszay 
446*cbe7e1b8SBalint Dobszay 	res = vm_get_flags(uctx, old_va, num_bytes, &vm_flags);
447*cbe7e1b8SBalint Dobszay 	if (res)
448*cbe7e1b8SBalint Dobszay 		return res;
449*cbe7e1b8SBalint Dobszay 	if (vm_flags & VM_FLAG_PERMANENT)
450*cbe7e1b8SBalint Dobszay 		return TEE_ERROR_ACCESS_DENIED;
451*cbe7e1b8SBalint Dobszay 
452*cbe7e1b8SBalint Dobszay 	res = vm_remap(uctx, &new_va, old_va, num_bytes, pad_begin,
453*cbe7e1b8SBalint Dobszay 		       pad_end);
454*cbe7e1b8SBalint Dobszay 	if (!res)
455*cbe7e1b8SBalint Dobszay 		reg_pair_from_64(new_va, &params[2].value.a,
456*cbe7e1b8SBalint Dobszay 				 &params[2].value.b);
457*cbe7e1b8SBalint Dobszay 
458*cbe7e1b8SBalint Dobszay 	return res;
459*cbe7e1b8SBalint Dobszay }
460