From b3218b9533b607dd53fec13671e3d91b50c0122a Mon Sep 17 00:00:00 2001 From: Randall Spangler Date: Fri, 18 May 2018 17:04:59 -0700 Subject: ccd_config: Ccd vendor command takes params struct This is needed so ccd_open() can see p->flags, for a subsequent change. No change to existing command behavior or binary size. BUG=b:79983505 BRANCH=cr50 TEST=gsctool -I still works Change-Id: I614d8c410e8bc55a5045e253469b2ec222078684 Signed-off-by: Randall Spangler Reviewed-on: https://chromium-review.googlesource.com/1072500 Reviewed-by: Vadim Bendebury --- common/ccd_config.c | 212 +++++++++++++++++++++++----------------------------- common/extension.c | 5 +- 2 files changed, 95 insertions(+), 122 deletions(-) diff --git a/common/ccd_config.c b/common/ccd_config.c index 78fc822d9f..677eb025ca 100644 --- a/common/ccd_config.c +++ b/common/ccd_config.c @@ -16,7 +16,6 @@ #include "hooks.h" #include "nvmem_vars.h" #include "physical_presence.h" -#include "shared_mem.h" #include "system.h" #include "system_chip.h" #include "task.h" @@ -56,6 +55,8 @@ enum ccd_unlock_restrict { */ struct ccd_vendor_cmd_header { struct tpm_cmd_header tpm_header; + + /* On input, the subcommand. On output, may contain EC return code */ uint8_t ccd_subcommand; } __packed; @@ -783,7 +784,7 @@ static int do_ccd_password(char *password) * 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 + * set, cleared, or entered to open/unlock). If argc value 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, @@ -791,39 +792,33 @@ static int do_ccd_password(char *password) * * Message header is always the same, the payload is the password, if * supplied. + * + * Expected output is nothing on success, or a single byte EC return code. */ 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; + uint8_t buf[sizeof(struct ccd_vendor_cmd_header) + + CCD_MAX_PASSWORD_SIZE]; + struct ccd_vendor_cmd_header *vch = (struct ccd_vendor_cmd_header *)buf; + size_t password_size = 0; uint32_t return_code; if (argc > 1) { password_size = strlen(password); - - if (password_size > CCD_MAX_PASSWORD_SIZE) + if (password_size > CCD_MAX_PASSWORD_SIZE) return EC_ERROR_PARAM1; - } else { - password_size = 0; } - command_size = sizeof(*vch) + password_size; - rv = shared_mem_acquire(command_size, (char **)&vch); - if (rv != EC_SUCCESS) - return rv; - /* Build the extension command to set/clear CCD password. */ vch->tpm_header.tag = htobe16(0x8001); /* TPM_ST_NO_SESSIONS */ - vch->tpm_header.size = htobe32(command_size); + vch->tpm_header.size = htobe32(sizeof(*vch) + password_size); vch->tpm_header.command_code = htobe32(TPM_CC_VENDOR_BIT_MASK); vch->tpm_header.subcommand_code = htobe16(VENDOR_CC_CCD); vch->ccd_subcommand = subcmd; memcpy(vch + 1, password, password_size); - tpm_alt_extension(&vch->tpm_header, command_size); + tpm_alt_extension(&vch->tpm_header, sizeof(buf)); /* * Return status in the command code field now, in case of error, @@ -832,26 +827,20 @@ static int ccd_command_wrapper(int argc, char *password, return_code = be32toh(vch->tpm_header.command_code); if ((return_code != EC_SUCCESS) && (return_code != VENDOR_RC_IN_PROGRESS)) { - rv = vch->ccd_subcommand; - } else { - rv = EC_SUCCESS; + return vch->ccd_subcommand; } - - shared_mem_release(vch); - return rv; + return EC_SUCCESS; } -static enum vendor_cmd_rc ccd_open(void *buf, - size_t input_size, - size_t *response_size) +static enum vendor_cmd_rc ccd_open(struct vendor_cmd_params *p) { int is_long = 1; int need_pp = 1; int rv; - char *buffer = buf; + char *buffer = p->buffer; if (force_disabled) { - *response_size = 1; + p->out_size = 1; buffer[0] = EC_ERROR_ACCESS_DENIED; return VENDOR_RC_NOT_ALLOWED; } @@ -861,15 +850,15 @@ static enum vendor_cmd_rc ccd_open(void *buf, /* FWMP blocks open even if a password is set */ if (!board_fwmp_allows_unlock()) { - *response_size = 1; + p->out_size = 1; buffer[0] = EC_ERROR_ACCESS_DENIED; return VENDOR_RC_NOT_ALLOWED; } /* If a password is set, check it */ if (raw_has_password()) { - if (!input_size) { - *response_size = 1; + if (!p->in_size) { + p->out_size = 1; buffer[0] = EC_ERROR_PARAM_COUNT; return VENDOR_RC_PASSWORD_REQUIRED; } @@ -878,10 +867,10 @@ static enum vendor_cmd_rc ccd_open(void *buf, * We know there is plenty of room in the TPM buffer this is * stored in. */ - buffer[input_size] = '\0'; + buffer[p->in_size] = '\0'; rv = raw_check_password(buffer); if (rv) { - *response_size = 1; + p->out_size = 1; buffer[0] = rv; return VENDOR_RC_INTERNAL_ERROR; } @@ -890,7 +879,7 @@ static enum vendor_cmd_rc ccd_open(void *buf, /* Fail and abort if already checking physical presence */ if (physical_detect_busy()) { physical_detect_abort(); - *response_size = 1; + p->out_size = 1; buffer[0] = EC_ERROR_BUSY; return VENDOR_RC_INTERNAL_ERROR; } @@ -912,7 +901,7 @@ static enum vendor_cmd_rc ccd_open(void *buf, ccprintf("Starting CCD open...\n"); rv = physical_detect_start(is_long, ccd_open_done_async); if (rv != EC_SUCCESS) { - *response_size = 1; + p->out_size = 1; buffer[0] = rv; return VENDOR_RC_INTERNAL_ERROR; } @@ -925,16 +914,14 @@ static enum vendor_cmd_rc ccd_open(void *buf, return VENDOR_RC_SUCCESS; } -static enum vendor_cmd_rc ccd_unlock(void *buf, - size_t input_size, - size_t *response_size) +static enum vendor_cmd_rc ccd_unlock(struct vendor_cmd_params *p) { int need_pp = 1; int rv; - char *buffer = buf; + char *buffer = p->buffer; if (force_disabled) { - *response_size = 1; + p->out_size = 1; buffer[0] = EC_ERROR_ACCESS_DENIED; return VENDOR_RC_NOT_ALLOWED; } @@ -950,14 +937,14 @@ static enum vendor_cmd_rc ccd_unlock(void *buf, /* Only allowed if password is already set, and not blocked by FWMP */ if (!raw_has_password() || !board_fwmp_allows_unlock()) { - *response_size = 1; + p->out_size = 1; buffer[0] = EC_ERROR_ACCESS_DENIED; return VENDOR_RC_NOT_ALLOWED; } /* Make sure password was specified */ - if (!input_size) { - *response_size = 1; + if (!p->in_size) { + p->out_size = 1; buffer[0] = EC_ERROR_PARAM_COUNT; return VENDOR_RC_PASSWORD_REQUIRED; } @@ -966,10 +953,10 @@ static enum vendor_cmd_rc ccd_unlock(void *buf, * Check the password. We know there is plenty of room in the TPM * buffer this is stored in. */ - buffer[input_size] = '\0'; + buffer[p->in_size] = '\0'; rv = raw_check_password(buffer); if (rv) { - *response_size = 1; + p->out_size = 1; buffer[0] = rv; return VENDOR_RC_INTERNAL_ERROR; } @@ -977,7 +964,7 @@ static enum vendor_cmd_rc ccd_unlock(void *buf, /* Fail and abort if already checking physical presence */ if (physical_detect_busy()) { physical_detect_abort(); - *response_size = 1; + p->out_size = 1; buffer[0] = EC_ERROR_BUSY; return VENDOR_RC_INTERNAL_ERROR; } @@ -997,7 +984,7 @@ static enum vendor_cmd_rc ccd_unlock(void *buf, ccprintf("Starting CCD unlock...\n"); rv = physical_detect_start(0, ccd_unlock_done); if (rv != EC_SUCCESS) { - *response_size = 1; + p->out_size = 1; buffer[0] = rv; return VENDOR_RC_INTERNAL_ERROR; } @@ -1010,9 +997,7 @@ static enum vendor_cmd_rc ccd_unlock(void *buf, return VENDOR_RC_SUCCESS; } -static enum vendor_cmd_rc ccd_lock(void *unused0, - size_t unused1, - size_t *response_size) +static enum vendor_cmd_rc ccd_lock(struct vendor_cmd_params *p) { /* Lock always works */ ccprintf("CCD locked.\n"); @@ -1295,43 +1280,39 @@ DECLARE_VENDOR_COMMAND(VENDOR_CC_MANAGE_CCD_PWD, manage_ccd_password); * The payload of the command is a text string to use to set or clear the * password. */ -static enum vendor_cmd_rc ccd_password(void *buf, - size_t input_size, - size_t *response_size) +static enum vendor_cmd_rc ccd_password(struct vendor_cmd_params *p) { int rv = EC_SUCCESS; char password[CCD_MAX_PASSWORD_SIZE + 1]; - char *response = buf; + char *response = p->buffer; if (password_state != PASSWORD_ALLOWED_STATE) { - *response_size = 1; + p->out_size = 1; *response = EC_ERROR_ACCESS_DENIED; return VENDOR_RC_NOT_ALLOWED; } - if (!input_size || (input_size >= sizeof(password))) { + if (!p->in_size || (p->in_size >= sizeof(password))) { rv = EC_ERROR_PARAM1; } else { - memcpy(password, buf, input_size); - password[input_size] = '\0'; + memcpy(password, p->buffer, p->in_size); + password[p->in_size] = '\0'; rv = do_ccd_password(password); - always_memset(password, 0, input_size); + always_memset(password, 0, p->in_size); } if (rv != EC_SUCCESS) { *response = rv; - *response_size = 1; + p->out_size = 1; return VENDOR_RC_INTERNAL_ERROR; } return VENDOR_RC_SUCCESS; } -static enum vendor_cmd_rc ccd_pp_poll(void *buf, - size_t input_size, - size_t *response_size) +static enum vendor_cmd_rc ccd_pp_poll(struct vendor_cmd_params *p) { - char *buffer = buf; + char *buffer = p->buffer; if ((ccd_state == CCD_STATE_OPENED) || (ccd_state == CCD_STATE_UNLOCKED)) { @@ -1349,48 +1330,38 @@ static enum vendor_cmd_rc ccd_pp_poll(void *buf, break; } } - *response_size = 1; + p->out_size = 1; return VENDOR_RC_SUCCESS; } -static enum vendor_cmd_rc ccd_pp_poll_unlock(void *buf, - size_t input_size, - size_t *response_size) +static enum vendor_cmd_rc ccd_pp_poll_unlock(struct vendor_cmd_params *p) { - char *buffer; + char *buffer = p->buffer; if ((ccd_state != CCD_STATE_OPENED) && (ccd_state != CCD_STATE_UNLOCKED)) - return ccd_pp_poll(buf, input_size, response_size); - + return ccd_pp_poll(p); - buffer = buf; - *response_size = 1; + p->out_size = 1; buffer[0] = CCD_PP_DONE; return VENDOR_RC_SUCCESS; } -static enum vendor_cmd_rc ccd_pp_poll_open(void *buf, - size_t input_size, - size_t *response_size) +static enum vendor_cmd_rc ccd_pp_poll_open(struct vendor_cmd_params *p) { - char *buffer; + char *buffer = p->buffer; if (ccd_state != CCD_STATE_OPENED) - return ccd_pp_poll(buf, input_size, response_size); - + return ccd_pp_poll(p); - buffer = buf; - *response_size = 1; + p->out_size = 1; buffer[0] = CCD_PP_DONE; return VENDOR_RC_SUCCESS; } -static enum vendor_cmd_rc ccd_get_info(void *buf, - size_t input_size, - size_t *response_size) +static enum vendor_cmd_rc ccd_get_info(struct vendor_cmd_params *p) { int i; struct ccd_info_response response = {}; @@ -1418,8 +1389,8 @@ static enum vendor_cmd_rc ccd_get_info(void *buf, htobe32(response.ccd_caps_defaults[i]); } - *response_size = sizeof(response); - memcpy(buf, &response, sizeof(response)); + p->out_size = sizeof(response); + memcpy(p->buffer, &response, sizeof(response)); return VENDOR_RC_SUCCESS; } @@ -1428,21 +1399,30 @@ static enum vendor_cmd_rc ccd_get_info(void *buf, * Common TPM Vendor command handler used to demultiplex various CCD commands * which need to be available both throuh CLI and over /dev/tpm0. */ -static enum vendor_cmd_rc ccd_vendor(enum vendor_cmd_cc code, - void *buf, - size_t input_size, - size_t *response_size) +static enum vendor_cmd_rc ccd_vendor(struct vendor_cmd_params *p) { - enum vendor_cmd_rc (*handler)(void *x, size_t y, size_t *t) = NULL; - char *buffer; + enum vendor_cmd_rc (*handler)(struct vendor_cmd_params *p); enum vendor_cmd_rc rc; /* - * buf points to the next byte after tpm header, i.e. to the CCD - * subcommand. Cache the pointer to make it easier to access and - * manipulate. + * The command buffer points to the next byte after tpm header, i.e. to + * the CCD subcommand. Cache the pointer to make it easier to access + * and manipulate. */ - buffer = buf; + char *buffer = p->buffer; + + /* + * Make sure the buffer is large enough to accommodate any CCD + * subcommand response (plus one byte, since the response is shifted), + * so we can skip size checks in the processing functions. + */ + if (p->out_size < sizeof(struct ccd_info_response) + 1) { + p->out_size = 0; + return VENDOR_RC_RESPONSE_TOO_BIG; + } + + /* Now we can assume no output data unless proven otherwise */ + p->out_size = 0; /* Pick what to do based on subcommand. */ switch (buffer[0]) { @@ -1476,34 +1456,26 @@ static enum vendor_cmd_rc ccd_vendor(enum vendor_cmd_cc code, default: CPRINTS("%s:%d - unknown subcommand\n", __func__, __LINE__); - break; + return VENDOR_RC_NO_SUCH_SUBCOMMAND; } - if (handler) { - /* - * Let's be optimistic: 0 usually means success. - * - * We know the buffer is large enough to accommodate any CCD - * subcommand response, so there is no size checks in the - * processing functions. - */ - *response_size = 0; - - rc = handler(buf + 1, input_size - 1, response_size); - - /* - * Move response up for the master to see it in the right - * place in the response buffer. - */ - memmove(buf, buf + 1, *response_size); - } else { - rc = VENDOR_RC_NO_SUCH_SUBCOMMAND; - *response_size = 0; - } + /* Shift buffer past the subcommand when calling the handler */ + p->buffer = buffer + 1; + p->in_size--; + rc = handler(p); + p->buffer = buffer; + p->in_size++; + /* + * Move response up for the master to see it in the right + * place in the response buffer. We have to do this because the + * first byte of the buffer on input was the subcommand, so we + * passed buffer + 1 in the handler call above. + */ + memmove(buffer, buffer + 1, p->out_size); return rc; } -DECLARE_VENDOR_COMMAND(VENDOR_CC_CCD, ccd_vendor); +DECLARE_VENDOR_COMMAND_P(VENDOR_CC_CCD, ccd_vendor); static enum vendor_cmd_rc ccd_disable_rma(enum vendor_cmd_cc code, void *buf, @@ -1557,7 +1529,7 @@ static enum vendor_cmd_rc ccd_disable_rma(enum vendor_cmd_cc code, } - ccd_lock(NULL, 0, NULL); + ccd_lock(NULL); /* * We do it here to make sure that the device comes out of RMA diff --git a/common/extension.c b/common/extension.c index fecb61ec9e..eaded0244f 100644 --- a/common/extension.c +++ b/common/extension.c @@ -18,8 +18,9 @@ uint32_t extension_route_command(struct vendor_cmd_params *p) const char *why_ignore = "not found"; #ifdef DEBUG_EXTENSION - CPRINTS("%s(%d,%s)", __func__, command_code, - flags & VENDOR_CMD_FROM_USB ? "USB" : "AP"); + CPRINTS("%s(%d,%s) is=%d os=%d", __func__, p->code, + p->flags & VENDOR_CMD_FROM_USB ? "USB" : "AP", + p->in_size, p->out_size); #endif /* Filter commands from USB */ -- cgit v1.2.1