diff options
Diffstat (limited to 'futility/cmd_gscvd.c')
-rw-r--r-- | futility/cmd_gscvd.c | 120 |
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, |