From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Fri, 26 Feb 2021 01:43:30 +0100 Subject: [PATCH] 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 --- util/grub-install-common.c | 2 +- util/grub-mkimage.c | 15 ++++++++++++++- util/mkimage.c | 44 +++++++++++++++++++++++++++++++++++++------- include/grub/util/install.h | 3 ++- docs/grub.texi | 21 +++++++++++++++++++++ 5 files changed, 75 insertions(+), 10 deletions(-) diff --git a/util/grub-install-common.c b/util/grub-install-common.c index d49a93d4740..b4192cf47a3 100644 --- a/util/grub-install-common.c +++ b/util/grub-install-common.c @@ -498,7 +498,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); + note, compression, NULL); while (dc--) grub_install_pop_module (); } diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c index 1e0bcf1bf4f..c674f76c42a 100644 --- a/util/grub-mkimage.c +++ b/util/grub-mkimage.c @@ -80,6 +80,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 } }; @@ -121,6 +122,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; @@ -215,6 +217,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; @@ -299,7 +308,8 @@ main (int argc, char *argv[]) arguments.memdisk, arguments.pubkeys, arguments.npubkeys, arguments.config, arguments.image_target, arguments.note, - arguments.comp); + arguments.comp, + arguments.sbat); grub_util_file_sync (fp); fclose (fp); @@ -310,5 +320,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 938a06a2d3f..44e2b8adfd8 100644 --- a/util/mkimage.c +++ b/util/mkimage.c @@ -1032,12 +1032,14 @@ grub_install_generate_image (const char *dir, const char *prefix, size_t npubkeys, char *config_path, const struct grub_install_image_target_desc *image_target, int note, - grub_compression_t comp) + grub_compression_t comp, + const char *sbat_path) { char *kernel_img, *core_img; size_t kernel_size, total_module_size, core_size, exec_size; size_t memdisk_size = 0, config_size = 0, config_size_pure = 0; size_t prefix_size = 0; + size_t sbat_size = 0; char *kernel_path; size_t offset; struct grub_util_path_list *path_list, *p, *next; @@ -1085,6 +1087,9 @@ grub_install_generate_image (const char *dir, const char *prefix, total_module_size += memdisk_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_pure = grub_util_get_image_size (config_path) + 1; @@ -1446,8 +1451,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; @@ -1462,8 +1468,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 (reloc_size, GRUB_PE32_FILE_ALIGNMENT) + sbat_size; header = pe_img = xcalloc (1, pe_size); memcpy (pe_img + raw_data, core_img, core_size); @@ -1478,7 +1491,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 (time (0)); c->characteristics = grub_host_to_target16 (GRUB_PE32_EXECUTABLE_IMAGE | GRUB_PE32_LINE_NUMS_STRIPPED @@ -1542,9 +1558,10 @@ grub_install_generate_image (const char *dir, const char *prefix, GRUB_PE32_SCN_MEM_READ); scn_size = ALIGN_UP (kernel_size - 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)); section = init_pe_section (image_target, section, ".data", &vma, scn_size, image_target->section_align, @@ -1553,7 +1570,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 - reloc_size - raw_data; + scn_size = pe_size - 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, @@ -1561,6 +1578,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 = 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); diff --git a/include/grub/util/install.h b/include/grub/util/install.h index aedcd29f905..02ae1c6425e 100644 --- a/include/grub/util/install.h +++ b/include/grub/util/install.h @@ -176,7 +176,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); + grub_compression_t comp, + const char *sbat_path); const struct grub_install_image_target_desc * grub_install_get_image_target (const char *arg); diff --git a/docs/grub.texi b/docs/grub.texi index 446574f3ddb..24840d00cf7 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -5498,6 +5498,7 @@ environment variables and commands are listed in the same order. @menu * Authentication and authorisation:: Users and access control * Using digital signatures:: Booting digitally signed code +* Secure Boot Advanced Targeting:: Embedded information for generation number based revocation * Lockdown:: Lockdown when booting on a secure setup @end menu @@ -5660,6 +5661,26 @@ or BIOS) configuration to cause the machine to boot from a different (attacker-controlled) device. GRUB is at best only one link in a secure boot chain. + +@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 Lockdown @section Lockdown when booting on a secure setup