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