diff options
author | Reka Norman <rekanorman@google.com> | 2023-03-28 16:47:02 +1100 |
---|---|---|
committer | Chromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2023-03-29 09:08:52 +0000 |
commit | 4305b64860fd7a6ad2b455229b9d5e1d1cf422d3 (patch) | |
tree | 1fa743cb2dd40d1d5d416fbf41e9ff350a128738 | |
parent | 9dda53be01264ffb261db33880831fce2ceb9450 (diff) | |
download | vboot-4305b64860fd7a6ad2b455229b9d5e1d1cf422d3.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.c | 6 | ||||
-rw-r--r-- | futility/updater.c | 8 | ||||
-rw-r--r-- | futility/updater.h | 3 | ||||
-rw-r--r-- | futility/updater_quirks.c | 29 | ||||
-rw-r--r-- | futility/updater_utils.c | 93 | ||||
-rw-r--r-- | futility/updater_utils.h | 13 | ||||
-rwxr-xr-x | tests/futility/test_update.sh | 7 |
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(§ion, 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(§ion, 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 \ |