xref: /optee_os/core/pta/system.c (revision 5843bb755f152c7961130e90bba969b8a1ce8f64)
1*5843bb75SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
2*5843bb75SJerome Forissier /*
3*5843bb75SJerome Forissier  * Copyright (c) 2018-2019, Linaro Limited
4*5843bb75SJerome Forissier  */
5*5843bb75SJerome Forissier 
6*5843bb75SJerome Forissier #include <assert.h>
7*5843bb75SJerome Forissier #include <crypto/crypto.h>
8*5843bb75SJerome Forissier #include <kernel/handle.h>
9*5843bb75SJerome Forissier #include <kernel/huk_subkey.h>
10*5843bb75SJerome Forissier #include <kernel/misc.h>
11*5843bb75SJerome Forissier #include <kernel/msg_param.h>
12*5843bb75SJerome Forissier #include <kernel/pseudo_ta.h>
13*5843bb75SJerome Forissier #include <kernel/user_ta.h>
14*5843bb75SJerome Forissier #include <kernel/user_ta_store.h>
15*5843bb75SJerome Forissier #include <ldelf.h>
16*5843bb75SJerome Forissier #include <mm/file.h>
17*5843bb75SJerome Forissier #include <mm/fobj.h>
18*5843bb75SJerome Forissier #include <mm/tee_mmu.h>
19*5843bb75SJerome Forissier #include <pta_system.h>
20*5843bb75SJerome Forissier #include <string.h>
21*5843bb75SJerome Forissier #include <tee_api_defines_extensions.h>
22*5843bb75SJerome Forissier #include <tee_api_defines.h>
23*5843bb75SJerome Forissier #include <util.h>
24*5843bb75SJerome Forissier 
25*5843bb75SJerome Forissier #define MAX_ENTROPY_IN			32u
26*5843bb75SJerome Forissier 
27*5843bb75SJerome Forissier struct bin_handle {
28*5843bb75SJerome Forissier 	const struct user_ta_store_ops *op;
29*5843bb75SJerome Forissier 	struct user_ta_store_handle *h;
30*5843bb75SJerome Forissier 	struct file *f;
31*5843bb75SJerome Forissier 	size_t offs_bytes;
32*5843bb75SJerome Forissier 	size_t size_bytes;
33*5843bb75SJerome Forissier };
34*5843bb75SJerome Forissier 
35*5843bb75SJerome Forissier struct system_ctx {
36*5843bb75SJerome Forissier 	struct handle_db db;
37*5843bb75SJerome Forissier 	const struct user_ta_store_ops *store_op;
38*5843bb75SJerome Forissier };
39*5843bb75SJerome Forissier 
40*5843bb75SJerome Forissier static unsigned int system_pnum;
41*5843bb75SJerome Forissier 
42*5843bb75SJerome Forissier static TEE_Result system_rng_reseed(struct tee_ta_session *s __unused,
43*5843bb75SJerome Forissier 				uint32_t param_types,
44*5843bb75SJerome Forissier 				TEE_Param params[TEE_NUM_PARAMS])
45*5843bb75SJerome Forissier {
46*5843bb75SJerome Forissier 	size_t entropy_sz;
47*5843bb75SJerome Forissier 	uint8_t *entropy_input;
48*5843bb75SJerome Forissier 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
49*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE,
50*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE,
51*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE);
52*5843bb75SJerome Forissier 
53*5843bb75SJerome Forissier 	if (exp_pt != param_types)
54*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
55*5843bb75SJerome Forissier 	entropy_input = params[0].memref.buffer;
56*5843bb75SJerome Forissier 	entropy_sz = params[0].memref.size;
57*5843bb75SJerome Forissier 
58*5843bb75SJerome Forissier 	/* Fortuna PRNG requires seed <= 32 bytes */
59*5843bb75SJerome Forissier 	if (!entropy_sz)
60*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
61*5843bb75SJerome Forissier 
62*5843bb75SJerome Forissier 	entropy_sz = MIN(entropy_sz, MAX_ENTROPY_IN);
63*5843bb75SJerome Forissier 
64*5843bb75SJerome Forissier 	crypto_rng_add_event(CRYPTO_RNG_SRC_NONSECURE, &system_pnum,
65*5843bb75SJerome Forissier 			     entropy_input, entropy_sz);
66*5843bb75SJerome Forissier 	return TEE_SUCCESS;
67*5843bb75SJerome Forissier }
68*5843bb75SJerome Forissier 
69*5843bb75SJerome Forissier static TEE_Result system_derive_ta_unique_key(struct tee_ta_session *s,
70*5843bb75SJerome Forissier 					      uint32_t param_types,
71*5843bb75SJerome Forissier 					      TEE_Param params[TEE_NUM_PARAMS])
72*5843bb75SJerome Forissier {
73*5843bb75SJerome Forissier 	size_t data_len = sizeof(TEE_UUID);
74*5843bb75SJerome Forissier 	TEE_Result res = TEE_ERROR_GENERIC;
75*5843bb75SJerome Forissier 	uint8_t *data = NULL;
76*5843bb75SJerome Forissier 	uint32_t access_flags = 0;
77*5843bb75SJerome Forissier 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
78*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_MEMREF_OUTPUT,
79*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE,
80*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE);
81*5843bb75SJerome Forissier 	struct user_ta_ctx *utc = NULL;
82*5843bb75SJerome Forissier 
83*5843bb75SJerome Forissier 	if (exp_pt != param_types)
84*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
85*5843bb75SJerome Forissier 
86*5843bb75SJerome Forissier 	if (params[0].memref.size > TA_DERIVED_EXTRA_DATA_MAX_SIZE ||
87*5843bb75SJerome Forissier 	    params[1].memref.size < TA_DERIVED_KEY_MIN_SIZE ||
88*5843bb75SJerome Forissier 	    params[1].memref.size > TA_DERIVED_KEY_MAX_SIZE)
89*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
90*5843bb75SJerome Forissier 
91*5843bb75SJerome Forissier 	utc = to_user_ta_ctx(s->ctx);
92*5843bb75SJerome Forissier 
93*5843bb75SJerome Forissier 	/*
94*5843bb75SJerome Forissier 	 * The derived key shall not end up in non-secure memory by
95*5843bb75SJerome Forissier 	 * mistake.
96*5843bb75SJerome Forissier 	 *
97*5843bb75SJerome Forissier 	 * Note that we're allowing shared memory as long as it's
98*5843bb75SJerome Forissier 	 * secure. This is needed because a TA always uses shared memory
99*5843bb75SJerome Forissier 	 * when communicating with another TA.
100*5843bb75SJerome Forissier 	 */
101*5843bb75SJerome Forissier 	access_flags = TEE_MEMORY_ACCESS_WRITE | TEE_MEMORY_ACCESS_ANY_OWNER |
102*5843bb75SJerome Forissier 		       TEE_MEMORY_ACCESS_SECURE;
103*5843bb75SJerome Forissier 	res = tee_mmu_check_access_rights(utc, access_flags,
104*5843bb75SJerome Forissier 					  (uaddr_t)params[1].memref.buffer,
105*5843bb75SJerome Forissier 					  params[1].memref.size);
106*5843bb75SJerome Forissier 	if (res != TEE_SUCCESS)
107*5843bb75SJerome Forissier 		return TEE_ERROR_SECURITY;
108*5843bb75SJerome Forissier 
109*5843bb75SJerome Forissier 	/* Take extra data into account. */
110*5843bb75SJerome Forissier 	if (ADD_OVERFLOW(data_len, params[0].memref.size, &data_len))
111*5843bb75SJerome Forissier 		return TEE_ERROR_SECURITY;
112*5843bb75SJerome Forissier 
113*5843bb75SJerome Forissier 	data = calloc(data_len, 1);
114*5843bb75SJerome Forissier 	if (!data)
115*5843bb75SJerome Forissier 		return TEE_ERROR_OUT_OF_MEMORY;
116*5843bb75SJerome Forissier 
117*5843bb75SJerome Forissier 	memcpy(data, &s->ctx->uuid, sizeof(TEE_UUID));
118*5843bb75SJerome Forissier 
119*5843bb75SJerome Forissier 	/* Append the user provided data */
120*5843bb75SJerome Forissier 	memcpy(data + sizeof(TEE_UUID), params[0].memref.buffer,
121*5843bb75SJerome Forissier 	       params[0].memref.size);
122*5843bb75SJerome Forissier 
123*5843bb75SJerome Forissier 	res = huk_subkey_derive(HUK_SUBKEY_UNIQUE_TA, data, data_len,
124*5843bb75SJerome Forissier 				params[1].memref.buffer,
125*5843bb75SJerome Forissier 				params[1].memref.size);
126*5843bb75SJerome Forissier 	free(data);
127*5843bb75SJerome Forissier 
128*5843bb75SJerome Forissier 	return res;
129*5843bb75SJerome Forissier }
130*5843bb75SJerome Forissier 
131*5843bb75SJerome Forissier static TEE_Result system_map_zi(struct tee_ta_session *s, uint32_t param_types,
132*5843bb75SJerome Forissier 				TEE_Param params[TEE_NUM_PARAMS])
133*5843bb75SJerome Forissier {
134*5843bb75SJerome Forissier 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
135*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_VALUE_INOUT,
136*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_VALUE_INPUT,
137*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE);
138*5843bb75SJerome Forissier 	struct user_ta_ctx *utc = to_user_ta_ctx(s->ctx);
139*5843bb75SJerome Forissier 	uint32_t prot = TEE_MATTR_URW | TEE_MATTR_PRW;
140*5843bb75SJerome Forissier 	uint32_t vm_flags = VM_FLAG_EXCLUSIVE_MOBJ;
141*5843bb75SJerome Forissier 	TEE_Result res = TEE_ERROR_GENERIC;
142*5843bb75SJerome Forissier 	struct mobj *mobj = NULL;
143*5843bb75SJerome Forissier 	uint32_t pad_begin = 0;
144*5843bb75SJerome Forissier 	struct fobj *f = NULL;
145*5843bb75SJerome Forissier 	uint32_t pad_end = 0;
146*5843bb75SJerome Forissier 	size_t num_bytes = 0;
147*5843bb75SJerome Forissier 	vaddr_t va = 0;
148*5843bb75SJerome Forissier 
149*5843bb75SJerome Forissier 	if (exp_pt != param_types)
150*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
151*5843bb75SJerome Forissier 	if (params[0].value.b & ~PTA_SYSTEM_MAP_FLAG_SHAREABLE)
152*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
153*5843bb75SJerome Forissier 
154*5843bb75SJerome Forissier 	if (params[0].value.b & PTA_SYSTEM_MAP_FLAG_SHAREABLE)
155*5843bb75SJerome Forissier 		vm_flags |= VM_FLAG_SHAREABLE;
156*5843bb75SJerome Forissier 
157*5843bb75SJerome Forissier 	num_bytes = params[0].value.a;
158*5843bb75SJerome Forissier 	va = reg_pair_to_64(params[1].value.a, params[1].value.b);
159*5843bb75SJerome Forissier 	pad_begin = params[2].value.a;
160*5843bb75SJerome Forissier 	pad_end = params[2].value.b;
161*5843bb75SJerome Forissier 
162*5843bb75SJerome Forissier 	f = fobj_ta_mem_alloc(ROUNDUP(num_bytes, SMALL_PAGE_SIZE) /
163*5843bb75SJerome Forissier 			      SMALL_PAGE_SIZE);
164*5843bb75SJerome Forissier 	if (!f)
165*5843bb75SJerome Forissier 		return TEE_ERROR_OUT_OF_MEMORY;
166*5843bb75SJerome Forissier 	mobj = mobj_with_fobj_alloc(f, NULL);
167*5843bb75SJerome Forissier 	fobj_put(f);
168*5843bb75SJerome Forissier 	if (!mobj)
169*5843bb75SJerome Forissier 		return TEE_ERROR_OUT_OF_MEMORY;
170*5843bb75SJerome Forissier 	res = vm_map_pad(utc, &va, num_bytes, prot, vm_flags,
171*5843bb75SJerome Forissier 			 mobj, 0, pad_begin, pad_end);
172*5843bb75SJerome Forissier 	if (res)
173*5843bb75SJerome Forissier 		mobj_free(mobj);
174*5843bb75SJerome Forissier 	else
175*5843bb75SJerome Forissier 		reg_pair_from_64(va, &params[1].value.a, &params[1].value.b);
176*5843bb75SJerome Forissier 
177*5843bb75SJerome Forissier 	return res;
178*5843bb75SJerome Forissier }
179*5843bb75SJerome Forissier 
180*5843bb75SJerome Forissier static TEE_Result system_unmap(struct tee_ta_session *s, uint32_t param_types,
181*5843bb75SJerome Forissier 			       TEE_Param params[TEE_NUM_PARAMS])
182*5843bb75SJerome Forissier {
183*5843bb75SJerome Forissier 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
184*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_VALUE_INPUT,
185*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE,
186*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE);
187*5843bb75SJerome Forissier 
188*5843bb75SJerome Forissier 	if (exp_pt != param_types)
189*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
190*5843bb75SJerome Forissier 
191*5843bb75SJerome Forissier 	if (params[0].value.b)
192*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
193*5843bb75SJerome Forissier 
194*5843bb75SJerome Forissier 	return vm_unmap(to_user_ta_ctx(s->ctx),
195*5843bb75SJerome Forissier 			reg_pair_to_64(params[1].value.a, params[1].value.b),
196*5843bb75SJerome Forissier 			ROUNDUP(params[0].value.a, SMALL_PAGE_SIZE));
197*5843bb75SJerome Forissier }
198*5843bb75SJerome Forissier 
199*5843bb75SJerome Forissier static void ta_bin_close(void *ptr)
200*5843bb75SJerome Forissier {
201*5843bb75SJerome Forissier 	struct bin_handle *binh = ptr;
202*5843bb75SJerome Forissier 
203*5843bb75SJerome Forissier 	if (binh) {
204*5843bb75SJerome Forissier 		if (binh->op && binh->h)
205*5843bb75SJerome Forissier 			binh->op->close(binh->h);
206*5843bb75SJerome Forissier 		file_put(binh->f);
207*5843bb75SJerome Forissier 	}
208*5843bb75SJerome Forissier 	free(binh);
209*5843bb75SJerome Forissier }
210*5843bb75SJerome Forissier 
211*5843bb75SJerome Forissier static TEE_Result system_open_ta_binary(struct system_ctx *ctx,
212*5843bb75SJerome Forissier 					uint32_t param_types,
213*5843bb75SJerome Forissier 					TEE_Param params[TEE_NUM_PARAMS])
214*5843bb75SJerome Forissier {
215*5843bb75SJerome Forissier 	TEE_Result res = TEE_SUCCESS;
216*5843bb75SJerome Forissier 	struct bin_handle *binh = NULL;
217*5843bb75SJerome Forissier 	int h = 0;
218*5843bb75SJerome Forissier 	TEE_UUID *uuid = NULL;
219*5843bb75SJerome Forissier 	uint8_t tag[FILE_TAG_SIZE] = { 0 };
220*5843bb75SJerome Forissier 	unsigned int tag_len = sizeof(tag);
221*5843bb75SJerome Forissier 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
222*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_VALUE_OUTPUT,
223*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE,
224*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE);
225*5843bb75SJerome Forissier 
226*5843bb75SJerome Forissier 	if (exp_pt != param_types)
227*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
228*5843bb75SJerome Forissier 	if (params[0].memref.size != sizeof(*uuid))
229*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
230*5843bb75SJerome Forissier 
231*5843bb75SJerome Forissier 	uuid = params[0].memref.buffer;
232*5843bb75SJerome Forissier 
233*5843bb75SJerome Forissier 	binh = calloc(1, sizeof(*binh));
234*5843bb75SJerome Forissier 	if (!binh)
235*5843bb75SJerome Forissier 		return TEE_ERROR_OUT_OF_MEMORY;
236*5843bb75SJerome Forissier 
237*5843bb75SJerome Forissier 	SCATTERED_ARRAY_FOREACH(binh->op, ta_stores, struct user_ta_store_ops) {
238*5843bb75SJerome Forissier 		DMSG("Lookup user TA ELF %pUl (%s)",
239*5843bb75SJerome Forissier 		     (void *)uuid, binh->op->description);
240*5843bb75SJerome Forissier 
241*5843bb75SJerome Forissier 		res = binh->op->open(uuid, &binh->h);
242*5843bb75SJerome Forissier 		DMSG("res=0x%x", res);
243*5843bb75SJerome Forissier 		if (res != TEE_ERROR_ITEM_NOT_FOUND &&
244*5843bb75SJerome Forissier 		    res != TEE_ERROR_STORAGE_NOT_AVAILABLE)
245*5843bb75SJerome Forissier 			break;
246*5843bb75SJerome Forissier 	}
247*5843bb75SJerome Forissier 	if (res)
248*5843bb75SJerome Forissier 		goto err;
249*5843bb75SJerome Forissier 
250*5843bb75SJerome Forissier 	res = binh->op->get_size(binh->h, &binh->size_bytes);
251*5843bb75SJerome Forissier 	if (res)
252*5843bb75SJerome Forissier 		goto err;
253*5843bb75SJerome Forissier 	res = binh->op->get_tag(binh->h, tag, &tag_len);
254*5843bb75SJerome Forissier 	if (res)
255*5843bb75SJerome Forissier 		goto err;
256*5843bb75SJerome Forissier 	binh->f = file_get_by_tag(tag, tag_len);
257*5843bb75SJerome Forissier 	if (!binh->f)
258*5843bb75SJerome Forissier 		goto err_oom;
259*5843bb75SJerome Forissier 
260*5843bb75SJerome Forissier 	h = handle_get(&ctx->db, binh);
261*5843bb75SJerome Forissier 	if (h < 0)
262*5843bb75SJerome Forissier 		goto err_oom;
263*5843bb75SJerome Forissier 
264*5843bb75SJerome Forissier 	return TEE_SUCCESS;
265*5843bb75SJerome Forissier err_oom:
266*5843bb75SJerome Forissier 	res = TEE_ERROR_OUT_OF_MEMORY;
267*5843bb75SJerome Forissier err:
268*5843bb75SJerome Forissier 	ta_bin_close(binh);
269*5843bb75SJerome Forissier 	return res;
270*5843bb75SJerome Forissier }
271*5843bb75SJerome Forissier 
272*5843bb75SJerome Forissier static TEE_Result system_close_ta_binary(struct system_ctx *ctx,
273*5843bb75SJerome Forissier 					 uint32_t param_types,
274*5843bb75SJerome Forissier 					 TEE_Param params[TEE_NUM_PARAMS])
275*5843bb75SJerome Forissier {
276*5843bb75SJerome Forissier 	TEE_Result res = TEE_SUCCESS;
277*5843bb75SJerome Forissier 	struct bin_handle *binh = NULL;
278*5843bb75SJerome Forissier 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
279*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE,
280*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE,
281*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE);
282*5843bb75SJerome Forissier 
283*5843bb75SJerome Forissier 	if (exp_pt != param_types)
284*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
285*5843bb75SJerome Forissier 
286*5843bb75SJerome Forissier 	if (params[0].value.b)
287*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
288*5843bb75SJerome Forissier 
289*5843bb75SJerome Forissier 	binh = handle_put(&ctx->db, params[0].value.a);
290*5843bb75SJerome Forissier 	if (!binh)
291*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
292*5843bb75SJerome Forissier 
293*5843bb75SJerome Forissier 	if (binh->offs_bytes < binh->size_bytes)
294*5843bb75SJerome Forissier 		res = binh->op->read(binh->h, NULL,
295*5843bb75SJerome Forissier 				     binh->size_bytes - binh->offs_bytes);
296*5843bb75SJerome Forissier 
297*5843bb75SJerome Forissier 	ta_bin_close(binh);
298*5843bb75SJerome Forissier 	return res;
299*5843bb75SJerome Forissier }
300*5843bb75SJerome Forissier 
301*5843bb75SJerome Forissier static TEE_Result binh_copy_to(struct bin_handle *binh, vaddr_t va,
302*5843bb75SJerome Forissier 			       size_t offs_bytes, size_t num_bytes)
303*5843bb75SJerome Forissier {
304*5843bb75SJerome Forissier 	TEE_Result res = TEE_SUCCESS;
305*5843bb75SJerome Forissier 	size_t l =  num_bytes;
306*5843bb75SJerome Forissier 
307*5843bb75SJerome Forissier 	if (offs_bytes < binh->offs_bytes)
308*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_STATE;
309*5843bb75SJerome Forissier 	if (offs_bytes > binh->offs_bytes) {
310*5843bb75SJerome Forissier 		res = binh->op->read(binh->h, NULL,
311*5843bb75SJerome Forissier 				     offs_bytes - binh->offs_bytes);
312*5843bb75SJerome Forissier 		if (res)
313*5843bb75SJerome Forissier 			return res;
314*5843bb75SJerome Forissier 		binh->offs_bytes = offs_bytes;
315*5843bb75SJerome Forissier 	}
316*5843bb75SJerome Forissier 
317*5843bb75SJerome Forissier 	if (binh->offs_bytes + l > binh->size_bytes) {
318*5843bb75SJerome Forissier 		size_t rb = binh->size_bytes - binh->offs_bytes;
319*5843bb75SJerome Forissier 
320*5843bb75SJerome Forissier 		res = binh->op->read(binh->h, (void *)va, rb);
321*5843bb75SJerome Forissier 		if (res)
322*5843bb75SJerome Forissier 			return res;
323*5843bb75SJerome Forissier 		memset((uint8_t *)va + rb, 0, l - rb);
324*5843bb75SJerome Forissier 		binh->offs_bytes = binh->size_bytes;
325*5843bb75SJerome Forissier 	} else {
326*5843bb75SJerome Forissier 		res = binh->op->read(binh->h, (void *)va, l);
327*5843bb75SJerome Forissier 		if (res)
328*5843bb75SJerome Forissier 			return res;
329*5843bb75SJerome Forissier 		binh->offs_bytes += l;
330*5843bb75SJerome Forissier 	}
331*5843bb75SJerome Forissier 
332*5843bb75SJerome Forissier 	return TEE_SUCCESS;
333*5843bb75SJerome Forissier }
334*5843bb75SJerome Forissier 
335*5843bb75SJerome Forissier static TEE_Result system_map_ta_binary(struct system_ctx *ctx,
336*5843bb75SJerome Forissier 				       struct tee_ta_session *s,
337*5843bb75SJerome Forissier 				       uint32_t param_types,
338*5843bb75SJerome Forissier 				       TEE_Param params[TEE_NUM_PARAMS])
339*5843bb75SJerome Forissier {
340*5843bb75SJerome Forissier 	const uint32_t accept_flags = PTA_SYSTEM_MAP_FLAG_SHAREABLE |
341*5843bb75SJerome Forissier 				      PTA_SYSTEM_MAP_FLAG_WRITEABLE |
342*5843bb75SJerome Forissier 				      PTA_SYSTEM_MAP_FLAG_EXECUTABLE;
343*5843bb75SJerome Forissier 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
344*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_VALUE_INPUT,
345*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_VALUE_INOUT,
346*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_VALUE_INPUT);
347*5843bb75SJerome Forissier 	struct user_ta_ctx *utc = to_user_ta_ctx(s->ctx);
348*5843bb75SJerome Forissier 	struct bin_handle *binh = NULL;
349*5843bb75SJerome Forissier 	TEE_Result res = TEE_SUCCESS;
350*5843bb75SJerome Forissier 	struct file_slice *fs = NULL;
351*5843bb75SJerome Forissier 	bool file_is_locked = false;
352*5843bb75SJerome Forissier 	struct mobj *mobj = NULL;
353*5843bb75SJerome Forissier 	uint32_t offs_bytes = 0;
354*5843bb75SJerome Forissier 	uint32_t offs_pages = 0;
355*5843bb75SJerome Forissier 	uint32_t num_bytes = 0;
356*5843bb75SJerome Forissier 	uint32_t pad_begin = 0;
357*5843bb75SJerome Forissier 	uint32_t pad_end = 0;
358*5843bb75SJerome Forissier 	size_t num_pages = 0;
359*5843bb75SJerome Forissier 	uint32_t flags = 0;
360*5843bb75SJerome Forissier 	uint32_t prot = 0;
361*5843bb75SJerome Forissier 	vaddr_t va = 0;
362*5843bb75SJerome Forissier 
363*5843bb75SJerome Forissier 	if (exp_pt != param_types)
364*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
365*5843bb75SJerome Forissier 
366*5843bb75SJerome Forissier 	binh = handle_lookup(&ctx->db, params[0].value.a);
367*5843bb75SJerome Forissier 	if (!binh)
368*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
369*5843bb75SJerome Forissier 	flags = params[0].value.b;
370*5843bb75SJerome Forissier 	offs_bytes = params[1].value.a;
371*5843bb75SJerome Forissier 	num_bytes = params[1].value.b;
372*5843bb75SJerome Forissier 	va = reg_pair_to_64(params[2].value.a, params[2].value.b);
373*5843bb75SJerome Forissier 	pad_begin = params[3].value.a;
374*5843bb75SJerome Forissier 	pad_end = params[3].value.b;
375*5843bb75SJerome Forissier 
376*5843bb75SJerome Forissier 	if ((flags & accept_flags) != flags)
377*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
378*5843bb75SJerome Forissier 
379*5843bb75SJerome Forissier 	if ((flags & PTA_SYSTEM_MAP_FLAG_SHAREABLE) &&
380*5843bb75SJerome Forissier 	    (flags & PTA_SYSTEM_MAP_FLAG_WRITEABLE))
381*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
382*5843bb75SJerome Forissier 
383*5843bb75SJerome Forissier 	if ((flags & PTA_SYSTEM_MAP_FLAG_EXECUTABLE) &&
384*5843bb75SJerome Forissier 	    (flags & PTA_SYSTEM_MAP_FLAG_WRITEABLE))
385*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
386*5843bb75SJerome Forissier 
387*5843bb75SJerome Forissier 	if (offs_bytes & SMALL_PAGE_MASK)
388*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
389*5843bb75SJerome Forissier 
390*5843bb75SJerome Forissier 	prot = TEE_MATTR_UR | TEE_MATTR_PR;
391*5843bb75SJerome Forissier 	if (flags & PTA_SYSTEM_MAP_FLAG_WRITEABLE)
392*5843bb75SJerome Forissier 		prot |= TEE_MATTR_UW | TEE_MATTR_PW;
393*5843bb75SJerome Forissier 	if (flags & PTA_SYSTEM_MAP_FLAG_EXECUTABLE)
394*5843bb75SJerome Forissier 		prot |= TEE_MATTR_UX;
395*5843bb75SJerome Forissier 
396*5843bb75SJerome Forissier 	offs_pages = offs_bytes >> SMALL_PAGE_SHIFT;
397*5843bb75SJerome Forissier 	num_pages = ROUNDUP(num_bytes, SMALL_PAGE_SIZE) / SMALL_PAGE_SIZE;
398*5843bb75SJerome Forissier 
399*5843bb75SJerome Forissier 	if (!file_trylock(binh->f)) {
400*5843bb75SJerome Forissier 		/*
401*5843bb75SJerome Forissier 		 * Before we can block on the file lock we must make all
402*5843bb75SJerome Forissier 		 * our page tables available for reclaiming in order to
403*5843bb75SJerome Forissier 		 * avoid a dead-lock with the other thread (which already
404*5843bb75SJerome Forissier 		 * is holding the file lock) mapping lots of memory below.
405*5843bb75SJerome Forissier 		 */
406*5843bb75SJerome Forissier 		tee_mmu_set_ctx(NULL);
407*5843bb75SJerome Forissier 		file_lock(binh->f);
408*5843bb75SJerome Forissier 		tee_mmu_set_ctx(s->ctx);
409*5843bb75SJerome Forissier 	}
410*5843bb75SJerome Forissier 	file_is_locked = true;
411*5843bb75SJerome Forissier 	fs = file_find_slice(binh->f, offs_pages);
412*5843bb75SJerome Forissier 	if (fs) {
413*5843bb75SJerome Forissier 		/* If there's registered slice it has to match */
414*5843bb75SJerome Forissier 		if (fs->page_offset != offs_pages ||
415*5843bb75SJerome Forissier 		    num_pages > fs->fobj->num_pages) {
416*5843bb75SJerome Forissier 			res = TEE_ERROR_BAD_PARAMETERS;
417*5843bb75SJerome Forissier 			goto err;
418*5843bb75SJerome Forissier 		}
419*5843bb75SJerome Forissier 
420*5843bb75SJerome Forissier 		/* If there's a slice we must be mapping shareable */
421*5843bb75SJerome Forissier 		if (!(flags & PTA_SYSTEM_MAP_FLAG_SHAREABLE)) {
422*5843bb75SJerome Forissier 			res = TEE_ERROR_BAD_PARAMETERS;
423*5843bb75SJerome Forissier 			goto err;
424*5843bb75SJerome Forissier 		}
425*5843bb75SJerome Forissier 
426*5843bb75SJerome Forissier 		mobj = mobj_with_fobj_alloc(fs->fobj, binh->f);
427*5843bb75SJerome Forissier 		if (!mobj) {
428*5843bb75SJerome Forissier 			res = TEE_ERROR_OUT_OF_MEMORY;
429*5843bb75SJerome Forissier 			goto err;
430*5843bb75SJerome Forissier 		}
431*5843bb75SJerome Forissier 		res = vm_map_pad(utc, &va, num_pages * SMALL_PAGE_SIZE, prot,
432*5843bb75SJerome Forissier 				 VM_FLAG_READONLY | VM_FLAG_EXCLUSIVE_MOBJ,
433*5843bb75SJerome Forissier 				 mobj, 0, pad_begin, pad_end);
434*5843bb75SJerome Forissier 		if (res)
435*5843bb75SJerome Forissier 			goto err;
436*5843bb75SJerome Forissier 	} else {
437*5843bb75SJerome Forissier 		struct fobj *f = fobj_ta_mem_alloc(num_pages);
438*5843bb75SJerome Forissier 		struct file *file = NULL;
439*5843bb75SJerome Forissier 		uint32_t vm_flags = VM_FLAG_EXCLUSIVE_MOBJ;
440*5843bb75SJerome Forissier 
441*5843bb75SJerome Forissier 		if (!f) {
442*5843bb75SJerome Forissier 			res = TEE_ERROR_OUT_OF_MEMORY;
443*5843bb75SJerome Forissier 			goto err;
444*5843bb75SJerome Forissier 		}
445*5843bb75SJerome Forissier 		if (!(flags & PTA_SYSTEM_MAP_FLAG_WRITEABLE)) {
446*5843bb75SJerome Forissier 			file = binh->f;
447*5843bb75SJerome Forissier 			vm_flags |= VM_FLAG_READONLY;
448*5843bb75SJerome Forissier 		}
449*5843bb75SJerome Forissier 
450*5843bb75SJerome Forissier 		mobj = mobj_with_fobj_alloc(f, file);
451*5843bb75SJerome Forissier 		fobj_put(f);
452*5843bb75SJerome Forissier 		if (!mobj) {
453*5843bb75SJerome Forissier 			res = TEE_ERROR_OUT_OF_MEMORY;
454*5843bb75SJerome Forissier 			goto err;
455*5843bb75SJerome Forissier 		}
456*5843bb75SJerome Forissier 		res = vm_map_pad(utc, &va, num_pages * SMALL_PAGE_SIZE,
457*5843bb75SJerome Forissier 				 TEE_MATTR_PRW, vm_flags, mobj, 0,
458*5843bb75SJerome Forissier 				 pad_begin, pad_end);
459*5843bb75SJerome Forissier 		if (res)
460*5843bb75SJerome Forissier 			goto err;
461*5843bb75SJerome Forissier 		res = binh_copy_to(binh, va, offs_bytes, num_bytes);
462*5843bb75SJerome Forissier 		if (res)
463*5843bb75SJerome Forissier 			goto err_unmap_va;
464*5843bb75SJerome Forissier 		res = vm_set_prot(utc, va, num_pages * SMALL_PAGE_SIZE, prot);
465*5843bb75SJerome Forissier 		if (res)
466*5843bb75SJerome Forissier 			goto err_unmap_va;
467*5843bb75SJerome Forissier 
468*5843bb75SJerome Forissier 		/*
469*5843bb75SJerome Forissier 		 * The context currently is active set it again to update
470*5843bb75SJerome Forissier 		 * the mapping.
471*5843bb75SJerome Forissier 		 */
472*5843bb75SJerome Forissier 		tee_mmu_set_ctx(s->ctx);
473*5843bb75SJerome Forissier 
474*5843bb75SJerome Forissier 		if (!(flags & PTA_SYSTEM_MAP_FLAG_WRITEABLE)) {
475*5843bb75SJerome Forissier 			res = file_add_slice(binh->f, f, offs_pages);
476*5843bb75SJerome Forissier 			if (res)
477*5843bb75SJerome Forissier 				goto err_unmap_va;
478*5843bb75SJerome Forissier 		}
479*5843bb75SJerome Forissier 	}
480*5843bb75SJerome Forissier 
481*5843bb75SJerome Forissier 	file_unlock(binh->f);
482*5843bb75SJerome Forissier 
483*5843bb75SJerome Forissier 	reg_pair_from_64(va, &params[2].value.a, &params[2].value.b);
484*5843bb75SJerome Forissier 	return TEE_SUCCESS;
485*5843bb75SJerome Forissier 
486*5843bb75SJerome Forissier err_unmap_va:
487*5843bb75SJerome Forissier 	if (vm_unmap(utc, va, num_pages * SMALL_PAGE_SIZE))
488*5843bb75SJerome Forissier 		panic();
489*5843bb75SJerome Forissier 
490*5843bb75SJerome Forissier 	/*
491*5843bb75SJerome Forissier 	 * The context currently is active set it again to update
492*5843bb75SJerome Forissier 	 * the mapping.
493*5843bb75SJerome Forissier 	 */
494*5843bb75SJerome Forissier 	tee_mmu_set_ctx(s->ctx);
495*5843bb75SJerome Forissier 
496*5843bb75SJerome Forissier err:
497*5843bb75SJerome Forissier 	mobj_free(mobj);
498*5843bb75SJerome Forissier 	if (file_is_locked)
499*5843bb75SJerome Forissier 		file_unlock(binh->f);
500*5843bb75SJerome Forissier 
501*5843bb75SJerome Forissier 	return res;
502*5843bb75SJerome Forissier }
503*5843bb75SJerome Forissier 
504*5843bb75SJerome Forissier static TEE_Result system_copy_from_ta_binary(struct system_ctx *ctx,
505*5843bb75SJerome Forissier 					     uint32_t param_types,
506*5843bb75SJerome Forissier 					     TEE_Param params[TEE_NUM_PARAMS])
507*5843bb75SJerome Forissier {
508*5843bb75SJerome Forissier 	struct bin_handle *binh = NULL;
509*5843bb75SJerome Forissier 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
510*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_MEMREF_OUTPUT,
511*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE,
512*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE);
513*5843bb75SJerome Forissier 
514*5843bb75SJerome Forissier 	if (exp_pt != param_types)
515*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
516*5843bb75SJerome Forissier 
517*5843bb75SJerome Forissier 	binh = handle_lookup(&ctx->db, params[0].value.a);
518*5843bb75SJerome Forissier 	if (!binh)
519*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
520*5843bb75SJerome Forissier 
521*5843bb75SJerome Forissier 	return binh_copy_to(binh, (vaddr_t)params[1].memref.buffer,
522*5843bb75SJerome Forissier 			    params[0].value.b, params[1].memref.size);
523*5843bb75SJerome Forissier }
524*5843bb75SJerome Forissier 
525*5843bb75SJerome Forissier static TEE_Result system_set_prot(struct tee_ta_session *s,
526*5843bb75SJerome Forissier 				  uint32_t param_types,
527*5843bb75SJerome Forissier 				  TEE_Param params[TEE_NUM_PARAMS])
528*5843bb75SJerome Forissier {
529*5843bb75SJerome Forissier 	const uint32_t accept_flags = PTA_SYSTEM_MAP_FLAG_WRITEABLE |
530*5843bb75SJerome Forissier 				      PTA_SYSTEM_MAP_FLAG_EXECUTABLE;
531*5843bb75SJerome Forissier 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
532*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_VALUE_INPUT,
533*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE,
534*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE);
535*5843bb75SJerome Forissier 	struct user_ta_ctx *utc = to_user_ta_ctx(s->ctx);
536*5843bb75SJerome Forissier 	uint32_t prot = TEE_MATTR_UR | TEE_MATTR_PR;
537*5843bb75SJerome Forissier 	TEE_Result res = TEE_SUCCESS;
538*5843bb75SJerome Forissier 	uint32_t vm_flags = 0;
539*5843bb75SJerome Forissier 	uint32_t flags = 0;
540*5843bb75SJerome Forissier 	vaddr_t va = 0;
541*5843bb75SJerome Forissier 	size_t sz = 0;
542*5843bb75SJerome Forissier 
543*5843bb75SJerome Forissier 	if (exp_pt != param_types)
544*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
545*5843bb75SJerome Forissier 
546*5843bb75SJerome Forissier 	flags = params[0].value.b;
547*5843bb75SJerome Forissier 
548*5843bb75SJerome Forissier 	if ((flags & accept_flags) != flags)
549*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
550*5843bb75SJerome Forissier 	if (flags & PTA_SYSTEM_MAP_FLAG_WRITEABLE)
551*5843bb75SJerome Forissier 		prot |= TEE_MATTR_UW | TEE_MATTR_PW;
552*5843bb75SJerome Forissier 	if (flags & PTA_SYSTEM_MAP_FLAG_EXECUTABLE)
553*5843bb75SJerome Forissier 		prot |= TEE_MATTR_UX;
554*5843bb75SJerome Forissier 
555*5843bb75SJerome Forissier 	va = reg_pair_to_64(params[1].value.a, params[1].value.b),
556*5843bb75SJerome Forissier 	sz = ROUNDUP(params[0].value.a, SMALL_PAGE_SIZE);
557*5843bb75SJerome Forissier 
558*5843bb75SJerome Forissier 	res = vm_get_flags(utc, va, sz, &vm_flags);
559*5843bb75SJerome Forissier 	if (res)
560*5843bb75SJerome Forissier 		return res;
561*5843bb75SJerome Forissier 
562*5843bb75SJerome Forissier 	/*
563*5843bb75SJerome Forissier 	 * If the segment is a mapping of a part of a file (vm_flags &
564*5843bb75SJerome Forissier 	 * VM_FLAG_READONLY) it cannot be made writeable as all mapped
565*5843bb75SJerome Forissier 	 * files are mapped read-only.
566*5843bb75SJerome Forissier 	 */
567*5843bb75SJerome Forissier 	if ((vm_flags & VM_FLAG_READONLY) &&
568*5843bb75SJerome Forissier 	    (prot & (TEE_MATTR_UW | TEE_MATTR_PW)))
569*5843bb75SJerome Forissier 		return TEE_ERROR_ACCESS_DENIED;
570*5843bb75SJerome Forissier 
571*5843bb75SJerome Forissier 	return vm_set_prot(utc, va, sz, prot);
572*5843bb75SJerome Forissier }
573*5843bb75SJerome Forissier 
574*5843bb75SJerome Forissier static TEE_Result system_remap(struct tee_ta_session *s, uint32_t param_types,
575*5843bb75SJerome Forissier 			       TEE_Param params[TEE_NUM_PARAMS])
576*5843bb75SJerome Forissier {
577*5843bb75SJerome Forissier 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
578*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_VALUE_INPUT,
579*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_VALUE_INOUT,
580*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_VALUE_INPUT);
581*5843bb75SJerome Forissier 	struct user_ta_ctx *utc = to_user_ta_ctx(s->ctx);
582*5843bb75SJerome Forissier 	TEE_Result res = TEE_SUCCESS;
583*5843bb75SJerome Forissier 	uint32_t num_bytes = 0;
584*5843bb75SJerome Forissier 	uint32_t pad_begin = 0;
585*5843bb75SJerome Forissier 	uint32_t pad_end = 0;
586*5843bb75SJerome Forissier 	vaddr_t old_va = 0;
587*5843bb75SJerome Forissier 	vaddr_t new_va = 0;
588*5843bb75SJerome Forissier 
589*5843bb75SJerome Forissier 	if (exp_pt != param_types)
590*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
591*5843bb75SJerome Forissier 
592*5843bb75SJerome Forissier 	num_bytes = params[0].value.a;
593*5843bb75SJerome Forissier 	old_va = reg_pair_to_64(params[1].value.a, params[1].value.b);
594*5843bb75SJerome Forissier 	new_va = reg_pair_to_64(params[2].value.a, params[2].value.b);
595*5843bb75SJerome Forissier 	pad_begin = params[3].value.a;
596*5843bb75SJerome Forissier 	pad_end = params[3].value.b;
597*5843bb75SJerome Forissier 
598*5843bb75SJerome Forissier 	res = vm_remap(utc, &new_va, old_va, num_bytes, pad_begin, pad_end);
599*5843bb75SJerome Forissier 	if (!res)
600*5843bb75SJerome Forissier 		reg_pair_from_64(new_va, &params[2].value.a,
601*5843bb75SJerome Forissier 				 &params[2].value.b);
602*5843bb75SJerome Forissier 
603*5843bb75SJerome Forissier 	return res;
604*5843bb75SJerome Forissier }
605*5843bb75SJerome Forissier 
606*5843bb75SJerome Forissier /* ldelf has the same architecture/register width as the kernel */
607*5843bb75SJerome Forissier #ifdef ARM32
608*5843bb75SJerome Forissier static const bool is_arm32 = true;
609*5843bb75SJerome Forissier #else
610*5843bb75SJerome Forissier static const bool is_arm32;
611*5843bb75SJerome Forissier #endif
612*5843bb75SJerome Forissier 
613*5843bb75SJerome Forissier static TEE_Result call_ldelf_dlopen(struct user_ta_ctx *utc, TEE_UUID *uuid,
614*5843bb75SJerome Forissier 				    uint32_t flags)
615*5843bb75SJerome Forissier {
616*5843bb75SJerome Forissier 	uaddr_t usr_stack = utc->ldelf_stack_ptr;
617*5843bb75SJerome Forissier 	TEE_Result res = TEE_ERROR_GENERIC;
618*5843bb75SJerome Forissier 	struct dl_entry_arg *arg = NULL;
619*5843bb75SJerome Forissier 	uint32_t panic_code = 0;
620*5843bb75SJerome Forissier 	uint32_t panicked = 0;
621*5843bb75SJerome Forissier 
622*5843bb75SJerome Forissier 	assert(uuid);
623*5843bb75SJerome Forissier 
624*5843bb75SJerome Forissier 	usr_stack -= ROUNDUP(sizeof(*arg), STACK_ALIGNMENT);
625*5843bb75SJerome Forissier 	arg = (struct dl_entry_arg *)usr_stack;
626*5843bb75SJerome Forissier 
627*5843bb75SJerome Forissier 	res = tee_mmu_check_access_rights(utc, TEE_MEMORY_ACCESS_READ |
628*5843bb75SJerome Forissier 					  TEE_MEMORY_ACCESS_WRITE |
629*5843bb75SJerome Forissier 					  TEE_MEMORY_ACCESS_ANY_OWNER,
630*5843bb75SJerome Forissier 					  (uaddr_t)arg, sizeof(*arg));
631*5843bb75SJerome Forissier 	if (res) {
632*5843bb75SJerome Forissier 		EMSG("ldelf stack is inaccessible!");
633*5843bb75SJerome Forissier 		return res;
634*5843bb75SJerome Forissier 	}
635*5843bb75SJerome Forissier 
636*5843bb75SJerome Forissier 	memset(arg, 0, sizeof(*arg));
637*5843bb75SJerome Forissier 	arg->cmd = LDELF_DL_ENTRY_DLOPEN;
638*5843bb75SJerome Forissier 	arg->dlopen.uuid = *uuid;
639*5843bb75SJerome Forissier 	arg->dlopen.flags = flags;
640*5843bb75SJerome Forissier 
641*5843bb75SJerome Forissier 	res = thread_enter_user_mode((vaddr_t)arg, 0, 0, 0,
642*5843bb75SJerome Forissier 				     usr_stack, utc->dl_entry_func,
643*5843bb75SJerome Forissier 				     is_arm32, &panicked, &panic_code);
644*5843bb75SJerome Forissier 	if (panicked) {
645*5843bb75SJerome Forissier 		EMSG("ldelf dl_entry function panicked");
646*5843bb75SJerome Forissier 		abort_print_current_ta();
647*5843bb75SJerome Forissier 		res = TEE_ERROR_TARGET_DEAD;
648*5843bb75SJerome Forissier 	}
649*5843bb75SJerome Forissier 	if (!res)
650*5843bb75SJerome Forissier 		res = arg->ret;
651*5843bb75SJerome Forissier 
652*5843bb75SJerome Forissier 	return res;
653*5843bb75SJerome Forissier }
654*5843bb75SJerome Forissier 
655*5843bb75SJerome Forissier static TEE_Result call_ldelf_dlsym(struct user_ta_ctx *utc, TEE_UUID *uuid,
656*5843bb75SJerome Forissier 				   const char *sym, size_t maxlen, vaddr_t *val)
657*5843bb75SJerome Forissier {
658*5843bb75SJerome Forissier 	uaddr_t usr_stack = utc->ldelf_stack_ptr;
659*5843bb75SJerome Forissier 	TEE_Result res = TEE_ERROR_GENERIC;
660*5843bb75SJerome Forissier 	struct dl_entry_arg *arg = NULL;
661*5843bb75SJerome Forissier 	uint32_t panic_code = 0;
662*5843bb75SJerome Forissier 	uint32_t panicked = 0;
663*5843bb75SJerome Forissier 	size_t len = strnlen(sym, maxlen);
664*5843bb75SJerome Forissier 
665*5843bb75SJerome Forissier 	if (len == maxlen)
666*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
667*5843bb75SJerome Forissier 
668*5843bb75SJerome Forissier 	usr_stack -= ROUNDUP(sizeof(*arg) + len + 1, STACK_ALIGNMENT);
669*5843bb75SJerome Forissier 	arg = (struct dl_entry_arg *)usr_stack;
670*5843bb75SJerome Forissier 
671*5843bb75SJerome Forissier 	res = tee_mmu_check_access_rights(utc, TEE_MEMORY_ACCESS_READ |
672*5843bb75SJerome Forissier 					  TEE_MEMORY_ACCESS_WRITE |
673*5843bb75SJerome Forissier 					  TEE_MEMORY_ACCESS_ANY_OWNER,
674*5843bb75SJerome Forissier 					  (uaddr_t)arg,
675*5843bb75SJerome Forissier 					  sizeof(*arg) + len + 1);
676*5843bb75SJerome Forissier 	if (res) {
677*5843bb75SJerome Forissier 		EMSG("ldelf stack is inaccessible!");
678*5843bb75SJerome Forissier 		return res;
679*5843bb75SJerome Forissier 	}
680*5843bb75SJerome Forissier 
681*5843bb75SJerome Forissier 	memset(arg, 0, sizeof(*arg));
682*5843bb75SJerome Forissier 	arg->cmd = LDELF_DL_ENTRY_DLSYM;
683*5843bb75SJerome Forissier 	arg->dlsym.uuid = *uuid;
684*5843bb75SJerome Forissier 	memcpy(arg->dlsym.symbol, sym, len);
685*5843bb75SJerome Forissier 	arg->dlsym.symbol[len + 1] = '\0';
686*5843bb75SJerome Forissier 
687*5843bb75SJerome Forissier 	res = thread_enter_user_mode((vaddr_t)arg, 0, 0, 0,
688*5843bb75SJerome Forissier 				     usr_stack, utc->dl_entry_func,
689*5843bb75SJerome Forissier 				     is_arm32, &panicked, &panic_code);
690*5843bb75SJerome Forissier 	if (panicked) {
691*5843bb75SJerome Forissier 		EMSG("ldelf dl_entry function panicked");
692*5843bb75SJerome Forissier 		abort_print_current_ta();
693*5843bb75SJerome Forissier 		res = TEE_ERROR_TARGET_DEAD;
694*5843bb75SJerome Forissier 	}
695*5843bb75SJerome Forissier 	if (!res) {
696*5843bb75SJerome Forissier 		res = arg->ret;
697*5843bb75SJerome Forissier 		if (!res)
698*5843bb75SJerome Forissier 			*val = arg->dlsym.val;
699*5843bb75SJerome Forissier 	}
700*5843bb75SJerome Forissier 
701*5843bb75SJerome Forissier 	return res;
702*5843bb75SJerome Forissier }
703*5843bb75SJerome Forissier 
704*5843bb75SJerome Forissier static TEE_Result system_dlopen(struct tee_ta_session *cs, uint32_t param_types,
705*5843bb75SJerome Forissier 				TEE_Param params[TEE_NUM_PARAMS])
706*5843bb75SJerome Forissier {
707*5843bb75SJerome Forissier 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
708*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_VALUE_INPUT,
709*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE,
710*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE);
711*5843bb75SJerome Forissier 	TEE_Result res = TEE_ERROR_GENERIC;
712*5843bb75SJerome Forissier 	struct tee_ta_session *s = NULL;
713*5843bb75SJerome Forissier 	struct user_ta_ctx *utc = NULL;
714*5843bb75SJerome Forissier 	TEE_UUID *uuid = NULL;
715*5843bb75SJerome Forissier 	uint32_t flags = 0;
716*5843bb75SJerome Forissier 
717*5843bb75SJerome Forissier 	if (exp_pt != param_types)
718*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
719*5843bb75SJerome Forissier 
720*5843bb75SJerome Forissier 	uuid = params[0].memref.buffer;
721*5843bb75SJerome Forissier 	if (!uuid || params[0].memref.size != sizeof(*uuid))
722*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
723*5843bb75SJerome Forissier 
724*5843bb75SJerome Forissier 	flags = params[1].value.a;
725*5843bb75SJerome Forissier 
726*5843bb75SJerome Forissier 	utc = to_user_ta_ctx(cs->ctx);
727*5843bb75SJerome Forissier 
728*5843bb75SJerome Forissier 	s = tee_ta_pop_current_session();
729*5843bb75SJerome Forissier 	res = call_ldelf_dlopen(utc, uuid, flags);
730*5843bb75SJerome Forissier 	tee_ta_push_current_session(s);
731*5843bb75SJerome Forissier 
732*5843bb75SJerome Forissier 	return res;
733*5843bb75SJerome Forissier }
734*5843bb75SJerome Forissier 
735*5843bb75SJerome Forissier static TEE_Result system_dlsym(struct tee_ta_session *cs, uint32_t param_types,
736*5843bb75SJerome Forissier 			       TEE_Param params[TEE_NUM_PARAMS])
737*5843bb75SJerome Forissier {
738*5843bb75SJerome Forissier 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
739*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_MEMREF_INPUT,
740*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_VALUE_OUTPUT,
741*5843bb75SJerome Forissier 					  TEE_PARAM_TYPE_NONE);
742*5843bb75SJerome Forissier 	TEE_Result res = TEE_ERROR_GENERIC;
743*5843bb75SJerome Forissier 	struct tee_ta_session *s = NULL;
744*5843bb75SJerome Forissier 	struct user_ta_ctx *utc = NULL;
745*5843bb75SJerome Forissier 	const char *sym = NULL;
746*5843bb75SJerome Forissier 	TEE_UUID *uuid = NULL;
747*5843bb75SJerome Forissier 	size_t maxlen = 0;
748*5843bb75SJerome Forissier 	vaddr_t va = 0;
749*5843bb75SJerome Forissier 
750*5843bb75SJerome Forissier 	if (exp_pt != param_types)
751*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
752*5843bb75SJerome Forissier 
753*5843bb75SJerome Forissier 	uuid = params[0].memref.buffer;
754*5843bb75SJerome Forissier 	if (uuid && params[0].memref.size != sizeof(*uuid))
755*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
756*5843bb75SJerome Forissier 
757*5843bb75SJerome Forissier 	sym = params[1].memref.buffer;
758*5843bb75SJerome Forissier 	if (!sym)
759*5843bb75SJerome Forissier 		return TEE_ERROR_BAD_PARAMETERS;
760*5843bb75SJerome Forissier 	maxlen = params[1].memref.size;
761*5843bb75SJerome Forissier 
762*5843bb75SJerome Forissier 	utc = to_user_ta_ctx(cs->ctx);
763*5843bb75SJerome Forissier 
764*5843bb75SJerome Forissier 	s = tee_ta_pop_current_session();
765*5843bb75SJerome Forissier 	res = call_ldelf_dlsym(utc, uuid, sym, maxlen, &va);
766*5843bb75SJerome Forissier 	tee_ta_push_current_session(s);
767*5843bb75SJerome Forissier 
768*5843bb75SJerome Forissier 	if (!res)
769*5843bb75SJerome Forissier 		reg_pair_from_64(va, &params[2].value.a, &params[2].value.b);
770*5843bb75SJerome Forissier 
771*5843bb75SJerome Forissier 	return res;
772*5843bb75SJerome Forissier }
773*5843bb75SJerome Forissier 
774*5843bb75SJerome Forissier static TEE_Result open_session(uint32_t param_types __unused,
775*5843bb75SJerome Forissier 			       TEE_Param params[TEE_NUM_PARAMS] __unused,
776*5843bb75SJerome Forissier 			       void **sess_ctx)
777*5843bb75SJerome Forissier {
778*5843bb75SJerome Forissier 	struct tee_ta_session *s = NULL;
779*5843bb75SJerome Forissier 	struct system_ctx *ctx = NULL;
780*5843bb75SJerome Forissier 
781*5843bb75SJerome Forissier 	/* Check that we're called from a user TA */
782*5843bb75SJerome Forissier 	s = tee_ta_get_calling_session();
783*5843bb75SJerome Forissier 	if (!s)
784*5843bb75SJerome Forissier 		return TEE_ERROR_ACCESS_DENIED;
785*5843bb75SJerome Forissier 	if (!is_user_ta_ctx(s->ctx))
786*5843bb75SJerome Forissier 		return TEE_ERROR_ACCESS_DENIED;
787*5843bb75SJerome Forissier 
788*5843bb75SJerome Forissier 	ctx = calloc(1, sizeof(*ctx));
789*5843bb75SJerome Forissier 	if (!ctx)
790*5843bb75SJerome Forissier 		return TEE_ERROR_OUT_OF_MEMORY;
791*5843bb75SJerome Forissier 
792*5843bb75SJerome Forissier 	*sess_ctx = ctx;
793*5843bb75SJerome Forissier 
794*5843bb75SJerome Forissier 	return TEE_SUCCESS;
795*5843bb75SJerome Forissier }
796*5843bb75SJerome Forissier 
797*5843bb75SJerome Forissier static void close_session(void *sess_ctx)
798*5843bb75SJerome Forissier {
799*5843bb75SJerome Forissier 	struct system_ctx *ctx = sess_ctx;
800*5843bb75SJerome Forissier 
801*5843bb75SJerome Forissier 	handle_db_destroy(&ctx->db, ta_bin_close);
802*5843bb75SJerome Forissier 	free(ctx);
803*5843bb75SJerome Forissier }
804*5843bb75SJerome Forissier 
805*5843bb75SJerome Forissier static TEE_Result invoke_command(void *sess_ctx, uint32_t cmd_id,
806*5843bb75SJerome Forissier 				 uint32_t param_types,
807*5843bb75SJerome Forissier 				 TEE_Param params[TEE_NUM_PARAMS])
808*5843bb75SJerome Forissier {
809*5843bb75SJerome Forissier 	struct tee_ta_session *s = tee_ta_get_calling_session();
810*5843bb75SJerome Forissier 
811*5843bb75SJerome Forissier 	switch (cmd_id) {
812*5843bb75SJerome Forissier 	case PTA_SYSTEM_ADD_RNG_ENTROPY:
813*5843bb75SJerome Forissier 		return system_rng_reseed(s, param_types, params);
814*5843bb75SJerome Forissier 	case PTA_SYSTEM_DERIVE_TA_UNIQUE_KEY:
815*5843bb75SJerome Forissier 		return system_derive_ta_unique_key(s, param_types, params);
816*5843bb75SJerome Forissier 	case PTA_SYSTEM_MAP_ZI:
817*5843bb75SJerome Forissier 		return system_map_zi(s, param_types, params);
818*5843bb75SJerome Forissier 	case PTA_SYSTEM_UNMAP:
819*5843bb75SJerome Forissier 		return system_unmap(s, param_types, params);
820*5843bb75SJerome Forissier 	case PTA_SYSTEM_OPEN_TA_BINARY:
821*5843bb75SJerome Forissier 		return system_open_ta_binary(sess_ctx, param_types, params);
822*5843bb75SJerome Forissier 	case PTA_SYSTEM_CLOSE_TA_BINARY:
823*5843bb75SJerome Forissier 		return system_close_ta_binary(sess_ctx, param_types, params);
824*5843bb75SJerome Forissier 	case PTA_SYSTEM_MAP_TA_BINARY:
825*5843bb75SJerome Forissier 		return system_map_ta_binary(sess_ctx, s, param_types, params);
826*5843bb75SJerome Forissier 	case PTA_SYSTEM_COPY_FROM_TA_BINARY:
827*5843bb75SJerome Forissier 		return system_copy_from_ta_binary(sess_ctx, param_types,
828*5843bb75SJerome Forissier 						  params);
829*5843bb75SJerome Forissier 	case PTA_SYSTEM_SET_PROT:
830*5843bb75SJerome Forissier 		return system_set_prot(s, param_types, params);
831*5843bb75SJerome Forissier 	case PTA_SYSTEM_REMAP:
832*5843bb75SJerome Forissier 		return system_remap(s, param_types, params);
833*5843bb75SJerome Forissier 	case PTA_SYSTEM_DLOPEN:
834*5843bb75SJerome Forissier 		return system_dlopen(s, param_types, params);
835*5843bb75SJerome Forissier 	case PTA_SYSTEM_DLSYM:
836*5843bb75SJerome Forissier 		return system_dlsym(s, param_types, params);
837*5843bb75SJerome Forissier 	default:
838*5843bb75SJerome Forissier 		break;
839*5843bb75SJerome Forissier 	}
840*5843bb75SJerome Forissier 
841*5843bb75SJerome Forissier 	return TEE_ERROR_NOT_IMPLEMENTED;
842*5843bb75SJerome Forissier }
843*5843bb75SJerome Forissier 
844*5843bb75SJerome Forissier pseudo_ta_register(.uuid = PTA_SYSTEM_UUID, .name = "system.pta",
845*5843bb75SJerome Forissier 		   .flags = PTA_DEFAULT_FLAGS | TA_FLAG_CONCURRENT,
846*5843bb75SJerome Forissier 		   .open_session_entry_point = open_session,
847*5843bb75SJerome Forissier 		   .close_session_entry_point = close_session,
848*5843bb75SJerome Forissier 		   .invoke_command_entry_point = invoke_command);
849