summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Bendebury <vbendeb@chromium.org>2022-11-07 17:48:04 -0800
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-11-14 21:44:15 +0000
commit5b46258340905c32aa5be7d0d5ad6ffad7bf71d9 (patch)
tree5d1c9b1df9cec4b59318514140c23ed5dd10f672
parent42b8994d8cdfc87d2a30aba37032538b65aaf102 (diff)
downloadchrome-ec-stabilize-15245.B-cr50_stab.tar.gz
gsctool: support setting CCD capabilitiesstabilize-15251.B-cr50_stabstabilize-15245.B-cr50_stab
It is necessary to allow the user to set certain capabilities using gsctool. Which exactly capabilities can be set and to which values is determined by the policies enforced by the chip, gsctool should provide a generic way of setting any existing capability to any legal value. The 'AllowUnverifiedRo' capability stands out, because it might require the operator's physical presence confirmation, similar to the 'ccd open' case. A new vendor subcommand is being added to pass desired capability and value to Ti50, as three byte payload the version, the capability and the value. Version and value are mapped by Ti50 into the appropriate enums. All available capability names can be seen in the output of 'gsctool -D -I', the accepted values are 'Default', 'IfOpened', and 'Always'. The new functionality is achieved by allowing the 'I' command line option to accept an optional argument, a string in the form of '<capability name>:<desired value>', where both parts of the string can be abbreviated and will be accepted case insensitive unless the abbreviation is ambiguous. Since this option is supported only by Ti50, gsctool will enforce the default Ti50 USB device ID when running this command over USB and in case of errors will remind the user that the setting capabilities is not supported on Cr50. BUG=b:257253538 TEST=tried running the command on Ti50 implementing support of the new vendor subcommand. # Attempt to set when CCD is locked $ gsctool -D -I | grep State State: Locked $ gsctool -I UartGscRxAPTx:always finding_device 18d1:504a Found device. found interface 3 endpoint 4, chunk_len 64 READY ------- Got error 7(NotAllowed) # Attempt to set to the current value when CCD is open $ gsctool -D -I | grep State State: Opened $ gsctool -I UartGscRxAPTx:always finding_device 18d1:504a Found device. found interface 3 endpoint 4, chunk_len 64 READY ------- # attempt to use ambiguous capability name $ gsctool -I UartGscRx:always finding_device 18d1:504a Found device. found interface 3 endpoint 4, chunk_len 64 READY ------- Ambiguous capability name # Attempt to use incorrect value abbreviation $ gsctool -I UartGscRxAPTx:x finding_device 18d1:504a Found device. found interface 3 endpoint 4, chunk_len 64 READY ------- Unsupported capability value # Various attempts to set AllowUnverifiedRo. Transitions from # default -> ifOpened -> Always require PP, transitions in the # opposite direction do not. $ gsctool -I allow:d finding_device 18d1:504a Found device. found interface 3 endpoint 4, chunk_len 64 READY ------- $ gsctool -I allow:if finding_device 18d1:504a Found device. found interface 3 endpoint 4, chunk_len 64 READY ------- Another press will be required! Press PP button now! Press PP button now! Press PP button now! Press PP button now! Press PP button now! Press PP button now! Press PP button now! PP Done! $ gsctool -I allow:a finding_device 18d1:504a Found device. found interface 3 endpoint 4, chunk_len 64 READY ------- Another press will be required! Press PP button now! Press PP button now! Press PP button now! Press PP button now! Press PP button now! Press PP button now! PP Done! $ gsctool -I allow:d finding_device 18d1:504a Found device. found interface 3 endpoint 4, chunk_len 64 READY ------- $ - also validated that misformatted capability/value combinations are rejected as expected: $ gsctool -I xyz: finding_device 18d1:504a Found device. found interface 3 endpoint 4, chunk_len 64 READY ------- Misformatted capability parameter: xyz: $ gsctool -I :xyz finding_device 18d1:504a Found device. found interface 3 endpoint 4, chunk_len 64 READY ------- Misformatted capability parameter: :xyz $ gsctool -I xyz finding_device 18d1:504a Found device. found interface 3 endpoint 4, chunk_len 64 READY ------- Misformatted capability parameter: xyz $ gsctool -I x:yz finding_device 18d1:504a Found device. found interface 3 endpoint 4, chunk_len 64 READY ------- Unknown capability name - tried setting capabilities when running on Brya, observed expected error messages. Signed-off-by: Vadim Bendebury <vbendeb@chromium.org> Change-Id: I803440501d0e3af3c2a645b52b42970b54695701 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/4010705 Reviewed-by: Mary Ruthven <mruthven@chromium.org>
-rw-r--r--extra/usb_updater/gsctool.c182
-rw-r--r--include/ccd_config.h3
-rw-r--r--include/tpm_vendor_cmds.h3
3 files changed, 179 insertions, 9 deletions
diff --git a/extra/usb_updater/gsctool.c b/extra/usb_updater/gsctool.c
index 0492bc309a..611d8754d2 100644
--- a/extra/usb_updater/gsctool.c
+++ b/extra/usb_updater/gsctool.c
@@ -98,7 +98,7 @@ static const struct ccd_capability_info ti50_cap_info[] = {
{"OpenFromUSB", CCD_CAP_STATE_IF_OPENED},
{"OverrideBatt", CCD_CAP_STATE_IF_OPENED},
/* The below capability is presently set to 'never' in ccd.rs. */
- {"BootUnverifiedRo", CCD_CAP_STATE_IF_OPENED},
+ {"AllowUnverifiedRo", CCD_CAP_STATE_IF_OPENED},
};
#define CR50_CCD_CAP_COUNT CCD_CAP_COUNT
@@ -458,18 +458,19 @@ static const struct option_container cmd_line_options[] = {
"VID:PID%USB device (default 18d1:5014 or 18d1:504a based on image)"},
{{"endorsement_seed", optional_argument, NULL, 'e'},
"[state]%get/set the endorsement key seed"},
- {{"fwver", no_argument, NULL, 'f'},
- "Report running Cr50 firmware versions"},
{{"factory", required_argument, NULL, 'F'},
"[enable|disable]%Control factory mode"},
+ {{"fwver", no_argument, NULL, 'f'},
+ "Report running Cr50 firmware versions"},
{{"getbootmode", no_argument, NULL, 'g'},
"Get the system boot mode"},
{{"help", no_argument, NULL, 'h'},
"Show this message"},
{{"erase_ap_ro_hash", no_argument, NULL, 'H'},
"Erase AP RO hash (possible only if Board ID is not set)"},
- {{"ccd_info", no_argument, NULL, 'I'},
- "Get information about CCD state"},
+ {{"ccd_info", optional_argument, NULL, 'I'},
+ "[capability:value]%Get information about CCD state or set capability"
+ " value if allowed"},
{{"board_id", optional_argument, NULL, 'i'},
"[ID[:FLAGS]]%Get or set Info1 board ID fields. ID could be 32 bit "
"hex or 4 character string."},
@@ -1718,6 +1719,156 @@ static void invalidate_inactive_rw(struct transfer_descriptor *td)
exit(update_error);
}
+/*
+ * Try setting CCD capability.
+ *
+ * The 'parameter' string includes capability and desired new state separated
+ * by a ':', both parts could be abbreviated and checked for the match as case
+ * insensitive.
+ *
+ * The result of the attempt depends on the policies installed on
+ * Ti50. The result could be on of the following:
+ *
+ * - success (capability is successfully changed, or is already at the
+ * requested level),
+ * - various errors if setting the capability is not allowed or something
+ * goes wrong on Ti50
+ * - request for physical presence confirmation
+ */
+static enum exit_values process_set_capabililty(struct transfer_descriptor *td,
+ const char *parameter)
+{
+ const char *colon;
+ size_t len;
+ size_t cap_index;
+ size_t i;
+ uint8_t rc;
+ const char *error_text;
+ const char *cr50_err =
+ "Note: setting capabilities not available on Cr50\n";
+ /*
+ * The payload is three bytes, command version, capability, and
+ * desired state, all expressed as u8.
+ */
+ struct __attribute__((__packed__)) {
+ uint8_t version;
+ uint8_t cap;
+ uint8_t value;
+ } command;
+ /*
+ * Translation table of possible desired capabilities, Cr50 values
+ * and duplicated in common/syscalls/src/ccd.rs::CcdCapState.
+ */
+ struct {
+ const char *state_name;
+ enum ccd_capability_state desired_state;
+ } states[] = {
+ {"default", CCD_CAP_STATE_DEFAULT},
+ {"always", CCD_CAP_STATE_ALWAYS},
+ {"if_opened", CCD_CAP_STATE_IF_OPENED},
+ };
+
+ /*
+ * Possible responses from Ti50 when trying to modify AlloUnverifiedRo
+ * capability. The values come from
+ * common/libs/tpm2/extension/src/lib.rs::TpmvReturnCode.
+ */
+ enum set_allow_unverified_ro_responses {
+ AUR_SUCCESS = 0,
+ AUR_BOGUS_ARGS = 1,
+ AUR_INTERNAL_ERROR = 6,
+ AUR_NOT_ALLOWED = 7,
+ AUR_IN_PROGRESS = 9,
+ };
+
+ /*
+ * Validate the parameter, for starters make sure that the colon
+ * symbol is present and is neither the first nor the last character
+ * in the string.
+ */
+ colon = strchr(parameter, ':');
+ if (!colon || (colon == parameter) || (colon[1] == '\0')) {
+ fprintf(stderr, "Misformatted capability parameter: %s\n",
+ parameter);
+ exit(update_error);
+ }
+
+ /*
+ * Find the capability index in the table, reject ambiguous
+ * abbreviations.
+ */
+ len = colon - parameter;
+ for (i = 0, cap_index = ARRAY_SIZE(ti50_cap_info);
+ i < ARRAY_SIZE(ti50_cap_info); i++) {
+ if (!strncasecmp(ti50_cap_info[i].name, parameter, len)) {
+ if (cap_index != ARRAY_SIZE(ti50_cap_info)) {
+ fprintf(stderr, "Ambiguous capability name\n");
+ exit(update_error);
+ }
+ cap_index = i;
+ }
+ }
+ if (cap_index == ARRAY_SIZE(ti50_cap_info)) {
+ fprintf(stderr, "Unknown capability name\n%s", cr50_err);
+ exit(update_error);
+ }
+
+ /* Calculate length of the desired value. */
+ len = strlen(parameter) - len - 1;
+
+ /* Find the value index in the table. */
+ for (i = 0; i < ARRAY_SIZE(states); i++) {
+ if (!strncasecmp(states[i].state_name, colon + 1, len))
+ break;
+ }
+ if (i == ARRAY_SIZE(states)) {
+ fprintf(stderr, "Unsupported capability value\n");
+ return update_error;
+ }
+
+ /* Prepare and send vendor command to request setting capability. */
+ command.version = CCD_VERSION;
+ command.cap = (uint8_t)cap_index;
+ command.value = (uint8_t)states[i].desired_state;
+
+ i = 0;
+ len = 1;
+ send_vendor_command(td, VENDOR_CC_SET_CAPABILITY,
+ &command, sizeof(command), &rc, &len);
+
+ if (len != 1) {
+ fprintf(stderr, "Unexpected return message size %zd\n", len);
+ if (len == 0)
+ fprintf(stderr, "%s", cr50_err);
+ return update_error;
+ }
+
+ switch (rc) {
+ case AUR_IN_PROGRESS:
+ /*
+ * Physical presence poll is required, note fall through to
+ * the next case.
+ */
+ poll_for_pp(td, VENDOR_CC_CCD, CCDV_PP_POLL_SET_CAPABILITY);
+ case AUR_SUCCESS:
+ return noop; /* All is well, no need to do anything. */
+ case AUR_BOGUS_ARGS:
+ error_text = "BogusArgs";
+ break;
+ case AUR_INTERNAL_ERROR:
+ error_text = "InternalError";
+ break;
+ case AUR_NOT_ALLOWED:
+ error_text = "NotAllowed";
+ break;
+ default:
+ error_text = "Unknown";
+ break;
+ }
+ fprintf(stderr, "Got error %d(%s)\n", rc, error_text);
+ return update_error;
+}
+
static void process_erase_ap_ro_hash(struct transfer_descriptor *td)
{
/* Try erasing AP RO hash, could fail if board ID is programmed. */
@@ -3744,6 +3895,8 @@ int main(int argc, char *argv[])
uint8_t sn_inc_rma_arg = 0;
int erase_ap_ro_hash = 0;
int is_dauntless = 0;
+ int set_capability = 0;
+ const char *capability_parameter = "";
/*
* All options which result in setting a Boolean flag to True, along
@@ -3756,7 +3909,6 @@ int main(int argc, char *argv[])
{ 'f', &show_fw_ver },
{ 'g', &get_boot_mode},
{ 'H', &erase_ap_ro_hash},
- { 'I', &ccd_info },
{ 'k', &ccd_lock },
{ 'o', &ccd_open },
{ 'P', &password },
@@ -3874,6 +4026,16 @@ int main(int argc, char *argv[])
case 'h':
usage(errorcnt);
break;
+ case 'I':
+ if (optarg) {
+ set_capability = 1;
+ capability_parameter = optarg;
+ /* Supported on Dauntless only. */
+ is_dauntless = 1;
+ } else {
+ ccd_info = 1;
+ }
+ break;
case 'i':
if (!parse_bid(optarg, &bid, &bid_action)) {
fprintf(stderr,
@@ -4014,6 +4176,7 @@ int main(int argc, char *argv[])
!erase_ap_ro_hash &&
!password &&
!rma &&
+ !set_capability &&
!show_fw_ver &&
!sn_bits &&
!sn_inc_rma &&
@@ -4059,9 +4222,9 @@ int main(int argc, char *argv[])
!!ccd_unlock + !!ccd_lock + !!ccd_info + !!get_flog +
!!get_boot_mode + !!openbox_desc_file + !!factory_mode +
(wp != WP_NONE) + !!get_endorsement_seed +
- !!erase_ap_ro_hash) > 1) {
+ !!erase_ap_ro_hash + !!set_capability) > 1) {
fprintf(stderr,
- "ERROR: options"
+ "ERROR: options "
"-e, -F, -g, -H, -I, -i, -k, -L, -O, -o, -P, -r, -U"
" and -w are mutually exclusive\n");
exit(update_error);
@@ -4090,6 +4253,9 @@ int main(int argc, char *argv[])
process_ccd_state(&td, ccd_unlock, ccd_open,
ccd_lock, ccd_info);
+ if (set_capability)
+ exit(process_set_capabililty(&td, capability_parameter));
+
if (password)
process_password(&td);
diff --git a/include/ccd_config.h b/include/ccd_config.h
index 13762c5b5e..61c0a44809 100644
--- a/include/ccd_config.h
+++ b/include/ccd_config.h
@@ -219,7 +219,8 @@ enum ccd_vendor_subcommands {
CCDV_LOCK = 3,
CCDV_PP_POLL_UNLOCK = 4,
CCDV_PP_POLL_OPEN = 5,
- CCDV_GET_INFO = 6
+ CCDV_GET_INFO = 6,
+ CCDV_PP_POLL_SET_CAPABILITY = 7,
};
enum ccd_pp_state {
diff --git a/include/tpm_vendor_cmds.h b/include/tpm_vendor_cmds.h
index 2be888c6a3..51f5143120 100644
--- a/include/tpm_vendor_cmds.h
+++ b/include/tpm_vendor_cmds.h
@@ -192,6 +192,9 @@ enum vendor_cmd_cc {
VENDOR_CC_GET_AP_RO_VERIFY_SETTING = 62,
VENDOR_CC_SET_AP_RO_VERIFY_SETTING = 63,
+ /* Ti50 only. */
+ VENDOR_CC_SET_CAPABILITY = 64,
+
LAST_VENDOR_COMMAND = 65535,
};