summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReka Norman <rekanorman@google.com>2023-03-28 16:47:02 +1100
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2023-03-29 09:08:52 +0000
commit4305b64860fd7a6ad2b455229b9d5e1d1cf422d3 (patch)
tree1fa743cb2dd40d1d5d416fbf41e9ff350a128738
parent9dda53be01264ffb261db33880831fce2ceb9450 (diff)
downloadvboot-factory-nissa-15199.B.tar.gz
futility: updater: Add --unlock_me optionfactory-nissa-15199.B
Add a --unlock_me option which unlocks the Intel ME before flashing by: - Unlocking the FLMSTR values in the descriptor. - Disabling GPR0 in the descriptor. This will be used in factory to support Flexible EOM. BRANCH=None BUG=b:273168873 TEST=Flash locked yaviks firmware with --unlock_me. Read firmware back and check that FLMSTR values are unlocked and GPR0 is disabled. Change-Id: Ie29f3c997c82a1bc58fe62f568f257e9dc375d94 Signed-off-by: Reka Norman <rekanorman@google.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/4380499 Tested-by: Phoebe Wang <phoebewang@chromium.org> Auto-Submit: Phoebe Wang <phoebewang@chromium.org> Commit-Queue: Cheng Yueh <cyueh@chromium.org> Reviewed-by: Cheng Yueh <cyueh@chromium.org>
-rw-r--r--futility/cmd_update.c6
-rw-r--r--futility/updater.c8
-rw-r--r--futility/updater.h3
-rw-r--r--futility/updater_quirks.c29
-rw-r--r--futility/updater_utils.c93
-rw-r--r--futility/updater_utils.h13
-rwxr-xr-xtests/futility/test_update.sh7
7 files changed, 135 insertions, 24 deletions
diff --git a/futility/cmd_update.c b/futility/cmd_update.c
index c47ab325..14858f33 100644
--- a/futility/cmd_update.c
+++ b/futility/cmd_update.c
@@ -33,6 +33,7 @@ enum {
OPT_SERVO_NORESET,
OPT_SIGNATURE,
OPT_SYS_PROPS,
+ OPT_UNLOCK_ME,
OPT_UNPACK,
OPT_WRITE_PROTECTION,
};
@@ -66,6 +67,7 @@ static struct option const long_opts[] = {
{"repack", 1, NULL, OPT_REPACK},
{"signature_id", 1, NULL, OPT_SIGNATURE},
{"sys_props", 1, NULL, OPT_SYS_PROPS},
+ {"unlock_me", 0, NULL, OPT_UNLOCK_ME},
{"unpack", 1, NULL, OPT_UNPACK},
{"wp", 1, NULL, OPT_WRITE_PROTECTION},
@@ -111,6 +113,7 @@ static void print_help(int argc, char *argv[])
" --list-quirks \tPrint all available quirks\n"
"-m, --mode=MODE \tRun updater in the specified mode\n"
" --manifest \tScan the archive to print a manifest in JSON\n"
+ " --unlock_me \tUnlock the Intel ME before flashing\n"
SHARED_FLASH_ARGS_HELP
"\n"
" * If both --manifest and --fast are specified, the updater\n"
@@ -191,6 +194,9 @@ static int do_update(int argc, char *argv[])
case OPT_UNPACK:
args.unpack = optarg;
break;
+ case OPT_UNLOCK_ME:
+ args.unlock_me = true;
+ break;
case OPT_QUIRKS:
args.quirks = optarg;
break;
diff --git a/futility/updater.c b/futility/updater.c
index 7f1e215f..b8fbcd6c 100644
--- a/futility/updater.c
+++ b/futility/updater.c
@@ -881,6 +881,7 @@ const char * const updater_error_messages[] = {
[UPDATE_ERR_ROOT_KEY] = "RW signed by incompatible root key "
"(different from RO).",
[UPDATE_ERR_TPM_ROLLBACK] = "RW not usable due to TPM anti-rollback.",
+ [UPDATE_ERR_UNLOCK_ME] = "Failed to unlock the Intel ME.",
[UPDATE_ERR_UNKNOWN] = "Unknown error.",
};
@@ -1058,6 +1059,11 @@ static enum updater_error_codes update_whole_firmware(
if (preserve_images(cfg))
VB2_DEBUG("Failed to preserve some sections - ignore.\n");
+ if (cfg->unlock_me && unlock_me(image_to)) {
+ ERROR("Failed unlocking Intel ME.\n");
+ return UPDATE_ERR_UNLOCK_ME;
+ }
+
INFO("Checking compatibility...\n");
if (!cfg->force_update) {
/* Check if the image_to itself is broken */
@@ -1542,6 +1548,8 @@ int updater_setup_config(struct updater_config *cfg,
override_dut_property(DUT_PROP_WP_SW, cfg, r);
}
+ cfg->unlock_me = arg->unlock_me;
+
/* Set up archive and load images. */
/* Always load images specified from command line directly. */
errorcnt += updater_load_images(
diff --git a/futility/updater.h b/futility/updater.h
index a4d1f1fa..5a3b9123 100644
--- a/futility/updater.h
+++ b/futility/updater.h
@@ -92,6 +92,7 @@ struct updater_config {
uint32_t gbb_flags;
bool detect_model;
bool dut_is_remote;
+ bool unlock_me;
};
struct updater_config_arguments {
@@ -110,6 +111,7 @@ struct updater_config_arguments {
int use_flash;
uint32_t gbb_flags;
bool detect_model_only;
+ bool unlock_me;
};
/*
@@ -180,6 +182,7 @@ enum updater_error_codes {
UPDATE_ERR_TARGET,
UPDATE_ERR_ROOT_KEY,
UPDATE_ERR_TPM_ROLLBACK,
+ UPDATE_ERR_UNLOCK_ME,
UPDATE_ERR_UNKNOWN,
};
diff --git a/futility/updater_quirks.c b/futility/updater_quirks.c
index 49b35caa..47ec08df 100644
--- a/futility/updater_quirks.c
+++ b/futility/updater_quirks.c
@@ -205,30 +205,7 @@ static int quirk_enlarge_image(struct updater_config *cfg)
*/
static int quirk_unlock_me_for_update(struct updater_config *cfg)
{
- struct firmware_section section;
- struct firmware_image *image_to = &cfg->image;
- const int flash_master_offset = 128;
- const uint8_t flash_master[] = {
- 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
- 0xff, 0xff
- };
-
- find_firmware_section(&section, image_to, FMAP_SI_DESC);
- if (section.size < flash_master_offset + ARRAY_SIZE(flash_master))
- return 0;
- if (memcmp(section.data + flash_master_offset, flash_master,
- ARRAY_SIZE(flash_master)) == 0) {
- VB2_DEBUG("Target ME not locked.\n");
- return 0;
- }
- /*
- * b/35568719: We should only update with unlocked ME and let
- * board-postinst lock it.
- */
- INFO("Changed Flash Master Values to unlocked.\n");
- memcpy(section.data + flash_master_offset, flash_master,
- ARRAY_SIZE(flash_master));
- return 0;
+ return unlock_flash_master(&cfg->image);
}
/*
@@ -236,6 +213,10 @@ static int quirk_unlock_me_for_update(struct updater_config *cfg)
* so the system has a chance to make sure SI_ME won't be corrupted on next boot
* before locking the Flash Master values in SI_DESC.
* Returns 0 on success, otherwise failure.
+ *
+ * TODO(b/270275115): Reuse the common unlock_flash_master() function and apply
+ * the Wilco-specific changes on top (or drop them if the common settings work
+ * for Wilco too).
*/
static int quirk_unlock_wilco_me_for_update(struct updater_config *cfg)
{
diff --git a/futility/updater_utils.c b/futility/updater_utils.c
index 90d9d554..cd2ee7d8 100644
--- a/futility/updater_utils.c
+++ b/futility/updater_utils.c
@@ -752,3 +752,96 @@ const char *get_firmware_rootkey_hash(const struct firmware_image *image)
return packed_key_sha1_string(rootkey);
}
+
+/*
+ * Overwrite the given offset of a section in the firmware image with the
+ * given values.
+ * Returns 0 on success, otherwise failure.
+ */
+static int overwrite_section(struct firmware_image *image,
+ const char *fmap_section, size_t offset,
+ size_t size, const uint8_t *new_values)
+{
+ struct firmware_section section;
+
+ find_firmware_section(&section, image, fmap_section);
+ if (section.size < offset + size) {
+ ERROR("Section smaller than given offset + size\n");
+ return -1;
+ }
+
+ if (memcmp(section.data + offset, new_values, size) == 0) {
+ VB2_DEBUG("Section already contains given values.\n");
+ return 0;
+ }
+
+ memcpy(section.data + offset, new_values, size);
+ return 0;
+}
+
+/*
+ * Unlock the Flash Master values in SI_DESC.
+ * Returns 0 on success, otherwise failure.
+ *
+ * TODO(b/270275115): Replace with a call to ifdtool.
+ */
+int unlock_flash_master(struct firmware_image *image)
+{
+ const int flash_master_offset = 0x80;
+ const uint8_t flash_master[] = {
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0xff, 0xff
+ };
+
+ if (overwrite_section(image, FMAP_SI_DESC, flash_master_offset,
+ ARRAY_SIZE(flash_master), flash_master)) {
+ ERROR("Failed unlocking Flash Master values\n");
+ return -1;
+ }
+
+ INFO("Changed Flash Master Values to unlocked.\n");
+ return 0;
+}
+
+/*
+ * Disable GPR0 (Global Protected Range). When enabled, it provides
+ * write-protection to part of the SI_ME region, specifically CSE_RO and
+ * part of CSE_DATA, so it must be disabled to allow updating SI_ME.
+ * Returns 0 on success, otherwise failure.
+ *
+ * TODO(b/270275115): Replace with a call to ifdtool.
+ */
+static int disable_gpr0(struct firmware_image *image)
+{
+ const int gpr0_offset = 0x154;
+ const uint8_t gpr0_value_disabled[] = { 0x00, 0x00, 0x00, 0x00 };
+
+ if (overwrite_section(image, FMAP_SI_DESC, gpr0_offset,
+ ARRAY_SIZE(gpr0_value_disabled),
+ gpr0_value_disabled)) {
+ ERROR("Failed disabling GPR0.\n");
+ return -1;
+ }
+
+ INFO("Disabled GPR0.\n");
+ return 0;
+}
+
+/*
+ * Unlock the Intel ME by:
+ * - Unlocking the FLMSTR values in the descriptor.
+ * - Disabling GPR0 in the descriptor.
+ * This allows the SI_DESC and SI_ME regions to be updated.
+ * Returns 0 on success, otherwise failure.
+ */
+int unlock_me(struct firmware_image *image)
+{
+ if (unlock_flash_master(image))
+ return -1;
+
+ if (disable_gpr0(image))
+ return -1;
+
+ INFO("Unlocked Intel ME.\n");
+ return 0;
+}
diff --git a/futility/updater_utils.h b/futility/updater_utils.h
index 27c3f57d..48afa10c 100644
--- a/futility/updater_utils.h
+++ b/futility/updater_utils.h
@@ -156,6 +156,19 @@ int preserve_firmware_section(const struct firmware_image *image_from,
const char *section_name);
/*
+ * Unlock the Flash Master values in SI_DESC.
+ */
+int unlock_flash_master(struct firmware_image *image);
+
+/*
+ * Unlock the Intel ME by:
+ * - Unlocking the FLMSTR values in the descriptor.
+ * - Disabling GPR0 in the descriptor.
+ * This allows the SI_DESC and SI_ME regions to be updated.
+ */
+int unlock_me(struct firmware_image *image);
+
+/*
* Returns rootkey hash of firmware image, or NULL on failure.
*/
const char *get_firmware_rootkey_hash(const struct firmware_image *image);
diff --git a/tests/futility/test_update.sh b/tests/futility/test_update.sh
index 19f2413e..32da0223 100755
--- a/tests/futility/test_update.sh
+++ b/tests/futility/test_update.sh
@@ -147,6 +147,9 @@ dd if=/dev/zero bs=8388608 count=1 | tr '\000' '\377' >>"${TMP}.expected.large"
cp -f "${TMP}.expected.full" "${TMP}.expected.me_unlocked"
patch_file "${TMP}.expected.me_unlocked" SI_DESC 128 \
"\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff"
+cp -f "${TMP}.expected.me_unlocked" "${TMP}.expected.me_unlocked_gpr0_disabled"
+patch_file "${TMP}.expected.me_unlocked_gpr0_disabled" SI_DESC 0x154 \
+ "\x00\x00\x00\x00"
cp -f "${TMP}.expected.full" "${TMP}.expected.me_preserved"
"${FUTILITY}" load_fmap "${TMP}.expected.me_preserved" \
"SI_ME:${TMP}.from/SI_ME"
@@ -344,6 +347,10 @@ test_update "Full update (--quirks unlock_me_for_update)" \
--quirks unlock_me_for_update \
-i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001
+test_update "Full update (--unlock_me)" \
+ "${FROM_IMAGE}" "${TMP}.expected.me_unlocked_gpr0_disabled" \
+ --unlock_me -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001
+
test_update "Full update (failure by --quirks min_platform_version)" \
"${FROM_IMAGE}" "!Need platform version >= 3 (current is 2)" \
--quirks min_platform_version=3 \