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