summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulius Werner <jwerner@chromium.org>2022-05-17 17:23:51 -0700
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-05-18 21:48:56 +0000
commitfa4c817abb6eb9421bb4296cd137947519c37651 (patch)
tree83b0de6486328109901e5416d631f92c96f15e82
parent523e7f1dde9193a68714ca5d8a70511f56577fae (diff)
downloadvboot-fa4c817abb6eb9421bb4296cd137947519c37651.tar.gz
futility: gscvd: Add -G flag for GBB ranges
This patch adds a new `--add_gbb`/`-G` flag to the `gscvd` command that can be used as a shorthand option to add the `GBB` FMAP section to the covered ranges. When adding the GBB, it is important that we exclude the HWID and HWID digest from the covered ranges, because they can vary between units and it would be too cumbersome to sign every possible HWID separately. Figuring out the right ranges to pass that exclude these individual fields of the structure manually from the build scripts would be very awkward, so let's add this option here where we can write the logic cleanly with C code and have all the vboot data structure definitions readily available. Also do some minor option parsing cleanups. BRANCH=none BUG=b:229015103 TEST=Created GSCVDs with this flag, manually confirmed with a hex editor that the correct ranges were created. Signed-off-by: Julius Werner <jwerner@chromium.org> Change-Id: I3bef5355506d831353afe6f534ae9303334d014c Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/3653203 Reviewed-by: Vadim Bendebury <vbendeb@chromium.org>
-rw-r--r--futility/cmd_gscvd.c120
1 files changed, 111 insertions, 9 deletions
diff --git a/futility/cmd_gscvd.c b/futility/cmd_gscvd.c
index d6187c9f..659716ae 100644
--- a/futility/cmd_gscvd.c
+++ b/futility/cmd_gscvd.c
@@ -60,6 +60,7 @@ static const struct option long_opts[] = {
/* name hasarg *flag val */
{"outfile", 1, NULL, OPT_OUTFILE},
{"ranges", 1, NULL, 'R'},
+ {"add_gbb", 0, NULL, 'G'},
{"board_id", 1, NULL, 'b'},
{"root_pub_key", 1, NULL, 'r'},
{"keyblock", 1, NULL, 'k'},
@@ -68,7 +69,7 @@ static const struct option long_opts[] = {
{}
};
-static const char *short_opts = "R:b:hk:p:r:";
+static const char *short_opts = "R:Gb:hk:p:r:";
static const char usage[] =
"\n"
@@ -82,6 +83,11 @@ static const char usage[] =
" hex tuples <offset>:<size>, the\n"
" areas of the RO covered by the\n"
" signature\n"
+ " -G|--add_gbb Add the `GBB` FMAP section to the\n"
+ " ranges covered by the signature.\n"
+ " This option takes special care\n"
+ " to exclude the HWID (and its\n"
+ " digest) from this range.\n"
" -b|--board_id <hex value> The Board ID of the board for which\n"
" the image is being signed\n"
" -r|--root_pub_key <file> The main public key, in .vbpubk\n"
@@ -285,7 +291,6 @@ static int parse_ranges(const char *input, struct gscvd_ro_ranges *output)
return -1;
}
- output->range_count = 0;
cursor = str;
do {
char *colon;
@@ -335,6 +340,71 @@ static int parse_ranges(const char *input, struct gscvd_ro_ranges *output)
}
/**
+ * Add GBB to ranges.
+ *
+ * Splits the `GBB` FMAP section into separate ranges to exclude the HWID string
+ * and the `hwid_digest` field in the header. Will also exclude the empty area
+ * behind the end of the actual GBB data.
+ *
+ * @param ranges pointer to the ranges container
+ * @param file pointer to the AP firmware file layout descriptor
+ */
+static int add_gbb(struct gscvd_ro_ranges *ranges, const struct file_buf *file)
+{
+ FmapAreaHeader *area;
+
+ if (!fmap_find_by_name(file->data, file->len, NULL, "GBB", &area)) {
+ ERROR("Could not find a GBB area in the FMAP.\n");
+ return 1;
+ }
+
+ struct vb2_gbb_header *gbb = (void *)file->data + area->area_offset;
+ uint32_t maxlen;
+
+ if (!futil_valid_gbb_header(gbb, area->area_size, &maxlen)) {
+ ERROR("GBB is invalid.\n");
+ return 1;
+ }
+
+ /*
+ * This implementation relies on the fact that no meaningful fields come
+ * after the `hwid_digest` field in the header. If we ever make new GBB
+ * versions that add more fields, the code below needs to be adapted.
+ * Older versions than 1.2 or GBBs with a bmpblk are not expected with
+ * GSCVD images.
+ */
+ if (gbb->major_version != 1 || gbb->minor_version != 2 ||
+ gbb->bmpfv_size != 0) {
+ ERROR("Unsupported GBB version.\n");
+ return 1;
+ }
+
+ uint32_t lower_key_offset = VB2_MIN(gbb->rootkey_offset,
+ gbb->recovery_key_offset);
+ if (gbb->hwid_offset > lower_key_offset) {
+ ERROR("Weird GBB layout (HWID should come first)\n");
+ return 1;
+ }
+
+ if (ranges->range_count >= ARRAY_SIZE(ranges->ranges) - 2) {
+ ERROR("Too many ranges, can't fit GBB!\n");
+ return 1;
+ }
+
+ ranges->ranges[ranges->range_count].offset = area->area_offset;
+ ranges->ranges[ranges->range_count].size =
+ offsetof(struct vb2_gbb_header, hwid_digest);
+ ranges->range_count++;
+
+ ranges->ranges[ranges->range_count].offset = area->area_offset +
+ lower_key_offset;
+ ranges->ranges[ranges->range_count].size = maxlen - lower_key_offset;
+ ranges->range_count++;
+
+ return 0;
+}
+
+/**
* Calculate hash of the RO ranges.
*
* @param ap_firmware_file pointer to the AP firmware file layout descriptor
@@ -887,6 +957,7 @@ static int do_gscvd(int argc, char *argv[])
{
int i;
int longindex;
+ bool do_gbb = false;
char *infile = NULL;
char *outfile = NULL;
char *work_file = NULL;
@@ -915,6 +986,9 @@ static int do_gscvd(int argc, char *argv[])
errorcount++;
}
break;
+ case 'G':
+ do_gbb = true;
+ break;
case 'b': {
char *e;
long long bid;
@@ -977,15 +1051,36 @@ static int do_gscvd(int argc, char *argv[])
return validate_gscvd(argc - 1, argv + 1);
if (optind != (argc - 1)) {
- ERROR("Misformatted command line\n%s\n", usage);
- return 1;
+ ERROR("Misformatted command line\n");
+ goto usage_out;
}
- if (errorcount || !ranges.range_count || !root_pubk || !kblock ||
- !plat_privk || (board_id == UINT32_MAX)) {
- /* Error message(s) should have been printed by now. */
- ERROR("%s\n", usage);
- return 1;
+ if (errorcount) /* Error message(s) should have been printed by now. */
+ goto usage_out;
+
+ if (!root_pubk) {
+ ERROR("Missing --root_pub_key argument\n");
+ goto usage_out;
+ }
+
+ if (!kblock) {
+ ERROR("Missing --keyblock argument\n");
+ goto usage_out;
+ }
+
+ if (!plat_privk) {
+ ERROR("Missing --platform_priv argument\n");
+ goto usage_out;
+ }
+
+ if (board_id == UINT32_MAX) {
+ ERROR("Missing --board_id argument\n");
+ goto usage_out;
+ }
+
+ if (!ranges.range_count && !do_gbb) {
+ ERROR("Missing --ranges argument\n");
+ goto usage_out;
}
infile = argv[optind];
@@ -1009,6 +1104,9 @@ static int do_gscvd(int argc, char *argv[])
if (load_ap_firmware(work_file, &ap_firmware_file, FILE_RW))
break;
+ if (do_gbb && add_gbb(&ranges, &ap_firmware_file))
+ break;
+
if (verify_ranges(&ranges, &ap_firmware_file))
break;
@@ -1036,6 +1134,10 @@ static int do_gscvd(int argc, char *argv[])
ap_firmware_file.len);
return rv;
+
+usage_out:
+ fputs(usage, stderr);
+ return 1;
}
DECLARE_FUTIL_COMMAND(gscvd, do_gscvd, VBOOT_VERSION_2_1,