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 <pjones@redhat.com>
Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>

Patch-Name: 2021-02-security/107-util-mkimage-Add-an-option-to-import-SBAT-metadata-into-a-.sbat-section.patch
This commit is contained in:
Peter Jones 2021-02-15 17:07:00 +01:00 committed by Colin Watson
parent 1c810627ec
commit 26ff81d1eb
6 changed files with 73 additions and 10 deletions

View File

@ -5635,6 +5635,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
@ -5813,6 +5814,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

View File

@ -183,7 +183,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);

View File

@ -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;

View File

@ -586,7 +586,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 ();
}

View File

@ -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;
}

View File

@ -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);