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
client_is_secure(struct ts_session * s)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 
validate_in_param(struct ts_session * s,struct mobj * mobj)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
validate_in_param(struct ts_session * s __unused,struct mobj * mobj __unused)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 */
copy_in_param(struct ts_session * s __maybe_unused,struct tee_ta_param * param,TEE_Param tee_param[TEE_NUM_PARAMS],bool did_map[TEE_NUM_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 						 mem->size);
86 				if (!va)
87 					return TEE_ERROR_BAD_PARAMETERS;
88 			} else {
89 				va = NULL;
90 			}
91 
92 			tee_param[n].memref.buffer = va;
93 			tee_param[n].memref.size = mem->size;
94 			break;
95 		default:
96 			memset(tee_param + n, 0, sizeof(TEE_Param));
97 			break;
98 		}
99 	}
100 
101 	return TEE_SUCCESS;
102 }
103 
update_out_param(TEE_Param tee_param[TEE_NUM_PARAMS],struct tee_ta_param * param)104 static void update_out_param(TEE_Param tee_param[TEE_NUM_PARAMS],
105 			     struct tee_ta_param *param)
106 {
107 	size_t n;
108 
109 	for (n = 0; n < TEE_NUM_PARAMS; n++) {
110 		switch (TEE_PARAM_TYPE_GET(param->types, n)) {
111 		case TEE_PARAM_TYPE_VALUE_OUTPUT:
112 		case TEE_PARAM_TYPE_VALUE_INOUT:
113 			param->u[n].val.a = tee_param[n].value.a;
114 			param->u[n].val.b = tee_param[n].value.b;
115 			break;
116 		case TEE_PARAM_TYPE_MEMREF_OUTPUT:
117 		case TEE_PARAM_TYPE_MEMREF_INOUT:
118 			param->u[n].mem.size = tee_param[n].memref.size;
119 			break;
120 		default:
121 			break;
122 		}
123 	}
124 }
125 
unmap_mapped_param(struct tee_ta_param * param,bool did_map[TEE_NUM_PARAMS])126 static void unmap_mapped_param(struct tee_ta_param *param,
127 			       bool did_map[TEE_NUM_PARAMS])
128 {
129 	size_t n;
130 
131 	for (n = 0; n < TEE_NUM_PARAMS; n++) {
132 		if (did_map[n]) {
133 			TEE_Result res __maybe_unused;
134 
135 			res = mobj_dec_map(param->u[n].mem.mobj);
136 			assert(!res);
137 		}
138 	}
139 }
140 
pseudo_ta_enter_open_session(struct ts_session * s)141 static TEE_Result pseudo_ta_enter_open_session(struct ts_session *s)
142 {
143 	TEE_Result res = TEE_SUCCESS;
144 	struct pseudo_ta_ctx *stc = to_pseudo_ta_ctx(s->ctx);
145 	struct tee_ta_session *ta_sess = to_ta_session(s);
146 	TEE_Param tee_param[TEE_NUM_PARAMS] = { };
147 	bool did_map[TEE_NUM_PARAMS] = { false };
148 
149 	ts_push_current_session(s);
150 	ta_sess->err_origin = TEE_ORIGIN_TRUSTED_APP;
151 
152 	if (stc->ctx.ref_count == 1 && stc->pseudo_ta->create_entry_point) {
153 		res = stc->pseudo_ta->create_entry_point();
154 		if (res != TEE_SUCCESS)
155 			goto out;
156 	}
157 
158 	if (stc->pseudo_ta->open_session_entry_point) {
159 		void **user_ctx = &s->user_ctx;
160 		uint32_t param_types = 0;
161 
162 		if (ta_sess->param) {
163 			res = copy_in_param(s, ta_sess->param, tee_param,
164 					    did_map);
165 			if (res != TEE_SUCCESS) {
166 				unmap_mapped_param(ta_sess->param, did_map);
167 				ta_sess->err_origin = TEE_ORIGIN_TEE;
168 				goto out;
169 			}
170 			param_types = ta_sess->param->types;
171 		}
172 
173 		res = stc->pseudo_ta->open_session_entry_point(param_types,
174 							       tee_param,
175 							       user_ctx);
176 		if (ta_sess->param) {
177 			update_out_param(tee_param, ta_sess->param);
178 			unmap_mapped_param(ta_sess->param, did_map);
179 		}
180 	}
181 
182 out:
183 	ts_pop_current_session();
184 	return res;
185 }
186 
pseudo_ta_enter_invoke_cmd(struct ts_session * s,uint32_t cmd)187 static TEE_Result pseudo_ta_enter_invoke_cmd(struct ts_session *s, uint32_t cmd)
188 {
189 	TEE_Result res = TEE_SUCCESS;
190 	struct pseudo_ta_ctx *stc = to_pseudo_ta_ctx(s->ctx);
191 	struct tee_ta_session *ta_sess = to_ta_session(s);
192 	uint32_t param_types = 0;
193 	TEE_Param tee_param[TEE_NUM_PARAMS] = { };
194 	bool did_map[TEE_NUM_PARAMS] = { false };
195 
196 	ts_push_current_session(s);
197 	if (ta_sess->param) {
198 		res = copy_in_param(s, ta_sess->param, tee_param, did_map);
199 		if (res != TEE_SUCCESS) {
200 			unmap_mapped_param(ta_sess->param, did_map);
201 			ta_sess->err_origin = TEE_ORIGIN_TEE;
202 			goto out;
203 		}
204 		param_types = ta_sess->param->types;
205 	}
206 
207 	ta_sess->err_origin = TEE_ORIGIN_TRUSTED_APP;
208 	res = stc->pseudo_ta->invoke_command_entry_point(s->user_ctx, cmd,
209 							 param_types,
210 							 tee_param);
211 	if (ta_sess->param) {
212 		update_out_param(tee_param, ta_sess->param);
213 		unmap_mapped_param(ta_sess->param, did_map);
214 	}
215 out:
216 	ts_pop_current_session();
217 	return res;
218 }
219 
pseudo_ta_enter_close_session(struct ts_session * s)220 static void pseudo_ta_enter_close_session(struct ts_session *s)
221 {
222 	struct pseudo_ta_ctx *stc = to_pseudo_ta_ctx(s->ctx);
223 	void *user_ctx = s->user_ctx;
224 
225 	ts_push_current_session(s);
226 
227 	if (stc->pseudo_ta->close_session_entry_point)
228 		stc->pseudo_ta->close_session_entry_point(user_ctx);
229 
230 	if (stc->ctx.ref_count == 1 && stc->pseudo_ta->destroy_entry_point)
231 		stc->pseudo_ta->destroy_entry_point();
232 
233 	ts_pop_current_session();
234 }
235 
pseudo_ta_destroy(struct ts_ctx * ctx)236 static void pseudo_ta_destroy(struct ts_ctx *ctx)
237 {
238 	free(to_pseudo_ta_ctx(ctx));
239 }
240 
241 static const struct ts_ops pseudo_ta_ops = {
242 	.enter_open_session = pseudo_ta_enter_open_session,
243 	.enter_invoke_cmd = pseudo_ta_enter_invoke_cmd,
244 	.enter_close_session = pseudo_ta_enter_close_session,
245 	.destroy = pseudo_ta_destroy,
246 };
247 
is_pseudo_ta_ctx(struct ts_ctx * ctx)248 bool is_pseudo_ta_ctx(struct ts_ctx *ctx)
249 {
250 	return ctx->ops == &pseudo_ta_ops;
251 }
252 
253 /* Insures declared pseudo TAs conforms with core expectations */
verify_pseudo_tas_conformance(void)254 static TEE_Result verify_pseudo_tas_conformance(void)
255 {
256 	const struct pseudo_ta_head *start =
257 		SCATTERED_ARRAY_BEGIN(pseudo_tas, struct pseudo_ta_head);
258 	const struct pseudo_ta_head *end =
259 		SCATTERED_ARRAY_END(pseudo_tas, struct pseudo_ta_head);
260 	const struct pseudo_ta_head *pta;
261 
262 	for (pta = start; pta < end; pta++) {
263 		const struct pseudo_ta_head *pta2;
264 
265 		/* PTAs must all have a specific UUID */
266 		for (pta2 = pta + 1; pta2 < end; pta2++) {
267 			if (!memcmp(&pta->uuid, &pta2->uuid, sizeof(TEE_UUID)))
268 				goto err;
269 		}
270 
271 		if (!pta->name ||
272 		    (pta->flags & PTA_MANDATORY_FLAGS) != PTA_MANDATORY_FLAGS ||
273 		    pta->flags & ~PTA_ALLOWED_FLAGS ||
274 		    !pta->invoke_command_entry_point)
275 			goto err;
276 	}
277 	return TEE_SUCCESS;
278 err:
279 	DMSG("pseudo TA error at %p", (void *)pta);
280 	panic("PTA");
281 }
282 
283 service_init(verify_pseudo_tas_conformance);
284 
285 /*-----------------------------------------------------------------------------
286  * Initialises a session based on the UUID or ptr to the ta
287  * Returns ptr to the session (ta_session) and a TEE_Result
288  *---------------------------------------------------------------------------*/
tee_ta_init_pseudo_ta_session(const TEE_UUID * uuid,struct tee_ta_session * s)289 TEE_Result tee_ta_init_pseudo_ta_session(const TEE_UUID *uuid,
290 			struct tee_ta_session *s)
291 {
292 	struct pseudo_ta_ctx *stc = NULL;
293 	struct tee_ta_ctx *ctx;
294 	const struct pseudo_ta_head *ta;
295 
296 	DMSG("Lookup pseudo TA %pUl", (void *)uuid);
297 
298 	ta = SCATTERED_ARRAY_BEGIN(pseudo_tas, struct pseudo_ta_head);
299 	while (true) {
300 		if (ta >= SCATTERED_ARRAY_END(pseudo_tas,
301 					      struct pseudo_ta_head))
302 			return TEE_ERROR_ITEM_NOT_FOUND;
303 		if (memcmp(&ta->uuid, uuid, sizeof(TEE_UUID)) == 0)
304 			break;
305 		ta++;
306 	}
307 
308 	/* Load a new TA and create a session */
309 	DMSG("Open %s", ta->name);
310 	stc = calloc(1, sizeof(struct pseudo_ta_ctx));
311 	if (!stc)
312 		return TEE_ERROR_OUT_OF_MEMORY;
313 	ctx = &stc->ctx;
314 
315 	ctx->ref_count = 1;
316 	ctx->flags = ta->flags;
317 	stc->pseudo_ta = ta;
318 	ctx->ts_ctx.uuid = ta->uuid;
319 	ctx->ts_ctx.ops = &pseudo_ta_ops;
320 
321 	mutex_lock(&tee_ta_mutex);
322 	s->ts_sess.ctx = &ctx->ts_ctx;
323 	TAILQ_INSERT_TAIL(&tee_ctxes, ctx, link);
324 	mutex_unlock(&tee_ta_mutex);
325 
326 	DMSG("%s : %pUl", stc->pseudo_ta->name, (void *)&ctx->ts_ctx.uuid);
327 
328 	return TEE_SUCCESS;
329 }
330