diff --git a/grub/util/grub-install.c b/grub/util/grub-install.c index 8a55ad4b8..724f7ec67 100644 --- a/grub/util/grub-install.c +++ b/grub/util/grub-install.c @@ -79,6 +79,7 @@ static char *label_color; static char *label_bgcolor; static char *product_version; static int add_rs_codes = 1; +static int uefi_secure_boot = 1; enum { @@ -109,7 +110,9 @@ enum OPTION_LABEL_FONT, OPTION_LABEL_COLOR, OPTION_LABEL_BGCOLOR, - OPTION_PRODUCT_VERSION + OPTION_PRODUCT_VERSION, + OPTION_UEFI_SECURE_BOOT, + OPTION_NO_UEFI_SECURE_BOOT }; static int fs_probe = 1; @@ -233,6 +236,14 @@ argp_parser (int key, char *arg, struct argp_state *state) bootloader_id = xstrdup (arg); return 0; + case OPTION_UEFI_SECURE_BOOT: + uefi_secure_boot = 1; + return 0; + + case OPTION_NO_UEFI_SECURE_BOOT: + uefi_secure_boot = 0; + return 0; + case ARGP_KEY_ARG: if (install_device) grub_util_error ("%s", _("More than one install device?")); @@ -302,6 +313,13 @@ static struct argp_option options[] = { {"label-color", OPTION_LABEL_COLOR, N_("COLOR"), 0, N_("use COLOR for label"), 2}, {"label-bgcolor", OPTION_LABEL_BGCOLOR, N_("COLOR"), 0, N_("use COLOR for label background"), 2}, {"product-version", OPTION_PRODUCT_VERSION, N_("STRING"), 0, N_("use STRING as product version"), 2}, + {"uefi-secure-boot", OPTION_UEFI_SECURE_BOOT, 0, 0, + N_("install an image usable with UEFI Secure Boot. " + "This option is only available on EFI."), 2}, + {"no-uefi-secure-boot", OPTION_NO_UEFI_SECURE_BOOT, 0, 0, + N_("do not install an image usable with UEFI Secure Boot, even if the " + "system was currently started using it. " + "This option is only available on EFI."), 2}, {0, 0, 0, 0, 0, 0} }; @@ -819,12 +837,31 @@ fill_core_services (const char *core_services) free (sysv_plist); } +static void +add_cryptomount(grub_device_t g_dev, char ** g_drives) +{ + char **curdrive; + if (g_dev->disk) + probe_cryptodisk_uuid (g_dev->disk); + + for (curdrive = g_drives + 1; *curdrive; curdrive++) + { + grub_device_t dev = grub_device_open (*curdrive); + if (!dev) + continue; + if (dev->disk) + probe_cryptodisk_uuid (dev->disk); + grub_device_close (dev); + } +} + int main (int argc, char *argv[]) { int is_efi = 0; const char *efi_distributor = NULL; - const char *efi_file = NULL; + const char *efi_suffix = NULL, *efi_suffix_upper = NULL; + char *efi_file = NULL; char **grub_devices; grub_fs_t grub_fs; grub_device_t grub_dev = NULL; @@ -1094,6 +1131,39 @@ main (int argc, char *argv[]) */ char *t; efi_distributor = bootloader_id; + switch (platform) + { + case GRUB_INSTALL_PLATFORM_I386_EFI: + efi_suffix = "ia32"; + efi_suffix_upper = "IA32"; + break; + case GRUB_INSTALL_PLATFORM_X86_64_EFI: + efi_suffix = "x64"; + efi_suffix_upper = "X64"; + break; + case GRUB_INSTALL_PLATFORM_IA64_EFI: + efi_suffix = "ia64"; + efi_suffix_upper = "IA64"; + break; + case GRUB_INSTALL_PLATFORM_ARM_EFI: + efi_suffix = "arm"; + efi_suffix_upper = "ARM"; + break; + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + efi_suffix = "aa64"; + efi_suffix_upper = "AA64"; + break; + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + efi_suffix = "riscv32"; + efi_suffix_upper = "RISCV32"; + break; + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: + efi_suffix = "riscv64"; + efi_suffix_upper = "RISCV64"; + break; + default: + break; + } if (removable) { /* The specification makes stricter requirements of removable @@ -1102,66 +1172,16 @@ main (int argc, char *argv[]) must have a specific file name depending on the architecture. */ efi_distributor = "BOOT"; - switch (platform) - { - case GRUB_INSTALL_PLATFORM_I386_EFI: - efi_file = "BOOTIA32.EFI"; - break; - case GRUB_INSTALL_PLATFORM_X86_64_EFI: - efi_file = "BOOTX64.EFI"; - break; - case GRUB_INSTALL_PLATFORM_IA64_EFI: - efi_file = "BOOTIA64.EFI"; - break; - case GRUB_INSTALL_PLATFORM_ARM_EFI: - efi_file = "BOOTARM.EFI"; - break; - case GRUB_INSTALL_PLATFORM_ARM64_EFI: - efi_file = "BOOTAA64.EFI"; - break; - case GRUB_INSTALL_PLATFORM_RISCV32_EFI: - efi_file = "BOOTRISCV32.EFI"; - break; - case GRUB_INSTALL_PLATFORM_RISCV64_EFI: - efi_file = "BOOTRISCV64.EFI"; - break; - default: - grub_util_error ("%s", _("You've found a bug")); - break; - } + if (!efi_suffix) + grub_util_error ("%s", _("You've found a bug")); + efi_file = xasprintf ("BOOT%s.EFI", efi_suffix_upper); } else { /* It is convenient for each architecture to have a different efi_file, so that different versions can be installed in parallel. */ - switch (platform) - { - case GRUB_INSTALL_PLATFORM_I386_EFI: - efi_file = "grubia32.efi"; - break; - case GRUB_INSTALL_PLATFORM_X86_64_EFI: - efi_file = "grubx64.efi"; - break; - case GRUB_INSTALL_PLATFORM_IA64_EFI: - efi_file = "grubia64.efi"; - break; - case GRUB_INSTALL_PLATFORM_ARM_EFI: - efi_file = "grubarm.efi"; - break; - case GRUB_INSTALL_PLATFORM_ARM64_EFI: - efi_file = "grubaa64.efi"; - break; - case GRUB_INSTALL_PLATFORM_RISCV32_EFI: - efi_file = "grubriscv32.efi"; - break; - case GRUB_INSTALL_PLATFORM_RISCV64_EFI: - efi_file = "grubriscv64.efi"; - break; - default: - efi_file = "grub.efi"; - break; - } + efi_file = xasprintf ("grub%s.efi", efi_suffix); } t = grub_util_path_concat (3, efidir, "EFI", efi_distributor); free (efidir); @@ -1367,14 +1387,51 @@ main (int argc, char *argv[]) } } - if (!have_abstractions) + char *efi_signed = NULL; + char *efi_unsigned = NULL; + switch (platform) + { + case GRUB_INSTALL_PLATFORM_I386_EFI: + case GRUB_INSTALL_PLATFORM_X86_64_EFI: + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: + { + char *dir = xasprintf ("%s-signed", grub_install_source_directory); + char *signed_image; + char *unsigned_image; + if (removable) + signed_image = xasprintf ("gcd%s.efi.signed", efi_suffix); + else + signed_image = xasprintf ("grub%s.efi.signed", efi_suffix); + efi_signed = grub_util_path_concat (2, dir, signed_image); + unsigned_image = xasprintf ("../../efi/grub%s.efi", efi_suffix); + efi_unsigned = grub_util_path_concat (2, grub_install_source_directory, + unsigned_image); + break; + } + + default: + break; + } + + if (!efi_signed || !grub_util_is_regular (efi_signed)) + if (efi_unsigned && grub_util_is_regular (efi_unsigned)) + efi_signed = efi_unsigned; + else + uefi_secure_boot = 0; + + /* alternative condition `|| uefi_secure_boot` breaks initial logic and + cryptomount command is not added when crypto_LUKS is used along with UEFI */ + if (!have_abstractions || uefi_secure_boot) { if ((disk_module && grub_strcmp (disk_module, "biosdisk") != 0) || grub_drives[1] || (!install_drive && platform != GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275) || (install_drive && !is_same_disk (grub_drives[0], install_drive)) - || !have_bootdev (platform)) + || !have_bootdev (platform) + || uefi_secure_boot) { char *uuid = NULL; /* generic method (used on coreboot and ata mod). */ @@ -1391,6 +1448,12 @@ main (int argc, char *argv[]) have_load_cfg = 1; if (uuid) { + /* add `cryptomount -u ` to /boot/efi/EFI//grub.cfg */ + if (config.is_cryptodisk_enabled && uefi_secure_boot && have_abstractions) + { + add_cryptomount(grub_dev, grub_drives); + } + prefix_drive = xasprintf ("(%s)", grub_drives[0]); fprintf (load_cfg_f, "search.fs_uuid %s root ", uuid); grub_install_push_module ("search_fs_uuid"); @@ -1530,18 +1593,7 @@ main (int argc, char *argv[]) { if (config.is_cryptodisk_enabled) { - if (grub_dev->disk) - probe_cryptodisk_uuid (grub_dev->disk); - - for (curdrive = grub_drives + 1; *curdrive; curdrive++) - { - grub_device_t dev = grub_device_open (*curdrive); - if (!dev) - continue; - if (dev->disk) - probe_cryptodisk_uuid (dev->disk); - grub_device_close (dev); - } + add_cryptomount(grub_dev, grub_drives); } prefix_drive = xasprintf ("(%s)", grub_drives[0]); } @@ -1902,7 +1954,71 @@ main (int argc, char *argv[]) case GRUB_INSTALL_PLATFORM_IA64_EFI: { char *dst = grub_util_path_concat (2, efidir, efi_file); - grub_install_copy_file (imgfile, dst, 1); + if (uefi_secure_boot) + { + char *shim_signed = NULL; + char *mok_signed = NULL, *mok_file = NULL; + char *fb_signed = NULL, *fb_file = NULL; + char *config_dst; + FILE *config_dst_f; + + shim_signed = xasprintf ("/usr/lib/shim/shim%s.efi.signed", efi_suffix); + mok_signed = xasprintf ("mm%s.efi.signed", efi_suffix); + mok_file = xasprintf ("mm%s.efi", efi_suffix); + fb_signed = xasprintf ("fb%s.efi.signed", efi_suffix); + fb_file = xasprintf ("fb%s.efi", efi_suffix); + + if (grub_util_is_regular (shim_signed)) + { + char *chained_base, *chained_dst; + char *mok_src, *mok_dst, *fb_src, *fb_dst; + if (!removable) + { + free (efi_file); + efi_file = xasprintf ("shim%s.efi", efi_suffix); + free (dst); + dst = grub_util_path_concat (2, efidir, efi_file); + } + grub_install_copy_file (shim_signed, dst, 1); + chained_base = xasprintf ("grub%s.efi", efi_suffix); + chained_dst = grub_util_path_concat (2, efidir, chained_base); + grub_install_copy_file (efi_signed, chained_dst, 1); + free (chained_dst); + free (chained_base); + + /* Not critical, so not an error if they are not present (as it + won't be for older releases); but if we have them, make + sure they are installed. */ + mok_src = grub_util_path_concat (2, "/usr/lib/shim/", + mok_signed); + mok_dst = grub_util_path_concat (2, efidir, + mok_file); + grub_install_copy_file (mok_src, + mok_dst, 0); + free (mok_src); + free (mok_dst); + + fb_src = grub_util_path_concat (2, "/usr/lib/shim/", + fb_signed); + fb_dst = grub_util_path_concat (2, efidir, + fb_file); + grub_install_copy_file (fb_src, + fb_dst, 0); + free (fb_src); + free (fb_dst); + } + else + grub_install_copy_file (efi_signed, dst, 1); + + config_dst = grub_util_path_concat (2, efidir, "grub.cfg"); + grub_install_copy_file (load_cfg, config_dst, 1); + config_dst_f = grub_util_fopen (config_dst, "ab"); + fprintf (config_dst_f, "configfile $prefix/grub.cfg\n"); + fclose (config_dst_f); + free (config_dst); + } + else + grub_install_copy_file (imgfile, dst, 1); grub_set_install_backup_ponr ();