From 7094d02b1afb139bad7db11bcf1c09d0c34889d5 Mon Sep 17 00:00:00 2001 From: Vadim Bendebury Date: Mon, 8 Jan 2018 12:47:29 -0800 Subject: cr50: pass essential ccd commands through tpm task context Using and extending the existing framework, move ccd commands 'password, lock, open, and unlock to the same processing path. The first three commands accept a single parameter, password. It is required for the password command and optional for unlock and open. The lock command does not require any parameters. Wiping the TPM, if necessary, now happens on the same context where CCD command is executed, i.e. the TPM task context. This is why the same context TPM reset function needs to be exported and used here. ccd_open() and ccd_unlock() could be further refactored, this would require a bit more effort to find appropriate balance between commonalities and differences. BRANCH=cr50 BUG=b:62537474 TEST=verified that ccd commands to open, unlock, lock and set and clear password all work. Change-Id: I2b9f2b550347b590a55bfaef262a4f050d3f4c1c Signed-off-by: Vadim Bendebury Reviewed-on: https://chromium-review.googlesource.com/854709 Reviewed-by: Randall Spangler (cherry picked from commit b31fca4b91f10be84a845222775b67553d63bf4e) Reviewed-on: https://chromium-review.googlesource.com/896757 --- common/ccd_config.c | 208 +++++++++++++++++++++++++++++++----------------- common/tpm_registers.c | 7 ++ include/tpm_registers.h | 6 ++ 3 files changed, 150 insertions(+), 71 deletions(-) diff --git a/common/ccd_config.c b/common/ccd_config.c index cbbf11570e..bbf3b10f67 100644 --- a/common/ccd_config.c +++ b/common/ccd_config.c @@ -570,13 +570,14 @@ static void ccd_open_done(void) { if (!ccd_is_cap_enabled(CCD_CAP_OPEN_WITHOUT_TPM_WIPE)) { /* Can't open unless wipe succeeds */ - if (board_wipe_tpm() != EC_SUCCESS) { + if (tpm_sync_reset(1) != EC_SUCCESS) { CPRINTS("CCD open TPM wipe failed"); return; } } - if (!ccd_is_cap_enabled(CCD_CAP_UNLOCK_WITHOUT_AP_REBOOT)) + if (!ccd_is_cap_enabled(CCD_CAP_UNLOCK_WITHOUT_AP_REBOOT) || + !ccd_is_cap_enabled(CCD_CAP_OPEN_WITHOUT_TPM_WIPE)) board_reboot_ap(); CPRINTS("CCD opened"); @@ -804,21 +805,37 @@ static int do_ccd_password(char *password) } /* - * Prepare a message containing a TPM vendor command, have the TPM task - * process the message and report the result to the caller. + * Common wrapper for CCD commands which are passed through the TPM task + * context. + * + * All commands could have a single parameter, which is the password (to be + * set, cleared, or entered to open/unlock). If argc calue exceeds 1, the + * pointer to password is set, it is checked not to exceed maximum size. + * + * If the check succeeds, prepare a message containing a TPM vendor command, + * have the TPM task process the message and report the result to the caller. * - * Message header is always the same, the caller supplies the subcommand code - * and payload, if any. + * Message header is always the same, the payload is the password, if + * supplied. */ -static int send_vendor_command(enum ccd_vendor_subcommands subcmd, - void *payload, size_t size) +static int ccd_command_wrapper(int argc, char *password, + enum ccd_vendor_subcommands subcmd) { int rv; struct ccd_vendor_cmd_header *vch; size_t command_size; + size_t password_size; + + if (argc > 1) { + password_size = strlen(password); + if (password_size > CCD_MAX_PASSWORD_SIZE) + return EC_ERROR_PARAM1; + } else { + password_size = 0; + } - command_size = sizeof(*vch) + size; + command_size = sizeof(*vch) + password_size; rv = shared_mem_acquire(command_size, (char **)&vch); if (rv != EC_SUCCESS) return rv; @@ -830,7 +847,7 @@ static int send_vendor_command(enum ccd_vendor_subcommands subcmd, vch->tpm_header.subcommand_code = htobe16(VENDOR_CC_CCD); vch->ccd_subcommand = subcmd; - memcpy(vch + 1, payload, size); + memcpy(vch + 1, password, password_size); tpm_alt_extension(&vch->tpm_header, command_size); /* @@ -845,54 +862,57 @@ static int send_vendor_command(enum ccd_vendor_subcommands subcmd, } shared_mem_release(vch); - return EC_SUCCESS; -} - -static int command_ccd_password(int argc, char **argv) -{ - size_t password_size; - - if (argc < 2) - return EC_ERROR_PARAM_COUNT; - - password_size = strlen(argv[1]); - - if (password_size > CCD_MAX_PASSWORD_SIZE) { - ccprintf("Password can not be longer than %d characters\n", - CCD_MAX_PASSWORD_SIZE); - return EC_ERROR_PARAM1; - } - - return send_vendor_command(CCDV_PASSWORD, argv[1], password_size); + return rv; } -static int command_ccd_open(int argc, char **argv) +static enum vendor_cmd_rc ccd_open(void *buf, + size_t input_size, + size_t *response_size) { int is_long = 1; int need_pp = 1; int rv; + char *buffer = buf; - if (force_disabled) - return EC_ERROR_ACCESS_DENIED; + if (force_disabled) { + *response_size = 1; + buffer[0] = EC_ERROR_ACCESS_DENIED; + return VENDOR_RC_NOT_ALLOWED; + } if (ccd_state == CCD_STATE_OPENED) - return EC_SUCCESS; + return VENDOR_RC_SUCCESS; if (raw_has_password()) { - if (argc < 2) - return EC_ERROR_PARAM_COUNT; + if (!input_size) { + *response_size = 1; + buffer[0] = EC_ERROR_PARAM_COUNT; + return VENDOR_RC_INTERNAL_ERROR; + } - rv = raw_check_password(argv[1]); - if (rv) - return rv; + /* + * We know there is plenty of room in the TPM buffer this is + * stored in. + */ + buffer[input_size] = '\0'; + rv = raw_check_password(buffer); + if (rv) { + *response_size = 1; + buffer[0] = rv; + return VENDOR_RC_INTERNAL_ERROR; + } } else if (!board_fwmp_allows_unlock()) { - return EC_ERROR_ACCESS_DENIED; + *response_size = 1; + buffer[0] = EC_ERROR_ACCESS_DENIED; + return VENDOR_RC_NOT_ALLOWED; } /* Fail and abort if already checking physical presence */ if (physical_detect_busy()) { physical_detect_abort(); - return EC_ERROR_BUSY; + *response_size = 1; + buffer[0] = EC_ERROR_BUSY; + return VENDOR_RC_INTERNAL_ERROR; } /* Reduce physical presence if enabled via config */ @@ -910,41 +930,65 @@ static int command_ccd_open(int argc, char **argv) if (need_pp) { /* Start physical presence detect */ ccprintf("Starting CCD open...\n"); - return physical_detect_start(is_long, ccd_open_done); + rv = physical_detect_start(is_long, ccd_open_done); + if (rv != EC_SUCCESS) { + *response_size = 1; + buffer[0] = rv; + return VENDOR_RC_INTERNAL_ERROR; + } } else { /* No physical presence required; go straight to done */ ccd_open_done(); - return EC_SUCCESS; } + + return VENDOR_RC_SUCCESS; } -static int command_ccd_unlock(int argc, char **argv) +static enum vendor_cmd_rc ccd_unlock(void *buf, + size_t input_size, + size_t *response_size) { int need_pp = 1; int rv; + char *buffer = buf; - if (force_disabled) - return EC_ERROR_ACCESS_DENIED; + if (force_disabled) { + *response_size = 1; + buffer[0] = EC_ERROR_ACCESS_DENIED; + return VENDOR_RC_NOT_ALLOWED; + } if (ccd_state == CCD_STATE_UNLOCKED) - return EC_SUCCESS; + return VENDOR_RC_SUCCESS; /* Can go from opened to unlocked with no delay or password */ if (ccd_state == CCD_STATE_OPENED) { ccd_unlock_done(); - return EC_SUCCESS; + return VENDOR_RC_SUCCESS; } if (raw_has_password()) { - if (argc < 2) - return EC_ERROR_PARAM_COUNT; + if (!input_size) { + *response_size = 1; + buffer[0] = EC_ERROR_PARAM_COUNT; + return VENDOR_RC_INTERNAL_ERROR; + } - rv = raw_check_password(argv[1]); - if (rv) - return rv; + /* + * We know there is plenty of room in the TPM buffer this is + * stored in. + */ + buffer[input_size] = '\0'; + rv = raw_check_password(buffer); + if (rv) { + *response_size = 1; + buffer[0] = rv; + return VENDOR_RC_INTERNAL_ERROR; + } } else if (!board_fwmp_allows_unlock()) { - /* Unlock disabled by FWMP */ - return EC_ERROR_ACCESS_DENIED; + *response_size = 1; + buffer[0] = EC_ERROR_ACCESS_DENIED; + return VENDOR_RC_NOT_ALLOWED; } else { /* * When unlock is requested via the console, physical presence @@ -969,7 +1013,9 @@ static int command_ccd_unlock(int argc, char **argv) /* Fail and abort if already checking physical presence */ if (physical_detect_busy()) { physical_detect_abort(); - return EC_ERROR_BUSY; + *response_size = 1; + buffer[0] = EC_ERROR_BUSY; + return VENDOR_RC_INTERNAL_ERROR; } /* Bypass physical presence check if configured to do so */ @@ -985,22 +1031,31 @@ static int command_ccd_unlock(int argc, char **argv) if (need_pp) { /* Start physical presence detect */ ccprintf("Starting CCD unlock...\n"); - return physical_detect_start(0, ccd_unlock_done); + rv = physical_detect_start(0, ccd_unlock_done); + if (rv != EC_SUCCESS) { + *response_size = 1; + buffer[0] = rv; + return VENDOR_RC_INTERNAL_ERROR; + } } else { /* Unlock immediately */ ccd_unlock_done(); - return EC_SUCCESS; } + return VENDOR_RC_SUCCESS; } -static int command_ccd_lock(void) +static enum vendor_cmd_rc ccd_lock(void *unused0, + size_t unused1, + size_t *response_size) { /* Lock always works */ ccprintf("CCD locked.\n"); ccd_set_state(CCD_STATE_LOCKED); - return EC_SUCCESS; + return VENDOR_RC_SUCCESS; } + + /* NOTE: Testlab command is console-only; no TPM vendor command for this */ static int command_ccd_testlab(int argc, char **argv) { @@ -1120,17 +1175,20 @@ static int command_ccd(int argc, char **argv) /* Commands to set state */ if (!strcasecmp(argv[1], "lock")) - return command_ccd_lock(); + return ccd_command_wrapper(0, NULL, CCDV_LOCK); if (!strcasecmp(argv[1], "unlock")) - return command_ccd_unlock(argc - 1, argv + 1); + return ccd_command_wrapper(argc - 1, argv[2], CCDV_UNLOCK); if (!strcasecmp(argv[1], "open")) - return command_ccd_open(argc - 1, argv + 1); + return ccd_command_wrapper(argc - 1, argv[2], CCDV_OPEN); /* Commands to configure capabilities */ if (!strcasecmp(argv[1], "set")) return command_ccd_set(argc - 1, argv + 1); - if (!strcasecmp(argv[1], "password")) - return command_ccd_password(argc - 1, argv + 1); + if (!strcasecmp(argv[1], "password")) { + if (argc != 3) + return EC_ERROR_PARAM_COUNT; + return ccd_command_wrapper(argc - 1, argv[2], CCDV_PASSWORD); + } if (!strcasecmp(argv[1], "reset")) return command_ccd_reset(argc - 1, argv + 1); @@ -1284,7 +1342,6 @@ static enum vendor_cmd_rc ccd_password(void *buf, return VENDOR_RC_INTERNAL_ERROR; } - *response_size = 0; return VENDOR_RC_SUCCESS; } @@ -1314,12 +1371,26 @@ static enum vendor_cmd_rc ccd_vendor(enum vendor_cmd_cc code, handler = ccd_password; break; + case CCDV_OPEN: + handler = ccd_open; + break; + + case CCDV_UNLOCK: + handler = ccd_unlock; + break; + + case CCDV_LOCK: + handler = ccd_lock; + break; + default: CPRINTS("%s:%d - unknown subcommand\n", __func__, __LINE__); break; } if (handler) { + *response_size = 0; /* Let's be optimistic: 0 means success. */ + rc = handler(buf + 1, input_size - 1, response_size); /* @@ -1386,12 +1457,7 @@ static enum vendor_cmd_rc ccd_disable_rma(enum vendor_cmd_cc code, } - rv = command_ccd_lock(); - if (rv != EC_SUCCESS) { - error_line = __LINE__; - break; - } - + ccd_lock(NULL, 0, NULL); *response_size = 0; return VENDOR_RC_SUCCESS; } while (0); diff --git a/common/tpm_registers.c b/common/tpm_registers.c index 5e73d573c9..fab6616f54 100644 --- a/common/tpm_registers.c +++ b/common/tpm_registers.c @@ -879,6 +879,13 @@ static void tpm_reset_now(int wipe_first) if_start(); } +int tpm_sync_reset(int wipe_first) +{ + tpm_reset_now(wipe_first); + + return wipe_result; +} + void tpm_task(void) { uint32_t evt; diff --git a/include/tpm_registers.h b/include/tpm_registers.h index 5da9ab6c2f..b82a355170 100644 --- a/include/tpm_registers.h +++ b/include/tpm_registers.h @@ -54,6 +54,12 @@ int tpm_reset_request(int wait_until_done, int wipe_nvmem_first); */ void tpm_reinstate_nvmem_commits(void); +/* + * To be called by functions running on the TPM task context. Returns + * EC_SUCCESS on successful reset. + */ +int tpm_sync_reset(int wipe_first); + /* * This structure describes the header of all commands and responses sent and * received over TPM FIFO. -- cgit v1.2.1