summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHung-Te Lin <hungte@chromium.org>2018-10-15 15:33:47 +0800
committerchrome-bot <chrome-bot@chromium.org>2018-10-22 06:16:35 -0700
commit4e066900210883a4f502e626998daf79b9b66665 (patch)
tree8111b86089364581014f83117b5167e3977fbb2a
parent92fe37cef28d58f6d64c625b30e72fab99ff42a5 (diff)
downloadvboot-4e066900210883a4f502e626998daf79b9b66665.tar.gz
futility: updater: Support white label from VPD and --signature_id
For white label devices, we have to select and patch key files (root key and vblock) by VPD (`whitelabel_tag` or `customization_id`). The white label tag VPD will be processed and converted to a "signature ID" for key selection. To support that, updater has to fetch current (system) image if the matched model is following white label (so we can read VPD from it). For developers who want to load and use particular files, they can use --signature_id to override VPD values. BUG=chromium:875551 TEST=TEST=make futil; tests/futility/run_test_scripts.sh $(pwd)/build/futility BRANCH=None Change-Id: I3630bae28d1a8493b56d0e5efd29f3c61a470379 Signed-off-by: Hung-Te Lin <hungte@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1278420
-rw-r--r--futility/cmd_update.c5
-rw-r--r--futility/updater.c58
-rw-r--r--futility/updater.h15
-rw-r--r--futility/updater_archive.c96
-rwxr-xr-xtests/futility/models/whitetip/setvars.sh21
-rwxr-xr-xtests/futility/test_update.sh47
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