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 = ¶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 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 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 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 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 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 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 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 */ 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 *---------------------------------------------------------------------------*/ 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