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 = ¶m->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