xref: /optee_os/core/kernel/pseudo_ta.c (revision 4edd96e6d7a7228e907cf498b23e5b5fbdaf39a0)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2014, STMicroelectronics International N.V.
4  * Copyright (c) 2015, Linaro Limited
5  * Copyright (c) 2020, Arm Limited
6  */
7 #include <initcall.h>
8 #include <kernel/linker.h>
9 #include <kernel/panic.h>
10 #include <kernel/pseudo_ta.h>
11 #include <kernel/tee_ta_manager.h>
12 #include <kernel/user_access.h>
13 #include <mm/core_memprot.h>
14 #include <mm/mobj.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <trace.h>
18 #include <types_ext.h>
19 
20 #ifdef CFG_SECURE_DATA_PATH
21 static bool client_is_secure(struct ts_session *s)
22 {
23 	/* rely on core entry to have constrained client IDs */
24 	if (to_ta_session(s)->clnt_id.login == TEE_LOGIN_TRUSTED_APP)
25 		return true;
26 
27 	return false;
28 }
29 
30 static bool validate_in_param(struct ts_session *s, struct mobj *mobj)
31 {
32 	/* Supplying NULL to query buffer size is OK */
33 	if (!mobj)
34 		return true;
35 
36 	/* for secure clients, core entry always holds valid memref objects */
37 	if (client_is_secure(s))
38 		return true;
39 
40 	/* all non-secure memory references are handled by PTAs */
41 	if (mobj_is_nonsec(mobj))
42 		return true;
43 
44 	return false;
45 }
46 #else
47 static bool validate_in_param(struct ts_session *s __unused,
48 			      struct mobj *mobj __unused)
49 {
50 	/* At this point, core has filled only valid accessible memref mobj */
51 	return true;
52 }
53 #endif
54 
55 /* Maps pseudo TA params */
56 static TEE_Result copy_in_param(struct ts_session *s __maybe_unused,
57 				struct tee_ta_param *param,
58 				TEE_Param tee_param[TEE_NUM_PARAMS],
59 				bool did_map[TEE_NUM_PARAMS])
60 {
61 	size_t n;
62 	void *va;
63 	struct param_mem *mem;
64 
65 	for (n = 0; n < TEE_NUM_PARAMS; n++) {
66 		switch (TEE_PARAM_TYPE_GET(param->types, n)) {
67 		case TEE_PARAM_TYPE_VALUE_INPUT:
68 		case TEE_PARAM_TYPE_VALUE_OUTPUT:
69 		case TEE_PARAM_TYPE_VALUE_INOUT:
70 			tee_param[n].value.a = param->u[n].val.a;
71 			tee_param[n].value.b = param->u[n].val.b;
72 			break;
73 		case TEE_PARAM_TYPE_MEMREF_INPUT:
74 		case TEE_PARAM_TYPE_MEMREF_OUTPUT:
75 		case TEE_PARAM_TYPE_MEMREF_INOUT:
76 			mem = &param->u[n].mem;
77 			if (!validate_in_param(s, mem->mobj))
78 				return TEE_ERROR_BAD_PARAMETERS;
79 			if (mem->size) {
80 				TEE_Result res = mobj_inc_map(mem->mobj);
81 
82 				if (res)
83 					return res;
84 				did_map[n] = true;
85 				va = mobj_get_va(mem->mobj, mem->offs,
86 						 mem->size);
87 				if (!va)
88 					return TEE_ERROR_BAD_PARAMETERS;
89 			} else {
90 				va = NULL;
91 			}
92 
93 			tee_param[n].memref.buffer = va;
94 			tee_param[n].memref.size = mem->size;
95 			break;
96 		default:
97 			memset(tee_param + n, 0, sizeof(TEE_Param));
98 			break;
99 		}
100 	}
101 
102 	return TEE_SUCCESS;
103 }
104 
105 static void update_out_param(TEE_Param tee_param[TEE_NUM_PARAMS],
106 			     struct tee_ta_param *param)
107 {
108 	size_t n;
109 
110 	for (n = 0; n < TEE_NUM_PARAMS; n++) {
111 		switch (TEE_PARAM_TYPE_GET(param->types, n)) {
112 		case TEE_PARAM_TYPE_VALUE_OUTPUT:
113 		case TEE_PARAM_TYPE_VALUE_INOUT:
114 			param->u[n].val.a = tee_param[n].value.a;
115 			param->u[n].val.b = tee_param[n].value.b;
116 			break;
117 		case TEE_PARAM_TYPE_MEMREF_OUTPUT:
118 		case TEE_PARAM_TYPE_MEMREF_INOUT:
119 			param->u[n].mem.size = tee_param[n].memref.size;
120 			break;
121 		default:
122 			break;
123 		}
124 	}
125 }
126 
127 static void unmap_mapped_param(struct tee_ta_param *param,
128 			       bool did_map[TEE_NUM_PARAMS])
129 {
130 	size_t n;
131 
132 	for (n = 0; n < TEE_NUM_PARAMS; n++) {
133 		if (did_map[n]) {
134 			TEE_Result res __maybe_unused;
135 
136 			res = mobj_dec_map(param->u[n].mem.mobj);
137 			assert(!res);
138 		}
139 	}
140 }
141 
142 static TEE_Result pseudo_ta_enter_open_session(struct ts_session *s)
143 {
144 	TEE_Result res = TEE_SUCCESS;
145 	struct pseudo_ta_ctx *stc = to_pseudo_ta_ctx(s->ctx);
146 	struct tee_ta_session *ta_sess = to_ta_session(s);
147 	TEE_Param tee_param[TEE_NUM_PARAMS] = { };
148 	bool did_map[TEE_NUM_PARAMS] = { false };
149 
150 	ts_push_current_session(s);
151 	ta_sess->err_origin = TEE_ORIGIN_TRUSTED_APP;
152 
153 	if (stc->ctx.ref_count == 1 && stc->pseudo_ta->create_entry_point) {
154 		res = stc->pseudo_ta->create_entry_point();
155 		if (res != TEE_SUCCESS)
156 			goto out;
157 	}
158 
159 	if (stc->pseudo_ta->open_session_entry_point) {
160 		void **user_ctx = &s->user_ctx;
161 		uint32_t param_types = 0;
162 
163 		if (ta_sess->param) {
164 			res = copy_in_param(s, ta_sess->param, tee_param,
165 					    did_map);
166 			if (res != TEE_SUCCESS) {
167 				unmap_mapped_param(ta_sess->param, did_map);
168 				ta_sess->err_origin = TEE_ORIGIN_TEE;
169 				goto out;
170 			}
171 			param_types = ta_sess->param->types;
172 		}
173 
174 		res = stc->pseudo_ta->open_session_entry_point(param_types,
175 							       tee_param,
176 							       user_ctx);
177 		if (ta_sess->param) {
178 			update_out_param(tee_param, ta_sess->param);
179 			unmap_mapped_param(ta_sess->param, did_map);
180 		}
181 	}
182 
183 out:
184 	ts_pop_current_session();
185 	return res;
186 }
187 
188 static TEE_Result pseudo_ta_enter_invoke_cmd(struct ts_session *s, uint32_t cmd)
189 {
190 	TEE_Result res = TEE_SUCCESS;
191 	struct pseudo_ta_ctx *stc = to_pseudo_ta_ctx(s->ctx);
192 	struct tee_ta_session *ta_sess = to_ta_session(s);
193 	uint32_t param_types = 0;
194 	TEE_Param tee_param[TEE_NUM_PARAMS] = { };
195 	bool did_map[TEE_NUM_PARAMS] = { false };
196 
197 	ts_push_current_session(s);
198 	if (ta_sess->param) {
199 		res = copy_in_param(s, ta_sess->param, tee_param, did_map);
200 		if (res != TEE_SUCCESS) {
201 			unmap_mapped_param(ta_sess->param, did_map);
202 			ta_sess->err_origin = TEE_ORIGIN_TEE;
203 			goto out;
204 		}
205 		param_types = ta_sess->param->types;
206 	}
207 
208 	ta_sess->err_origin = TEE_ORIGIN_TRUSTED_APP;
209 	res = stc->pseudo_ta->invoke_command_entry_point(s->user_ctx, cmd,
210 							 param_types,
211 							 tee_param);
212 	if (ta_sess->param) {
213 		update_out_param(tee_param, ta_sess->param);
214 		unmap_mapped_param(ta_sess->param, did_map);
215 	}
216 out:
217 	ts_pop_current_session();
218 	return res;
219 }
220 
221 static void pseudo_ta_enter_close_session(struct ts_session *s)
222 {
223 	struct pseudo_ta_ctx *stc = to_pseudo_ta_ctx(s->ctx);
224 	void *user_ctx = s->user_ctx;
225 
226 	ts_push_current_session(s);
227 
228 	if (stc->pseudo_ta->close_session_entry_point)
229 		stc->pseudo_ta->close_session_entry_point(user_ctx);
230 
231 	if (stc->ctx.ref_count == 1 && stc->pseudo_ta->destroy_entry_point)
232 		stc->pseudo_ta->destroy_entry_point();
233 
234 	ts_pop_current_session();
235 }
236 
237 static void pseudo_ta_destroy(struct ts_ctx *ctx)
238 {
239 	free(to_pseudo_ta_ctx(ctx));
240 }
241 
242 static const struct ts_ops pseudo_ta_ops = {
243 	.enter_open_session = pseudo_ta_enter_open_session,
244 	.enter_invoke_cmd = pseudo_ta_enter_invoke_cmd,
245 	.enter_close_session = pseudo_ta_enter_close_session,
246 	.destroy = pseudo_ta_destroy,
247 };
248 
249 bool is_pseudo_ta_ctx(struct ts_ctx *ctx)
250 {
251 	return ctx->ops == &pseudo_ta_ops;
252 }
253 
254 /* Insures declared pseudo TAs conforms with core expectations */
255 static TEE_Result verify_pseudo_tas_conformance(void)
256 {
257 	const struct pseudo_ta_head *start =
258 		SCATTERED_ARRAY_BEGIN(pseudo_tas, struct pseudo_ta_head);
259 	const struct pseudo_ta_head *end =
260 		SCATTERED_ARRAY_END(pseudo_tas, struct pseudo_ta_head);
261 	const struct pseudo_ta_head *pta;
262 
263 	for (pta = start; pta < end; pta++) {
264 		const struct pseudo_ta_head *pta2;
265 
266 		/* PTAs must all have a specific UUID */
267 		for (pta2 = pta + 1; pta2 < end; pta2++) {
268 			if (!memcmp(&pta->uuid, &pta2->uuid, sizeof(TEE_UUID)))
269 				goto err;
270 		}
271 
272 		if (!pta->name ||
273 		    (pta->flags & PTA_MANDATORY_FLAGS) != PTA_MANDATORY_FLAGS ||
274 		    pta->flags & ~PTA_ALLOWED_FLAGS ||
275 		    !pta->invoke_command_entry_point)
276 			goto err;
277 	}
278 	return TEE_SUCCESS;
279 err:
280 	DMSG("pseudo TA error at %p", (void *)pta);
281 	panic("PTA");
282 }
283 
284 service_init(verify_pseudo_tas_conformance);
285 
286 /*-----------------------------------------------------------------------------
287  * Initialises a session based on the UUID or ptr to the ta
288  * Returns ptr to the session (ta_session) and a TEE_Result
289  *---------------------------------------------------------------------------*/
290 TEE_Result tee_ta_init_pseudo_ta_session(const TEE_UUID *uuid,
291 			struct tee_ta_session *s)
292 {
293 	struct pseudo_ta_ctx *stc = NULL;
294 	struct tee_ta_ctx *ctx;
295 	const struct pseudo_ta_head *ta;
296 
297 	DMSG("Lookup pseudo TA %pUl", (void *)uuid);
298 
299 	ta = SCATTERED_ARRAY_BEGIN(pseudo_tas, struct pseudo_ta_head);
300 	while (true) {
301 		if (ta >= SCATTERED_ARRAY_END(pseudo_tas,
302 					      struct pseudo_ta_head))
303 			return TEE_ERROR_ITEM_NOT_FOUND;
304 		if (memcmp(&ta->uuid, uuid, sizeof(TEE_UUID)) == 0)
305 			break;
306 		ta++;
307 	}
308 
309 	/* Load a new TA and create a session */
310 	DMSG("Open %s", ta->name);
311 	stc = calloc(1, sizeof(struct pseudo_ta_ctx));
312 	if (!stc)
313 		return TEE_ERROR_OUT_OF_MEMORY;
314 	ctx = &stc->ctx;
315 
316 	ctx->ref_count = 1;
317 	ctx->flags = ta->flags;
318 	stc->pseudo_ta = ta;
319 	ctx->ts_ctx.uuid = ta->uuid;
320 	ctx->ts_ctx.ops = &pseudo_ta_ops;
321 
322 	mutex_lock(&tee_ta_mutex);
323 	s->ts_sess.ctx = &ctx->ts_ctx;
324 	TAILQ_INSERT_TAIL(&tee_ctxes, ctx, link);
325 	mutex_unlock(&tee_ta_mutex);
326 
327 	DMSG("%s : %pUl", stc->pseudo_ta->name, (void *)&ctx->ts_ctx.uuid);
328 
329 	return TEE_SUCCESS;
330 }
331 
332 TEE_Result to_bounce_params(uint32_t param_types,
333 			    TEE_Param params[TEE_NUM_PARAMS],
334 			    TEE_Param bparams[TEE_NUM_PARAMS],
335 			    TEE_Param **oparams)
336 {
337 	TEE_Result res = TEE_ERROR_GENERIC;
338 	void *kptr = NULL;
339 	void *uptr = NULL;
340 	size_t size = 0;
341 	int i = 0;
342 
343 	if (!is_caller_ta_with_pan()) {
344 		*oparams = params;
345 		return TEE_SUCCESS;
346 	}
347 
348 	for (i = 0; i < TEE_NUM_PARAMS; i++) {
349 		switch (TEE_PARAM_TYPE_GET(param_types, i)) {
350 		case TEE_PARAM_TYPE_MEMREF_INPUT:
351 		case TEE_PARAM_TYPE_MEMREF_OUTPUT:
352 		case TEE_PARAM_TYPE_MEMREF_INOUT:
353 			size = params[i].memref.size;
354 			uptr = params[i].memref.buffer;
355 			kptr = bb_alloc(size);
356 			if (!kptr)
357 				return TEE_ERROR_OUT_OF_MEMORY;
358 			bparams[i].memref.buffer = kptr;
359 			bparams[i].memref.size = size;
360 			break;
361 		default:
362 			break;
363 		}
364 		switch (TEE_PARAM_TYPE_GET(param_types, i)) {
365 		case TEE_PARAM_TYPE_MEMREF_INPUT:
366 		case TEE_PARAM_TYPE_MEMREF_INOUT:
367 			res = copy_from_user(kptr, uptr, size);
368 			if (res)
369 				return res;
370 			break;
371 		case TEE_PARAM_TYPE_VALUE_INPUT:
372 		case TEE_PARAM_TYPE_VALUE_INOUT:
373 			bparams[i].value.a = params[i].value.a;
374 			bparams[i].value.b = params[i].value.b;
375 			break;
376 		default:
377 			break;
378 		}
379 	}
380 	*oparams = bparams;
381 
382 	return TEE_SUCCESS;
383 }
384 
385 TEE_Result from_bounce_params(uint32_t param_types,
386 			      TEE_Param params[TEE_NUM_PARAMS],
387 			      TEE_Param bparams[TEE_NUM_PARAMS],
388 			      TEE_Param *eparams)
389 {
390 	TEE_Result res = TEE_ERROR_GENERIC;
391 	void *kptr = NULL;
392 	void *uptr = NULL;
393 	size_t size = 0;
394 	int i = 0;
395 
396 	if (eparams == params)
397 		return TEE_SUCCESS;
398 
399 	for (i = 0; i < TEE_NUM_PARAMS; i++) {
400 		switch (TEE_PARAM_TYPE_GET(param_types, i)) {
401 		case TEE_PARAM_TYPE_MEMREF_OUTPUT:
402 		case TEE_PARAM_TYPE_MEMREF_INOUT:
403 			uptr = params[i].memref.buffer;
404 			kptr = bparams[i].memref.buffer;
405 			size = bparams[i].memref.size;
406 			res = copy_to_user(uptr, kptr, size);
407 			if (res)
408 				return res;
409 			params[i].memref.size = size;
410 			break;
411 		case TEE_PARAM_TYPE_VALUE_OUTPUT:
412 		case TEE_PARAM_TYPE_VALUE_INOUT:
413 			params[i].value.a = bparams[i].value.a;
414 			params[i].value.b = bparams[i].value.b;
415 			break;
416 		default:
417 			break;
418 		}
419 	}
420 
421 	return res;
422 }
423