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 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