From c128817e4493836b9877e573820782036dea2163 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Mon, 15 Feb 2021 17:07:00 +0100 Subject: [PATCH 38/46] util/mkimage: Add an option to import SBAT metadata into a .sbat section Add a --sbat option to the grub-mkimage tool which allows us to import an SBAT metadata formatted as a CSV file into a .sbat section of the EFI binary. Signed-off-by: Peter Jones Signed-off-by: Javier Martinez Canillas Reviewed-by: Daniel Kiper --- docs/grub.texi | 19 ++++++++++++++++ include/grub/util/install.h | 3 ++- include/grub/util/mkimage.h | 1 + util/grub-install-common.c | 2 +- util/grub-mkimage.c | 15 ++++++++++++- util/mkimage.c | 43 +++++++++++++++++++++++++++++++------ 6 files changed, 73 insertions(+), 10 deletions(-) diff --git a/docs/grub.texi b/docs/grub.texi index cf29a1797..fa0b49737 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -5612,6 +5612,7 @@ environment variables and commands are listed in the same order. * Authentication and authorisation:: Users and access control * Using digital signatures:: Booting digitally signed code * UEFI secure boot and shim:: Booting digitally signed PE files +* Secure Boot Advanced Targeting:: Embedded information for generation number based revocation * Measured Boot:: Measuring boot components * Lockdown:: Lockdown when booting on a secure setup @end menu @@ -5791,6 +5792,24 @@ and @command{memrw} will not be available when the UEFI secure boot is enabled. This is done for security reasons and are enforced by the GRUB Lockdown mechanism (@pxref{Lockdown}). +@node Secure Boot Advanced Targeting +@section Embedded information for generation number based revocation + +The Secure Boot Advanced Targeting (SBAT) is a mechanism to allow the revocation +of components in the boot path by using generation numbers embedded into the EFI +binaries. The SBAT metadata is located in an .sbat data section that has set of +UTF-8 strings as comma-separated values (CSV). See +@uref{https://github.com/rhboot/shim/blob/main/SBAT.md} for more details. + +To add a data section containing the SBAT information into the binary, the +@option{--sbat} option of @command{grub-mkimage} command should be used. The content +of a CSV file, encoded with UTF-8, is copied as is to the .sbat data section into +the generated EFI binary. The CSV file can be stored anywhere on the file system. + +@example +grub-mkimage -O x86_64-efi -o grubx64.efi -p '(tftp)/grub' --sbat sbat.csv efinet tftp +@end example + @node Measured Boot @section Measuring boot components diff --git a/include/grub/util/install.h b/include/grub/util/install.h index 1541ee233..6ee3b4516 100644 --- a/include/grub/util/install.h +++ b/include/grub/util/install.h @@ -184,7 +184,8 @@ grub_install_generate_image (const char *dir, const char *prefix, char *config_path, const struct grub_install_image_target_desc *image_target, int note, - grub_compression_t comp, const char *dtb_file); + grub_compression_t comp, const char *dtb_file, + const char *sbat_path); const struct grub_install_image_target_desc * grub_install_get_image_target (const char *arg); diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h index ba9f568f6..3819a6744 100644 --- a/include/grub/util/mkimage.h +++ b/include/grub/util/mkimage.h @@ -24,6 +24,7 @@ struct grub_mkimage_layout size_t exec_size; size_t kernel_size; size_t bss_size; + size_t sbat_size; grub_uint64_t start_address; void *reloc_section; size_t reloc_size; diff --git a/util/grub-install-common.c b/util/grub-install-common.c index d1894f7c1..052f3ef3d 100644 --- a/util/grub-install-common.c +++ b/util/grub-install-common.c @@ -546,7 +546,7 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, grub_install_generate_image (dir, prefix, fp, outname, modules.entries, memdisk_path, pubkeys, npubkeys, config_path, tgt, - note, compression, dtb); + note, compression, dtb, NULL); while (dc--) grub_install_pop_module (); } diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c index 912564e36..75b884710 100644 --- a/util/grub-mkimage.c +++ b/util/grub-mkimage.c @@ -81,6 +81,7 @@ static struct argp_option options[] = { {"output", 'o', N_("FILE"), 0, N_("output a generated image to FILE [default=stdout]"), 0}, {"format", 'O', N_("FORMAT"), 0, 0, 0}, {"compression", 'C', "(xz|none|auto)", 0, N_("choose the compression to use for core image"), 0}, + {"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 0}, {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, { 0, 0, 0, 0, 0, 0 } }; @@ -123,6 +124,7 @@ struct arguments size_t npubkeys; char *font; char *config; + char *sbat; int note; const struct grub_install_image_target_desc *image_target; grub_compression_t comp; @@ -224,6 +226,13 @@ argp_parser (int key, char *arg, struct argp_state *state) arguments->prefix = xstrdup (arg); break; + case 's': + if (arguments->sbat) + free (arguments->sbat); + + arguments->sbat = xstrdup (arg); + break; + case 'v': verbosity++; break; @@ -309,7 +318,8 @@ main (int argc, char *argv[]) arguments.memdisk, arguments.pubkeys, arguments.npubkeys, arguments.config, arguments.image_target, arguments.note, - arguments.comp, arguments.dtb); + arguments.comp, arguments.dtb, + arguments.sbat); if (grub_util_file_sync (fp) < 0) grub_util_error (_("cannot sync `%s': %s"), arguments.output ? : "stdout", @@ -328,5 +338,8 @@ main (int argc, char *argv[]) if (arguments.output) free (arguments.output); + if (arguments.sbat) + free (arguments.sbat); + return 0; } diff --git a/util/mkimage.c b/util/mkimage.c index 8b475a691..b354ec1d9 100644 --- a/util/mkimage.c +++ b/util/mkimage.c @@ -869,12 +869,13 @@ grub_install_generate_image (const char *dir, const char *prefix, char *memdisk_path, char **pubkey_paths, size_t npubkeys, char *config_path, const struct grub_install_image_target_desc *image_target, - int note, grub_compression_t comp, const char *dtb_path) + int note, grub_compression_t comp, const char *dtb_path, + const char *sbat_path) { char *kernel_img, *core_img; size_t total_module_size, core_size; size_t memdisk_size = 0, config_size = 0; - size_t prefix_size = 0, dtb_size = 0; + size_t prefix_size = 0, dtb_size = 0, sbat_size = 0; char *kernel_path; size_t offset; struct grub_util_path_list *path_list, *p; @@ -925,6 +926,9 @@ grub_install_generate_image (const char *dir, const char *prefix, total_module_size += dtb_size + sizeof (struct grub_module_header); } + if (sbat_path != NULL && image_target->id != IMAGE_EFI) + grub_util_error (_(".sbat section can be embedded into EFI images only")); + if (config_path) { config_size = ALIGN_ADDR (grub_util_get_image_size (config_path) + 1); @@ -1289,8 +1293,9 @@ grub_install_generate_image (const char *dir, const char *prefix, break; case IMAGE_EFI: { - char *pe_img, *header; + char *pe_img, *pe_sbat, *header; struct grub_pe32_section_table *section; + size_t n_sections = 4; size_t scn_size; grub_uint32_t vma, raw_data; size_t pe_size, header_size; @@ -1305,8 +1310,15 @@ grub_install_generate_image (const char *dir, const char *prefix, header_size = EFI64_HEADER_SIZE; vma = raw_data = header_size; + + if (sbat_path != NULL) + { + sbat_size = ALIGN_ADDR (grub_util_get_image_size (sbat_path)); + sbat_size = ALIGN_UP (sbat_size, GRUB_PE32_FILE_ALIGNMENT); + } + pe_size = ALIGN_UP (header_size + core_size, GRUB_PE32_FILE_ALIGNMENT) + - ALIGN_UP (layout.reloc_size, GRUB_PE32_FILE_ALIGNMENT); + ALIGN_UP (layout.reloc_size, GRUB_PE32_FILE_ALIGNMENT) + sbat_size; header = pe_img = xcalloc (1, pe_size); memcpy (pe_img + raw_data, core_img, core_size); @@ -1321,7 +1333,10 @@ grub_install_generate_image (const char *dir, const char *prefix, + GRUB_PE32_SIGNATURE_SIZE); c->machine = grub_host_to_target16 (image_target->pe_target); - c->num_sections = grub_host_to_target16 (4); + if (sbat_path != NULL) + n_sections++; + + c->num_sections = grub_host_to_target16 (n_sections); c->time = grub_host_to_target32 (STABLE_EMBEDDING_TIMESTAMP); c->characteristics = grub_host_to_target16 (GRUB_PE32_EXECUTABLE_IMAGE | GRUB_PE32_LINE_NUMS_STRIPPED @@ -1383,7 +1398,8 @@ grub_install_generate_image (const char *dir, const char *prefix, GRUB_PE32_SCN_MEM_READ); scn_size = ALIGN_UP (layout.kernel_size - layout.exec_size, GRUB_PE32_FILE_ALIGNMENT); - PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (scn_size + + /* ALIGN_UP (sbat_size, GRUB_PE32_FILE_ALIGNMENT) is done earlier. */ + PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (scn_size + sbat_size + ALIGN_UP (total_module_size, GRUB_PE32_FILE_ALIGNMENT)); @@ -1394,7 +1410,7 @@ grub_install_generate_image (const char *dir, const char *prefix, GRUB_PE32_SCN_MEM_READ | GRUB_PE32_SCN_MEM_WRITE); - scn_size = pe_size - layout.reloc_size - raw_data; + scn_size = pe_size - layout.reloc_size - sbat_size - raw_data; section = init_pe_section (image_target, section, "mods", &vma, scn_size, image_target->section_align, &raw_data, scn_size, @@ -1402,6 +1418,19 @@ grub_install_generate_image (const char *dir, const char *prefix, GRUB_PE32_SCN_MEM_READ | GRUB_PE32_SCN_MEM_WRITE); + if (sbat_path != NULL) + { + pe_sbat = pe_img + raw_data; + grub_util_load_image (sbat_path, pe_sbat); + + section = init_pe_section (image_target, section, ".sbat", + &vma, sbat_size, + image_target->section_align, + &raw_data, sbat_size, + GRUB_PE32_SCN_CNT_INITIALIZED_DATA | + GRUB_PE32_SCN_MEM_READ); + } + scn_size = layout.reloc_size; PE_OHDR (o32, o64, base_relocation_table.rva) = grub_host_to_target32 (vma); PE_OHDR (o32, o64, base_relocation_table.size) = grub_host_to_target32 (scn_size); -- 2.26.2