diff options
-rw-r--r-- | futility/cmd_update.c | 5 | ||||
-rw-r--r-- | futility/updater.c | 58 | ||||
-rw-r--r-- | futility/updater.h | 15 | ||||
-rw-r--r-- | futility/updater_archive.c | 96 | ||||
-rwxr-xr-x | tests/futility/models/whitetip/setvars.sh | 21 | ||||
-rwxr-xr-x | tests/futility/test_update.sh | 47 |
6 files changed, 229 insertions, 13 deletions
diff --git a/futility/cmd_update.c b/futility/cmd_update.c index ce81660d..2ba8a4e8 100644 --- a/futility/cmd_update.c +++ b/futility/cmd_update.c @@ -27,6 +27,7 @@ static struct option const long_opts[] = { {"list-quirks", 0, NULL, 'L'}, {"mode", 1, NULL, 'm'}, {"model", 1, NULL, 'M'}, + {"signature_id", 1, NULL, 'G'}, {"manifest", 0, NULL, 'A'}, {"factory", 0, NULL, 'Y'}, {"force", 0, NULL, 'F'}, @@ -66,6 +67,7 @@ static void print_help(int argc, char *argv[]) " --wp=1|0 \tSpecify write protection status\n" " --emulate=FILE \tEmulate system firmware using file\n" " --model=MODEL \tOverride system model for images\n" + " --signature_id=S\tOverride signature ID for key files\n" " --sys_props=LIST\tList of system properties to override\n" "-d, --debug \tPrint debugging messages\n" "-v, --verbose \tPrint verbose messages\n" @@ -113,6 +115,9 @@ static int do_update(int argc, char *argv[]) case 'M': args.model = optarg; break; + case 'G': + args.signature_id = optarg; + break; case 'A': args.do_manifest = 1; break; diff --git a/futility/updater.c b/futility/updater.c index 17b12a2b..0d69641b 100644 --- a/futility/updater.c +++ b/futility/updater.c @@ -1668,13 +1668,49 @@ static int updater_load_images(struct updater_config *cfg, } /* + * Applies white label information to an existing model config. + * Returns 0 on success, otherwise failure. + */ +static int updater_apply_white_label(struct updater_config *cfg, + struct model_config *model, + const char *signature_id) +{ + const char *tmp_image = NULL; + + assert(model->is_white_label); + if (!signature_id) { + if (cfg->image_current.data) { + tmp_image = updater_create_temp_file(cfg); + if (!tmp_image) + return 1; + if (vb2_write_file(tmp_image, cfg->image_current.data, + cfg->image_current.size)) { + ERROR("Failed writing temporary image file."); + return 1; + } + } else { + printf("Loading system firmware for white label..\n"); + load_system_firmware(cfg, &cfg->image_current); + tmp_image = cfg->image_current.file_name; + } + if (!tmp_image) { + ERROR("Failed to get system current firmware"); + return 1; + } + } + return !!model_apply_white_label( + model, cfg->archive, signature_id, tmp_image); +} + +/* * Setup what the updater has to do against an archive. * Returns number of failures, or 0 on success. */ static int updater_setup_archive( struct updater_config *cfg, const struct updater_config_arguments *arg, - struct manifest *manifest) + struct manifest *manifest, + int is_factory) { int errorcnt = 0; struct archive *ar = cfg->archive; @@ -1691,6 +1727,23 @@ static int updater_setup_archive( if (!model) return ++errorcnt; + if (model->is_white_label) { + /* + * It is fine to fail in updater_apply_white_label for factory + * mode so we are not checking the return value; instead we + * verify if the patches do contain new root key. + */ + updater_apply_white_label(cfg, (struct model_config *)model, + arg->signature_id); + if (!model->patches.rootkey) { + if (!is_factory) { + ERROR("Need VPD set for white label."); + return ++errorcnt; + } + fprintf(stderr, "Warning: No VPD for white label.\n"); + } + } + errorcnt += updater_load_images( cfg, model->image, model->ec_image, model->pd_image); errorcnt += patch_image_by_model(&cfg->image, model, ar); @@ -1796,7 +1849,8 @@ int updater_setup_config(struct updater_config *cfg, if (arg->archive) { struct manifest *m = new_manifest_from_archive(cfg->archive); if (m) { - errorcnt += updater_setup_archive(cfg, arg, m); + errorcnt += updater_setup_archive( + cfg, arg, m, cfg->factory_update); delete_manifest(m); } else { ERROR("Failure in archive: %s", arg->archive); diff --git a/futility/updater.h b/futility/updater.h index c1405663..ae6db16a 100644 --- a/futility/updater.h +++ b/futility/updater.h @@ -114,7 +114,7 @@ struct updater_config { struct updater_config_arguments { char *image, *ec_image, *pd_image; char *archive, *quirks, *mode; - char *programmer, *model; + char *programmer, *model, *signature_id; char *emulation, *sys_props, *write_protection; int is_factory, try_update, force_update, do_manifest; int verbosity; @@ -131,6 +131,7 @@ struct model_config { char *image, *ec_image, *pd_image; struct patch_config patches; char *signature_id; + int is_white_label; }; struct manifest { @@ -324,4 +325,16 @@ int patch_image_by_model( const struct model_config *manifest_find_model(const struct manifest *manifest, const char *model_name); +/* + * Applies white label information to an existing model configuration. + * Collects signature ID information from either parameter signature_id or + * image file (via VPD) and updates model.patches for key files. + * Returns 0 on success, otherwise failure. + */ +int model_apply_white_label( + struct model_config *model, + struct archive *archive, + const char *signature_id, + const char *image); + #endif /* VBOOT_REFERENCE_FUTILITY_UPDATER_H_ */ diff --git a/futility/updater_archive.c b/futility/updater_archive.c index e08f736a..7ce210f3 100644 --- a/futility/updater_archive.c +++ b/futility/updater_archive.c @@ -65,6 +65,8 @@ static const char * const SETVARS_IMAGE_MAIN = "IMAGE_MAIN", * const DIR_KEYSET = "keyset", * const DIR_MODELS = "models", * const DEFAULT_MODEL_NAME = "default", + * const VPD_WHITELABEL_TAG = "whitelabel_tag", + * const VPD_CUSTOMIZATION_ID = "customization_id", * const ENV_VAR_MODEL_DIR = "${MODEL_DIR}", * const PATH_STARTSWITH_KEYSET = "keyset/", * const PATH_ENDSWITH_SERVARS = "/setvars.sh"; @@ -365,16 +367,16 @@ int archive_read_file(struct archive *ar, const char *fname, * -- End of archive implementations -- */ -/* Utility function to convert a string to all lowercase. */ -static void str_tolower(char *s) +/* Utility function to convert a string. */ +static void str_convert(char *s, int (*convert)(int c)) { int c; for (; *s; s++) { c = *s; - if (!isascii(c) || !isalpha(c)) + if (!isascii(c)) continue; - *s = tolower(c); + *s = convert(c); } } @@ -393,6 +395,23 @@ static int str_startswith(const char *name, const char *pattern) return strncmp(name, pattern, strlen(pattern)) == 0; } +/* Returns the VPD value by given key name, or NULL on error (or no value). */ +static char *vpd_get_value(const char *fpath, const char *key) +{ + char *command, *result; + + assert(fpath); + ASPRINTF(&command, "vpd -g %s -f %s 2>/dev/null", key, fpath); + result = host_shell(command); + free(command); + + if (result && !*result) { + free(result); + result = NULL; + } + return result; +} + /* * Reads and parses a setvars type file from archive, then stores into config. * Returns 0 on success (at least one entry found), otherwise failure. @@ -442,9 +461,11 @@ static int model_config_parse_setvars_file( cfg->ec_image = strdup(v); else if (strcmp(k, SETVARS_IMAGE_PD) == 0) cfg->pd_image = strdup(v); - else if (strcmp(k, SETVARS_SIGNATURE_ID) == 0) + else if (strcmp(k, SETVARS_SIGNATURE_ID) == 0) { cfg->signature_id = strdup(v); - else + if (str_startswith(v, SIG_ID_IN_VPD_PREFIX)) + cfg->is_white_label = 1; + } else found_valid = 0; free(expand_path); valid += found_valid; @@ -690,6 +711,65 @@ const struct model_config *manifest_find_model(const struct manifest *manifest, } /* + * Applies white label information to an existing model configuration. + * Collects signature ID information from either parameter signature_id or + * image file (via VPD) and updates model.patches for key files. + * Returns 0 on success, otherwise failure. + */ +int model_apply_white_label( + struct model_config *model, + struct archive *archive, + const char *signature_id, + const char *image) +{ + char *sig_id = NULL; + int r = 0; + + if (!signature_id) { + int remove_dash = 0, prefix_model = model->signature_id ? 1 : 0; + char *wl_tag = vpd_get_value(image, VPD_WHITELABEL_TAG); + + if (!wl_tag) { + if (model->signature_id) + return -1; + wl_tag = vpd_get_value(image, VPD_CUSTOMIZATION_ID); + /* customization_id in format LOEM[-VARIANT]. */ + remove_dash = 1; + + } + if (!wl_tag) + return 1; + + if (remove_dash) { + char *dash = strchr(wl_tag, '-'); + if (dash) + *dash = '\0'; + } + if (!prefix_model) + str_convert(wl_tag, toupper); + + sig_id = wl_tag; + if (prefix_model) + ASPRINTF(&sig_id, "%s-%s", model->name, wl_tag); + else + wl_tag = NULL; + free(wl_tag); + signature_id = sig_id; + } + + DEBUG("Find white label patches by signature ID: '%s'.", signature_id); + find_patches_for_model(model, archive, signature_id); + if (!model->patches.rootkey) { + ERROR("No keys found for signature_id: '%s'", signature_id); + r = 1; + } else { + printf("Applied for white label: %s\n", signature_id); + } + free(sig_id); + return r; +} + +/* * Creates a new manifest object by scanning files in archive. * Returns the manifest on success, otherwise NULL for failure. */ @@ -720,13 +800,15 @@ struct manifest *new_manifest_from_archive(struct archive *archive) if (strtok(image.ro_version, "_")) token = strtok(NULL, "."); if (token && *token) { - str_tolower(token); + str_convert(token, tolower); model.name = strdup(token); } free_firmware_image(&image); } if (!model.name) model.name = strdup(DEFAULT_MODEL_NAME); + if (manifest.has_keyset) + model.is_white_label = 1; manifest_add_model(&manifest, &model); manifest.default_model = manifest.num - 1; } diff --git a/tests/futility/models/whitetip/setvars.sh b/tests/futility/models/whitetip/setvars.sh new file mode 100755 index 00000000..4b9cb406 --- /dev/null +++ b/tests/futility/models/whitetip/setvars.sh @@ -0,0 +1,21 @@ +#!/bin/sh +# Copyright 2017 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This is a template file which provides settings for firmware update of a +# particular model. The pack_firmware.py script uses this to create a working +# setvars-model.sh script. + +# Version information for model whitetip +TARGET_RO_FWID="Google_Coral.10068.45.0" +TARGET_FWID="Google_Coral.10068.45.0" +TARGET_ECID="coral_v1.1.7272-0b44fba22" +TARGET_PDID="" +TARGET_PLATFORM="Google_Coral" + +# Image and key files for model whitetip +IMAGE_MAIN="images/bios_coral.bin" +IMAGE_EC="" +IMAGE_PD="" +SIGNATURE_ID="sig-id-in-customization-id" diff --git a/tests/futility/test_update.sh b/tests/futility/test_update.sh index 32fe921e..215f9918 100755 --- a/tests/futility/test_update.sh +++ b/tests/futility/test_update.sh @@ -296,7 +296,10 @@ test_update "Full update (--quirks min_platform_version)" \ # Test archive and manifest. A="${TMP}.archive" -mkdir -p "${A}" +mkdir -p "${A}/bin" +echo 'echo "${WL_TAG}"' >"${A}/bin/vpd" +chmod +x "${A}/bin/vpd" + cp -f "${LINK_BIOS}" "${A}/bios.bin" echo "TEST: Manifest (--manifest)" ${FUTILITY} update -a "${A}" --manifest >"${TMP}.json.out" @@ -307,12 +310,41 @@ test_update "Full update (--archive, single package)" \ "${FROM_IMAGE}" "${TMP}.expected.full" \ -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 -rm -f "${A}/bios.bin" +mkdir -p "${A}/keyset" +cp -f "${LINK_BIOS}" "${A}/bios.bin" +cp -f "${TMP}.to/rootkey" "${A}/keyset/rootkey.WL" +cp -f "${TMP}.to/VBLOCK_A" "${A}/keyset/vblock_A.WL" +cp -f "${TMP}.to/VBLOCK_B" "${A}/keyset/vblock_B.WL" +${FUTILITY} gbb -s --rootkey="${TMP}.from/rootkey" "${A}/bios.bin" +${FUTILITY} load_fmap "${A}/bios.bin" VBLOCK_A:"${TMP}.from/VBLOCK_A" +${FUTILITY} load_fmap "${A}/bios.bin" VBLOCK_B:"${TMP}.from/VBLOCK_B" + +test_update "Full update (--archive, whitelabel, no VPD)" \ + "${A}/bios.bin" "!Need VPD set for white" \ + -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 + +test_update "Full update (--archive, whitelabel, no VPD - factory mode)" \ + "${LINK_BIOS}" "${A}/bios.bin" \ + -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 --mode=factory + +test_update "Full update (--archive, WL, single package)" \ + "${A}/bios.bin" "${LINK_BIOS}" \ + -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 --signature_id=WL + +WL_TAG="WL" PATH="${A}/bin:${PATH}" \ + test_update "Full update (--archive, WL, fake vpd)" \ + "${A}/bios.bin" "${LINK_BIOS}" \ + -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 + +# Test archive with Unified Build contents. cp -r "${SCRIPTDIR}/models" "${A}/" mkdir -p "${A}/images" +mv "${A}/bios.bin" "${A}/images/bios_coral.bin" cp -f "${PEPPY_BIOS}" "${A}/images/bios_peppy.bin" cp -f "${LINK_BIOS}" "${A}/images/bios_link.bin" - +cp -f "${TMP}.to/rootkey" "${A}/keyset/rootkey.whitetip-wl" +cp -f "${TMP}.to/VBLOCK_A" "${A}/keyset/vblock_A.whitetip-wl" +cp -f "${TMP}.to/VBLOCK_B" "${A}/keyset/vblock_B.whitetip-wl" cp -f "${PEPPY_BIOS}" "${FROM_IMAGE}.ap" cp -f "${LINK_BIOS}" "${FROM_IMAGE}.al" patch_file ${FROM_IMAGE}.ap FW_MAIN_A 0 "corrupted" @@ -326,6 +358,15 @@ test_update "Full update (--archive, model=peppy)" \ test_update "Full update (--archive, model=unknown)" \ "${FROM_IMAGE}.ap" "!Model 'unknown' is not defined" \ -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 --model=unknown +test_update "Full update (--archive, model=whitetip, signature_id=WL)" \ + "${FROM_IMAGE}.al" "${LINK_BIOS}" \ + -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 --model=whitetip \ + --signature_id=whitetip-wl + +WL_TAG="wl" PATH="${A}/bin:${PATH}" \ + test_update "Full update (-a, model=WL, fake VPD)" \ + "${FROM_IMAGE}.al" "${LINK_BIOS}" \ + -a "${A}" --wp=0 --sys_props 0,0x10001,1,3 --model=whitetip # Test special programmer if type flashrom >/dev/null 2>&1; then |