From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Mon, 15 Feb 2021 17:07:00 +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 | 43 ++++++++++++++++++++++++++++++++++++------- include/grub/util/install.h | 3 ++- include/grub/util/mkimage.h | 1 + docs/grub.texi | 19 +++++++++++++++++++ 6 files changed, 73 insertions(+), 10 deletions(-) diff --git a/util/grub-install-common.c b/util/grub-install-common.c index fa6b65347ea..fde4ca7fc8c 100644 --- a/util/grub-install-common.c +++ b/util/grub-install-common.c @@ -537,7 +537,7 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, pubkeys, npubkeys, x509keys, nx509keys, config_path, tgt, - note, appsig_size, compression, dtb); + note, appsig_size, compression, dtb, NULL); while (dc--) grub_install_pop_module (); } diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c index 394d2dc5fc9..17a86261ffc 100644 --- a/util/grub-mkimage.c +++ b/util/grub-mkimage.c @@ -82,6 +82,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}, {"appended-signature-size", 'S', N_("SIZE"), 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 0}, { 0, 0, 0, 0, 0, 0 } @@ -127,6 +128,7 @@ struct arguments size_t nx509keys; char *font; char *config; + char *sbat; int note; size_t appsig_size; const struct grub_install_image_target_desc *image_target; @@ -244,6 +246,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; @@ -331,7 +340,8 @@ main (int argc, char *argv[]) arguments.nx509keys, arguments.config, arguments.image_target, arguments.note, arguments.appsig_size, - arguments.comp, arguments.dtb); + arguments.comp, arguments.dtb, + arguments.sbat); grub_util_file_sync (fp); fclose (fp); @@ -346,5 +356,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 0f5ae2a76f2..16418e245d3 100644 --- a/util/mkimage.c +++ b/util/mkimage.c @@ -826,12 +826,13 @@ grub_install_generate_image (const char *dir, const char *prefix, char **x509key_paths, size_t nx509keys, char *config_path, const struct grub_install_image_target_desc *image_target, - int note, size_t appsig_size, grub_compression_t comp, const char *dtb_path) + int note, size_t appsig_size, 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; @@ -895,6 +896,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); @@ -1277,8 +1281,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; @@ -1293,8 +1298,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); @@ -1309,7 +1321,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 @@ -1371,7 +1386,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)); @@ -1382,7 +1398,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, @@ -1390,6 +1406,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); diff --git a/include/grub/util/install.h b/include/grub/util/install.h index 95059285bd4..dad17561c4f 100644 --- a/include/grub/util/install.h +++ b/include/grub/util/install.h @@ -187,7 +187,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, size_t appsig_size, - 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 cef7fffa7ae..f48d544c28a 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/docs/grub.texi b/docs/grub.texi index 314bbeb8471..52e6e5763b8 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -5719,6 +5719,7 @@ environment variables and commands are listed in the same order. * Using GPG-style digital signatures:: Booting digitally signed code * Using appended signatures:: An alternative approach to booting digitally signed code * Signing GRUB itself:: Ensuring the integrity of the GRUB core image +* Secure Boot Advanced Targeting:: Embedded information for generation number based revocation * Lockdown:: Lockdown when booting on a secure setup @end menu @@ -6010,6 +6011,24 @@ As with UEFI secure boot, it is necessary to build in the required modules, or sign them separately. +@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