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
client_is_secure(struct ts_session * s)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
validate_in_param(struct ts_session * s,struct mobj * mobj)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
validate_in_param(struct ts_session * s __unused,struct mobj * mobj __unused)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 */
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])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 = ¶m->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
update_out_param(TEE_Param tee_param[TEE_NUM_PARAMS],struct tee_ta_param * param)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
unmap_mapped_param(struct tee_ta_param * param,bool did_map[TEE_NUM_PARAMS])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
pseudo_ta_enter_open_session(struct ts_session * s)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
pseudo_ta_enter_invoke_cmd(struct ts_session * s,uint32_t cmd)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
pseudo_ta_enter_close_session(struct ts_session * s)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
pseudo_ta_destroy(struct ts_ctx * ctx)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
is_pseudo_ta_ctx(struct ts_ctx * ctx)249 bool __noprof 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 */
verify_pseudo_tas_conformance(void)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 *---------------------------------------------------------------------------*/
tee_ta_init_pseudo_ta_session(const TEE_UUID * uuid,struct tee_ta_session * s)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 /*
298 * Caller is expected to hold tee_ta_mutex for safe changes
299 * in @s and registering of the context in tee_ctxes list.
300 */
301 assert(mutex_is_locked(&tee_ta_mutex));
302
303 DMSG("Lookup pseudo TA %pUl", (void *)uuid);
304
305 ta = SCATTERED_ARRAY_BEGIN(pseudo_tas, struct pseudo_ta_head);
306 while (true) {
307 if (ta >= SCATTERED_ARRAY_END(pseudo_tas,
308 struct pseudo_ta_head))
309 return TEE_ERROR_ITEM_NOT_FOUND;
310 if (memcmp(&ta->uuid, uuid, sizeof(TEE_UUID)) == 0)
311 break;
312 ta++;
313 }
314
315 DMSG("Open %s", ta->name);
316 stc = calloc(1, sizeof(struct pseudo_ta_ctx));
317 if (!stc)
318 return TEE_ERROR_OUT_OF_MEMORY;
319 ctx = &stc->ctx;
320
321 ctx->ref_count = 1;
322 ctx->flags = ta->flags;
323 stc->pseudo_ta = ta;
324 ctx->ts_ctx.uuid = ta->uuid;
325 ctx->ts_ctx.ops = &pseudo_ta_ops;
326
327 s->ts_sess.ctx = &ctx->ts_ctx;
328 TAILQ_INSERT_TAIL(&tee_ctxes, ctx, link);
329
330 DMSG("%s : %pUl", stc->pseudo_ta->name, (void *)&ctx->ts_ctx.uuid);
331
332 return TEE_SUCCESS;
333 }
334
to_bounce_params(uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS],TEE_Param bparams[TEE_NUM_PARAMS],TEE_Param ** oparams)335 TEE_Result to_bounce_params(uint32_t param_types,
336 TEE_Param params[TEE_NUM_PARAMS],
337 TEE_Param bparams[TEE_NUM_PARAMS],
338 TEE_Param **oparams)
339 {
340 TEE_Result res = TEE_ERROR_GENERIC;
341 void *kptr = NULL;
342 void *uptr = NULL;
343 size_t size = 0;
344 int i = 0;
345
346 if (!is_caller_ta_with_pan()) {
347 *oparams = params;
348 return TEE_SUCCESS;
349 }
350
351 for (i = 0; i < TEE_NUM_PARAMS; i++) {
352 switch (TEE_PARAM_TYPE_GET(param_types, i)) {
353 case TEE_PARAM_TYPE_MEMREF_INPUT:
354 case TEE_PARAM_TYPE_MEMREF_OUTPUT:
355 case TEE_PARAM_TYPE_MEMREF_INOUT:
356 size = params[i].memref.size;
357 uptr = params[i].memref.buffer;
358 kptr = bb_alloc(size);
359 if (!kptr)
360 return TEE_ERROR_OUT_OF_MEMORY;
361 bparams[i].memref.buffer = kptr;
362 bparams[i].memref.size = size;
363 break;
364 default:
365 break;
366 }
367 switch (TEE_PARAM_TYPE_GET(param_types, i)) {
368 case TEE_PARAM_TYPE_MEMREF_INPUT:
369 case TEE_PARAM_TYPE_MEMREF_INOUT:
370 res = copy_from_user(kptr, uptr, size);
371 if (res)
372 return res;
373 break;
374 case TEE_PARAM_TYPE_VALUE_INPUT:
375 case TEE_PARAM_TYPE_VALUE_INOUT:
376 bparams[i].value.a = params[i].value.a;
377 bparams[i].value.b = params[i].value.b;
378 break;
379 default:
380 break;
381 }
382 }
383 *oparams = bparams;
384
385 return TEE_SUCCESS;
386 }
387
from_bounce_params(uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS],TEE_Param bparams[TEE_NUM_PARAMS],TEE_Param * eparams)388 TEE_Result from_bounce_params(uint32_t param_types,
389 TEE_Param params[TEE_NUM_PARAMS],
390 TEE_Param bparams[TEE_NUM_PARAMS],
391 TEE_Param *eparams)
392 {
393 TEE_Result res = TEE_ERROR_GENERIC;
394 void *kptr = NULL;
395 void *uptr = NULL;
396 size_t size = 0;
397 int i = 0;
398
399 if (eparams == params)
400 return TEE_SUCCESS;
401
402 for (i = 0; i < TEE_NUM_PARAMS; i++) {
403 switch (TEE_PARAM_TYPE_GET(param_types, i)) {
404 case TEE_PARAM_TYPE_MEMREF_OUTPUT:
405 case TEE_PARAM_TYPE_MEMREF_INOUT:
406 uptr = params[i].memref.buffer;
407 kptr = bparams[i].memref.buffer;
408 size = bparams[i].memref.size;
409 res = copy_to_user(uptr, kptr, size);
410 if (res)
411 return res;
412 params[i].memref.size = size;
413 break;
414 case TEE_PARAM_TYPE_VALUE_OUTPUT:
415 case TEE_PARAM_TYPE_VALUE_INOUT:
416 params[i].value.a = bparams[i].value.a;
417 params[i].value.b = bparams[i].value.b;
418 break;
419 default:
420 break;
421 }
422 }
423
424 return res;
425 }
426