diff options
-rw-r--r-- | common/ccd_config.c | 208 | ||||
-rw-r--r-- | common/tpm_registers.c | 7 | ||||
-rw-r--r-- | 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 4b58b84434..cf6871150f 100644 --- a/common/ccd_config.c +++ b/common/ccd_config.c @@ -571,13 +571,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"); @@ -805,21 +806,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; @@ -831,7 +848,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); /* @@ -846,54 +863,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 */ @@ -911,41 +931,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 @@ -970,7 +1014,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 */ @@ -986,22 +1032,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) { @@ -1121,17 +1176,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); @@ -1285,7 +1343,6 @@ static enum vendor_cmd_rc ccd_password(void *buf, return VENDOR_RC_INTERNAL_ERROR; } - *response_size = 0; return VENDOR_RC_SUCCESS; } @@ -1315,12 +1372,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); /* @@ -1387,12 +1458,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 8c39270a7d..a6d726a2e9 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 @@ -55,6 +55,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. * |