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