1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2015-2016, Linaro Limited 4 * Copyright (c) 2014, STMicroelectronics International N.V. 5 */ 6 7 #include <assert.h> 8 #include <compiler.h> 9 #include <initcall.h> 10 #include <io.h> 11 #include <kernel/linker.h> 12 #include <kernel/msg_param.h> 13 #include <kernel/notif.h> 14 #include <kernel/panic.h> 15 #include <kernel/tee_misc.h> 16 #include <mm/core_memprot.h> 17 #include <mm/core_mmu.h> 18 #include <mm/mobj.h> 19 #include <optee_msg.h> 20 #include <string.h> 21 #include <tee/entry_std.h> 22 #include <tee/tee_cryp_utl.h> 23 #include <tee/uuid.h> 24 #include <util.h> 25 26 #define SHM_CACHE_ATTRS \ 27 (uint32_t)(core_mmu_is_shm_cached() ? \ 28 TEE_MATTR_MEM_TYPE_CACHED : TEE_MATTR_MEM_TYPE_DEV) 29 30 /* Sessions opened from normal world */ 31 static struct tee_ta_session_head tee_open_sessions = 32 TAILQ_HEAD_INITIALIZER(tee_open_sessions); 33 34 #ifdef CFG_CORE_RESERVED_SHM 35 static struct mobj *shm_mobj; 36 #endif 37 #ifdef CFG_SECURE_DATA_PATH 38 static struct mobj **sdp_mem_mobjs; 39 #endif 40 41 static unsigned int session_pnum; 42 43 static bool __maybe_unused param_mem_from_mobj(struct param_mem *mem, 44 struct mobj *mobj, 45 const paddr_t pa, 46 const size_t sz) 47 { 48 paddr_t b; 49 50 if (mobj_get_pa(mobj, 0, 0, &b) != TEE_SUCCESS) 51 panic("mobj_get_pa failed"); 52 53 if (!core_is_buffer_inside(pa, MAX(sz, 1UL), b, mobj->size)) 54 return false; 55 56 mem->mobj = mobj_get(mobj); 57 mem->offs = pa - b; 58 mem->size = sz; 59 return true; 60 } 61 62 #ifdef CFG_CORE_FFA 63 static TEE_Result set_fmem_param(const struct optee_msg_param_fmem *fmem, 64 struct param_mem *mem) 65 { 66 size_t req_size = 0; 67 uint64_t global_id = READ_ONCE(fmem->global_id); 68 size_t sz = READ_ONCE(fmem->size); 69 70 if (global_id == OPTEE_MSG_FMEM_INVALID_GLOBAL_ID && !sz) { 71 mem->mobj = NULL; 72 mem->offs = 0; 73 mem->size = 0; 74 return TEE_SUCCESS; 75 } 76 mem->mobj = mobj_ffa_get_by_cookie(global_id, 77 READ_ONCE(fmem->internal_offs)); 78 if (!mem->mobj) 79 return TEE_ERROR_BAD_PARAMETERS; 80 81 mem->offs = reg_pair_to_64(READ_ONCE(fmem->offs_high), 82 READ_ONCE(fmem->offs_low)); 83 mem->size = sz; 84 85 /* 86 * Check that the supplied offset and size is covered by the 87 * previously verified MOBJ. 88 */ 89 if (ADD_OVERFLOW(mem->offs, mem->size, &req_size) || 90 mem->mobj->size < req_size) 91 return TEE_ERROR_SECURITY; 92 93 return TEE_SUCCESS; 94 } 95 #else /*!CFG_CORE_FFA*/ 96 /* fill 'struct param_mem' structure if buffer matches a valid memory object */ 97 static TEE_Result set_tmem_param(const struct optee_msg_param_tmem *tmem, 98 uint32_t attr, struct param_mem *mem) 99 { 100 struct mobj __maybe_unused **mobj; 101 paddr_t pa = READ_ONCE(tmem->buf_ptr); 102 size_t sz = READ_ONCE(tmem->size); 103 104 /* 105 * Handle NULL memory reference 106 */ 107 if (!pa) { 108 mem->mobj = NULL; 109 mem->offs = 0; 110 mem->size = 0; 111 return TEE_SUCCESS; 112 } 113 114 /* Handle non-contiguous reference from a shared memory area */ 115 if (attr & OPTEE_MSG_ATTR_NONCONTIG) { 116 uint64_t shm_ref = READ_ONCE(tmem->shm_ref); 117 118 mem->mobj = msg_param_mobj_from_noncontig(pa, sz, shm_ref, 119 false); 120 if (!mem->mobj) 121 return TEE_ERROR_BAD_PARAMETERS; 122 mem->offs = 0; 123 mem->size = sz; 124 return TEE_SUCCESS; 125 } 126 127 #ifdef CFG_CORE_RESERVED_SHM 128 /* Handle memory reference in the contiguous shared memory */ 129 if (param_mem_from_mobj(mem, shm_mobj, pa, sz)) 130 return TEE_SUCCESS; 131 #endif 132 133 #ifdef CFG_SECURE_DATA_PATH 134 /* Handle memory reference to Secure Data Path memory areas */ 135 for (mobj = sdp_mem_mobjs; *mobj; mobj++) 136 if (param_mem_from_mobj(mem, *mobj, pa, sz)) 137 return TEE_SUCCESS; 138 #endif 139 140 return TEE_ERROR_BAD_PARAMETERS; 141 } 142 143 #ifdef CFG_CORE_DYN_SHM 144 static TEE_Result set_rmem_param(const struct optee_msg_param_rmem *rmem, 145 struct param_mem *mem) 146 { 147 size_t req_size = 0; 148 uint64_t shm_ref = READ_ONCE(rmem->shm_ref); 149 size_t sz = READ_ONCE(rmem->size); 150 151 mem->mobj = mobj_reg_shm_get_by_cookie(shm_ref); 152 if (!mem->mobj) 153 return TEE_ERROR_BAD_PARAMETERS; 154 155 mem->offs = READ_ONCE(rmem->offs); 156 mem->size = sz; 157 158 /* 159 * Check that the supplied offset and size is covered by the 160 * previously verified MOBJ. 161 */ 162 if (ADD_OVERFLOW(mem->offs, mem->size, &req_size) || 163 mem->mobj->size < req_size) 164 return TEE_ERROR_SECURITY; 165 166 return TEE_SUCCESS; 167 } 168 #endif /*CFG_CORE_DYN_SHM*/ 169 #endif /*!CFG_CORE_FFA*/ 170 171 static TEE_Result copy_in_params(const struct optee_msg_param *params, 172 uint32_t num_params, 173 struct tee_ta_param *ta_param, 174 uint64_t *saved_attr) 175 { 176 TEE_Result res; 177 size_t n; 178 uint8_t pt[TEE_NUM_PARAMS] = { 0 }; 179 180 if (num_params > TEE_NUM_PARAMS) 181 return TEE_ERROR_BAD_PARAMETERS; 182 183 memset(ta_param, 0, sizeof(*ta_param)); 184 185 for (n = 0; n < num_params; n++) { 186 uint32_t attr; 187 188 saved_attr[n] = READ_ONCE(params[n].attr); 189 190 if (saved_attr[n] & OPTEE_MSG_ATTR_META) 191 return TEE_ERROR_BAD_PARAMETERS; 192 193 attr = saved_attr[n] & OPTEE_MSG_ATTR_TYPE_MASK; 194 switch (attr) { 195 case OPTEE_MSG_ATTR_TYPE_NONE: 196 pt[n] = TEE_PARAM_TYPE_NONE; 197 break; 198 case OPTEE_MSG_ATTR_TYPE_VALUE_INPUT: 199 case OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT: 200 case OPTEE_MSG_ATTR_TYPE_VALUE_INOUT: 201 pt[n] = TEE_PARAM_TYPE_VALUE_INPUT + attr - 202 OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 203 ta_param->u[n].val.a = READ_ONCE(params[n].u.value.a); 204 ta_param->u[n].val.b = READ_ONCE(params[n].u.value.b); 205 break; 206 #ifdef CFG_CORE_FFA 207 case OPTEE_MSG_ATTR_TYPE_FMEM_INPUT: 208 case OPTEE_MSG_ATTR_TYPE_FMEM_OUTPUT: 209 case OPTEE_MSG_ATTR_TYPE_FMEM_INOUT: 210 res = set_fmem_param(¶ms[n].u.fmem, 211 &ta_param->u[n].mem); 212 if (res) 213 return res; 214 pt[n] = TEE_PARAM_TYPE_MEMREF_INPUT + attr - 215 OPTEE_MSG_ATTR_TYPE_FMEM_INPUT; 216 break; 217 #else /*!CFG_CORE_FFA*/ 218 case OPTEE_MSG_ATTR_TYPE_TMEM_INPUT: 219 case OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT: 220 case OPTEE_MSG_ATTR_TYPE_TMEM_INOUT: 221 res = set_tmem_param(¶ms[n].u.tmem, saved_attr[n], 222 &ta_param->u[n].mem); 223 if (res) 224 return res; 225 pt[n] = TEE_PARAM_TYPE_MEMREF_INPUT + attr - 226 OPTEE_MSG_ATTR_TYPE_TMEM_INPUT; 227 break; 228 #ifdef CFG_CORE_DYN_SHM 229 case OPTEE_MSG_ATTR_TYPE_RMEM_INPUT: 230 case OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT: 231 case OPTEE_MSG_ATTR_TYPE_RMEM_INOUT: 232 res = set_rmem_param(¶ms[n].u.rmem, 233 &ta_param->u[n].mem); 234 if (res) 235 return res; 236 pt[n] = TEE_PARAM_TYPE_MEMREF_INPUT + attr - 237 OPTEE_MSG_ATTR_TYPE_RMEM_INPUT; 238 break; 239 #endif /*CFG_CORE_DYN_SHM*/ 240 #endif /*!CFG_CORE_FFA*/ 241 default: 242 return TEE_ERROR_BAD_PARAMETERS; 243 } 244 } 245 246 ta_param->types = TEE_PARAM_TYPES(pt[0], pt[1], pt[2], pt[3]); 247 248 return TEE_SUCCESS; 249 } 250 251 static void cleanup_shm_refs(const uint64_t *saved_attr, 252 struct tee_ta_param *param, uint32_t num_params) 253 { 254 size_t n; 255 256 for (n = 0; n < MIN((unsigned int)TEE_NUM_PARAMS, num_params); n++) { 257 switch (saved_attr[n]) { 258 case OPTEE_MSG_ATTR_TYPE_TMEM_INPUT: 259 case OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT: 260 case OPTEE_MSG_ATTR_TYPE_TMEM_INOUT: 261 #ifdef CFG_CORE_DYN_SHM 262 case OPTEE_MSG_ATTR_TYPE_RMEM_INPUT: 263 case OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT: 264 case OPTEE_MSG_ATTR_TYPE_RMEM_INOUT: 265 #endif 266 mobj_put(param->u[n].mem.mobj); 267 break; 268 default: 269 break; 270 } 271 } 272 } 273 274 static void copy_out_param(struct tee_ta_param *ta_param, uint32_t num_params, 275 struct optee_msg_param *params, uint64_t *saved_attr) 276 { 277 size_t n; 278 279 for (n = 0; n < num_params; n++) { 280 switch (TEE_PARAM_TYPE_GET(ta_param->types, n)) { 281 case TEE_PARAM_TYPE_MEMREF_OUTPUT: 282 case TEE_PARAM_TYPE_MEMREF_INOUT: 283 switch (saved_attr[n] & OPTEE_MSG_ATTR_TYPE_MASK) { 284 case OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT: 285 case OPTEE_MSG_ATTR_TYPE_TMEM_INOUT: 286 params[n].u.tmem.size = ta_param->u[n].mem.size; 287 break; 288 case OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT: 289 case OPTEE_MSG_ATTR_TYPE_RMEM_INOUT: 290 params[n].u.rmem.size = ta_param->u[n].mem.size; 291 break; 292 default: 293 break; 294 } 295 break; 296 case TEE_PARAM_TYPE_VALUE_OUTPUT: 297 case TEE_PARAM_TYPE_VALUE_INOUT: 298 params[n].u.value.a = ta_param->u[n].val.a; 299 params[n].u.value.b = ta_param->u[n].val.b; 300 break; 301 default: 302 break; 303 } 304 } 305 } 306 307 /* 308 * Extracts mandatory parameter for open session. 309 * 310 * Returns 311 * false : mandatory parameter wasn't found or malformatted 312 * true : paramater found and OK 313 */ 314 static TEE_Result get_open_session_meta(size_t num_params, 315 struct optee_msg_param *params, 316 size_t *num_meta, TEE_UUID *uuid, 317 TEE_Identity *clnt_id) 318 { 319 const uint32_t req_attr = OPTEE_MSG_ATTR_META | 320 OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 321 322 if (num_params < 2) 323 return TEE_ERROR_BAD_PARAMETERS; 324 325 if (params[0].attr != req_attr || params[1].attr != req_attr) 326 return TEE_ERROR_BAD_PARAMETERS; 327 328 tee_uuid_from_octets(uuid, (void *)¶ms[0].u.value); 329 clnt_id->login = params[1].u.value.c; 330 switch (clnt_id->login) { 331 case TEE_LOGIN_PUBLIC: 332 case TEE_LOGIN_REE_KERNEL: 333 memset(&clnt_id->uuid, 0, sizeof(clnt_id->uuid)); 334 break; 335 case TEE_LOGIN_USER: 336 case TEE_LOGIN_GROUP: 337 case TEE_LOGIN_APPLICATION: 338 case TEE_LOGIN_APPLICATION_USER: 339 case TEE_LOGIN_APPLICATION_GROUP: 340 tee_uuid_from_octets(&clnt_id->uuid, 341 (void *)¶ms[1].u.value); 342 break; 343 default: 344 return TEE_ERROR_BAD_PARAMETERS; 345 } 346 347 *num_meta = 2; 348 return TEE_SUCCESS; 349 } 350 351 static void entry_open_session(struct optee_msg_arg *arg, uint32_t num_params) 352 { 353 TEE_Result res = TEE_ERROR_GENERIC; 354 TEE_ErrorOrigin err_orig = TEE_ORIGIN_TEE; 355 struct tee_ta_session *s = NULL; 356 TEE_Identity clnt_id = { }; 357 TEE_UUID uuid = { }; 358 struct tee_ta_param param = { }; 359 size_t num_meta = 0; 360 uint64_t saved_attr[TEE_NUM_PARAMS] = { 0 }; 361 362 res = get_open_session_meta(num_params, arg->params, &num_meta, &uuid, 363 &clnt_id); 364 if (res != TEE_SUCCESS) 365 goto out; 366 367 res = copy_in_params(arg->params + num_meta, num_params - num_meta, 368 ¶m, saved_attr); 369 if (res != TEE_SUCCESS) 370 goto cleanup_shm_refs; 371 372 res = tee_ta_open_session(&err_orig, &s, &tee_open_sessions, &uuid, 373 &clnt_id, TEE_TIMEOUT_INFINITE, ¶m); 374 if (res != TEE_SUCCESS) 375 s = NULL; 376 copy_out_param(¶m, num_params - num_meta, arg->params + num_meta, 377 saved_attr); 378 379 /* 380 * The occurrence of open/close session command is usually 381 * un-predictable, using this property to increase randomness 382 * of prng 383 */ 384 plat_prng_add_jitter_entropy(CRYPTO_RNG_SRC_JITTER_SESSION, 385 &session_pnum); 386 387 cleanup_shm_refs: 388 cleanup_shm_refs(saved_attr, ¶m, num_params - num_meta); 389 390 out: 391 if (s) 392 arg->session = s->id; 393 else 394 arg->session = 0; 395 arg->ret = res; 396 arg->ret_origin = err_orig; 397 } 398 399 static void entry_close_session(struct optee_msg_arg *arg, uint32_t num_params) 400 { 401 TEE_Result res; 402 struct tee_ta_session *s; 403 404 if (num_params) { 405 res = TEE_ERROR_BAD_PARAMETERS; 406 goto out; 407 } 408 409 plat_prng_add_jitter_entropy(CRYPTO_RNG_SRC_JITTER_SESSION, 410 &session_pnum); 411 412 s = tee_ta_find_session(arg->session, &tee_open_sessions); 413 res = tee_ta_close_session(s, &tee_open_sessions, NSAPP_IDENTITY); 414 out: 415 arg->ret = res; 416 arg->ret_origin = TEE_ORIGIN_TEE; 417 } 418 419 static void entry_invoke_command(struct optee_msg_arg *arg, uint32_t num_params) 420 { 421 TEE_Result res; 422 TEE_ErrorOrigin err_orig = TEE_ORIGIN_TEE; 423 struct tee_ta_session *s; 424 struct tee_ta_param param = { 0 }; 425 uint64_t saved_attr[TEE_NUM_PARAMS] = { 0 }; 426 427 res = copy_in_params(arg->params, num_params, ¶m, saved_attr); 428 if (res != TEE_SUCCESS) 429 goto out; 430 431 s = tee_ta_get_session(arg->session, true, &tee_open_sessions); 432 if (!s) { 433 res = TEE_ERROR_BAD_PARAMETERS; 434 goto out; 435 } 436 437 res = tee_ta_invoke_command(&err_orig, s, NSAPP_IDENTITY, 438 TEE_TIMEOUT_INFINITE, arg->func, ¶m); 439 440 tee_ta_put_session(s); 441 442 copy_out_param(¶m, num_params, arg->params, saved_attr); 443 444 out: 445 cleanup_shm_refs(saved_attr, ¶m, num_params); 446 447 arg->ret = res; 448 arg->ret_origin = err_orig; 449 } 450 451 static void entry_cancel(struct optee_msg_arg *arg, uint32_t num_params) 452 { 453 TEE_Result res; 454 TEE_ErrorOrigin err_orig = TEE_ORIGIN_TEE; 455 struct tee_ta_session *s; 456 457 if (num_params) { 458 res = TEE_ERROR_BAD_PARAMETERS; 459 goto out; 460 } 461 462 s = tee_ta_get_session(arg->session, false, &tee_open_sessions); 463 if (!s) { 464 res = TEE_ERROR_BAD_PARAMETERS; 465 goto out; 466 } 467 468 res = tee_ta_cancel_command(&err_orig, s, NSAPP_IDENTITY); 469 tee_ta_put_session(s); 470 471 out: 472 arg->ret = res; 473 arg->ret_origin = err_orig; 474 } 475 476 #ifndef CFG_CORE_FFA 477 #ifdef CFG_CORE_DYN_SHM 478 static void register_shm(struct optee_msg_arg *arg, uint32_t num_params) 479 { 480 struct optee_msg_param_tmem *tmem = NULL; 481 struct mobj *mobj = NULL; 482 483 arg->ret = TEE_ERROR_BAD_PARAMETERS; 484 485 if (num_params != 1 || 486 (arg->params[0].attr != 487 (OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT | OPTEE_MSG_ATTR_NONCONTIG))) 488 return; 489 490 tmem = &arg->params[0].u.tmem; 491 mobj = msg_param_mobj_from_noncontig(tmem->buf_ptr, tmem->size, 492 tmem->shm_ref, false); 493 494 if (!mobj) 495 return; 496 497 mobj_reg_shm_unguard(mobj); 498 arg->ret = TEE_SUCCESS; 499 } 500 501 static void unregister_shm(struct optee_msg_arg *arg, uint32_t num_params) 502 { 503 if (num_params == 1) { 504 uint64_t cookie = arg->params[0].u.rmem.shm_ref; 505 TEE_Result res = mobj_reg_shm_release_by_cookie(cookie); 506 507 if (res) 508 EMSG("Can't find mapping with given cookie"); 509 arg->ret = res; 510 } else { 511 arg->ret = TEE_ERROR_BAD_PARAMETERS; 512 arg->ret_origin = TEE_ORIGIN_TEE; 513 } 514 } 515 #endif /*CFG_CORE_DYN_SHM*/ 516 #endif 517 518 void nsec_sessions_list_head(struct tee_ta_session_head **open_sessions) 519 { 520 *open_sessions = &tee_open_sessions; 521 } 522 523 /* Note: this function is weak to let platforms add special handling */ 524 TEE_Result __weak tee_entry_std(struct optee_msg_arg *arg, uint32_t num_params) 525 { 526 return __tee_entry_std(arg, num_params); 527 } 528 529 /* 530 * If tee_entry_std() is overridden, it's still supposed to call this 531 * function. 532 */ 533 TEE_Result __tee_entry_std(struct optee_msg_arg *arg, uint32_t num_params) 534 { 535 TEE_Result res = TEE_SUCCESS; 536 537 /* Enable foreign interrupts for STD calls */ 538 thread_set_foreign_intr(true); 539 switch (arg->cmd) { 540 case OPTEE_MSG_CMD_OPEN_SESSION: 541 entry_open_session(arg, num_params); 542 break; 543 case OPTEE_MSG_CMD_CLOSE_SESSION: 544 entry_close_session(arg, num_params); 545 break; 546 case OPTEE_MSG_CMD_INVOKE_COMMAND: 547 entry_invoke_command(arg, num_params); 548 break; 549 case OPTEE_MSG_CMD_CANCEL: 550 entry_cancel(arg, num_params); 551 break; 552 #ifndef CFG_CORE_FFA 553 #ifdef CFG_CORE_DYN_SHM 554 case OPTEE_MSG_CMD_REGISTER_SHM: 555 register_shm(arg, num_params); 556 break; 557 case OPTEE_MSG_CMD_UNREGISTER_SHM: 558 unregister_shm(arg, num_params); 559 break; 560 #endif 561 #endif 562 563 case OPTEE_MSG_CMD_DO_BOTTOM_HALF: 564 if (IS_ENABLED(CFG_CORE_ASYNC_NOTIF)) 565 notif_deliver_event(NOTIF_EVENT_DO_BOTTOM_HALF); 566 else 567 goto err; 568 break; 569 case OPTEE_MSG_CMD_STOP_ASYNC_NOTIF: 570 if (IS_ENABLED(CFG_CORE_ASYNC_NOTIF)) 571 notif_deliver_event(NOTIF_EVENT_STOPPED); 572 else 573 goto err; 574 break; 575 576 default: 577 err: 578 EMSG("Unknown cmd 0x%x", arg->cmd); 579 res = TEE_ERROR_NOT_IMPLEMENTED; 580 } 581 582 return res; 583 } 584 585 static TEE_Result default_mobj_init(void) 586 { 587 #ifdef CFG_CORE_RESERVED_SHM 588 shm_mobj = mobj_phys_alloc(default_nsec_shm_paddr, 589 default_nsec_shm_size, SHM_CACHE_ATTRS, 590 CORE_MEM_NSEC_SHM); 591 if (!shm_mobj) 592 panic("Failed to register shared memory"); 593 #endif 594 595 #ifdef CFG_SECURE_DATA_PATH 596 sdp_mem_mobjs = core_sdp_mem_create_mobjs(); 597 if (!sdp_mem_mobjs) 598 panic("Failed to register SDP memory"); 599 #endif 600 601 return TEE_SUCCESS; 602 } 603 604 driver_init_late(default_mobj_init); 605