diff --git a/0001-include-grub-i386-linux.h-Include-missing-grub-types.patch b/0001-include-grub-i386-linux.h-Include-missing-grub-types.patch new file mode 100644 index 0000000..be0c3f4 --- /dev/null +++ b/0001-include-grub-i386-linux.h-Include-missing-grub-types.patch @@ -0,0 +1,39 @@ +From f756ab3eac93346c3945eeb254773436ea3e1607 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Thu, 3 Dec 2020 16:01:43 +0100 +Subject: [PATCH 01/46] include/grub/i386/linux.h: Include missing + header +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This header uses types defined in but does not include it, +which leads to compile errors like the following: + +In file included from ../include/grub/cpu/linux.h:19, + from kern/efi/sb.c:21: +../include/grub/i386/linux.h:80:3: error: unknown type name ‘grub_uint64_t’ + 80 | grub_uint64_t addr; + +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + include/grub/i386/linux.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h +index ce30e7fb0..6da5f030f 100644 +--- a/include/grub/i386/linux.h ++++ b/include/grub/i386/linux.h +@@ -19,6 +19,8 @@ + #ifndef GRUB_I386_LINUX_HEADER + #define GRUB_I386_LINUX_HEADER 1 + ++#include ++ + #define GRUB_LINUX_I386_MAGIC_SIGNATURE 0x53726448 /* "HdrS" */ + #define GRUB_LINUX_DEFAULT_SETUP_SECTS 4 + #define GRUB_LINUX_INITRD_MAX_ADDRESS 0x37FFFFFF +-- +2.26.2 + diff --git a/0001-linuxefi-fail-kernel-validation-without-shim-protoco.patch b/0001-linuxefi-fail-kernel-validation-without-shim-protoco.patch deleted file mode 100644 index 2400a54..0000000 --- a/0001-linuxefi-fail-kernel-validation-without-shim-protoco.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 1b4f4b2f5cd9b804a5bb66861b659d05d9a4f35a Mon Sep 17 00:00:00 2001 -From: Michael Chang -Date: Mon, 17 Aug 2020 17:09:01 +0800 -Subject: [PATCH 1/2] linuxefi: fail kernel validation without shim protocol. - -If certificates that signed grub are installed into db, grub can be -booted directly. It will then boot any kernel without signature -validation. The booted kernel will think it was booted in secureboot -mode and will implement lockdown, yet it could have been tampered. - -This version of the patch skips calling verification, when booted -without secureboot. - -CVE-2020-15705 - -Reported-by: Mathieu Trudel-Lapierre -Also-by: Dimitri John Ledkov -Signed-off-by: Michael Chang ---- - grub-core/loader/i386/efi/linux.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c -index 61b2d5177..8017e8c05 100644 ---- a/grub-core/loader/i386/efi/linux.c -+++ b/grub-core/loader/i386/efi/linux.c -@@ -172,6 +172,23 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - goto fail; - } - -+ if (grub_efi_secure_boot()) -+ { -+ grub_dl_t mod; -+ -+ mod = grub_dl_get ("shim_lock"); -+ if (!mod) -+ { -+ grub_error (GRUB_ERR_ACCESS_DENIED, N_("shim_lock module is not loaded")); -+ goto fail; -+ } -+ if (!grub_dl_is_persistent (mod)) -+ { -+ grub_error (GRUB_ERR_ACCESS_DENIED, N_("shim_lock protocol is not available")); -+ goto fail; -+ } -+ } -+ - file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); - if (! file) - goto fail; --- -2.26.2 - diff --git a/0001-shim_lock-Disable-GRUB_VERIFY_FLAGS_DEFER_AUTH-if-se.patch b/0001-shim_lock-Disable-GRUB_VERIFY_FLAGS_DEFER_AUTH-if-se.patch deleted file mode 100644 index f1c6f2e..0000000 --- a/0001-shim_lock-Disable-GRUB_VERIFY_FLAGS_DEFER_AUTH-if-se.patch +++ /dev/null @@ -1,41 +0,0 @@ -From a60cfeacdeefb21215d35c4cad025e57de900352 Mon Sep 17 00:00:00 2001 -From: Michael Chang -Date: Thu, 27 Aug 2020 13:18:25 +0800 -Subject: [PATCH] shim_lock: Disable GRUB_VERIFY_FLAGS_DEFER_AUTH if secure - boot off - -The GRUB_VERIFY_FLAGS_DEFER_AUTH is enabled regardless secure boot -status that will cause error [1] on loading external grub modules if -secure boot turned off in which shim protocol itself did not verify -images so should not request verification for external modules either. - -This patch fixed the problem by adding the secure boot status check -before requesting other verifiers to verify external module, therefore -external module loading can work after shim_lock module loaded and -secure boot turned off. - -[1] error: verification requested but nobody cares: -(hd0,gpt10)/boot/grub2/x86_64-efi/linux.mod. - -Signed-off-by: Michael Chang ---- - grub-core/commands/efi/shim_lock.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/grub-core/commands/efi/shim_lock.c b/grub-core/commands/efi/shim_lock.c -index 764098cfc..18d121297 100644 ---- a/grub-core/commands/efi/shim_lock.c -+++ b/grub-core/commands/efi/shim_lock.c -@@ -82,7 +82,8 @@ shim_lock_init (grub_file_t io, enum grub_file_type type, - - case GRUB_FILE_TYPE_ACPI_TABLE: - case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE: -- *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH; -+ if (grub_efi_secure_boot()) -+ *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH; - - return GRUB_ERR_NONE; - --- -2.26.2 - diff --git a/0002-efi-Make-shim_lock-GUID-and-protocol-type-public.patch b/0002-efi-Make-shim_lock-GUID-and-protocol-type-public.patch new file mode 100644 index 0000000..c629230 --- /dev/null +++ b/0002-efi-Make-shim_lock-GUID-and-protocol-type-public.patch @@ -0,0 +1,96 @@ +From 3b60f205de1450ed6bbe8655bfb59ea0dac4ad78 Mon Sep 17 00:00:00 2001 +From: Daniel Kiper +Date: Thu, 3 Dec 2020 16:01:45 +0100 +Subject: [PATCH 02/46] efi: Make shim_lock GUID and protocol type public + +The GUID will be used to properly detect and report UEFI Secure Boot +status to the x86 Linux kernel. The functionality will be added by +subsequent patches. The shim_lock protocol type is made public for +completeness. + +Additionally, fix formatting of four preceding GUIDs. + +Signed-off-by: Daniel Kiper +Signed-off-by: Marco A Benatto +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/commands/efi/shim_lock.c | 12 ------------ + include/grub/efi/api.h | 19 +++++++++++++++---- + 2 files changed, 15 insertions(+), 16 deletions(-) + +diff --git a/grub-core/commands/efi/shim_lock.c b/grub-core/commands/efi/shim_lock.c +index 764098cfc..d8f52d721 100644 +--- a/grub-core/commands/efi/shim_lock.c ++++ b/grub-core/commands/efi/shim_lock.c +@@ -27,18 +27,6 @@ + + GRUB_MOD_LICENSE ("GPLv3+"); + +-#define GRUB_EFI_SHIM_LOCK_GUID \ +- { 0x605dab50, 0xe046, 0x4300, \ +- { 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 } \ +- } +- +-struct grub_efi_shim_lock_protocol +-{ +- grub_efi_status_t +- (*verify) (void *buffer, grub_uint32_t size); +-}; +-typedef struct grub_efi_shim_lock_protocol grub_efi_shim_lock_protocol_t; +- + static grub_efi_guid_t shim_lock_guid = GRUB_EFI_SHIM_LOCK_GUID; + static grub_efi_shim_lock_protocol_t *sl; + +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index 21efee3f3..b5cef9a88 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -316,22 +316,27 @@ + + #define GRUB_EFI_SAL_TABLE_GUID \ + { 0xeb9d2d32, 0x2d88, 0x11d3, \ +- { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ ++ { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + + #define GRUB_EFI_HCDP_TABLE_GUID \ + { 0xf951938d, 0x620b, 0x42ef, \ +- { 0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98 } \ ++ { 0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98 } \ + } + + #define GRUB_EFI_DEVICE_TREE_GUID \ + { 0xb1b621d5, 0xf19c, 0x41a5, \ +- { 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0 } \ ++ { 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0 } \ + } + + #define GRUB_EFI_VENDOR_APPLE_GUID \ + { 0x2B0585EB, 0xD8B8, 0x49A9, \ +- { 0x8B, 0x8C, 0xE2, 0x1B, 0x01, 0xAE, 0xF2, 0xB7 } \ ++ { 0x8B, 0x8C, 0xE2, 0x1B, 0x01, 0xAE, 0xF2, 0xB7 } \ ++ } ++ ++#define GRUB_EFI_SHIM_LOCK_GUID \ ++ { 0x605dab50, 0xe046, 0x4300, \ ++ { 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 } \ + } + + #define GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID \ +@@ -1970,6 +1975,12 @@ struct grub_efi_ip6_config_manual_address { + }; + typedef struct grub_efi_ip6_config_manual_address grub_efi_ip6_config_manual_address_t; + ++struct grub_efi_shim_lock_protocol ++{ ++ grub_efi_status_t (*verify) (void *buffer, grub_uint32_t size); ++}; ++typedef struct grub_efi_shim_lock_protocol grub_efi_shim_lock_protocol_t; ++ + #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \ + || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \ + || defined(__riscv) +-- +2.26.2 + diff --git a/0003-efi-Return-grub_efi_status_t-from-grub_efi_get_varia.patch b/0003-efi-Return-grub_efi_status_t-from-grub_efi_get_varia.patch new file mode 100644 index 0000000..fc84360 --- /dev/null +++ b/0003-efi-Return-grub_efi_status_t-from-grub_efi_get_varia.patch @@ -0,0 +1,146 @@ +From 10ee52fd565c9a88d9428a837c7f753a6c7fac5b Mon Sep 17 00:00:00 2001 +From: Daniel Kiper +Date: Thu, 3 Dec 2020 16:01:46 +0100 +Subject: [PATCH 03/46] efi: Return grub_efi_status_t from + grub_efi_get_variable() + +This is needed to properly detect and report UEFI Secure Boot status +to the x86 Linux kernel. The functionality will be added by subsequent +patches. + +Signed-off-by: Daniel Kiper +Signed-off-by: Marco A Benatto +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/commands/efi/efifwsetup.c | 8 ++++---- + grub-core/kern/efi/efi.c | 16 +++++++++------- + grub-core/video/efi_gop.c | 2 +- + include/grub/efi/efi.h | 7 ++++--- + 4 files changed, 18 insertions(+), 15 deletions(-) + +diff --git a/grub-core/commands/efi/efifwsetup.c b/grub-core/commands/efi/efifwsetup.c +index 7a137a72a..eaca03283 100644 +--- a/grub-core/commands/efi/efifwsetup.c ++++ b/grub-core/commands/efi/efifwsetup.c +@@ -38,8 +38,8 @@ grub_cmd_fwsetup (grub_command_t cmd __attribute__ ((unused)), + grub_size_t oi_size; + grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID; + +- old_os_indications = grub_efi_get_variable ("OsIndications", &global, +- &oi_size); ++ grub_efi_get_variable ("OsIndications", &global, &oi_size, ++ (void **) &old_os_indications); + + if (old_os_indications != NULL && oi_size == sizeof (os_indications)) + os_indications |= *old_os_indications; +@@ -63,8 +63,8 @@ efifwsetup_is_supported (void) + grub_size_t oi_size = 0; + grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID; + +- os_indications_supported = grub_efi_get_variable ("OsIndicationsSupported", +- &global, &oi_size); ++ grub_efi_get_variable ("OsIndicationsSupported", &global, &oi_size, ++ (void **) &os_indications_supported); + + if (!os_indications_supported) + return 0; +diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c +index 02d298b0c..9fd136694 100644 +--- a/grub-core/kern/efi/efi.c ++++ b/grub-core/kern/efi/efi.c +@@ -222,9 +222,9 @@ grub_efi_set_variable(const char *var, const grub_efi_guid_t *guid, + return grub_error (GRUB_ERR_IO, "could not set EFI variable `%s'", var); + } + +-void * ++grub_efi_status_t + grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid, +- grub_size_t *datasize_out) ++ grub_size_t *datasize_out, void **data_out) + { + grub_efi_status_t status; + grub_efi_uintn_t datasize = 0; +@@ -233,13 +233,14 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid, + void *data; + grub_size_t len, len16; + ++ *data_out = NULL; + *datasize_out = 0; + + len = grub_strlen (var); + len16 = len * GRUB_MAX_UTF16_PER_UTF8; + var16 = grub_calloc (len16 + 1, sizeof (var16[0])); + if (!var16) +- return NULL; ++ return GRUB_EFI_OUT_OF_RESOURCES; + len16 = grub_utf8_to_utf16 (var16, len16, (grub_uint8_t *) var, len, NULL); + var16[len16] = 0; + +@@ -250,14 +251,14 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid, + if (status != GRUB_EFI_BUFFER_TOO_SMALL || !datasize) + { + grub_free (var16); +- return NULL; ++ return status; + } + + data = grub_malloc (datasize); + if (!data) + { + grub_free (var16); +- return NULL; ++ return GRUB_EFI_OUT_OF_RESOURCES; + } + + status = efi_call_5 (r->get_variable, var16, guid, NULL, &datasize, data); +@@ -265,12 +266,13 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid, + + if (status == GRUB_EFI_SUCCESS) + { ++ *data_out = data; + *datasize_out = datasize; +- return data; ++ return status; + } + + grub_free (data); +- return NULL; ++ return status; + } + + grub_efi_boolean_t +diff --git a/grub-core/video/efi_gop.c b/grub-core/video/efi_gop.c +index df29853f0..962f0eb8f 100644 +--- a/grub-core/video/efi_gop.c ++++ b/grub-core/video/efi_gop.c +@@ -310,7 +310,7 @@ grub_video_gop_get_edid (struct grub_video_edid_info *edid_info) + char edidname[] = "agp-internal-edid"; + grub_size_t datasize; + grub_uint8_t *data; +- data = grub_efi_get_variable (edidname, &efi_var_guid, &datasize); ++ grub_efi_get_variable (edidname, &efi_var_guid, &datasize, (void **) &data); + if (data && datasize > 16) + { + copy_size = datasize - 16; +diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h +index 085ee0524..f27d3a365 100644 +--- a/include/grub/efi/efi.h ++++ b/include/grub/efi/efi.h +@@ -77,9 +77,10 @@ grub_err_t EXPORT_FUNC (grub_efi_set_virtual_address_map) (grub_efi_uintn_t memo + grub_efi_uintn_t descriptor_size, + grub_efi_uint32_t descriptor_version, + grub_efi_memory_descriptor_t *virtual_map); +-void *EXPORT_FUNC (grub_efi_get_variable) (const char *variable, +- const grub_efi_guid_t *guid, +- grub_size_t *datasize_out); ++grub_efi_status_t EXPORT_FUNC (grub_efi_get_variable) (const char *variable, ++ const grub_efi_guid_t *guid, ++ grub_size_t *datasize_out, ++ void **data_out); + grub_err_t + EXPORT_FUNC (grub_efi_set_variable) (const char *var, + const grub_efi_guid_t *guid, +-- +2.26.2 + diff --git a/0004-efi-Add-a-function-to-read-EFI-variables-with-attrib.patch b/0004-efi-Add-a-function-to-read-EFI-variables-with-attrib.patch new file mode 100644 index 0000000..282d414 --- /dev/null +++ b/0004-efi-Add-a-function-to-read-EFI-variables-with-attrib.patch @@ -0,0 +1,79 @@ +From 5f2d71f71bc62c5cffbe27a9ee247803a77dc032 Mon Sep 17 00:00:00 2001 +From: Daniel Kiper +Date: Thu, 3 Dec 2020 16:01:47 +0100 +Subject: [PATCH 04/46] efi: Add a function to read EFI variables with + attributes + +It will be used to properly detect and report UEFI Secure Boot status to +the x86 Linux kernel. The functionality will be added by subsequent patches. + +Signed-off-by: Ignat Korchagin +Signed-off-by: Daniel Kiper +Signed-off-by: Marco A Benatto +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/kern/efi/efi.c | 16 +++++++++++++--- + include/grub/efi/efi.h | 5 +++++ + 2 files changed, 18 insertions(+), 3 deletions(-) + +diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c +index 9fd136694..92e99b441 100644 +--- a/grub-core/kern/efi/efi.c ++++ b/grub-core/kern/efi/efi.c +@@ -223,8 +223,11 @@ grub_efi_set_variable(const char *var, const grub_efi_guid_t *guid, + } + + grub_efi_status_t +-grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid, +- grub_size_t *datasize_out, void **data_out) ++grub_efi_get_variable_with_attributes (const char *var, ++ const grub_efi_guid_t *guid, ++ grub_size_t *datasize_out, ++ void **data_out, ++ grub_efi_uint32_t *attributes) + { + grub_efi_status_t status; + grub_efi_uintn_t datasize = 0; +@@ -261,7 +264,7 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid, + return GRUB_EFI_OUT_OF_RESOURCES; + } + +- status = efi_call_5 (r->get_variable, var16, guid, NULL, &datasize, data); ++ status = efi_call_5 (r->get_variable, var16, guid, attributes, &datasize, data); + grub_free (var16); + + if (status == GRUB_EFI_SUCCESS) +@@ -303,6 +306,13 @@ grub_efi_secure_boot (void) + return ret; + } + ++grub_efi_status_t ++grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid, ++ grub_size_t *datasize_out, void **data_out) ++{ ++ return grub_efi_get_variable_with_attributes (var, guid, datasize_out, data_out, NULL); ++} ++ + #pragma GCC diagnostic ignored "-Wcast-align" + + /* Search the mods section from the PE32/PE32+ image. This code uses +diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h +index f27d3a365..568d80030 100644 +--- a/include/grub/efi/efi.h ++++ b/include/grub/efi/efi.h +@@ -77,6 +77,11 @@ grub_err_t EXPORT_FUNC (grub_efi_set_virtual_address_map) (grub_efi_uintn_t memo + grub_efi_uintn_t descriptor_size, + grub_efi_uint32_t descriptor_version, + grub_efi_memory_descriptor_t *virtual_map); ++grub_efi_status_t EXPORT_FUNC (grub_efi_get_variable_with_attributes) (const char *variable, ++ const grub_efi_guid_t *guid, ++ grub_size_t *datasize_out, ++ void **data_out, ++ grub_efi_uint32_t *attributes); + grub_efi_status_t EXPORT_FUNC (grub_efi_get_variable) (const char *variable, + const grub_efi_guid_t *guid, + grub_size_t *datasize_out, +-- +2.26.2 + diff --git a/0005-efi-Add-secure-boot-detection.patch b/0005-efi-Add-secure-boot-detection.patch new file mode 100644 index 0000000..e7f2550 --- /dev/null +++ b/0005-efi-Add-secure-boot-detection.patch @@ -0,0 +1,210 @@ +From 12650d0953372674fb587c2e6331257fc7a90a94 Mon Sep 17 00:00:00 2001 +From: Daniel Kiper +Date: Thu, 3 Dec 2020 16:01:48 +0100 +Subject: [PATCH 05/46] efi: Add secure boot detection + +Introduce grub_efi_get_secureboot() function which returns whether +UEFI Secure Boot is enabled or not on UEFI systems. + +Signed-off-by: Ignat Korchagin +Signed-off-by: Daniel Kiper +Signed-off-by: Marco A Benatto +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/Makefile.am | 1 + + grub-core/Makefile.core.def | 1 + + grub-core/kern/efi/sb.c | 109 ++++++++++++++++++++++++++++++++++++ + include/grub/efi/sb.h | 40 +++++++++++++ + 4 files changed, 151 insertions(+) + create mode 100644 grub-core/kern/efi/sb.c + create mode 100644 include/grub/efi/sb.h + +diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am +index ede596170..5ff3afd62 100644 +--- a/grub-core/Makefile.am ++++ b/grub-core/Makefile.am +@@ -71,6 +71,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/command.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/device.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/disk.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/dl.h ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/sb.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/env.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/env_private.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/err.h +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index ce4f71ebe..072b1628c 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -203,6 +203,7 @@ kernel = { + efi = term/efi/console.c; + efi = kern/acpi.c; + efi = kern/efi/acpi.c; ++ efi = kern/efi/sb.c; + i386_coreboot = kern/i386/pc/acpi.c; + i386_multiboot = kern/i386/pc/acpi.c; + i386_coreboot = kern/acpi.c; +diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c +new file mode 100644 +index 000000000..19658d962 +--- /dev/null ++++ b/grub-core/kern/efi/sb.c +@@ -0,0 +1,109 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ * ++ * UEFI Secure Boot related checkings. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * Determine whether we're in secure boot mode. ++ * ++ * Please keep the logic in sync with the Linux kernel, ++ * drivers/firmware/efi/libstub/secureboot.c:efi_get_secureboot(). ++ */ ++grub_uint8_t ++grub_efi_get_secureboot (void) ++{ ++ static grub_efi_guid_t efi_variable_guid = GRUB_EFI_GLOBAL_VARIABLE_GUID; ++ static grub_efi_guid_t efi_shim_lock_guid = GRUB_EFI_SHIM_LOCK_GUID; ++ grub_efi_status_t status; ++ grub_efi_uint32_t attr = 0; ++ grub_size_t size = 0; ++ grub_uint8_t *secboot = NULL; ++ grub_uint8_t *setupmode = NULL; ++ grub_uint8_t *moksbstate = NULL; ++ grub_uint8_t secureboot = GRUB_EFI_SECUREBOOT_MODE_UNKNOWN; ++ const char *secureboot_str = "UNKNOWN"; ++ ++ status = grub_efi_get_variable ("SecureBoot", &efi_variable_guid, ++ &size, (void **) &secboot); ++ ++ if (status == GRUB_EFI_NOT_FOUND) ++ { ++ secureboot = GRUB_EFI_SECUREBOOT_MODE_DISABLED; ++ goto out; ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ goto out; ++ ++ status = grub_efi_get_variable ("SetupMode", &efi_variable_guid, ++ &size, (void **) &setupmode); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ goto out; ++ ++ if ((*secboot == 0) || (*setupmode == 1)) ++ { ++ secureboot = GRUB_EFI_SECUREBOOT_MODE_DISABLED; ++ goto out; ++ } ++ ++ /* ++ * See if a user has put the shim into insecure mode. If so, and if the ++ * variable doesn't have the runtime attribute set, we might as well ++ * honor that. ++ */ ++ status = grub_efi_get_variable_with_attributes ("MokSBState", &efi_shim_lock_guid, ++ &size, (void **) &moksbstate, &attr); ++ ++ /* If it fails, we don't care why. Default to secure. */ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ secureboot = GRUB_EFI_SECUREBOOT_MODE_ENABLED; ++ goto out; ++ } ++ ++ if (!(attr & GRUB_EFI_VARIABLE_RUNTIME_ACCESS) && *moksbstate == 1) ++ { ++ secureboot = GRUB_EFI_SECUREBOOT_MODE_DISABLED; ++ goto out; ++ } ++ ++ secureboot = GRUB_EFI_SECUREBOOT_MODE_ENABLED; ++ ++ out: ++ grub_free (moksbstate); ++ grub_free (setupmode); ++ grub_free (secboot); ++ ++ if (secureboot == GRUB_EFI_SECUREBOOT_MODE_DISABLED) ++ secureboot_str = "Disabled"; ++ else if (secureboot == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ secureboot_str = "Enabled"; ++ ++ grub_dprintf ("efi", "UEFI Secure Boot state: %s\n", secureboot_str); ++ ++ return secureboot; ++} +diff --git a/include/grub/efi/sb.h b/include/grub/efi/sb.h +new file mode 100644 +index 000000000..a33d985e3 +--- /dev/null ++++ b/include/grub/efi/sb.h +@@ -0,0 +1,40 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_EFI_SB_H ++#define GRUB_EFI_SB_H 1 ++ ++#include ++#include ++ ++#define GRUB_EFI_SECUREBOOT_MODE_UNSET 0 ++#define GRUB_EFI_SECUREBOOT_MODE_UNKNOWN 1 ++#define GRUB_EFI_SECUREBOOT_MODE_DISABLED 2 ++#define GRUB_EFI_SECUREBOOT_MODE_ENABLED 3 ++ ++#ifdef GRUB_MACHINE_EFI ++extern grub_uint8_t ++EXPORT_FUNC (grub_efi_get_secureboot) (void); ++#else ++static inline grub_uint8_t ++grub_efi_get_secureboot (void) ++{ ++ return GRUB_EFI_SECUREBOOT_MODE_UNSET; ++} ++#endif ++#endif /* GRUB_EFI_SB_H */ +-- +2.26.2 + diff --git a/0006-efi-Only-register-shim_lock-verifier-if-shim_lock-pr.patch b/0006-efi-Only-register-shim_lock-verifier-if-shim_lock-pr.patch new file mode 100644 index 0000000..f9f8663 --- /dev/null +++ b/0006-efi-Only-register-shim_lock-verifier-if-shim_lock-pr.patch @@ -0,0 +1,90 @@ +From a0659724e8fb6ddc9b6db68973e50637cf781605 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Thu, 3 Dec 2020 16:01:49 +0100 +Subject: [PATCH 06/46] efi: Only register shim_lock verifier if shim_lock + protocol is found and SB enabled + +The shim_lock module registers a verifier to call shim's verify, but the +handler is registered even when the shim_lock protocol was not installed. + +This doesn't cause a NULL pointer dereference in shim_lock_write() because +the shim_lock_init() function just returns GRUB_ERR_NONE if sl isn't set. + +But in that case there's no point to even register the shim_lock verifier +since won't do anything. Additionally, it is only useful when Secure Boot +is enabled. + +Finally, don't assume that the shim_lock protocol will always be present +when the shim_lock_write() function is called, and check for it on every +call to this function. + +Reported-by: Michael Chang +Reported-by: Peter Jones +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/commands/efi/shim_lock.c | 17 ++++++++++------- + 1 file changed, 10 insertions(+), 7 deletions(-) + +diff --git a/grub-core/commands/efi/shim_lock.c b/grub-core/commands/efi/shim_lock.c +index d8f52d721..f7f3109d6 100644 +--- a/grub-core/commands/efi/shim_lock.c ++++ b/grub-core/commands/efi/shim_lock.c +@@ -20,6 +20,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -28,7 +29,6 @@ + GRUB_MOD_LICENSE ("GPLv3+"); + + static grub_efi_guid_t shim_lock_guid = GRUB_EFI_SHIM_LOCK_GUID; +-static grub_efi_shim_lock_protocol_t *sl; + + /* List of modules which cannot be loaded if UEFI secure boot mode is enabled. */ + static const char * const disabled_mods[] = {"iorw", "memrw", "wrmsr", NULL}; +@@ -43,9 +43,6 @@ shim_lock_init (grub_file_t io, enum grub_file_type type, + + *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; + +- if (!sl) +- return GRUB_ERR_NONE; +- + switch (type & GRUB_FILE_TYPE_MASK) + { + case GRUB_FILE_TYPE_GRUB_MODULE: +@@ -100,6 +97,11 @@ shim_lock_init (grub_file_t io, enum grub_file_type type, + static grub_err_t + shim_lock_write (void *context __attribute__ ((unused)), void *buf, grub_size_t size) + { ++ grub_efi_shim_lock_protocol_t *sl = grub_efi_locate_protocol (&shim_lock_guid, 0); ++ ++ if (sl == NULL) ++ return grub_error (GRUB_ERR_ACCESS_DENIED, N_("shim_lock protocol not found")); ++ + if (sl->verify (buf, size) != GRUB_EFI_SUCCESS) + return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad shim signature")); + +@@ -115,12 +117,13 @@ struct grub_file_verifier shim_lock = + + GRUB_MOD_INIT(shim_lock) + { +- sl = grub_efi_locate_protocol (&shim_lock_guid, 0); +- grub_verifier_register (&shim_lock); ++ grub_efi_shim_lock_protocol_t *sl = grub_efi_locate_protocol (&shim_lock_guid, 0); + +- if (!sl) ++ if (sl == NULL || grub_efi_get_secureboot () != GRUB_EFI_SECUREBOOT_MODE_ENABLED) + return; + ++ grub_verifier_register (&shim_lock); ++ + grub_dl_set_persistent (mod); + } + +-- +2.26.2 + diff --git a/0007-linuxefi-fail-kernel-validation-without-shim-protoco.patch b/0007-linuxefi-fail-kernel-validation-without-shim-protoco.patch deleted file mode 100644 index 26f193a..0000000 --- a/0007-linuxefi-fail-kernel-validation-without-shim-protoco.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 496890ebd2605eb1ff15f8d96c30b5d617f1bb85 Mon Sep 17 00:00:00 2001 -From: Michael Chang -Date: Fri, 6 Nov 2020 11:19:06 +0000 -Subject: [PATCH 7/9] linuxefi: fail kernel validation without shim protocol. - -If certificates that signed grub are installed into db, grub can be -booted directly. It will then boot any kernel without signature -validation. The booted kernel will think it was booted in secureboot -mode and will implement lockdown, yet it could have been tampered. - -This version of the patch skips calling verification, when booted -without secureboot. And is indented with gnu ident. - -CVE-2020-15705 - -Reported-by: Mathieu Trudel-Lapierre -Signed-off-by: Michael Chang ---- - grub-core/loader/arm64/efi/linux.c | 38 +++++++++++++++++++++++------- - 1 file changed, 29 insertions(+), 9 deletions(-) - -diff --git a/grub-core/loader/arm64/efi/linux.c b/grub-core/loader/arm64/efi/linux.c -index a4041be5c..0e5782caa 100644 ---- a/grub-core/loader/arm64/efi/linux.c -+++ b/grub-core/loader/arm64/efi/linux.c -@@ -58,21 +58,35 @@ struct grub_efi_shim_lock - }; - typedef struct grub_efi_shim_lock grub_efi_shim_lock_t; - --static grub_efi_boolean_t -+// Returns 1 on success, -1 on error, 0 when not available -+static int - grub_linuxefi_secure_validate (void *data, grub_uint32_t size) - { - grub_efi_guid_t guid = SHIM_LOCK_GUID; - grub_efi_shim_lock_t *shim_lock; -+ grub_efi_status_t status; - - shim_lock = grub_efi_locate_protocol(&guid, NULL); -- -+ grub_dprintf ("secureboot", "shim_lock: %p\n", shim_lock); - if (!shim_lock) -- return 1; -+ { -+ grub_dprintf ("secureboot", "shim not available\n"); -+ return 0; -+ } - -- if (shim_lock->verify(data, size) == GRUB_EFI_SUCCESS) -- return 1; -+ grub_dprintf ("secureboot", "Asking shim to verify kernel signature\n"); -+ status = shim_lock->verify (data, size); -+ grub_dprintf ("secureboot", "shim_lock->verify(): %ld\n", (long int)status); -+ if (status == GRUB_EFI_SUCCESS) -+ { -+ grub_dprintf ("secureboot", "Kernel signature verification passed\n"); -+ return 1; -+ } - -- return 0; -+ grub_dprintf ("secureboot", "Kernel signature verification failed (0x%lx)\n", -+ (unsigned long) status); -+ -+ return -1; - } - - #pragma GCC diagnostic push -@@ -399,6 +413,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - struct linux_arch_kernel_header lh; - struct grub_armxx_linux_pe_header *pe; - grub_err_t err; -+ int rc; - - grub_dl_ref (my_mod); - -@@ -443,10 +458,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - - grub_dprintf ("linux", "kernel @ %p\n", kernel_addr); - -- if (!grub_linuxefi_secure_validate (kernel_addr, kernel_size)) -+ if (grub_efi_secure_boot ()) - { -- grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]); -- goto fail; -+ rc = grub_linuxefi_secure_validate (kernel_addr, kernel_size); -+ if (rc <= 0) -+ { -+ grub_error (GRUB_ERR_INVALID_COMMAND, -+ N_("%s has invalid signature"), argv[0]); -+ goto fail; -+ } - } - - pe = (void *)((unsigned long)kernel_addr + lh.hdr_offset); --- -2.26.2 - diff --git a/0007-verifiers-Move-verifiers-API-to-kernel-image.patch b/0007-verifiers-Move-verifiers-API-to-kernel-image.patch new file mode 100644 index 0000000..bad1957 --- /dev/null +++ b/0007-verifiers-Move-verifiers-API-to-kernel-image.patch @@ -0,0 +1,129 @@ +From ea5950d8597278ba9066f24d7abcee403f825668 Mon Sep 17 00:00:00 2001 +From: Marco A Benatto +Date: Wed, 23 Sep 2020 11:33:33 -0400 +Subject: [PATCH 07/46] verifiers: Move verifiers API to kernel image + +Move verifiers API from a module to the kernel image, so it can be +used there as well. There are no functional changes in this patch. + +Signed-off-by: Marco A Benatto +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/Makefile.am | 1 + + grub-core/Makefile.core.def | 6 +----- + grub-core/kern/main.c | 4 ++++ + grub-core/{commands => kern}/verifiers.c | 8 ++------ + include/grub/verify.h | 9 ++++++--- + 5 files changed, 14 insertions(+), 14 deletions(-) + rename grub-core/{commands => kern}/verifiers.c (97%) + +diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am +index 5ff3afd62..3569b7101 100644 +--- a/grub-core/Makefile.am ++++ b/grub-core/Makefile.am +@@ -91,6 +91,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/parser.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/partition.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/term.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/time.h ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/verify.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm_private.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/net.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/memory.h +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 072b1628c..5cb869f5b 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -140,6 +140,7 @@ kernel = { + common = kern/rescue_parser.c; + common = kern/rescue_reader.c; + common = kern/term.c; ++ common = kern/verifiers.c; + + noemu = kern/compiler-rt.c; + noemu = kern/mm.c; +@@ -943,11 +944,6 @@ module = { + cppflags = '-I$(srcdir)/lib/posix_wrap'; + }; + +-module = { +- name = verifiers; +- common = commands/verifiers.c; +-}; +- + module = { + name = shim_lock; + common = commands/efi/shim_lock.c; +diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c +index 9cad0c448..73967e2f5 100644 +--- a/grub-core/kern/main.c ++++ b/grub-core/kern/main.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + + #ifdef GRUB_MACHINE_PCBIOS + #include +@@ -274,6 +275,9 @@ grub_main (void) + grub_printf ("Welcome to GRUB!\n\n"); + grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); + ++ /* Init verifiers API. */ ++ grub_verifiers_init (); ++ + grub_load_config (); + + grub_boot_time ("Before loading embedded modules."); +diff --git a/grub-core/commands/verifiers.c b/grub-core/kern/verifiers.c +similarity index 97% +rename from grub-core/commands/verifiers.c +rename to grub-core/kern/verifiers.c +index 7b9297cd3..3d19bffd1 100644 +--- a/grub-core/commands/verifiers.c ++++ b/grub-core/kern/verifiers.c +@@ -218,12 +218,8 @@ grub_verify_string (char *str, enum grub_verify_string_type type) + return GRUB_ERR_NONE; + } + +-GRUB_MOD_INIT(verifiers) ++void ++grub_verifiers_init (void) + { + grub_file_filter_register (GRUB_FILE_FILTER_VERIFY, grub_verifiers_open); + } +- +-GRUB_MOD_FINI(verifiers) +-{ +- grub_file_filter_unregister (GRUB_FILE_FILTER_VERIFY); +-} +diff --git a/include/grub/verify.h b/include/grub/verify.h +index ea0491433..cd129c398 100644 +--- a/include/grub/verify.h ++++ b/include/grub/verify.h +@@ -64,7 +64,10 @@ struct grub_file_verifier + grub_err_t (*verify_string) (char *str, enum grub_verify_string_type type); + }; + +-extern struct grub_file_verifier *grub_file_verifiers; ++extern struct grub_file_verifier *EXPORT_VAR (grub_file_verifiers); ++ ++extern void ++grub_verifiers_init (void); + + static inline void + grub_verifier_register (struct grub_file_verifier *ver) +@@ -78,7 +81,7 @@ grub_verifier_unregister (struct grub_file_verifier *ver) + grub_list_remove (GRUB_AS_LIST (ver)); + } + +-grub_err_t +-grub_verify_string (char *str, enum grub_verify_string_type type); ++extern grub_err_t ++EXPORT_FUNC (grub_verify_string) (char *str, enum grub_verify_string_type type); + + #endif /* ! GRUB_VERIFY_HEADER */ +-- +2.26.2 + diff --git a/0008-efi-Move-the-shim_lock-verifier-to-the-GRUB-core.patch b/0008-efi-Move-the-shim_lock-verifier-to-the-GRUB-core.patch new file mode 100644 index 0000000..7b06143 --- /dev/null +++ b/0008-efi-Move-the-shim_lock-verifier-to-the-GRUB-core.patch @@ -0,0 +1,368 @@ +From b16919b634129e377431e96bc3252179fed83a40 Mon Sep 17 00:00:00 2001 +From: Marco A Benatto +Date: Wed, 23 Sep 2020 14:21:14 -0400 +Subject: [PATCH 08/46] efi: Move the shim_lock verifier to the GRUB core + +Move the shim_lock verifier from its own module into the core image. The +Secure Boot lockdown mechanism has the intent to prevent the load of any +unsigned code or binary when Secure Boot is enabled. + +The reason is that GRUB must be able to prevent executing untrusted code +if UEFI Secure Boot is enabled, without depending on external modules. + +Signed-off-by: Marco A Benatto +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + docs/grub.texi | 9 +- + grub-core/Makefile.core.def | 6 -- + grub-core/commands/efi/shim_lock.c | 133 ----------------------------- + grub-core/kern/efi/init.c | 4 + + grub-core/kern/efi/sb.c | 105 +++++++++++++++++++++++ + include/grub/efi/sb.h | 3 + + 6 files changed, 117 insertions(+), 143 deletions(-) + delete mode 100644 grub-core/commands/efi/shim_lock.c + +diff --git a/docs/grub.texi b/docs/grub.texi +index bd0e02057..d3fbc81db 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -5764,15 +5764,16 @@ secure boot chain. + @section UEFI secure boot and shim support + + The GRUB, except the @command{chainloader} command, works with the UEFI secure +-boot and the shim. This functionality is provided by the shim_lock module. It +-is recommend to build in this and other required modules into the @file{core.img}. ++boot and the shim. This functionality is provided by the shim_lock verifier. It ++is built into the @file{core.img} and is registered if the UEFI secure boot is ++enabled. ++ + All modules not stored in the @file{core.img} and the ACPI tables for the + @command{acpi} command have to be signed, e.g. using PGP. Additionally, the + @command{iorw}, the @command{memrw} and the @command{wrmsr} commands are + prohibited if the UEFI secure boot is enabled. This is done due to + security reasons. All above mentioned requirements are enforced by the +-shim_lock module. And itself it is a persistent module which means that +-it cannot be unloaded if it was loaded into the memory. ++shim_lock verifier logic. + + @node Measured Boot + @section Measuring boot components +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 5cb869f5b..8c8f8c579 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -944,12 +944,6 @@ module = { + cppflags = '-I$(srcdir)/lib/posix_wrap'; + }; + +-module = { +- name = shim_lock; +- common = commands/efi/shim_lock.c; +- enable = x86_64_efi; +-}; +- + module = { + name = hdparm; + common = commands/hdparm.c; +diff --git a/grub-core/commands/efi/shim_lock.c b/grub-core/commands/efi/shim_lock.c +deleted file mode 100644 +index f7f3109d6..000000000 +--- a/grub-core/commands/efi/shim_lock.c ++++ /dev/null +@@ -1,133 +0,0 @@ +-/* +- * GRUB -- GRand Unified Bootloader +- * Copyright (C) 2017 Free Software Foundation, Inc. +- * +- * GRUB is free software: you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation, either version 3 of the License, or +- * (at your option) any later version. +- * +- * GRUB is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with GRUB. If not, see . +- * +- * EFI shim lock verifier. +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-GRUB_MOD_LICENSE ("GPLv3+"); +- +-static grub_efi_guid_t shim_lock_guid = GRUB_EFI_SHIM_LOCK_GUID; +- +-/* List of modules which cannot be loaded if UEFI secure boot mode is enabled. */ +-static const char * const disabled_mods[] = {"iorw", "memrw", "wrmsr", NULL}; +- +-static grub_err_t +-shim_lock_init (grub_file_t io, enum grub_file_type type, +- void **context __attribute__ ((unused)), +- enum grub_verify_flags *flags) +-{ +- const char *b, *e; +- int i; +- +- *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; +- +- switch (type & GRUB_FILE_TYPE_MASK) +- { +- case GRUB_FILE_TYPE_GRUB_MODULE: +- /* Establish GRUB module name. */ +- b = grub_strrchr (io->name, '/'); +- e = grub_strrchr (io->name, '.'); +- +- b = b ? (b + 1) : io->name; +- e = e ? e : io->name + grub_strlen (io->name); +- e = (e > b) ? e : io->name + grub_strlen (io->name); +- +- for (i = 0; disabled_mods[i]; i++) +- if (!grub_strncmp (b, disabled_mods[i], grub_strlen (b) - grub_strlen (e))) +- { +- grub_error (GRUB_ERR_ACCESS_DENIED, +- N_("module cannot be loaded in UEFI secure boot mode: %s"), +- io->name); +- return GRUB_ERR_ACCESS_DENIED; +- } +- +- /* Fall through. */ +- +- case GRUB_FILE_TYPE_ACPI_TABLE: +- case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE: +- *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH; +- +- return GRUB_ERR_NONE; +- +- case GRUB_FILE_TYPE_LINUX_KERNEL: +- case GRUB_FILE_TYPE_MULTIBOOT_KERNEL: +- case GRUB_FILE_TYPE_BSD_KERNEL: +- case GRUB_FILE_TYPE_XNU_KERNEL: +- case GRUB_FILE_TYPE_PLAN9_KERNEL: +- for (i = 0; disabled_mods[i]; i++) +- if (grub_dl_get (disabled_mods[i])) +- { +- grub_error (GRUB_ERR_ACCESS_DENIED, +- N_("cannot boot due to dangerous module in memory: %s"), +- disabled_mods[i]); +- return GRUB_ERR_ACCESS_DENIED; +- } +- +- *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK; +- +- /* Fall through. */ +- +- default: +- return GRUB_ERR_NONE; +- } +-} +- +-static grub_err_t +-shim_lock_write (void *context __attribute__ ((unused)), void *buf, grub_size_t size) +-{ +- grub_efi_shim_lock_protocol_t *sl = grub_efi_locate_protocol (&shim_lock_guid, 0); +- +- if (sl == NULL) +- return grub_error (GRUB_ERR_ACCESS_DENIED, N_("shim_lock protocol not found")); +- +- if (sl->verify (buf, size) != GRUB_EFI_SUCCESS) +- return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad shim signature")); +- +- return GRUB_ERR_NONE; +-} +- +-struct grub_file_verifier shim_lock = +- { +- .name = "shim_lock", +- .init = shim_lock_init, +- .write = shim_lock_write +- }; +- +-GRUB_MOD_INIT(shim_lock) +-{ +- grub_efi_shim_lock_protocol_t *sl = grub_efi_locate_protocol (&shim_lock_guid, 0); +- +- if (sl == NULL || grub_efi_get_secureboot () != GRUB_EFI_SECUREBOOT_MODE_ENABLED) +- return; +- +- grub_verifier_register (&shim_lock); +- +- grub_dl_set_persistent (mod); +-} +- +-GRUB_MOD_FINI(shim_lock) +-{ +- grub_verifier_unregister (&shim_lock); +-} +diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c +index 5c7876e42..9c143eed7 100644 +--- a/grub-core/kern/efi/init.c ++++ b/grub-core/kern/efi/init.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -40,6 +41,9 @@ grub_efi_init (void) + /* Initialize the memory management system. */ + grub_efi_mm_init (); + ++ /* Register the shim_lock verifier if UEFI Secure Boot is enabled. */ ++ grub_shim_lock_verifier_setup (); ++ + efi_call_4 (grub_efi_system_table->boot_services->set_watchdog_timer, + 0, 0, 0, NULL); + +diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c +index 19658d962..8bd5e936d 100644 +--- a/grub-core/kern/efi/sb.c ++++ b/grub-core/kern/efi/sb.c +@@ -22,9 +22,16 @@ + #include + #include + #include ++#include + #include + #include + #include ++#include ++ ++static grub_efi_guid_t shim_lock_guid = GRUB_EFI_SHIM_LOCK_GUID; ++ ++/* List of modules which cannot be loaded if UEFI secure boot mode is enabled. */ ++static const char * const disabled_mods[] = {"iorw", "memrw", "wrmsr", NULL}; + + /* + * Determine whether we're in secure boot mode. +@@ -107,3 +114,101 @@ grub_efi_get_secureboot (void) + + return secureboot; + } ++ ++static grub_err_t ++shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)), ++ enum grub_file_type type, ++ void **context __attribute__ ((unused)), ++ enum grub_verify_flags *flags) ++{ ++ const char *b, *e; ++ int i; ++ ++ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; ++ ++ switch (type & GRUB_FILE_TYPE_MASK) ++ { ++ case GRUB_FILE_TYPE_GRUB_MODULE: ++ /* Establish GRUB module name. */ ++ b = grub_strrchr (io->name, '/'); ++ e = grub_strrchr (io->name, '.'); ++ ++ b = b ? (b + 1) : io->name; ++ e = e ? e : io->name + grub_strlen (io->name); ++ e = (e > b) ? e : io->name + grub_strlen (io->name); ++ ++ for (i = 0; disabled_mods[i]; i++) ++ if (!grub_strncmp (b, disabled_mods[i], grub_strlen (b) - grub_strlen (e))) ++ { ++ grub_error (GRUB_ERR_ACCESS_DENIED, ++ N_("module cannot be loaded in UEFI secure boot mode: %s"), ++ io->name); ++ return GRUB_ERR_ACCESS_DENIED; ++ } ++ ++ /* Fall through. */ ++ ++ case GRUB_FILE_TYPE_ACPI_TABLE: ++ case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE: ++ *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH; ++ ++ return GRUB_ERR_NONE; ++ ++ case GRUB_FILE_TYPE_LINUX_KERNEL: ++ case GRUB_FILE_TYPE_MULTIBOOT_KERNEL: ++ case GRUB_FILE_TYPE_BSD_KERNEL: ++ case GRUB_FILE_TYPE_XNU_KERNEL: ++ case GRUB_FILE_TYPE_PLAN9_KERNEL: ++ for (i = 0; disabled_mods[i]; i++) ++ if (grub_dl_get (disabled_mods[i])) ++ { ++ grub_error (GRUB_ERR_ACCESS_DENIED, ++ N_("cannot boot due to dangerous module in memory: %s"), ++ disabled_mods[i]); ++ return GRUB_ERR_ACCESS_DENIED; ++ } ++ ++ *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK; ++ ++ /* Fall through. */ ++ ++ default: ++ return GRUB_ERR_NONE; ++ } ++} ++ ++static grub_err_t ++shim_lock_verifier_write (void *context __attribute__ ((unused)), void *buf, grub_size_t size) ++{ ++ grub_efi_shim_lock_protocol_t *sl = grub_efi_locate_protocol (&shim_lock_guid, 0); ++ ++ if (!sl) ++ return grub_error (GRUB_ERR_ACCESS_DENIED, N_("shim_lock protocol not found")); ++ ++ if (sl->verify (buf, size) != GRUB_EFI_SUCCESS) ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad shim signature")); ++ ++ return GRUB_ERR_NONE; ++} ++ ++struct grub_file_verifier shim_lock_verifier = ++ { ++ .name = "shim_lock_verifier", ++ .init = shim_lock_verifier_init, ++ .write = shim_lock_verifier_write ++ }; ++ ++void ++grub_shim_lock_verifier_setup (void) ++{ ++ grub_efi_shim_lock_protocol_t *sl = ++ grub_efi_locate_protocol (&shim_lock_guid, 0); ++ ++ if (!sl) ++ return; ++ ++ if (grub_efi_get_secureboot () != GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ ++ grub_verifier_register (&shim_lock_verifier); ++} +diff --git a/include/grub/efi/sb.h b/include/grub/efi/sb.h +index a33d985e3..30c4335bb 100644 +--- a/include/grub/efi/sb.h ++++ b/include/grub/efi/sb.h +@@ -30,6 +30,9 @@ + #ifdef GRUB_MACHINE_EFI + extern grub_uint8_t + EXPORT_FUNC (grub_efi_get_secureboot) (void); ++ ++extern void ++grub_shim_lock_verifier_setup (void); + #else + static inline grub_uint8_t + grub_efi_get_secureboot (void) +-- +2.26.2 + diff --git a/0009-kern-Add-lockdown-support.patch b/0009-kern-Add-lockdown-support.patch new file mode 100644 index 0000000..b1c5bac --- /dev/null +++ b/0009-kern-Add-lockdown-support.patch @@ -0,0 +1,430 @@ +From 1aebb5645e749917034444b24b88825ea557cae9 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Mon, 28 Sep 2020 20:08:02 +0200 +Subject: [PATCH 09/46] kern: Add lockdown support + +When the GRUB starts on a secure boot platform, some commands can be +used to subvert the protections provided by the verification mechanism and +could lead to booting untrusted system. + +To prevent that situation, allow GRUB to be locked down. That way the code +may check if GRUB has been locked down and further restrict the commands +that are registered or what subset of their functionality could be used. + +The lockdown support adds the following components: + +* The grub_lockdown() function which can be used to lockdown GRUB if, + e.g., UEFI Secure Boot is enabled. + +* The grub_is_lockdown() function which can be used to check if the GRUB + was locked down. + +* A verifier that flags OS kernels, the GRUB modules, Device Trees and ACPI + tables as GRUB_VERIFY_FLAGS_DEFER_AUTH to defer verification to other + verifiers. These files are only successfully verified if another registered + verifier returns success. Otherwise, the whole verification process fails. + + For example, PE/COFF binaries verification can be done by the shim_lock + verifier which validates the signatures using the shim_lock protocol. + However, the verification is not deferred directly to the shim_lock verifier. + The shim_lock verifier is hooked into the verification process instead. + +* A set of grub_{command,extcmd}_lockdown functions that can be used by + code registering command handlers, to only register unsafe commands if + the GRUB has not been locked down. + +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + conf/Makefile.common | 2 + + docs/grub-dev.texi | 27 +++++++++++++ + docs/grub.texi | 8 ++++ + grub-core/Makefile.am | 5 ++- + grub-core/Makefile.core.def | 1 + + grub-core/commands/extcmd.c | 23 +++++++++++ + grub-core/kern/command.c | 24 +++++++++++ + grub-core/kern/lockdown.c | 80 +++++++++++++++++++++++++++++++++++++ + include/grub/command.h | 5 +++ + include/grub/extcmd.h | 7 ++++ + include/grub/lockdown.h | 44 ++++++++++++++++++++ + 11 files changed, 225 insertions(+), 1 deletion(-) + create mode 100644 grub-core/kern/lockdown.c + create mode 100644 include/grub/lockdown.h + +diff --git a/conf/Makefile.common b/conf/Makefile.common +index 6cd71cbb2..2a1a886f6 100644 +--- a/conf/Makefile.common ++++ b/conf/Makefile.common +@@ -84,7 +84,9 @@ CPPFLAGS_PARTTOOL_LIST = -Dgrub_parttool_register=PARTTOOL_LIST_MARKER + CPPFLAGS_TERMINAL_LIST = '-Dgrub_term_register_input(...)=INPUT_TERMINAL_LIST_MARKER(__VA_ARGS__)' + CPPFLAGS_TERMINAL_LIST += '-Dgrub_term_register_output(...)=OUTPUT_TERMINAL_LIST_MARKER(__VA_ARGS__)' + CPPFLAGS_COMMAND_LIST = '-Dgrub_register_command(...)=COMMAND_LIST_MARKER(__VA_ARGS__)' ++CPPFLAGS_COMMAND_LIST += '-Dgrub_register_command_lockdown(...)=COMMAND_LOCKDOWN_LIST_MARKER(__VA_ARGS__)' + CPPFLAGS_COMMAND_LIST += '-Dgrub_register_extcmd(...)=EXTCOMMAND_LIST_MARKER(__VA_ARGS__)' ++CPPFLAGS_COMMAND_LIST += '-Dgrub_register_extcmd_lockdown(...)=EXTCOMMAND_LOCKDOWN_LIST_MARKER(__VA_ARGS__)' + CPPFLAGS_COMMAND_LIST += '-Dgrub_register_command_p1(...)=P1COMMAND_LIST_MARKER(__VA_ARGS__)' + CPPFLAGS_FDT_LIST := '-Dgrub_fdtbus_register(...)=FDT_DRIVER_LIST_MARKER(__VA_ARGS__)' + CPPFLAGS_MARKER = $(CPPFLAGS_FS_LIST) $(CPPFLAGS_VIDEO_LIST) \ +diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi +index ee389fd83..635ec7231 100644 +--- a/docs/grub-dev.texi ++++ b/docs/grub-dev.texi +@@ -86,6 +86,7 @@ This edition documents version @value{VERSION}. + * PFF2 Font File Format:: + * Graphical Menu Software Design:: + * Verifiers framework:: ++* Lockdown framework:: + * Copying This Manual:: Copying This Manual + * Index:: + @end menu +@@ -2086,6 +2087,32 @@ Optionally at the end of the file @samp{fini}, if it exists, is called with just + the context. If you return no error during any of @samp{init}, @samp{write} and + @samp{fini} then the file is considered as having succeded verification. + ++@node Lockdown framework ++@chapter Lockdown framework ++ ++The GRUB can be locked down, which is a restricted mode where some operations ++are not allowed. For instance, some commands cannot be used when the GRUB is ++locked down. ++ ++The function ++@code{grub_lockdown()} is used to lockdown GRUB and the function ++@code{grub_is_lockdown()} function can be used to check whether lockdown is ++enabled or not. When enabled, the function returns @samp{GRUB_LOCKDOWN_ENABLED} ++and @samp{GRUB_LOCKDOWN_DISABLED} when is not enabled. ++ ++The following functions can be used to register the commands that can only be ++used when lockdown is disabled: ++ ++@itemize ++ ++@item @code{grub_cmd_lockdown()} registers command which should not run when the ++GRUB is in lockdown mode. ++ ++@item @code{grub_cmd_lockdown()} registers extended command which should not run ++when the GRUB is in lockdown mode. ++ ++@end itemize ++ + @node Copying This Manual + @appendix Copying This Manual + +diff --git a/docs/grub.texi b/docs/grub.texi +index d3fbc81db..a459a71e4 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -5598,6 +5598,7 @@ environment variables and commands are listed in the same order. + * Using digital signatures:: Booting digitally signed code + * UEFI secure boot and shim:: Booting digitally signed PE files + * Measured Boot:: Measuring boot components ++* Lockdown:: Lockdown when booting on a secure setup + @end menu + + @node Authentication and authorisation +@@ -5812,6 +5813,13 @@ into @file{core.img} in order to avoid a potential gap in measurement between + + Measured boot is currently only supported on EFI platforms. + ++@node Lockdown ++@section Lockdown when booting on a secure setup ++ ++The GRUB can be locked down when booted on a secure boot environment, for example ++if the UEFI secure boot is enabled. On a locked down configuration, the GRUB will ++be restricted and some operations/commands cannot be executed. ++ + @node Platform limitations + @chapter Platform limitations + +diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am +index 3569b7101..6b2e5e139 100644 +--- a/grub-core/Makefile.am ++++ b/grub-core/Makefile.am +@@ -80,6 +80,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fs.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i18n.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/kernel.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/list.h ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lockdown.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/misc.h + if COND_emu + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/compiler-rt-emu.h +@@ -378,8 +379,10 @@ command.lst: $(MARKER_FILES) + b=`basename $$pp .marker`; \ + sed -n \ + -e "/EXTCOMMAND_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/*\1: $$b/;p;}" \ ++ -e "/EXTCOMMAND_LOCKDOWN_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/*\1: $$b/;p;}" \ + -e "/P1COMMAND_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/*\1: $$b/;p;}" \ +- -e "/COMMAND_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/\1: $$b/;p;}" $$pp; \ ++ -e "/COMMAND_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/\1: $$b/;p;}" \ ++ -e "/COMMAND_LOCKDOWN_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/\1: $$b/;p;}" $$pp; \ + done) | sort -u > $@ + platform_DATA += command.lst + CLEANFILES += command.lst +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 8c8f8c579..a00e7f983 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -205,6 +205,7 @@ kernel = { + efi = kern/acpi.c; + efi = kern/efi/acpi.c; + efi = kern/efi/sb.c; ++ efi = kern/lockdown.c; + i386_coreboot = kern/i386/pc/acpi.c; + i386_multiboot = kern/i386/pc/acpi.c; + i386_coreboot = kern/acpi.c; +diff --git a/grub-core/commands/extcmd.c b/grub-core/commands/extcmd.c +index 69574e2b0..90a5ca24a 100644 +--- a/grub-core/commands/extcmd.c ++++ b/grub-core/commands/extcmd.c +@@ -19,6 +19,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -110,6 +111,28 @@ grub_register_extcmd (const char *name, grub_extcmd_func_t func, + summary, description, parser, 1); + } + ++static grub_err_t ++grub_extcmd_lockdown (grub_extcmd_context_t ctxt __attribute__ ((unused)), ++ int argc __attribute__ ((unused)), ++ char **argv __attribute__ ((unused))) ++{ ++ return grub_error (GRUB_ERR_ACCESS_DENIED, ++ N_("%s: the command is not allowed when lockdown is enforced"), ++ ctxt->extcmd->cmd->name); ++} ++ ++grub_extcmd_t ++grub_register_extcmd_lockdown (const char *name, grub_extcmd_func_t func, ++ grub_command_flags_t flags, const char *summary, ++ const char *description, ++ const struct grub_arg_option *parser) ++{ ++ if (grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED) ++ func = grub_extcmd_lockdown; ++ ++ return grub_register_extcmd (name, func, flags, summary, description, parser); ++} ++ + void + grub_unregister_extcmd (grub_extcmd_t ext) + { +diff --git a/grub-core/kern/command.c b/grub-core/kern/command.c +index acd721879..4aabcd4b5 100644 +--- a/grub-core/kern/command.c ++++ b/grub-core/kern/command.c +@@ -17,6 +17,7 @@ + * along with GRUB. If not, see . + */ + ++#include + #include + #include + +@@ -77,6 +78,29 @@ grub_register_command_prio (const char *name, + return cmd; + } + ++static grub_err_t ++grub_cmd_lockdown (grub_command_t cmd __attribute__ ((unused)), ++ int argc __attribute__ ((unused)), ++ char **argv __attribute__ ((unused))) ++ ++{ ++ return grub_error (GRUB_ERR_ACCESS_DENIED, ++ N_("%s: the command is not allowed when lockdown is enforced"), ++ cmd->name); ++} ++ ++grub_command_t ++grub_register_command_lockdown (const char *name, ++ grub_command_func_t func, ++ const char *summary, ++ const char *description) ++{ ++ if (grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED) ++ func = grub_cmd_lockdown; ++ ++ return grub_register_command_prio (name, func, summary, description, 0); ++} ++ + void + grub_unregister_command (grub_command_t cmd) + { +diff --git a/grub-core/kern/lockdown.c b/grub-core/kern/lockdown.c +new file mode 100644 +index 000000000..1e56c0b80 +--- /dev/null ++++ b/grub-core/kern/lockdown.c +@@ -0,0 +1,80 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++static int lockdown = GRUB_LOCKDOWN_DISABLED; ++ ++static grub_err_t ++lockdown_verifier_init (grub_file_t io __attribute__ ((unused)), ++ enum grub_file_type type, ++ void **context __attribute__ ((unused)), ++ enum grub_verify_flags *flags) ++{ ++ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; ++ ++ switch (type & GRUB_FILE_TYPE_MASK) ++ { ++ case GRUB_FILE_TYPE_GRUB_MODULE: ++ case GRUB_FILE_TYPE_LINUX_KERNEL: ++ case GRUB_FILE_TYPE_MULTIBOOT_KERNEL: ++ case GRUB_FILE_TYPE_XEN_HYPERVISOR: ++ case GRUB_FILE_TYPE_BSD_KERNEL: ++ case GRUB_FILE_TYPE_XNU_KERNEL: ++ case GRUB_FILE_TYPE_PLAN9_KERNEL: ++ case GRUB_FILE_TYPE_NTLDR: ++ case GRUB_FILE_TYPE_TRUECRYPT: ++ case GRUB_FILE_TYPE_FREEDOS: ++ case GRUB_FILE_TYPE_PXECHAINLOADER: ++ case GRUB_FILE_TYPE_PCCHAINLOADER: ++ case GRUB_FILE_TYPE_COREBOOT_CHAINLOADER: ++ case GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE: ++ case GRUB_FILE_TYPE_ACPI_TABLE: ++ case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE: ++ *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH; ++ ++ /* Fall through. */ ++ ++ default: ++ return GRUB_ERR_NONE; ++ } ++} ++ ++struct grub_file_verifier lockdown_verifier = ++ { ++ .name = "lockdown_verifier", ++ .init = lockdown_verifier_init, ++ }; ++ ++void ++grub_lockdown (void) ++{ ++ lockdown = GRUB_LOCKDOWN_ENABLED; ++ ++ grub_verifier_register (&lockdown_verifier); ++} ++ ++int ++grub_is_lockdown (void) ++{ ++ return lockdown; ++} +diff --git a/include/grub/command.h b/include/grub/command.h +index eee4e847e..2a6f7f846 100644 +--- a/include/grub/command.h ++++ b/include/grub/command.h +@@ -86,6 +86,11 @@ EXPORT_FUNC(grub_register_command_prio) (const char *name, + const char *summary, + const char *description, + int prio); ++grub_command_t ++EXPORT_FUNC(grub_register_command_lockdown) (const char *name, ++ grub_command_func_t func, ++ const char *summary, ++ const char *description); + void EXPORT_FUNC(grub_unregister_command) (grub_command_t cmd); + + static inline grub_command_t +diff --git a/include/grub/extcmd.h b/include/grub/extcmd.h +index 19fe59266..fe9248b8b 100644 +--- a/include/grub/extcmd.h ++++ b/include/grub/extcmd.h +@@ -62,6 +62,13 @@ grub_extcmd_t EXPORT_FUNC(grub_register_extcmd) (const char *name, + const char *description, + const struct grub_arg_option *parser); + ++grub_extcmd_t EXPORT_FUNC(grub_register_extcmd_lockdown) (const char *name, ++ grub_extcmd_func_t func, ++ grub_command_flags_t flags, ++ const char *summary, ++ const char *description, ++ const struct grub_arg_option *parser); ++ + grub_extcmd_t EXPORT_FUNC(grub_register_extcmd_prio) (const char *name, + grub_extcmd_func_t func, + grub_command_flags_t flags, +diff --git a/include/grub/lockdown.h b/include/grub/lockdown.h +new file mode 100644 +index 000000000..40531fa82 +--- /dev/null ++++ b/include/grub/lockdown.h +@@ -0,0 +1,44 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_LOCKDOWN_H ++#define GRUB_LOCKDOWN_H 1 ++ ++#include ++ ++#define GRUB_LOCKDOWN_DISABLED 0 ++#define GRUB_LOCKDOWN_ENABLED 1 ++ ++#ifdef GRUB_MACHINE_EFI ++extern void ++EXPORT_FUNC (grub_lockdown) (void); ++extern int ++EXPORT_FUNC (grub_is_lockdown) (void); ++#else ++static inline void ++grub_lockdown (void) ++{ ++} ++ ++static inline int ++grub_is_lockdown (void) ++{ ++ return GRUB_LOCKDOWN_DISABLED; ++} ++#endif ++#endif /* ! GRUB_LOCKDOWN_H */ +-- +2.26.2 + diff --git a/0010-kern-lockdown-Set-a-variable-if-the-GRUB-is-locked-d.patch b/0010-kern-lockdown-Set-a-variable-if-the-GRUB-is-locked-d.patch new file mode 100644 index 0000000..d23f3ef --- /dev/null +++ b/0010-kern-lockdown-Set-a-variable-if-the-GRUB-is-locked-d.patch @@ -0,0 +1,57 @@ +From 959db537b12c5e76c244ccc51cbbed7f27b0abe2 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Tue, 2 Feb 2021 19:59:48 +0100 +Subject: [PATCH 10/46] kern/lockdown: Set a variable if the GRUB is locked + down + +It may be useful for scripts to determine whether the GRUB is locked +down or not. Add the lockdown variable which is set to "y" when the GRUB +is locked down. + +Suggested-by: Dimitri John Ledkov +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + docs/grub.texi | 3 +++ + grub-core/kern/lockdown.c | 4 ++++ + 2 files changed, 7 insertions(+) + +diff --git a/docs/grub.texi b/docs/grub.texi +index a459a71e4..3a4d18e06 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -5820,6 +5820,9 @@ The GRUB can be locked down when booted on a secure boot environment, for exampl + if the UEFI secure boot is enabled. On a locked down configuration, the GRUB will + be restricted and some operations/commands cannot be executed. + ++The @samp{lockdown} variable is set to @samp{y} when the GRUB is locked down. ++Otherwise it does not exit. ++ + @node Platform limitations + @chapter Platform limitations + +diff --git a/grub-core/kern/lockdown.c b/grub-core/kern/lockdown.c +index 1e56c0b80..0bc70fd42 100644 +--- a/grub-core/kern/lockdown.c ++++ b/grub-core/kern/lockdown.c +@@ -18,6 +18,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -71,6 +72,9 @@ grub_lockdown (void) + lockdown = GRUB_LOCKDOWN_ENABLED; + + grub_verifier_register (&lockdown_verifier); ++ ++ grub_env_set ("lockdown", "y"); ++ grub_env_export ("lockdown"); + } + + int +-- +2.26.2 + diff --git a/0011-efi-Lockdown-the-GRUB-when-the-UEFI-Secure-Boot-is-e.patch b/0011-efi-Lockdown-the-GRUB-when-the-UEFI-Secure-Boot-is-e.patch new file mode 100644 index 0000000..2f886b1 --- /dev/null +++ b/0011-efi-Lockdown-the-GRUB-when-the-UEFI-Secure-Boot-is-e.patch @@ -0,0 +1,49 @@ +From a255fd33e08015335aeac619348536b5fda8303e Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Mon, 28 Sep 2020 20:08:29 +0200 +Subject: [PATCH 11/46] efi: Lockdown the GRUB when the UEFI Secure Boot is + enabled + +If the UEFI Secure Boot is enabled then the GRUB must be locked down +to prevent executing code that can potentially be used to subvert its +verification mechanisms. + +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/kern/efi/init.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c +index 9c143eed7..08ef2b8f4 100644 +--- a/grub-core/kern/efi/init.c ++++ b/grub-core/kern/efi/init.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -41,8 +42,15 @@ grub_efi_init (void) + /* Initialize the memory management system. */ + grub_efi_mm_init (); + +- /* Register the shim_lock verifier if UEFI Secure Boot is enabled. */ +- grub_shim_lock_verifier_setup (); ++ /* ++ * Lockdown the GRUB and register the shim_lock verifier ++ * if the UEFI Secure Boot is enabled. ++ */ ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ { ++ grub_lockdown (); ++ grub_shim_lock_verifier_setup (); ++ } + + efi_call_4 (grub_efi_system_table->boot_services->set_watchdog_timer, + 0, 0, 0, NULL); +-- +2.26.2 + diff --git a/0012-efi-Use-grub_is_lockdown-instead-of-hardcoding-a-dis.patch b/0012-efi-Use-grub_is_lockdown-instead-of-hardcoding-a-dis.patch new file mode 100644 index 0000000..1f94953 --- /dev/null +++ b/0012-efi-Use-grub_is_lockdown-instead-of-hardcoding-a-dis.patch @@ -0,0 +1,231 @@ +From fd04f7a20cffb4bde9deb688f4e33e5ff2c80181 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Mon, 28 Sep 2020 20:08:33 +0200 +Subject: [PATCH 12/46] efi: Use grub_is_lockdown() instead of hardcoding a + disabled modules list + +Now the GRUB can check if it has been locked down and this can be used to +prevent executing commands that can be utilized to circumvent the UEFI +Secure Boot mechanisms. So, instead of hardcoding a list of modules that +have to be disabled, prevent the usage of commands that can be dangerous. + +This not only allows the commands to be disabled on other platforms, but +also properly separate the concerns. Since the shim_lock verifier logic +should be only about preventing to run untrusted binaries and not about +defining these kind of policies. + +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + docs/grub.texi | 15 +++++++----- + grub-core/commands/i386/wrmsr.c | 5 ++-- + grub-core/commands/iorw.c | 19 +++++++-------- + grub-core/commands/memrw.c | 19 +++++++-------- + grub-core/kern/efi/sb.c | 41 --------------------------------- + 5 files changed, 32 insertions(+), 67 deletions(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index 3a4d18e06..6d8d32b0b 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -5256,6 +5256,9 @@ only applies to the particular cpu/core/thread that runs the command. + Also, if you specify a reserved or unimplemented MSR address, it will + cause a general protection exception (which is not currently being handled) + and the system will reboot. ++ ++Note: The command is not allowed when lockdown is enforced (@pxref{Lockdown}). ++ This is done to prevent subverting various security mechanisms. + @end deffn + + @node xen_hypervisor +@@ -5769,12 +5772,12 @@ boot and the shim. This functionality is provided by the shim_lock verifier. It + is built into the @file{core.img} and is registered if the UEFI secure boot is + enabled. + +-All modules not stored in the @file{core.img} and the ACPI tables for the +-@command{acpi} command have to be signed, e.g. using PGP. Additionally, the +-@command{iorw}, the @command{memrw} and the @command{wrmsr} commands are +-prohibited if the UEFI secure boot is enabled. This is done due to +-security reasons. All above mentioned requirements are enforced by the +-shim_lock verifier logic. ++All GRUB modules not stored in the @file{core.img}, OS kernels, ACPI tables, ++Device Trees, etc. have to be signed, e.g, using PGP. Additionally, the commands ++that can be used to subvert the UEFI secure boot mechanism, such as @command{iorw} ++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 Measured Boot + @section Measuring boot components +diff --git a/grub-core/commands/i386/wrmsr.c b/grub-core/commands/i386/wrmsr.c +index 9c5e510eb..56a29c29f 100644 +--- a/grub-core/commands/i386/wrmsr.c ++++ b/grub-core/commands/i386/wrmsr.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -83,8 +84,8 @@ grub_cmd_msr_write (grub_command_t cmd __attribute__ ((unused)), int argc, char + + GRUB_MOD_INIT(wrmsr) + { +- cmd_write = grub_register_command ("wrmsr", grub_cmd_msr_write, N_("ADDR VALUE"), +- N_("Write a value to a CPU model specific register.")); ++ cmd_write = grub_register_command_lockdown ("wrmsr", grub_cmd_msr_write, N_("ADDR VALUE"), ++ N_("Write a value to a CPU model specific register.")); + } + + GRUB_MOD_FINI(wrmsr) +diff --git a/grub-core/commands/iorw.c b/grub-core/commands/iorw.c +index a0c164e54..584baec8f 100644 +--- a/grub-core/commands/iorw.c ++++ b/grub-core/commands/iorw.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -131,17 +132,17 @@ GRUB_MOD_INIT(memrw) + N_("PORT"), N_("Read 32-bit value from PORT."), + options); + cmd_write_byte = +- grub_register_command ("outb", grub_cmd_write, +- N_("PORT VALUE [MASK]"), +- N_("Write 8-bit VALUE to PORT.")); ++ grub_register_command_lockdown ("outb", grub_cmd_write, ++ N_("PORT VALUE [MASK]"), ++ N_("Write 8-bit VALUE to PORT.")); + cmd_write_word = +- grub_register_command ("outw", grub_cmd_write, +- N_("PORT VALUE [MASK]"), +- N_("Write 16-bit VALUE to PORT.")); ++ grub_register_command_lockdown ("outw", grub_cmd_write, ++ N_("PORT VALUE [MASK]"), ++ N_("Write 16-bit VALUE to PORT.")); + cmd_write_dword = +- grub_register_command ("outl", grub_cmd_write, +- N_("ADDR VALUE [MASK]"), +- N_("Write 32-bit VALUE to PORT.")); ++ grub_register_command_lockdown ("outl", grub_cmd_write, ++ N_("ADDR VALUE [MASK]"), ++ N_("Write 32-bit VALUE to PORT.")); + } + + GRUB_MOD_FINI(memrw) +diff --git a/grub-core/commands/memrw.c b/grub-core/commands/memrw.c +index 98769eadb..d401a6db0 100644 +--- a/grub-core/commands/memrw.c ++++ b/grub-core/commands/memrw.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -133,17 +134,17 @@ GRUB_MOD_INIT(memrw) + N_("ADDR"), N_("Read 32-bit value from ADDR."), + options); + cmd_write_byte = +- grub_register_command ("write_byte", grub_cmd_write, +- N_("ADDR VALUE [MASK]"), +- N_("Write 8-bit VALUE to ADDR.")); ++ grub_register_command_lockdown ("write_byte", grub_cmd_write, ++ N_("ADDR VALUE [MASK]"), ++ N_("Write 8-bit VALUE to ADDR.")); + cmd_write_word = +- grub_register_command ("write_word", grub_cmd_write, +- N_("ADDR VALUE [MASK]"), +- N_("Write 16-bit VALUE to ADDR.")); ++ grub_register_command_lockdown ("write_word", grub_cmd_write, ++ N_("ADDR VALUE [MASK]"), ++ N_("Write 16-bit VALUE to ADDR.")); + cmd_write_dword = +- grub_register_command ("write_dword", grub_cmd_write, +- N_("ADDR VALUE [MASK]"), +- N_("Write 32-bit VALUE to ADDR.")); ++ grub_register_command_lockdown ("write_dword", grub_cmd_write, ++ N_("ADDR VALUE [MASK]"), ++ N_("Write 32-bit VALUE to ADDR.")); + } + + GRUB_MOD_FINI(memrw) +diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c +index 8bd5e936d..5d7210a82 100644 +--- a/grub-core/kern/efi/sb.c ++++ b/grub-core/kern/efi/sb.c +@@ -30,9 +30,6 @@ + + static grub_efi_guid_t shim_lock_guid = GRUB_EFI_SHIM_LOCK_GUID; + +-/* List of modules which cannot be loaded if UEFI secure boot mode is enabled. */ +-static const char * const disabled_mods[] = {"iorw", "memrw", "wrmsr", NULL}; +- + /* + * Determine whether we're in secure boot mode. + * +@@ -121,53 +118,15 @@ shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)), + void **context __attribute__ ((unused)), + enum grub_verify_flags *flags) + { +- const char *b, *e; +- int i; +- + *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; + + switch (type & GRUB_FILE_TYPE_MASK) + { +- case GRUB_FILE_TYPE_GRUB_MODULE: +- /* Establish GRUB module name. */ +- b = grub_strrchr (io->name, '/'); +- e = grub_strrchr (io->name, '.'); +- +- b = b ? (b + 1) : io->name; +- e = e ? e : io->name + grub_strlen (io->name); +- e = (e > b) ? e : io->name + grub_strlen (io->name); +- +- for (i = 0; disabled_mods[i]; i++) +- if (!grub_strncmp (b, disabled_mods[i], grub_strlen (b) - grub_strlen (e))) +- { +- grub_error (GRUB_ERR_ACCESS_DENIED, +- N_("module cannot be loaded in UEFI secure boot mode: %s"), +- io->name); +- return GRUB_ERR_ACCESS_DENIED; +- } +- +- /* Fall through. */ +- +- case GRUB_FILE_TYPE_ACPI_TABLE: +- case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE: +- *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH; +- +- return GRUB_ERR_NONE; +- + case GRUB_FILE_TYPE_LINUX_KERNEL: + case GRUB_FILE_TYPE_MULTIBOOT_KERNEL: + case GRUB_FILE_TYPE_BSD_KERNEL: + case GRUB_FILE_TYPE_XNU_KERNEL: + case GRUB_FILE_TYPE_PLAN9_KERNEL: +- for (i = 0; disabled_mods[i]; i++) +- if (grub_dl_get (disabled_mods[i])) +- { +- grub_error (GRUB_ERR_ACCESS_DENIED, +- N_("cannot boot due to dangerous module in memory: %s"), +- disabled_mods[i]); +- return GRUB_ERR_ACCESS_DENIED; +- } +- + *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK; + + /* Fall through. */ +-- +2.26.2 + diff --git a/0013-acpi-Don-t-register-the-acpi-command-when-locked-dow.patch b/0013-acpi-Don-t-register-the-acpi-command-when-locked-dow.patch new file mode 100644 index 0000000..d1e9553 --- /dev/null +++ b/0013-acpi-Don-t-register-the-acpi-command-when-locked-dow.patch @@ -0,0 +1,75 @@ +From 08c63ad119ce0c0d0de56d9878f0be6811f623d4 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Mon, 28 Sep 2020 20:08:41 +0200 +Subject: [PATCH 13/46] acpi: Don't register the acpi command when locked down +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The command is not allowed when lockdown is enforced. Otherwise an +attacker can instruct the GRUB to load an SSDT table to overwrite +the kernel lockdown configuration and later load and execute +unsigned code. + +Fixes: CVE-2020-14372 + +Reported-by: Máté Kukri +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + docs/grub.texi | 5 +++++ + grub-core/commands/acpi.c | 15 ++++++++------- + 2 files changed, 13 insertions(+), 7 deletions(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index 6d8d32b0b..2ee8721a1 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -3986,6 +3986,11 @@ Normally, this command will replace the Root System Description Pointer + (RSDP) in the Extended BIOS Data Area to point to the new tables. If the + @option{--no-ebda} option is used, the new tables will be known only to + GRUB, but may be used by GRUB's EFI emulation. ++ ++Note: The command is not allowed when lockdown is enforced (@pxref{Lockdown}). ++ Otherwise an attacker can instruct the GRUB to load an SSDT table to ++ overwrite the kernel lockdown configuration and later load and execute ++ unsigned code. + @end deffn + + +diff --git a/grub-core/commands/acpi.c b/grub-core/commands/acpi.c +index 5a1499aa0..1215f2a62 100644 +--- a/grub-core/commands/acpi.c ++++ b/grub-core/commands/acpi.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + #ifdef GRUB_MACHINE_EFI + #include +@@ -775,13 +776,13 @@ static grub_extcmd_t cmd; + + GRUB_MOD_INIT(acpi) + { +- cmd = grub_register_extcmd ("acpi", grub_cmd_acpi, 0, +- N_("[-1|-2] [--exclude=TABLE1,TABLE2|" +- "--load-only=TABLE1,TABLE2] FILE1" +- " [FILE2] [...]"), +- N_("Load host ACPI tables and tables " +- "specified by arguments."), +- options); ++ cmd = grub_register_extcmd_lockdown ("acpi", grub_cmd_acpi, 0, ++ N_("[-1|-2] [--exclude=TABLE1,TABLE2|" ++ "--load-only=TABLE1,TABLE2] FILE1" ++ " [FILE2] [...]"), ++ N_("Load host ACPI tables and tables " ++ "specified by arguments."), ++ options); + } + + GRUB_MOD_FINI(acpi) +-- +2.26.2 + diff --git a/0014-mmap-Don-t-register-cutmem-and-badram-commands-when-.patch b/0014-mmap-Don-t-register-cutmem-and-badram-commands-when-.patch new file mode 100644 index 0000000..9e182c3 --- /dev/null +++ b/0014-mmap-Don-t-register-cutmem-and-badram-commands-when-.patch @@ -0,0 +1,69 @@ +From cbd4d630728847bcc3eb82c4a1667fc7ba6de73a Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Wed, 14 Oct 2020 16:33:42 +0200 +Subject: [PATCH 14/46] mmap: Don't register cutmem and badram commands when + lockdown is enforced + +The cutmem and badram commands can be used to remove EFI memory regions +and potentially disable the UEFI Secure Boot. Prevent the commands to be +registered if the GRUB is locked down. + +Fixes: CVE-2020-27779 + +Reported-by: Teddy Reed +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + docs/grub.texi | 4 ++++ + grub-core/mmap/mmap.c | 13 +++++++------ + 2 files changed, 11 insertions(+), 6 deletions(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index 2ee8721a1..70bf91f40 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -4051,6 +4051,10 @@ this page is to be filtered. This syntax makes it easy to represent patterns + that are often result of memory damage, due to physical distribution of memory + cells. + ++Note: The command is not allowed when lockdown is enforced (@pxref{Lockdown}). ++ This prevents removing EFI memory regions to potentially subvert the ++ security mechanisms provided by the UEFI secure boot. ++ + @node blocklist + @subsection blocklist + +diff --git a/grub-core/mmap/mmap.c b/grub-core/mmap/mmap.c +index 57b4e9a72..7ebf32e1e 100644 +--- a/grub-core/mmap/mmap.c ++++ b/grub-core/mmap/mmap.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -534,12 +535,12 @@ static grub_command_t cmd, cmd_cut; + + GRUB_MOD_INIT(mmap) + { +- cmd = grub_register_command ("badram", grub_cmd_badram, +- N_("ADDR1,MASK1[,ADDR2,MASK2[,...]]"), +- N_("Declare memory regions as faulty (badram).")); +- cmd_cut = grub_register_command ("cutmem", grub_cmd_cutmem, +- N_("FROM[K|M|G] TO[K|M|G]"), +- N_("Remove any memory regions in specified range.")); ++ cmd = grub_register_command_lockdown ("badram", grub_cmd_badram, ++ N_("ADDR1,MASK1[,ADDR2,MASK2[,...]]"), ++ N_("Declare memory regions as faulty (badram).")); ++ cmd_cut = grub_register_command_lockdown ("cutmem", grub_cmd_cutmem, ++ N_("FROM[K|M|G] TO[K|M|G]"), ++ N_("Remove any memory regions in specified range.")); + + } + +-- +2.26.2 + diff --git a/0015-commands-Restrict-commands-that-can-load-BIOS-or-DT-.patch b/0015-commands-Restrict-commands-that-can-load-BIOS-or-DT-.patch new file mode 100644 index 0000000..3dfa27f --- /dev/null +++ b/0015-commands-Restrict-commands-that-can-load-BIOS-or-DT-.patch @@ -0,0 +1,104 @@ +From d1a40f870dbcb55280f57673c1d9c2c7110df42a Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Wed, 24 Feb 2021 09:00:05 +0100 +Subject: [PATCH 15/46] commands: Restrict commands that can load BIOS or DT + blobs when locked down + +There are some more commands that should be restricted when the GRUB is +locked down. Following is the list of commands and reasons to restrict: + + * fakebios: creates BIOS-like structures for backward compatibility with + existing OSes. This should not be allowed when locked down. + + * loadbios: reads a BIOS dump from storage and loads it. This action + should not be allowed when locked down. + + * devicetree: loads a Device Tree blob and passes it to the OS. It replaces + any Device Tree provided by the firmware. This also should + not be allowed when locked down. + +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + docs/grub.texi | 3 +++ + grub-core/commands/efi/loadbios.c | 16 ++++++++-------- + grub-core/loader/arm/linux.c | 6 +++--- + grub-core/loader/efi/fdt.c | 4 ++-- + 4 files changed, 16 insertions(+), 13 deletions(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index 70bf91f40..cf29a1797 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -4236,6 +4236,9 @@ Load a device tree blob (.dtb) from a filesystem, for later use by a Linux + kernel. Does not perform merging with any device tree supplied by firmware, + but rather replaces it completely. + @ref{GNU/Linux}. ++ ++Note: The command is not allowed when lockdown is enforced (@pxref{Lockdown}). ++ This is done to prevent subverting various security mechanisms. + @end deffn + + @node distrust +diff --git a/grub-core/commands/efi/loadbios.c b/grub-core/commands/efi/loadbios.c +index d41d521a4..5c7725f8b 100644 +--- a/grub-core/commands/efi/loadbios.c ++++ b/grub-core/commands/efi/loadbios.c +@@ -205,14 +205,14 @@ static grub_command_t cmd_fakebios, cmd_loadbios; + + GRUB_MOD_INIT(loadbios) + { +- cmd_fakebios = grub_register_command ("fakebios", grub_cmd_fakebios, +- 0, N_("Create BIOS-like structures for" +- " backward compatibility with" +- " existing OS.")); +- +- cmd_loadbios = grub_register_command ("loadbios", grub_cmd_loadbios, +- N_("BIOS_DUMP [INT10_DUMP]"), +- N_("Load BIOS dump.")); ++ cmd_fakebios = grub_register_command_lockdown ("fakebios", grub_cmd_fakebios, ++ 0, N_("Create BIOS-like structures for" ++ " backward compatibility with" ++ " existing OS.")); ++ ++ cmd_loadbios = grub_register_command_lockdown ("loadbios", grub_cmd_loadbios, ++ N_("BIOS_DUMP [INT10_DUMP]"), ++ N_("Load BIOS dump.")); + } + + GRUB_MOD_FINI(loadbios) +diff --git a/grub-core/loader/arm/linux.c b/grub-core/loader/arm/linux.c +index d70c17486..ed23dc71e 100644 +--- a/grub-core/loader/arm/linux.c ++++ b/grub-core/loader/arm/linux.c +@@ -493,9 +493,9 @@ GRUB_MOD_INIT (linux) + 0, N_("Load Linux.")); + cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, + 0, N_("Load initrd.")); +- cmd_devicetree = grub_register_command ("devicetree", grub_cmd_devicetree, +- /* TRANSLATORS: DTB stands for device tree blob. */ +- 0, N_("Load DTB file.")); ++ cmd_devicetree = grub_register_command_lockdown ("devicetree", grub_cmd_devicetree, ++ /* TRANSLATORS: DTB stands for device tree blob. */ ++ 0, N_("Load DTB file.")); + my_mod = mod; + current_fdt = (const void *) grub_arm_firmware_get_boot_data (); + machine_type = grub_arm_firmware_get_machine_type (); +diff --git a/grub-core/loader/efi/fdt.c b/grub-core/loader/efi/fdt.c +index ee9c5592c..003d07cd8 100644 +--- a/grub-core/loader/efi/fdt.c ++++ b/grub-core/loader/efi/fdt.c +@@ -165,8 +165,8 @@ static grub_command_t cmd_devicetree; + GRUB_MOD_INIT (fdt) + { + cmd_devicetree = +- grub_register_command ("devicetree", grub_cmd_devicetree, 0, +- N_("Load DTB file.")); ++ grub_register_command_lockdown ("devicetree", grub_cmd_devicetree, 0, ++ N_("Load DTB file.")); + } + + GRUB_MOD_FINI (fdt) +-- +2.26.2 + diff --git a/0016-commands-setpci-Restrict-setpci-command-when-locked-.patch b/0016-commands-setpci-Restrict-setpci-command-when-locked-.patch new file mode 100644 index 0000000..69902d5 --- /dev/null +++ b/0016-commands-setpci-Restrict-setpci-command-when-locked-.patch @@ -0,0 +1,37 @@ +From 3e5b0593346fde8d92dd4e87ce15ff07e0cacf88 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Wed, 24 Feb 2021 22:59:59 +0100 +Subject: [PATCH 16/46] commands/setpci: Restrict setpci command when locked + down + +This command can set PCI devices register values, which makes it dangerous +in a locked down configuration. Restrict it so can't be used on this setup. + +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/commands/setpci.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/grub-core/commands/setpci.c b/grub-core/commands/setpci.c +index d5bc97d60..fa2ba7d89 100644 +--- a/grub-core/commands/setpci.c ++++ b/grub-core/commands/setpci.c +@@ -329,10 +329,10 @@ static grub_extcmd_t cmd; + + GRUB_MOD_INIT(setpci) + { +- cmd = grub_register_extcmd ("setpci", grub_cmd_setpci, 0, +- N_("[-s POSITION] [-d DEVICE] [-v VAR] " +- "REGISTER[=VALUE[:MASK]]"), +- N_("Manipulate PCI devices."), options); ++ cmd = grub_register_extcmd_lockdown ("setpci", grub_cmd_setpci, 0, ++ N_("[-s POSITION] [-d DEVICE] [-v VAR] " ++ "REGISTER[=VALUE[:MASK]]"), ++ N_("Manipulate PCI devices."), options); + } + + GRUB_MOD_FINI(setpci) +-- +2.26.2 + diff --git a/0017-commands-hdparm-Restrict-hdparm-command-when-locked-.patch b/0017-commands-hdparm-Restrict-hdparm-command-when-locked-.patch new file mode 100644 index 0000000..d11e21a --- /dev/null +++ b/0017-commands-hdparm-Restrict-hdparm-command-when-locked-.patch @@ -0,0 +1,35 @@ +From 75dd393392f16194904c8958a22fe12034f915a3 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Wed, 24 Feb 2021 12:59:29 +0100 +Subject: [PATCH 17/46] commands/hdparm: Restrict hdparm command when locked + down + +The command can be used to get/set ATA disk parameters. Some of these can +be dangerous since change the disk behavior. Restrict it when locked down. + +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/commands/hdparm.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/grub-core/commands/hdparm.c b/grub-core/commands/hdparm.c +index d3fa9661e..2e2319e64 100644 +--- a/grub-core/commands/hdparm.c ++++ b/grub-core/commands/hdparm.c +@@ -436,9 +436,9 @@ static grub_extcmd_t cmd; + + GRUB_MOD_INIT(hdparm) + { +- cmd = grub_register_extcmd ("hdparm", grub_cmd_hdparm, 0, +- N_("[OPTIONS] DISK"), +- N_("Get/set ATA disk parameters."), options); ++ cmd = grub_register_extcmd_lockdown ("hdparm", grub_cmd_hdparm, 0, ++ N_("[OPTIONS] DISK"), ++ N_("Get/set ATA disk parameters."), options); + } + + GRUB_MOD_FINI(hdparm) +-- +2.26.2 + diff --git a/0018-gdb-Restrict-GDB-access-when-locked-down.patch b/0018-gdb-Restrict-GDB-access-when-locked-down.patch new file mode 100644 index 0000000..50eaa1b --- /dev/null +++ b/0018-gdb-Restrict-GDB-access-when-locked-down.patch @@ -0,0 +1,61 @@ +From a4df9a0d74376aa4fc82f8c86c280cb087de01be Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Wed, 24 Feb 2021 15:03:26 +0100 +Subject: [PATCH 18/46] gdb: Restrict GDB access when locked down + +The gdbstub* commands allow to start and control a GDB stub running on +local host that can be used to connect from a remote debugger. Restrict +this functionality when the GRUB is locked down. + +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/gdb/gdb.c | 32 ++++++++++++++++++-------------- + 1 file changed, 18 insertions(+), 14 deletions(-) + +diff --git a/grub-core/gdb/gdb.c b/grub-core/gdb/gdb.c +index 847a1e1e3..1818cb6f8 100644 +--- a/grub-core/gdb/gdb.c ++++ b/grub-core/gdb/gdb.c +@@ -75,20 +75,24 @@ static grub_command_t cmd, cmd_stop, cmd_break; + GRUB_MOD_INIT (gdb) + { + grub_gdb_idtinit (); +- cmd = grub_register_command ("gdbstub", grub_cmd_gdbstub, +- N_("PORT"), +- /* TRANSLATORS: GDB stub is a small part of +- GDB functionality running on local host +- which allows remote debugger to +- connect to it. */ +- N_("Start GDB stub on given port")); +- cmd_break = grub_register_command ("gdbstub_break", grub_cmd_gdb_break, +- /* TRANSLATORS: this refers to triggering +- a breakpoint so that the user will land +- into GDB. */ +- 0, N_("Break into GDB")); +- cmd_stop = grub_register_command ("gdbstub_stop", grub_cmd_gdbstop, +- 0, N_("Stop GDB stub")); ++ cmd = grub_register_command_lockdown ("gdbstub", grub_cmd_gdbstub, ++ N_("PORT"), ++ /* ++ * TRANSLATORS: GDB stub is a small part of ++ * GDB functionality running on local host ++ * which allows remote debugger to ++ * connect to it. ++ */ ++ N_("Start GDB stub on given port")); ++ cmd_break = grub_register_command_lockdown ("gdbstub_break", grub_cmd_gdb_break, ++ /* ++ * TRANSLATORS: this refers to triggering ++ * a breakpoint so that the user will land ++ * into GDB. ++ */ ++ 0, N_("Break into GDB")); ++ cmd_stop = grub_register_command_lockdown ("gdbstub_stop", grub_cmd_gdbstop, ++ 0, N_("Stop GDB stub")); + } + + GRUB_MOD_FINI (gdb) +-- +2.26.2 + diff --git a/0019-loader-xnu-Don-t-allow-loading-extension-and-package.patch b/0019-loader-xnu-Don-t-allow-loading-extension-and-package.patch new file mode 100644 index 0000000..47a816a --- /dev/null +++ b/0019-loader-xnu-Don-t-allow-loading-extension-and-package.patch @@ -0,0 +1,60 @@ +From da75051bd36ce97b94254f17a6a94b5cbdf77d48 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Wed, 24 Feb 2021 14:44:38 +0100 +Subject: [PATCH 19/46] loader/xnu: Don't allow loading extension and packages + when locked down + +The shim_lock verifier validates the XNU kernels but no its extensions +and packages. Prevent these to be loaded when the GRUB is locked down. + +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/loader/xnu.c | 31 +++++++++++++++++-------------- + 1 file changed, 17 insertions(+), 14 deletions(-) + +diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c +index 77d7060e1..07232d2a1 100644 +--- a/grub-core/loader/xnu.c ++++ b/grub-core/loader/xnu.c +@@ -1482,20 +1482,23 @@ GRUB_MOD_INIT(xnu) + N_("Load XNU image.")); + cmd_kernel64 = grub_register_command ("xnu_kernel64", grub_cmd_xnu_kernel64, + 0, N_("Load 64-bit XNU image.")); +- cmd_mkext = grub_register_command ("xnu_mkext", grub_cmd_xnu_mkext, 0, +- N_("Load XNU extension package.")); +- cmd_kext = grub_register_command ("xnu_kext", grub_cmd_xnu_kext, 0, +- N_("Load XNU extension.")); +- cmd_kextdir = grub_register_command ("xnu_kextdir", grub_cmd_xnu_kextdir, +- /* TRANSLATORS: OSBundleRequired is a +- variable name in xnu extensions +- manifests. It behaves mostly like +- GNU/Linux runlevels. +- */ +- N_("DIRECTORY [OSBundleRequired]"), +- /* TRANSLATORS: There are many extensions +- in extension directory. */ +- N_("Load XNU extension directory.")); ++ cmd_mkext = grub_register_command_lockdown ("xnu_mkext", grub_cmd_xnu_mkext, 0, ++ N_("Load XNU extension package.")); ++ cmd_kext = grub_register_command_lockdown ("xnu_kext", grub_cmd_xnu_kext, 0, ++ N_("Load XNU extension.")); ++ cmd_kextdir = grub_register_command_lockdown ("xnu_kextdir", grub_cmd_xnu_kextdir, ++ /* ++ * TRANSLATORS: OSBundleRequired is ++ * a variable name in xnu extensions ++ * manifests. It behaves mostly like ++ * GNU/Linux runlevels. ++ */ ++ N_("DIRECTORY [OSBundleRequired]"), ++ /* ++ * TRANSLATORS: There are many extensions ++ * in extension directory. ++ */ ++ N_("Load XNU extension directory.")); + cmd_ramdisk = grub_register_command ("xnu_ramdisk", grub_cmd_xnu_ramdisk, 0, + /* TRANSLATORS: ramdisk here isn't identifier. It can be translated. */ + N_("Load XNU ramdisk. " +-- +2.26.2 + diff --git a/0020-dl-Only-allow-unloading-modules-that-are-not-depende.patch b/0020-dl-Only-allow-unloading-modules-that-are-not-depende.patch new file mode 100644 index 0000000..0b9861d --- /dev/null +++ b/0020-dl-Only-allow-unloading-modules-that-are-not-depende.patch @@ -0,0 +1,87 @@ +From 01df3544dd3ea226e2832735c0284fc6d9157347 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Tue, 29 Sep 2020 14:08:55 +0200 +Subject: [PATCH 20/46] dl: Only allow unloading modules that are not + dependencies + +When a module is attempted to be removed its reference counter is always +decremented. This means that repeated rmmod invocations will cause the +module to be unloaded even if another module depends on it. + +This may lead to a use-after-free scenario allowing an attacker to execute +arbitrary code and by-pass the UEFI Secure Boot protection. + +While being there, add the extern keyword to some function declarations in +that header file. + +Fixes: CVE-2020-25632 + +Reported-by: Chris Coulson +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/commands/minicmd.c | 7 +++++-- + grub-core/kern/dl.c | 9 +++++++++ + include/grub/dl.h | 8 +++++--- + 3 files changed, 19 insertions(+), 5 deletions(-) + +diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c +index 6bbce3128..fa498931e 100644 +--- a/grub-core/commands/minicmd.c ++++ b/grub-core/commands/minicmd.c +@@ -140,8 +140,11 @@ grub_mini_cmd_rmmod (struct grub_command *cmd __attribute__ ((unused)), + if (grub_dl_is_persistent (mod)) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "cannot unload persistent module"); + +- if (grub_dl_unref (mod) <= 0) +- grub_dl_unload (mod); ++ if (grub_dl_ref_count (mod) > 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "cannot unload referenced module"); ++ ++ grub_dl_unref (mod); ++ grub_dl_unload (mod); + + return 0; + } +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index 2a8372e14..e02f2afc5 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -553,6 +553,15 @@ grub_dl_unref (grub_dl_t mod) + return --mod->ref_count; + } + ++int ++grub_dl_ref_count (grub_dl_t mod) ++{ ++ if (mod == NULL) ++ return 0; ++ ++ return mod->ref_count; ++} ++ + static void + grub_dl_flush_cache (grub_dl_t mod) + { +diff --git a/include/grub/dl.h b/include/grub/dl.h +index f03c03561..b3753c9ca 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -203,9 +203,11 @@ grub_dl_t EXPORT_FUNC(grub_dl_load) (const char *name); + grub_dl_t grub_dl_load_core (void *addr, grub_size_t size); + grub_dl_t EXPORT_FUNC(grub_dl_load_core_noinit) (void *addr, grub_size_t size); + int EXPORT_FUNC(grub_dl_unload) (grub_dl_t mod); +-void grub_dl_unload_unneeded (void); +-int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod); +-int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod); ++extern void grub_dl_unload_unneeded (void); ++extern int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod); ++extern int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod); ++extern int EXPORT_FUNC(grub_dl_ref_count) (grub_dl_t mod); ++ + extern grub_dl_t EXPORT_VAR(grub_dl_head); + + #ifndef GRUB_UTIL +-- +2.26.2 + diff --git a/0021-usb-Avoid-possible-out-of-bound-accesses-caused-by-m.patch b/0021-usb-Avoid-possible-out-of-bound-accesses-caused-by-m.patch new file mode 100644 index 0000000..0fe7a45 --- /dev/null +++ b/0021-usb-Avoid-possible-out-of-bound-accesses-caused-by-m.patch @@ -0,0 +1,115 @@ +From 6f8f29ca383eaa60a0eab00d4a934a072190c128 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Fri, 11 Dec 2020 19:19:21 +0100 +Subject: [PATCH 21/46] usb: Avoid possible out-of-bound accesses caused by + malicious devices + +The maximum number of configurations and interfaces are fixed but there is +no out-of-bound checking to prevent a malicious USB device to report large +values for these and cause accesses outside the arrays' memory. + +Fixes: CVE-2020-25647 + +Reported-by: Joseph Tartaro (IOActive) +Reported-by: Ilja Van Sprundel +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + grub-core/bus/usb/usb.c | 15 ++++++++++++--- + include/grub/usb.h | 10 +++++++--- + 2 files changed, 19 insertions(+), 6 deletions(-) + +diff --git a/grub-core/bus/usb/usb.c b/grub-core/bus/usb/usb.c +index 8da5e4c74..7cb3cc230 100644 +--- a/grub-core/bus/usb/usb.c ++++ b/grub-core/bus/usb/usb.c +@@ -75,6 +75,9 @@ grub_usb_controller_iterate (grub_usb_controller_iterate_hook_t hook, + grub_usb_err_t + grub_usb_clear_halt (grub_usb_device_t dev, int endpoint) + { ++ if (endpoint >= GRUB_USB_MAX_TOGGLE) ++ return GRUB_USB_ERR_BADDEVICE; ++ + dev->toggle[endpoint] = 0; + return grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT + | GRUB_USB_REQTYPE_STANDARD +@@ -134,10 +137,10 @@ grub_usb_device_initialize (grub_usb_device_t dev) + return err; + descdev = &dev->descdev; + +- for (i = 0; i < 8; i++) ++ for (i = 0; i < GRUB_USB_MAX_CONF; i++) + dev->config[i].descconf = NULL; + +- if (descdev->configcnt == 0) ++ if (descdev->configcnt == 0 || descdev->configcnt > GRUB_USB_MAX_CONF) + { + err = GRUB_USB_ERR_BADDEVICE; + goto fail; +@@ -172,6 +175,12 @@ grub_usb_device_initialize (grub_usb_device_t dev) + /* Skip the configuration descriptor. */ + pos = dev->config[i].descconf->length; + ++ if (dev->config[i].descconf->numif > GRUB_USB_MAX_IF) ++ { ++ err = GRUB_USB_ERR_BADDEVICE; ++ goto fail; ++ } ++ + /* Read all interfaces. */ + for (currif = 0; currif < dev->config[i].descconf->numif; currif++) + { +@@ -217,7 +226,7 @@ grub_usb_device_initialize (grub_usb_device_t dev) + + fail: + +- for (i = 0; i < 8; i++) ++ for (i = 0; i < GRUB_USB_MAX_CONF; i++) + grub_free (dev->config[i].descconf); + + return err; +diff --git a/include/grub/usb.h b/include/grub/usb.h +index 512ae1dd0..6475c552f 100644 +--- a/include/grub/usb.h ++++ b/include/grub/usb.h +@@ -23,6 +23,10 @@ + #include + #include + ++#define GRUB_USB_MAX_CONF 8 ++#define GRUB_USB_MAX_IF 32 ++#define GRUB_USB_MAX_TOGGLE 256 ++ + typedef struct grub_usb_device *grub_usb_device_t; + typedef struct grub_usb_controller *grub_usb_controller_t; + typedef struct grub_usb_controller_dev *grub_usb_controller_dev_t; +@@ -167,7 +171,7 @@ struct grub_usb_configuration + struct grub_usb_desc_config *descconf; + + /* Interfaces associated to this configuration. */ +- struct grub_usb_interface interf[32]; ++ struct grub_usb_interface interf[GRUB_USB_MAX_IF]; + }; + + struct grub_usb_hub_port +@@ -191,7 +195,7 @@ struct grub_usb_device + struct grub_usb_controller controller; + + /* Device configurations (after opening the device). */ +- struct grub_usb_configuration config[8]; ++ struct grub_usb_configuration config[GRUB_USB_MAX_CONF]; + + /* Device address. */ + int addr; +@@ -203,7 +207,7 @@ struct grub_usb_device + int initialized; + + /* Data toggle values (used for bulk transfers only). */ +- int toggle[256]; ++ int toggle[GRUB_USB_MAX_TOGGLE]; + + /* Used by libusb wrapper. Schedulded for removal. */ + void *data; +-- +2.26.2 + diff --git a/0022-lib-arg-Block-repeated-short-options-that-require-an.patch b/0022-lib-arg-Block-repeated-short-options-that-require-an.patch new file mode 100644 index 0000000..dc80d76 --- /dev/null +++ b/0022-lib-arg-Block-repeated-short-options-that-require-an.patch @@ -0,0 +1,54 @@ +From fafede32c0ed3bc1953c5663b58036a58fb7b6bd Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 22 Jan 2021 16:07:29 +1100 +Subject: [PATCH 22/46] lib/arg: Block repeated short options that require an + argument + +Fuzzing found the following crash: + + search -hhhhhhhhhhhhhf + +We didn't allocate enough option space for 13 hints because the +allocation code counts the number of discrete arguments (i.e. argc). +However, the shortopt parsing code will happily keep processing +a combination of short options without checking if those short +options require an argument. This means you can easily end writing +past the allocated option space. + +This fixes a OOB write which can cause heap corruption. + +Fixes: CVE-2021-20225 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/lib/arg.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/grub-core/lib/arg.c b/grub-core/lib/arg.c +index 3288609a5..537c5e94b 100644 +--- a/grub-core/lib/arg.c ++++ b/grub-core/lib/arg.c +@@ -299,6 +299,19 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv, + it can have an argument value. */ + if (*curshort) + { ++ /* ++ * Only permit further short opts if this one doesn't ++ * require a value. ++ */ ++ if (opt->type != ARG_TYPE_NONE && ++ !(opt->flags & GRUB_ARG_OPTION_OPTIONAL)) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("missing mandatory option for `%s'"), ++ opt->longarg); ++ goto fail; ++ } ++ + if (parse_option (cmd, opt, 0, usr) || grub_errno) + goto fail; + } +-- +2.26.2 + diff --git a/0023-commands-menuentry-Fix-quoting-in-setparams_prefix.patch b/0023-commands-menuentry-Fix-quoting-in-setparams_prefix.patch new file mode 100644 index 0000000..ad4911a --- /dev/null +++ b/0023-commands-menuentry-Fix-quoting-in-setparams_prefix.patch @@ -0,0 +1,46 @@ +From 833324355ed1c88b509a2c5e8632a190ce11bf40 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 22 Jan 2021 17:10:48 +1100 +Subject: [PATCH 23/46] commands/menuentry: Fix quoting in setparams_prefix() + +Commit 9acdcbf32542 (use single quotes in menuentry setparams command) +says that expressing a quoted single quote will require 3 characters. It +actually requires (and always did require!) 4 characters: + + str: a'b => a'\''b + len: 3 => 6 (2 for the letters + 4 for the quote) + +This leads to not allocating enough memory and thus out of bounds writes +that have been observed to cause heap corruption. + +Allocate 4 bytes for each single quote. + +Commit 22e7dbb2bb81 (Fix quoting in legacy parser.) does the same +quoting, but it adds 3 as extra overhead on top of the single byte that +the quote already needs. So it's correct. + +Fixes: CVE-2021-20233 +Fixes: 9acdcbf32542 (use single quotes in menuentry setparams command) + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +--- + grub-core/commands/menuentry.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c +index 348d72dac..c36913752 100644 +--- a/grub-core/commands/menuentry.c ++++ b/grub-core/commands/menuentry.c +@@ -233,7 +233,7 @@ setparams_prefix (int argc, char **args) + len += 3; /* 3 = 1 space + 2 quotes */ + p = args[i]; + while (*p) +- len += (*p++ == '\'' ? 3 : 1); ++ len += (*p++ == '\'' ? 4 : 1); + } + + result = grub_malloc (len + 2); +-- +2.26.2 + diff --git a/0024-kern-parser-Fix-resource-leak-if-argc-0.patch b/0024-kern-parser-Fix-resource-leak-if-argc-0.patch new file mode 100644 index 0000000..4bdedb0 --- /dev/null +++ b/0024-kern-parser-Fix-resource-leak-if-argc-0.patch @@ -0,0 +1,50 @@ +From 61aebf1dd8213cd8e3d4b3493f4bb4c221331c17 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Fri, 22 Jan 2021 12:32:41 +0000 +Subject: [PATCH 24/46] kern/parser: Fix resource leak if argc == 0 + +After processing the command-line yet arriving at the point where we are +setting argv, we are allocating memory, even if argc == 0, which makes +no sense since we never put anything into the allocated argv. + +The solution is to simply return that we've successfully processed the +arguments but that argc == 0, and also ensure that argv is NULL when +we're not allocating anything in it. + +There are only 2 callers of this function, and both are handling a zero +value in argc assuming nothing is allocated in argv. + +Fixes: CID 96680 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/kern/parser.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c +index 619db3122..d1cf061ad 100644 +--- a/grub-core/kern/parser.c ++++ b/grub-core/kern/parser.c +@@ -146,6 +146,7 @@ grub_parser_split_cmdline (const char *cmdline, + int i; + + *argc = 0; ++ *argv = NULL; + do + { + if (!rd || !*rd) +@@ -207,6 +208,10 @@ grub_parser_split_cmdline (const char *cmdline, + (*argc)++; + } + ++ /* If there are no args, then we're done. */ ++ if (!*argc) ++ return 0; ++ + /* Reserve memory for the return values. */ + args = grub_malloc (bp - buffer); + if (!args) +-- +2.26.2 + diff --git a/0025-kern-parser-Fix-a-memory-leak.patch b/0025-kern-parser-Fix-a-memory-leak.patch new file mode 100644 index 0000000..3d4866b --- /dev/null +++ b/0025-kern-parser-Fix-a-memory-leak.patch @@ -0,0 +1,76 @@ +From b6e9ddb100e90665d090d7f92cdc69f03f0a6498 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Wed, 18 Nov 2020 00:59:24 +0000 +Subject: [PATCH 25/46] kern/parser: Fix a memory leak + +The getline() function supplied to grub_parser_split_cmdline() returns +a newly allocated buffer and can be called multiple times, but the +returned buffer is never freed. + +Signed-off-by: Chris Coulson +Reviewed-by: Daniel Kiper +--- + grub-core/kern/parser.c | 20 ++++++++++++++++---- + 1 file changed, 16 insertions(+), 4 deletions(-) + +diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c +index d1cf061ad..39e4df65b 100644 +--- a/grub-core/kern/parser.c ++++ b/grub-core/kern/parser.c +@@ -140,6 +140,7 @@ grub_parser_split_cmdline (const char *cmdline, + char buffer[1024]; + char *bp = buffer; + char *rd = (char *) cmdline; ++ char *rp = rd; + char varname[200]; + char *vp = varname; + char *args; +@@ -149,10 +150,18 @@ grub_parser_split_cmdline (const char *cmdline, + *argv = NULL; + do + { +- if (!rd || !*rd) ++ if (rp == NULL || *rp == '\0') + { ++ if (rd != cmdline) ++ { ++ grub_free (rd); ++ rd = rp = NULL; ++ } + if (getline) +- getline (&rd, 1, getline_data); ++ { ++ getline (&rd, 1, getline_data); ++ rp = rd; ++ } + else + break; + } +@@ -160,12 +169,12 @@ grub_parser_split_cmdline (const char *cmdline, + if (!rd) + break; + +- for (; *rd; rd++) ++ for (; *rp != '\0'; rp++) + { + grub_parser_state_t newstate; + char use; + +- newstate = grub_parser_cmdline_state (state, *rd, &use); ++ newstate = grub_parser_cmdline_state (state, *rp, &use); + + /* If a variable was being processed and this character does + not describe the variable anymore, write the variable to +@@ -198,6 +207,9 @@ grub_parser_split_cmdline (const char *cmdline, + } + while (state != GRUB_PARSER_STATE_TEXT && !check_varstate (state)); + ++ if (rd != cmdline) ++ grub_free (rd); ++ + /* A special case for when the last character was part of a + variable. */ + add_var (varname, &bp, &vp, state, GRUB_PARSER_STATE_TEXT); +-- +2.26.2 + diff --git a/0026-kern-parser-Introduce-process_char-helper.patch b/0026-kern-parser-Introduce-process_char-helper.patch new file mode 100644 index 0000000..418b8dd --- /dev/null +++ b/0026-kern-parser-Introduce-process_char-helper.patch @@ -0,0 +1,119 @@ +From 80b048e51705c78638afecac539e53e80647f8bd Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Tue, 5 Jan 2021 22:17:28 +0000 +Subject: [PATCH 26/46] kern/parser: Introduce process_char() helper + +grub_parser_split_cmdline() iterates over each command line character. +In order to add error checking and to simplify the subsequent error +handling, split the character processing in to a separate function. + +Signed-off-by: Chris Coulson +Reviewed-by: Daniel Kiper +--- + grub-core/kern/parser.c | 74 +++++++++++++++++++++++++---------------- + 1 file changed, 46 insertions(+), 28 deletions(-) + +diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c +index 39e4df65b..0d3582bd8 100644 +--- a/grub-core/kern/parser.c ++++ b/grub-core/kern/parser.c +@@ -1,7 +1,7 @@ + /* parser.c - the part of the parser that can return partial tokens */ + /* + * GRUB -- GRand Unified Bootloader +- * Copyright (C) 2005,2007,2009 Free Software Foundation, Inc. ++ * Copyright (C) 2005,2007,2009,2021 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -129,6 +129,46 @@ add_var (char *varname, char **bp, char **vp, + *((*bp)++) = *val; + } + ++static grub_err_t ++process_char (char c, char *buffer, char **bp, char *varname, char **vp, ++ grub_parser_state_t state, int *argc, ++ grub_parser_state_t *newstate) ++{ ++ char use; ++ ++ *newstate = grub_parser_cmdline_state (state, c, &use); ++ ++ /* ++ * If a variable was being processed and this character does ++ * not describe the variable anymore, write the variable to ++ * the buffer. ++ */ ++ add_var (varname, bp, vp, state, *newstate); ++ ++ if (check_varstate (*newstate)) ++ { ++ if (use) ++ *((*vp)++) = use; ++ } ++ else if (*newstate == GRUB_PARSER_STATE_TEXT && ++ state != GRUB_PARSER_STATE_ESC && grub_isspace (use)) ++ { ++ /* ++ * Don't add more than one argument if multiple ++ * spaces are used. ++ */ ++ if (*bp != buffer && *((*bp) - 1) != '\0') ++ { ++ *((*bp)++) = '\0'; ++ (*argc)++; ++ } ++ } ++ else if (use) ++ *((*bp)++) = use; ++ ++ return GRUB_ERR_NONE; ++} ++ + grub_err_t + grub_parser_split_cmdline (const char *cmdline, + grub_reader_getline_t getline, void *getline_data, +@@ -172,35 +212,13 @@ grub_parser_split_cmdline (const char *cmdline, + for (; *rp != '\0'; rp++) + { + grub_parser_state_t newstate; +- char use; +- +- newstate = grub_parser_cmdline_state (state, *rp, &use); + +- /* If a variable was being processed and this character does +- not describe the variable anymore, write the variable to +- the buffer. */ +- add_var (varname, &bp, &vp, state, newstate); +- +- if (check_varstate (newstate)) +- { +- if (use) +- *(vp++) = use; +- } +- else ++ if (process_char (*rp, buffer, &bp, varname, &vp, state, argc, ++ &newstate) != GRUB_ERR_NONE) + { +- if (newstate == GRUB_PARSER_STATE_TEXT +- && state != GRUB_PARSER_STATE_ESC && grub_isspace (use)) +- { +- /* Don't add more than one argument if multiple +- spaces are used. */ +- if (bp != buffer && *(bp - 1)) +- { +- *(bp++) = '\0'; +- (*argc)++; +- } +- } +- else if (use) +- *(bp++) = use; ++ if (rd != cmdline) ++ grub_free (rd); ++ return grub_errno; + } + state = newstate; + } +-- +2.26.2 + diff --git a/0027-kern-parser-Introduce-terminate_arg-helper.patch b/0027-kern-parser-Introduce-terminate_arg-helper.patch new file mode 100644 index 0000000..4794dbd --- /dev/null +++ b/0027-kern-parser-Introduce-terminate_arg-helper.patch @@ -0,0 +1,65 @@ +From b4086b4baa1412fc962b9f88aa5e2a982afee0da Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Thu, 7 Jan 2021 19:53:55 +0000 +Subject: [PATCH 27/46] kern/parser: Introduce terminate_arg() helper + +process_char() and grub_parser_split_cmdline() use similar code for +terminating the most recent argument. Add a helper function for this. + +Signed-off-by: Chris Coulson +Reviewed-by: Daniel Kiper +--- + grub-core/kern/parser.c | 23 +++++++++++++---------- + 1 file changed, 13 insertions(+), 10 deletions(-) + +diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c +index 0d3582bd8..572c67089 100644 +--- a/grub-core/kern/parser.c ++++ b/grub-core/kern/parser.c +@@ -129,6 +129,16 @@ add_var (char *varname, char **bp, char **vp, + *((*bp)++) = *val; + } + ++static void ++terminate_arg (char *buffer, char **bp, int *argc) ++{ ++ if (*bp != buffer && *((*bp) - 1) != '\0') ++ { ++ *((*bp)++) = '\0'; ++ (*argc)++; ++ } ++} ++ + static grub_err_t + process_char (char c, char *buffer, char **bp, char *varname, char **vp, + grub_parser_state_t state, int *argc, +@@ -157,11 +167,7 @@ process_char (char c, char *buffer, char **bp, char *varname, char **vp, + * Don't add more than one argument if multiple + * spaces are used. + */ +- if (*bp != buffer && *((*bp) - 1) != '\0') +- { +- *((*bp)++) = '\0'; +- (*argc)++; +- } ++ terminate_arg (buffer, bp, argc); + } + else if (use) + *((*bp)++) = use; +@@ -232,11 +238,8 @@ grub_parser_split_cmdline (const char *cmdline, + variable. */ + add_var (varname, &bp, &vp, state, GRUB_PARSER_STATE_TEXT); + +- if (bp != buffer && *(bp - 1)) +- { +- *(bp++) = '\0'; +- (*argc)++; +- } ++ /* Ensure that the last argument is terminated. */ ++ terminate_arg (buffer, &bp, argc); + + /* If there are no args, then we're done. */ + if (!*argc) +-- +2.26.2 + diff --git a/0028-kern-parser-Refactor-grub_parser_split_cmdline-clean.patch b/0028-kern-parser-Refactor-grub_parser_split_cmdline-clean.patch new file mode 100644 index 0000000..30aa57f --- /dev/null +++ b/0028-kern-parser-Refactor-grub_parser_split_cmdline-clean.patch @@ -0,0 +1,92 @@ +From 550c0e6582b6be09b0af2fb2775a149f51c51bbc Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Wed, 6 Jan 2021 13:54:26 +0000 +Subject: [PATCH 28/46] kern/parser: Refactor grub_parser_split_cmdline() + cleanup + +Introduce a common function epilogue used for cleaning up on all +return paths, which will simplify additional error handling to be +introduced in a subsequent commit. + +Signed-off-by: Chris Coulson +Reviewed-by: Daniel Kiper +--- + grub-core/kern/parser.c | 35 ++++++++++++++++++++--------------- + 1 file changed, 20 insertions(+), 15 deletions(-) + +diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c +index 572c67089..e010eaa1f 100644 +--- a/grub-core/kern/parser.c ++++ b/grub-core/kern/parser.c +@@ -221,19 +221,13 @@ grub_parser_split_cmdline (const char *cmdline, + + if (process_char (*rp, buffer, &bp, varname, &vp, state, argc, + &newstate) != GRUB_ERR_NONE) +- { +- if (rd != cmdline) +- grub_free (rd); +- return grub_errno; +- } ++ goto fail; ++ + state = newstate; + } + } + while (state != GRUB_PARSER_STATE_TEXT && !check_varstate (state)); + +- if (rd != cmdline) +- grub_free (rd); +- + /* A special case for when the last character was part of a + variable. */ + add_var (varname, &bp, &vp, state, GRUB_PARSER_STATE_TEXT); +@@ -243,20 +237,20 @@ grub_parser_split_cmdline (const char *cmdline, + + /* If there are no args, then we're done. */ + if (!*argc) +- return 0; ++ { ++ grub_errno = GRUB_ERR_NONE; ++ goto out; ++ } + + /* Reserve memory for the return values. */ + args = grub_malloc (bp - buffer); + if (!args) +- return grub_errno; ++ goto fail; + grub_memcpy (args, buffer, bp - buffer); + + *argv = grub_calloc (*argc + 1, sizeof (char *)); + if (!*argv) +- { +- grub_free (args); +- return grub_errno; +- } ++ goto fail; + + /* The arguments are separated with 0's, setup argv so it points to + the right values. */ +@@ -269,7 +263,18 @@ grub_parser_split_cmdline (const char *cmdline, + bp++; + } + +- return 0; ++ grub_errno = GRUB_ERR_NONE; ++ ++ out: ++ if (rd != cmdline) ++ grub_free (rd); ++ ++ return grub_errno; ++ ++ fail: ++ grub_free (*argv); ++ grub_free (args); ++ goto out; + } + + /* Helper for grub_parser_execute. */ +-- +2.26.2 + diff --git a/0029-kern-buffer-Add-variable-sized-heap-buffer.patch b/0029-kern-buffer-Add-variable-sized-heap-buffer.patch new file mode 100644 index 0000000..db1a209 --- /dev/null +++ b/0029-kern-buffer-Add-variable-sized-heap-buffer.patch @@ -0,0 +1,307 @@ +From 6fa7584551965d6e444ca1a934839c6538646d0d Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Thu, 7 Jan 2021 15:15:43 +0000 +Subject: [PATCH 29/46] kern/buffer: Add variable sized heap buffer + +Add a new variable sized heap buffer type (grub_buffer_t) with simple +operations for appending data, accessing the data and maintaining +a read cursor. + +Signed-off-by: Chris Coulson +Reviewed-by: Daniel Kiper +--- + grub-core/Makefile.core.def | 1 + + grub-core/kern/buffer.c | 117 +++++++++++++++++++++++++++++ + include/grub/buffer.h | 144 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 262 insertions(+) + create mode 100644 grub-core/kern/buffer.c + create mode 100644 include/grub/buffer.h + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index a00e7f983..eac42a7b7 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -123,6 +123,7 @@ kernel = { + riscv32_efi_startup = kern/riscv/efi/startup.S; + riscv64_efi_startup = kern/riscv/efi/startup.S; + ++ common = kern/buffer.c; + common = kern/command.c; + common = kern/corecmd.c; + common = kern/device.c; +diff --git a/grub-core/kern/buffer.c b/grub-core/kern/buffer.c +new file mode 100644 +index 000000000..9f5f8b867 +--- /dev/null ++++ b/grub-core/kern/buffer.c +@@ -0,0 +1,117 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2021 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++grub_buffer_t ++grub_buffer_new (grub_size_t sz) ++{ ++ struct grub_buffer *ret; ++ ++ ret = (struct grub_buffer *) grub_malloc (sizeof (*ret)); ++ if (ret == NULL) ++ return NULL; ++ ++ ret->data = (grub_uint8_t *) grub_malloc (sz); ++ if (ret->data == NULL) ++ { ++ grub_free (ret); ++ return NULL; ++ } ++ ++ ret->sz = sz; ++ ret->pos = 0; ++ ret->used = 0; ++ ++ return ret; ++} ++ ++void ++grub_buffer_free (grub_buffer_t buf) ++{ ++ grub_free (buf->data); ++ grub_free (buf); ++} ++ ++grub_err_t ++grub_buffer_ensure_space (grub_buffer_t buf, grub_size_t req) ++{ ++ grub_uint8_t *d; ++ grub_size_t newsz = 1; ++ ++ /* Is the current buffer size adequate? */ ++ if (buf->sz >= req) ++ return GRUB_ERR_NONE; ++ ++ /* Find the smallest power-of-2 size that satisfies the request. */ ++ while (newsz < req) ++ { ++ if (newsz == 0) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("requested buffer size is too large")); ++ newsz <<= 1; ++ } ++ ++ d = (grub_uint8_t *) grub_realloc (buf->data, newsz); ++ if (d == NULL) ++ return grub_errno; ++ ++ buf->data = d; ++ buf->sz = newsz; ++ ++ return GRUB_ERR_NONE; ++} ++ ++void * ++grub_buffer_take_data (grub_buffer_t buf) ++{ ++ void *data = buf->data; ++ ++ buf->data = NULL; ++ buf->sz = buf->pos = buf->used = 0; ++ ++ return data; ++} ++ ++void ++grub_buffer_reset (grub_buffer_t buf) ++{ ++ buf->pos = buf->used = 0; ++} ++ ++grub_err_t ++grub_buffer_advance_read_pos (grub_buffer_t buf, grub_size_t n) ++{ ++ grub_size_t newpos; ++ ++ if (grub_add (buf->pos, n, &newpos)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); ++ ++ if (newpos > buf->used) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("new read is position beyond the end of the written data")); ++ ++ buf->pos = newpos; ++ ++ return GRUB_ERR_NONE; ++} +diff --git a/include/grub/buffer.h b/include/grub/buffer.h +new file mode 100644 +index 000000000..f4b10cf28 +--- /dev/null ++++ b/include/grub/buffer.h +@@ -0,0 +1,144 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2021 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_BUFFER_H ++#define GRUB_BUFFER_H 1 ++ ++#include ++#include ++#include ++#include ++#include ++ ++struct grub_buffer ++{ ++ grub_uint8_t *data; ++ grub_size_t sz; ++ grub_size_t pos; ++ grub_size_t used; ++}; ++ ++/* ++ * grub_buffer_t represents a simple variable sized byte buffer with ++ * read and write cursors. It currently only implements ++ * functionality required by the only user in GRUB (append byte[s], ++ * peeking data at a specified position and updating the read cursor. ++ * Some things that this doesn't do yet are: ++ * - Reading a portion of the buffer by copying data from the current ++ * read position in to a caller supplied destination buffer and then ++ * automatically updating the read cursor. ++ * - Dropping the read part at the start of the buffer when an append ++ * requires more space. ++ */ ++typedef struct grub_buffer *grub_buffer_t; ++ ++/* Allocate a new buffer with the specified initial size. */ ++extern grub_buffer_t grub_buffer_new (grub_size_t sz); ++ ++/* Free the buffer and its resources. */ ++extern void grub_buffer_free (grub_buffer_t buf); ++ ++/* Return the number of unread bytes in this buffer. */ ++static inline grub_size_t ++grub_buffer_get_unread_bytes (grub_buffer_t buf) ++{ ++ return buf->used - buf->pos; ++} ++ ++/* ++ * Ensure that the buffer size is at least the requested ++ * number of bytes. ++ */ ++extern grub_err_t grub_buffer_ensure_space (grub_buffer_t buf, grub_size_t req); ++ ++/* ++ * Append the specified number of bytes from the supplied ++ * data to the buffer. ++ */ ++static inline grub_err_t ++grub_buffer_append_data (grub_buffer_t buf, const void *data, grub_size_t len) ++{ ++ grub_size_t req; ++ ++ if (grub_add (buf->used, len, &req)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); ++ ++ if (grub_buffer_ensure_space (buf, req) != GRUB_ERR_NONE) ++ return grub_errno; ++ ++ grub_memcpy (&buf->data[buf->used], data, len); ++ buf->used = req; ++ ++ return GRUB_ERR_NONE; ++} ++ ++/* Append the supplied character to the buffer. */ ++static inline grub_err_t ++grub_buffer_append_char (grub_buffer_t buf, char c) ++{ ++ return grub_buffer_append_data (buf, &c, 1); ++} ++ ++/* ++ * Forget and return the underlying data buffer. The caller ++ * becomes the owner of this buffer, and must free it when it ++ * is no longer required. ++ */ ++extern void *grub_buffer_take_data (grub_buffer_t buf); ++ ++/* Reset this buffer. Note that this does not deallocate any resources. */ ++void grub_buffer_reset (grub_buffer_t buf); ++ ++/* ++ * Return a pointer to the underlying data buffer at the specified ++ * offset from the current read position. Note that this pointer may ++ * become invalid if the buffer is mutated further. ++ */ ++static inline void * ++grub_buffer_peek_data_at (grub_buffer_t buf, grub_size_t off) ++{ ++ if (grub_add (buf->pos, off, &off)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected.")); ++ return NULL; ++ } ++ ++ if (off >= buf->used) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("peek out of range")); ++ return NULL; ++ } ++ ++ return &buf->data[off]; ++} ++ ++/* ++ * Return a pointer to the underlying data buffer at the current ++ * read position. Note that this pointer may become invalid if the ++ * buffer is mutated further. ++ */ ++static inline void * ++grub_buffer_peek_data (grub_buffer_t buf) ++{ ++ return grub_buffer_peek_data_at (buf, 0); ++} ++ ++/* Advance the read position by the specified number of bytes. */ ++extern grub_err_t grub_buffer_advance_read_pos (grub_buffer_t buf, grub_size_t n); ++ ++#endif /* GRUB_BUFFER_H */ +-- +2.26.2 + diff --git a/0030-kern-parser-Fix-a-stack-buffer-overflow.patch b/0030-kern-parser-Fix-a-stack-buffer-overflow.patch new file mode 100644 index 0000000..597d8fc --- /dev/null +++ b/0030-kern-parser-Fix-a-stack-buffer-overflow.patch @@ -0,0 +1,247 @@ +From e26b56b819c65d251d12175dd82fab4679cfbc87 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Thu, 7 Jan 2021 19:21:03 +0000 +Subject: [PATCH 30/46] kern/parser: Fix a stack buffer overflow + +grub_parser_split_cmdline() expands variable names present in the supplied +command line in to their corresponding variable contents and uses a 1 kiB +stack buffer for temporary storage without sufficient bounds checking. If +the function is called with a command line that references a variable with +a sufficiently large payload, it is possible to overflow the stack +buffer via tab completion, corrupt the stack frame and potentially +control execution. + +Fixes: CVE-2020-27749 + +Reported-by: Chris Coulson +Signed-off-by: Chris Coulson +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/kern/parser.c | 110 ++++++++++++++++++++++++---------------- + 1 file changed, 67 insertions(+), 43 deletions(-) + +diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c +index e010eaa1f..6ab7aa427 100644 +--- a/grub-core/kern/parser.c ++++ b/grub-core/kern/parser.c +@@ -18,6 +18,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -107,8 +108,8 @@ check_varstate (grub_parser_state_t s) + } + + +-static void +-add_var (char *varname, char **bp, char **vp, ++static grub_err_t ++add_var (grub_buffer_t varname, grub_buffer_t buf, + grub_parser_state_t state, grub_parser_state_t newstate) + { + const char *val; +@@ -116,31 +117,41 @@ add_var (char *varname, char **bp, char **vp, + /* Check if a variable was being read in and the end of the name + was reached. */ + if (!(check_varstate (state) && !check_varstate (newstate))) +- return; ++ return GRUB_ERR_NONE; ++ ++ if (grub_buffer_append_char (varname, '\0') != GRUB_ERR_NONE) ++ return grub_errno; + +- *((*vp)++) = '\0'; +- val = grub_env_get (varname); +- *vp = varname; ++ val = grub_env_get ((const char *) grub_buffer_peek_data (varname)); ++ grub_buffer_reset (varname); + if (!val) +- return; ++ return GRUB_ERR_NONE; + + /* Insert the contents of the variable in the buffer. */ +- for (; *val; val++) +- *((*bp)++) = *val; ++ return grub_buffer_append_data (buf, val, grub_strlen (val)); + } + +-static void +-terminate_arg (char *buffer, char **bp, int *argc) ++static grub_err_t ++terminate_arg (grub_buffer_t buffer, int *argc) + { +- if (*bp != buffer && *((*bp) - 1) != '\0') +- { +- *((*bp)++) = '\0'; +- (*argc)++; +- } ++ grub_size_t unread = grub_buffer_get_unread_bytes (buffer); ++ ++ if (unread == 0) ++ return GRUB_ERR_NONE; ++ ++ if (*(const char *) grub_buffer_peek_data_at (buffer, unread - 1) == '\0') ++ return GRUB_ERR_NONE; ++ ++ if (grub_buffer_append_char (buffer, '\0') != GRUB_ERR_NONE) ++ return grub_errno; ++ ++ (*argc)++; ++ ++ return GRUB_ERR_NONE; + } + + static grub_err_t +-process_char (char c, char *buffer, char **bp, char *varname, char **vp, ++process_char (char c, grub_buffer_t buffer, grub_buffer_t varname, + grub_parser_state_t state, int *argc, + grub_parser_state_t *newstate) + { +@@ -153,12 +164,13 @@ process_char (char c, char *buffer, char **bp, char *varname, char **vp, + * not describe the variable anymore, write the variable to + * the buffer. + */ +- add_var (varname, bp, vp, state, *newstate); ++ if (add_var (varname, buffer, state, *newstate) != GRUB_ERR_NONE) ++ return grub_errno; + + if (check_varstate (*newstate)) + { + if (use) +- *((*vp)++) = use; ++ return grub_buffer_append_char (varname, use); + } + else if (*newstate == GRUB_PARSER_STATE_TEXT && + state != GRUB_PARSER_STATE_ESC && grub_isspace (use)) +@@ -167,10 +179,10 @@ process_char (char c, char *buffer, char **bp, char *varname, char **vp, + * Don't add more than one argument if multiple + * spaces are used. + */ +- terminate_arg (buffer, bp, argc); ++ return terminate_arg (buffer, argc); + } + else if (use) +- *((*bp)++) = use; ++ return grub_buffer_append_char (buffer, use); + + return GRUB_ERR_NONE; + } +@@ -181,19 +193,22 @@ grub_parser_split_cmdline (const char *cmdline, + int *argc, char ***argv) + { + grub_parser_state_t state = GRUB_PARSER_STATE_TEXT; +- /* XXX: Fixed size buffer, perhaps this buffer should be dynamically +- allocated. */ +- char buffer[1024]; +- char *bp = buffer; ++ grub_buffer_t buffer, varname; + char *rd = (char *) cmdline; + char *rp = rd; +- char varname[200]; +- char *vp = varname; +- char *args; + int i; + + *argc = 0; + *argv = NULL; ++ ++ buffer = grub_buffer_new (1024); ++ if (buffer == NULL) ++ return grub_errno; ++ ++ varname = grub_buffer_new (200); ++ if (varname == NULL) ++ goto fail; ++ + do + { + if (rp == NULL || *rp == '\0') +@@ -219,7 +234,7 @@ grub_parser_split_cmdline (const char *cmdline, + { + grub_parser_state_t newstate; + +- if (process_char (*rp, buffer, &bp, varname, &vp, state, argc, ++ if (process_char (*rp, buffer, varname, state, argc, + &newstate) != GRUB_ERR_NONE) + goto fail; + +@@ -230,10 +245,12 @@ grub_parser_split_cmdline (const char *cmdline, + + /* A special case for when the last character was part of a + variable. */ +- add_var (varname, &bp, &vp, state, GRUB_PARSER_STATE_TEXT); ++ if (add_var (varname, buffer, state, GRUB_PARSER_STATE_TEXT) != GRUB_ERR_NONE) ++ goto fail; + + /* Ensure that the last argument is terminated. */ +- terminate_arg (buffer, &bp, argc); ++ if (terminate_arg (buffer, argc) != GRUB_ERR_NONE) ++ goto fail; + + /* If there are no args, then we're done. */ + if (!*argc) +@@ -242,38 +259,45 @@ grub_parser_split_cmdline (const char *cmdline, + goto out; + } + +- /* Reserve memory for the return values. */ +- args = grub_malloc (bp - buffer); +- if (!args) +- goto fail; +- grub_memcpy (args, buffer, bp - buffer); +- + *argv = grub_calloc (*argc + 1, sizeof (char *)); + if (!*argv) + goto fail; + + /* The arguments are separated with 0's, setup argv so it points to + the right values. */ +- bp = args; + for (i = 0; i < *argc; i++) + { +- (*argv)[i] = bp; +- while (*bp) +- bp++; +- bp++; ++ char *arg; ++ ++ if (i > 0) ++ { ++ if (grub_buffer_advance_read_pos (buffer, 1) != GRUB_ERR_NONE) ++ goto fail; ++ } ++ ++ arg = (char *) grub_buffer_peek_data (buffer); ++ if (arg == NULL || ++ grub_buffer_advance_read_pos (buffer, grub_strlen (arg)) != GRUB_ERR_NONE) ++ goto fail; ++ ++ (*argv)[i] = arg; + } + ++ /* Keep memory for the return values. */ ++ grub_buffer_take_data (buffer); ++ + grub_errno = GRUB_ERR_NONE; + + out: + if (rd != cmdline) + grub_free (rd); ++ grub_buffer_free (buffer); ++ grub_buffer_free (varname); + + return grub_errno; + + fail: + grub_free (*argv); +- grub_free (args); + goto out; + } + +-- +2.26.2 + diff --git a/0031-util-mkimage-Remove-unused-code-to-add-BSS-section.patch b/0031-util-mkimage-Remove-unused-code-to-add-BSS-section.patch new file mode 100644 index 0000000..ef4a9d9 --- /dev/null +++ b/0031-util-mkimage-Remove-unused-code-to-add-BSS-section.patch @@ -0,0 +1,60 @@ +From 88862305f889d23a176c936ff337a8f3ec492efd Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Thu, 11 Feb 2021 17:06:49 +0100 +Subject: [PATCH 31/46] util/mkimage: Remove unused code to add BSS section + +The code is compiled out so there is no reason to keep it. + +Additionally, don't set bss_size field since we do not add a BSS section. + +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + util/mkimage.c | 17 ----------------- + 1 file changed, 17 deletions(-) + +diff --git a/util/mkimage.c b/util/mkimage.c +index 37d6249f1..32bb8ea68 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -1304,7 +1304,6 @@ grub_install_generate_image (const char *dir, const char *prefix, + o->code_size = grub_host_to_target32 (layout.exec_size); + o->data_size = grub_cpu_to_le32 (reloc_addr - layout.exec_size + - header_size); +- o->bss_size = grub_cpu_to_le32 (layout.bss_size); + o->entry_addr = grub_cpu_to_le32 (layout.start_address); + o->code_base = grub_cpu_to_le32 (header_size); + +@@ -1342,7 +1341,6 @@ grub_install_generate_image (const char *dir, const char *prefix, + o->code_size = grub_host_to_target32 (layout.exec_size); + o->data_size = grub_cpu_to_le32 (reloc_addr - layout.exec_size + - header_size); +- o->bss_size = grub_cpu_to_le32 (layout.bss_size); + o->entry_addr = grub_cpu_to_le32 (layout.start_address); + o->code_base = grub_cpu_to_le32 (header_size); + o->image_base = 0; +@@ -1387,21 +1385,6 @@ grub_install_generate_image (const char *dir, const char *prefix, + = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA + | GRUB_PE32_SCN_MEM_READ + | GRUB_PE32_SCN_MEM_WRITE); +- +-#if 0 +- bss_section = data_section + 1; +- strcpy (bss_section->name, ".bss"); +- bss_section->virtual_size = grub_cpu_to_le32 (layout.bss_size); +- bss_section->virtual_address = grub_cpu_to_le32 (header_size + layout.kernel_size); +- bss_section->raw_data_size = 0; +- bss_section->raw_data_offset = 0; +- bss_section->characteristics +- = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_MEM_READ +- | GRUB_PE32_SCN_MEM_WRITE +- | GRUB_PE32_SCN_ALIGN_64BYTES +- | GRUB_PE32_SCN_CNT_INITIALIZED_DATA +- | 0x80); +-#endif + + mods_section = data_section + 1; + strcpy (mods_section->name, "mods"); +-- +2.26.2 + diff --git a/0032-util-mkimage-Use-grub_host_to_target32-instead-of-gr.patch b/0032-util-mkimage-Use-grub_host_to_target32-instead-of-gr.patch new file mode 100644 index 0000000..c5fc163 --- /dev/null +++ b/0032-util-mkimage-Use-grub_host_to_target32-instead-of-gr.patch @@ -0,0 +1,112 @@ +From 6e003a43373e87683f3c5b783cdc8e423e1a6bc3 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 15 Feb 2021 13:59:21 +0100 +Subject: [PATCH 32/46] util/mkimage: Use grub_host_to_target32() instead of + grub_cpu_to_le32() + +The latter doesn't take into account the target image endianness. There is +a grub_cpu_to_le32_compile_time() but no compile time variant for function +grub_host_to_target32(). So, let's keep using the other one for this case. + +Signed-off-by: Peter Jones +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + util/mkimage.c | 44 ++++++++++++++++++++++---------------------- + 1 file changed, 22 insertions(+), 22 deletions(-) + +diff --git a/util/mkimage.c b/util/mkimage.c +index 32bb8ea68..02944f28e 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -1302,10 +1302,10 @@ grub_install_generate_image (const char *dir, const char *prefix, + + sizeof (struct grub_pe32_coff_header)); + o->magic = grub_host_to_target16 (GRUB_PE32_PE32_MAGIC); + o->code_size = grub_host_to_target32 (layout.exec_size); +- o->data_size = grub_cpu_to_le32 (reloc_addr - layout.exec_size ++ o->data_size = grub_host_to_target32 (reloc_addr - layout.exec_size + - header_size); +- o->entry_addr = grub_cpu_to_le32 (layout.start_address); +- o->code_base = grub_cpu_to_le32 (header_size); ++ o->entry_addr = grub_host_to_target32 (layout.start_address); ++ o->code_base = grub_host_to_target32 (header_size); + + o->data_base = grub_host_to_target32 (header_size + layout.exec_size); + +@@ -1339,10 +1339,10 @@ grub_install_generate_image (const char *dir, const char *prefix, + + sizeof (struct grub_pe32_coff_header)); + o->magic = grub_host_to_target16 (GRUB_PE32_PE64_MAGIC); + o->code_size = grub_host_to_target32 (layout.exec_size); +- o->data_size = grub_cpu_to_le32 (reloc_addr - layout.exec_size ++ o->data_size = grub_host_to_target32 (reloc_addr - layout.exec_size + - header_size); +- o->entry_addr = grub_cpu_to_le32 (layout.start_address); +- o->code_base = grub_cpu_to_le32 (header_size); ++ o->entry_addr = grub_host_to_target32 (layout.start_address); ++ o->code_base = grub_host_to_target32 (header_size); + o->image_base = 0; + o->section_alignment = grub_host_to_target32 (image_target->section_align); + o->file_alignment = grub_host_to_target32 (GRUB_PE32_FILE_ALIGNMENT); +@@ -1366,10 +1366,10 @@ grub_install_generate_image (const char *dir, const char *prefix, + /* The sections. */ + text_section = sections; + strcpy (text_section->name, ".text"); +- text_section->virtual_size = grub_cpu_to_le32 (layout.exec_size); +- text_section->virtual_address = grub_cpu_to_le32 (header_size); +- text_section->raw_data_size = grub_cpu_to_le32 (layout.exec_size); +- text_section->raw_data_offset = grub_cpu_to_le32 (header_size); ++ text_section->virtual_size = grub_host_to_target32 (layout.exec_size); ++ text_section->virtual_address = grub_host_to_target32 (header_size); ++ text_section->raw_data_size = grub_host_to_target32 (layout.exec_size); ++ text_section->raw_data_offset = grub_host_to_target32 (header_size); + text_section->characteristics = grub_cpu_to_le32_compile_time ( + GRUB_PE32_SCN_CNT_CODE + | GRUB_PE32_SCN_MEM_EXECUTE +@@ -1377,10 +1377,10 @@ grub_install_generate_image (const char *dir, const char *prefix, + + data_section = text_section + 1; + strcpy (data_section->name, ".data"); +- data_section->virtual_size = grub_cpu_to_le32 (layout.kernel_size - layout.exec_size); +- data_section->virtual_address = grub_cpu_to_le32 (header_size + layout.exec_size); +- data_section->raw_data_size = grub_cpu_to_le32 (layout.kernel_size - layout.exec_size); +- data_section->raw_data_offset = grub_cpu_to_le32 (header_size + layout.exec_size); ++ data_section->virtual_size = grub_host_to_target32 (layout.kernel_size - layout.exec_size); ++ data_section->virtual_address = grub_host_to_target32 (header_size + layout.exec_size); ++ data_section->raw_data_size = grub_host_to_target32 (layout.kernel_size - layout.exec_size); ++ data_section->raw_data_offset = grub_host_to_target32 (header_size + layout.exec_size); + data_section->characteristics + = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA + | GRUB_PE32_SCN_MEM_READ +@@ -1388,10 +1388,10 @@ grub_install_generate_image (const char *dir, const char *prefix, + + mods_section = data_section + 1; + strcpy (mods_section->name, "mods"); +- mods_section->virtual_size = grub_cpu_to_le32 (reloc_addr - layout.kernel_size - header_size); +- mods_section->virtual_address = grub_cpu_to_le32 (header_size + layout.kernel_size + layout.bss_size); +- mods_section->raw_data_size = grub_cpu_to_le32 (reloc_addr - layout.kernel_size - header_size); +- mods_section->raw_data_offset = grub_cpu_to_le32 (header_size + layout.kernel_size); ++ mods_section->virtual_size = grub_host_to_target32 (reloc_addr - layout.kernel_size - header_size); ++ mods_section->virtual_address = grub_host_to_target32 (header_size + layout.kernel_size + layout.bss_size); ++ mods_section->raw_data_size = grub_host_to_target32 (reloc_addr - layout.kernel_size - header_size); ++ mods_section->raw_data_offset = grub_host_to_target32 (header_size + layout.kernel_size); + mods_section->characteristics + = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA + | GRUB_PE32_SCN_MEM_READ +@@ -1399,10 +1399,10 @@ grub_install_generate_image (const char *dir, const char *prefix, + + reloc_section = mods_section + 1; + strcpy (reloc_section->name, ".reloc"); +- reloc_section->virtual_size = grub_cpu_to_le32 (layout.reloc_size); +- reloc_section->virtual_address = grub_cpu_to_le32 (reloc_addr + layout.bss_size); +- reloc_section->raw_data_size = grub_cpu_to_le32 (layout.reloc_size); +- reloc_section->raw_data_offset = grub_cpu_to_le32 (reloc_addr); ++ reloc_section->virtual_size = grub_host_to_target32 (layout.reloc_size); ++ reloc_section->virtual_address = grub_host_to_target32 (reloc_addr + layout.bss_size); ++ reloc_section->raw_data_size = grub_host_to_target32 (layout.reloc_size); ++ reloc_section->raw_data_offset = grub_host_to_target32 (reloc_addr); + reloc_section->characteristics + = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA + | GRUB_PE32_SCN_MEM_DISCARDABLE +-- +2.26.2 + diff --git a/0033-util-mkimage-Always-use-grub_host_to_target32-to-ini.patch b/0033-util-mkimage-Always-use-grub_host_to_target32-to-ini.patch new file mode 100644 index 0000000..e25b3d5 --- /dev/null +++ b/0033-util-mkimage-Always-use-grub_host_to_target32-to-ini.patch @@ -0,0 +1,38 @@ +From 4bf74d11396e0adde218a3129599f145459852f3 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 15 Feb 2021 14:14:24 +0100 +Subject: [PATCH 33/46] util/mkimage: Always use grub_host_to_target32() to + initialize PE stack and heap stuff + +This change does not impact final result of initialization itself. +However, it eases PE code unification in subsequent patches. + +Signed-off-by: Peter Jones +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + util/mkimage.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/util/mkimage.c b/util/mkimage.c +index 02944f28e..b94bfb781 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -1351,10 +1351,10 @@ grub_install_generate_image (const char *dir, const char *prefix, + o->subsystem = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION); + + /* Do these really matter? */ +- o->stack_reserve_size = grub_host_to_target64 (0x10000); +- o->stack_commit_size = grub_host_to_target64 (0x10000); +- o->heap_reserve_size = grub_host_to_target64 (0x10000); +- o->heap_commit_size = grub_host_to_target64 (0x10000); ++ o->stack_reserve_size = grub_host_to_target32 (0x10000); ++ o->stack_commit_size = grub_host_to_target32 (0x10000); ++ o->heap_reserve_size = grub_host_to_target32 (0x10000); ++ o->heap_commit_size = grub_host_to_target32 (0x10000); + + o->num_data_directories + = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); +-- +2.26.2 + diff --git a/0034-util-mkimage-Unify-more-of-the-PE32-and-PE32-header-.patch b/0034-util-mkimage-Unify-more-of-the-PE32-and-PE32-header-.patch new file mode 100644 index 0000000..1f63c9a --- /dev/null +++ b/0034-util-mkimage-Unify-more-of-the-PE32-and-PE32-header-.patch @@ -0,0 +1,169 @@ +From 17db90317938d492561af63f0cc7356c6dadb46a Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 15 Feb 2021 14:19:31 +0100 +Subject: [PATCH 34/46] util/mkimage: Unify more of the PE32 and PE32+ header + set-up + +There's quite a bit of code duplication in the code that sets the optional +header for PE32 and PE32+. The two are very similar with the exception of +a few fields that have type grub_uint64_t instead of grub_uint32_t. + +Factor out the common code and add a PE_OHDR() macro that simplifies the +set-up and make the code more readable. + +Signed-off-by: Peter Jones +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + util/mkimage.c | 111 +++++++++++++++++++++++-------------------------- + 1 file changed, 51 insertions(+), 60 deletions(-) + +diff --git a/util/mkimage.c b/util/mkimage.c +index b94bfb781..a039039db 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -816,6 +816,21 @@ grub_install_get_image_targets_string (void) + return formats; + } + ++/* ++ * tmp_ is just here so the compiler knows we'll never derefernce a NULL. ++ * It should get fully optimized away. ++ */ ++#define PE_OHDR(o32, o64, field) (*( \ ++{ \ ++ __typeof__((o64)->field) tmp_; \ ++ __typeof__((o64)->field) *ret_ = &tmp_; \ ++ if (o32) \ ++ ret_ = (void *)(&((o32)->field)); \ ++ else if (o64) \ ++ ret_ = (void *)(&((o64)->field)); \ ++ ret_; \ ++})) ++ + void + grub_install_generate_image (const char *dir, const char *prefix, + FILE *out, const char *outname, char *mods[], +@@ -1252,6 +1267,8 @@ grub_install_generate_image (const char *dir, const char *prefix, + static const grub_uint8_t stub[] = GRUB_PE32_MSDOS_STUB; + int header_size; + int reloc_addr; ++ struct grub_pe32_optional_header *o32 = NULL; ++ struct grub_pe64_optional_header *o64 = NULL; + + if (image_target->voidp_sizeof == 4) + header_size = EFI32_HEADER_SIZE; +@@ -1293,76 +1310,50 @@ grub_install_generate_image (const char *dir, const char *prefix, + /* The PE Optional header. */ + if (image_target->voidp_sizeof == 4) + { +- struct grub_pe32_optional_header *o; +- + c->optional_header_size = grub_host_to_target16 (sizeof (struct grub_pe32_optional_header)); + +- o = (struct grub_pe32_optional_header *) +- (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE +- + sizeof (struct grub_pe32_coff_header)); +- o->magic = grub_host_to_target16 (GRUB_PE32_PE32_MAGIC); +- o->code_size = grub_host_to_target32 (layout.exec_size); +- o->data_size = grub_host_to_target32 (reloc_addr - layout.exec_size +- - header_size); +- o->entry_addr = grub_host_to_target32 (layout.start_address); +- o->code_base = grub_host_to_target32 (header_size); +- +- o->data_base = grub_host_to_target32 (header_size + layout.exec_size); +- +- o->image_base = 0; +- o->section_alignment = grub_host_to_target32 (image_target->section_align); +- o->file_alignment = grub_host_to_target32 (GRUB_PE32_FILE_ALIGNMENT); +- o->image_size = grub_host_to_target32 (pe_size); +- o->header_size = grub_host_to_target32 (header_size); +- o->subsystem = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION); +- +- /* Do these really matter? */ +- o->stack_reserve_size = grub_host_to_target32 (0x10000); +- o->stack_commit_size = grub_host_to_target32 (0x10000); +- o->heap_reserve_size = grub_host_to_target32 (0x10000); +- o->heap_commit_size = grub_host_to_target32 (0x10000); +- +- o->num_data_directories = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); ++ o32 = (struct grub_pe32_optional_header *) ++ (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE + ++ sizeof (struct grub_pe32_coff_header)); ++ o32->magic = grub_host_to_target16 (GRUB_PE32_PE32_MAGIC); ++ o32->data_base = grub_host_to_target32 (header_size + layout.exec_size); + +- o->base_relocation_table.rva = grub_host_to_target32 (reloc_addr); +- o->base_relocation_table.size = grub_host_to_target32 (layout.reloc_size); +- sections = o + 1; ++ sections = o32 + 1; + } + else + { +- struct grub_pe64_optional_header *o; +- + c->optional_header_size = grub_host_to_target16 (sizeof (struct grub_pe64_optional_header)); + +- o = (struct grub_pe64_optional_header *) +- (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE +- + sizeof (struct grub_pe32_coff_header)); +- o->magic = grub_host_to_target16 (GRUB_PE32_PE64_MAGIC); +- o->code_size = grub_host_to_target32 (layout.exec_size); +- o->data_size = grub_host_to_target32 (reloc_addr - layout.exec_size +- - header_size); +- o->entry_addr = grub_host_to_target32 (layout.start_address); +- o->code_base = grub_host_to_target32 (header_size); +- o->image_base = 0; +- o->section_alignment = grub_host_to_target32 (image_target->section_align); +- o->file_alignment = grub_host_to_target32 (GRUB_PE32_FILE_ALIGNMENT); +- o->image_size = grub_host_to_target32 (pe_size); +- o->header_size = grub_host_to_target32 (header_size); +- o->subsystem = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION); +- +- /* Do these really matter? */ +- o->stack_reserve_size = grub_host_to_target32 (0x10000); +- o->stack_commit_size = grub_host_to_target32 (0x10000); +- o->heap_reserve_size = grub_host_to_target32 (0x10000); +- o->heap_commit_size = grub_host_to_target32 (0x10000); +- +- o->num_data_directories +- = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); ++ o64 = (struct grub_pe64_optional_header *) ++ (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE + ++ sizeof (struct grub_pe32_coff_header)); ++ o64->magic = grub_host_to_target16 (GRUB_PE32_PE64_MAGIC); + +- o->base_relocation_table.rva = grub_host_to_target32 (reloc_addr); +- o->base_relocation_table.size = grub_host_to_target32 (layout.reloc_size); +- sections = o + 1; ++ sections = o64 + 1; + } ++ ++ PE_OHDR (o32, o64, code_size) = grub_host_to_target32 (layout.exec_size); ++ PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (reloc_addr - layout.exec_size - header_size); ++ PE_OHDR (o32, o64, entry_addr) = grub_host_to_target32 (layout.start_address); ++ PE_OHDR (o32, o64, code_base) = grub_host_to_target32 (header_size); ++ ++ PE_OHDR (o32, o64, image_base) = 0; ++ PE_OHDR (o32, o64, section_alignment) = grub_host_to_target32 (image_target->section_align); ++ PE_OHDR (o32, o64, file_alignment) = grub_host_to_target32 (GRUB_PE32_FILE_ALIGNMENT); ++ PE_OHDR (o32, o64, image_size) = grub_host_to_target32 (pe_size); ++ PE_OHDR (o32, o64, header_size) = grub_host_to_target32 (header_size); ++ PE_OHDR (o32, o64, subsystem) = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION); ++ ++ /* Do these really matter? */ ++ PE_OHDR (o32, o64, stack_reserve_size) = grub_host_to_target32 (0x10000); ++ PE_OHDR (o32, o64, stack_commit_size) = grub_host_to_target32 (0x10000); ++ PE_OHDR (o32, o64, heap_reserve_size) = grub_host_to_target32 (0x10000); ++ PE_OHDR (o32, o64, heap_commit_size) = grub_host_to_target32 (0x10000); ++ ++ PE_OHDR (o32, o64, num_data_directories) = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); ++ PE_OHDR (o32, o64, base_relocation_table.rva) = grub_host_to_target32 (reloc_addr); ++ PE_OHDR (o32, o64, base_relocation_table.size) = grub_host_to_target32 (layout.reloc_size); ++ + /* The sections. */ + text_section = sections; + strcpy (text_section->name, ".text"); +-- +2.26.2 + diff --git a/0035-util-mkimage-Reorder-PE-optional-header-fields-set-u.patch b/0035-util-mkimage-Reorder-PE-optional-header-fields-set-u.patch new file mode 100644 index 0000000..4c4db2d --- /dev/null +++ b/0035-util-mkimage-Reorder-PE-optional-header-fields-set-u.patch @@ -0,0 +1,72 @@ +From fbacfa8211adbd1acaf264f7b1292781121a7195 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 15 Feb 2021 14:21:48 +0100 +Subject: [PATCH 35/46] util/mkimage: Reorder PE optional header fields set-up + +This makes the PE32 and PE32+ header fields set-up easier to follow by +setting them closer to the initialization of their related sections. + +Signed-off-by: Peter Jones +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + util/mkimage.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/util/mkimage.c b/util/mkimage.c +index a039039db..deaef5666 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -1332,16 +1332,12 @@ grub_install_generate_image (const char *dir, const char *prefix, + sections = o64 + 1; + } + +- PE_OHDR (o32, o64, code_size) = grub_host_to_target32 (layout.exec_size); +- PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (reloc_addr - layout.exec_size - header_size); ++ PE_OHDR (o32, o64, header_size) = grub_host_to_target32 (header_size); + PE_OHDR (o32, o64, entry_addr) = grub_host_to_target32 (layout.start_address); +- PE_OHDR (o32, o64, code_base) = grub_host_to_target32 (header_size); +- + PE_OHDR (o32, o64, image_base) = 0; ++ PE_OHDR (o32, o64, image_size) = grub_host_to_target32 (pe_size); + PE_OHDR (o32, o64, section_alignment) = grub_host_to_target32 (image_target->section_align); + PE_OHDR (o32, o64, file_alignment) = grub_host_to_target32 (GRUB_PE32_FILE_ALIGNMENT); +- PE_OHDR (o32, o64, image_size) = grub_host_to_target32 (pe_size); +- PE_OHDR (o32, o64, header_size) = grub_host_to_target32 (header_size); + PE_OHDR (o32, o64, subsystem) = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION); + + /* Do these really matter? */ +@@ -1351,10 +1347,10 @@ grub_install_generate_image (const char *dir, const char *prefix, + PE_OHDR (o32, o64, heap_commit_size) = grub_host_to_target32 (0x10000); + + PE_OHDR (o32, o64, num_data_directories) = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); +- PE_OHDR (o32, o64, base_relocation_table.rva) = grub_host_to_target32 (reloc_addr); +- PE_OHDR (o32, o64, base_relocation_table.size) = grub_host_to_target32 (layout.reloc_size); + + /* The sections. */ ++ PE_OHDR (o32, o64, code_base) = grub_host_to_target32 (header_size); ++ PE_OHDR (o32, o64, code_size) = grub_host_to_target32 (layout.exec_size); + text_section = sections; + strcpy (text_section->name, ".text"); + text_section->virtual_size = grub_host_to_target32 (layout.exec_size); +@@ -1366,6 +1362,8 @@ grub_install_generate_image (const char *dir, const char *prefix, + | GRUB_PE32_SCN_MEM_EXECUTE + | GRUB_PE32_SCN_MEM_READ); + ++ PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (reloc_addr - layout.exec_size - header_size); ++ + data_section = text_section + 1; + strcpy (data_section->name, ".data"); + data_section->virtual_size = grub_host_to_target32 (layout.kernel_size - layout.exec_size); +@@ -1388,6 +1386,8 @@ grub_install_generate_image (const char *dir, const char *prefix, + | GRUB_PE32_SCN_MEM_READ + | GRUB_PE32_SCN_MEM_WRITE); + ++ PE_OHDR (o32, o64, base_relocation_table.rva) = grub_host_to_target32 (reloc_addr); ++ PE_OHDR (o32, o64, base_relocation_table.size) = grub_host_to_target32 (layout.reloc_size); + reloc_section = mods_section + 1; + strcpy (reloc_section->name, ".reloc"); + reloc_section->virtual_size = grub_host_to_target32 (layout.reloc_size); +-- +2.26.2 + diff --git a/0036-util-mkimage-Improve-data_size-value-calculation.patch b/0036-util-mkimage-Improve-data_size-value-calculation.patch new file mode 100644 index 0000000..be62027 --- /dev/null +++ b/0036-util-mkimage-Improve-data_size-value-calculation.patch @@ -0,0 +1,49 @@ +From 805d58de7a06687572fba8f8d0f4110204246f2d Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 11 Feb 2021 17:07:33 +0100 +Subject: [PATCH 36/46] util/mkimage: Improve data_size value calculation + +According to "Microsoft Portable Executable and Common Object File Format +Specification", the Optional Header SizeOfInitializedData field contains: + + Size of the initialized data section, or the sum of all such sections if + there are multiple data sections. + +Make this explicit by adding the GRUB kernel data size to the sum of all +the modules sizes. The ALIGN_UP() is not required by the PE spec but do +it to avoid alignment issues. + +Signed-off-by: Peter Jones +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + util/mkimage.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/util/mkimage.c b/util/mkimage.c +index deaef5666..853a52179 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -1260,6 +1260,7 @@ grub_install_generate_image (const char *dir, const char *prefix, + void *pe_img; + grub_uint8_t *header; + void *sections; ++ size_t scn_size; + size_t pe_size; + struct grub_pe32_coff_header *c; + struct grub_pe32_section_table *text_section, *data_section; +@@ -1362,7 +1363,10 @@ grub_install_generate_image (const char *dir, const char *prefix, + | GRUB_PE32_SCN_MEM_EXECUTE + | GRUB_PE32_SCN_MEM_READ); + +- PE_OHDR (o32, o64, data_size) = grub_host_to_target32 (reloc_addr - layout.exec_size - header_size); ++ 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 (total_module_size, ++ GRUB_PE32_FILE_ALIGNMENT)); + + data_section = text_section + 1; + strcpy (data_section->name, ".data"); +-- +2.26.2 + diff --git a/0037-util-mkimage-Refactor-section-setup-to-use-a-helper.patch b/0037-util-mkimage-Refactor-section-setup-to-use-a-helper.patch new file mode 100644 index 0000000..35ac99c --- /dev/null +++ b/0037-util-mkimage-Refactor-section-setup-to-use-a-helper.patch @@ -0,0 +1,220 @@ +From aa25aa5d9ce91e862cc951225c5aabc78c4d4366 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 15 Feb 2021 14:58:06 +0100 +Subject: [PATCH 37/46] util/mkimage: Refactor section setup to use a helper + +Add a init_pe_section() helper function to setup PE sections. This makes +the code simpler and easier to read. + +Signed-off-by: Peter Jones +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +--- + util/mkimage.c | 143 ++++++++++++++++++++++++++----------------------- + 1 file changed, 77 insertions(+), 66 deletions(-) + +diff --git a/util/mkimage.c b/util/mkimage.c +index 853a52179..8b475a691 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -816,6 +816,38 @@ grub_install_get_image_targets_string (void) + return formats; + } + ++/* ++ * The image_target parameter is used by the grub_host_to_target32() macro. ++ */ ++static struct grub_pe32_section_table * ++init_pe_section(const struct grub_install_image_target_desc *image_target, ++ struct grub_pe32_section_table *section, ++ const char * const name, ++ grub_uint32_t *vma, grub_uint32_t vsz, grub_uint32_t valign, ++ grub_uint32_t *rda, grub_uint32_t rsz, ++ grub_uint32_t characteristics) ++{ ++ size_t len = strlen (name); ++ ++ if (len > sizeof (section->name)) ++ grub_util_error (_("section name %s length is bigger than %lu"), ++ name, (unsigned long) sizeof (section->name)); ++ ++ memcpy (section->name, name, len); ++ ++ section->virtual_address = grub_host_to_target32 (*vma); ++ section->virtual_size = grub_host_to_target32 (vsz); ++ (*vma) = ALIGN_UP (*vma + vsz, valign); ++ ++ section->raw_data_offset = grub_host_to_target32 (*rda); ++ section->raw_data_size = grub_host_to_target32 (rsz); ++ (*rda) = ALIGN_UP (*rda + rsz, GRUB_PE32_FILE_ALIGNMENT); ++ ++ section->characteristics = grub_host_to_target32 (characteristics); ++ ++ return section + 1; ++} ++ + /* + * tmp_ is just here so the compiler knows we'll never derefernce a NULL. + * It should get fully optimized away. +@@ -1257,17 +1289,13 @@ grub_install_generate_image (const char *dir, const char *prefix, + break; + case IMAGE_EFI: + { +- void *pe_img; +- grub_uint8_t *header; +- void *sections; ++ char *pe_img, *header; ++ struct grub_pe32_section_table *section; + size_t scn_size; +- size_t pe_size; ++ grub_uint32_t vma, raw_data; ++ size_t pe_size, header_size; + struct grub_pe32_coff_header *c; +- struct grub_pe32_section_table *text_section, *data_section; +- struct grub_pe32_section_table *mods_section, *reloc_section; + static const grub_uint8_t stub[] = GRUB_PE32_MSDOS_STUB; +- int header_size; +- int reloc_addr; + struct grub_pe32_optional_header *o32 = NULL; + struct grub_pe64_optional_header *o64 = NULL; + +@@ -1276,17 +1304,12 @@ grub_install_generate_image (const char *dir, const char *prefix, + else + header_size = EFI64_HEADER_SIZE; + +- reloc_addr = ALIGN_UP (header_size + core_size, +- GRUB_PE32_FILE_ALIGNMENT); ++ vma = raw_data = header_size; ++ pe_size = ALIGN_UP (header_size + core_size, GRUB_PE32_FILE_ALIGNMENT) + ++ ALIGN_UP (layout.reloc_size, GRUB_PE32_FILE_ALIGNMENT); ++ header = pe_img = xcalloc (1, pe_size); + +- pe_size = ALIGN_UP (reloc_addr + layout.reloc_size, +- GRUB_PE32_FILE_ALIGNMENT); +- pe_img = xmalloc (reloc_addr + layout.reloc_size); +- memset (pe_img, 0, header_size); +- memcpy ((char *) pe_img + header_size, core_img, core_size); +- memset ((char *) pe_img + header_size + core_size, 0, reloc_addr - (header_size + core_size)); +- memcpy ((char *) pe_img + reloc_addr, layout.reloc_section, layout.reloc_size); +- header = pe_img; ++ memcpy (pe_img + raw_data, core_img, core_size); + + /* The magic. */ + memcpy (header, stub, GRUB_PE32_MSDOS_STUB_SIZE); +@@ -1319,18 +1342,17 @@ grub_install_generate_image (const char *dir, const char *prefix, + o32->magic = grub_host_to_target16 (GRUB_PE32_PE32_MAGIC); + o32->data_base = grub_host_to_target32 (header_size + layout.exec_size); + +- sections = o32 + 1; ++ section = (struct grub_pe32_section_table *)(o32 + 1); + } + else + { + c->optional_header_size = grub_host_to_target16 (sizeof (struct grub_pe64_optional_header)); +- + o64 = (struct grub_pe64_optional_header *) + (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE + + sizeof (struct grub_pe32_coff_header)); + o64->magic = grub_host_to_target16 (GRUB_PE32_PE64_MAGIC); + +- sections = o64 + 1; ++ section = (struct grub_pe32_section_table *)(o64 + 1); + } + + PE_OHDR (o32, o64, header_size) = grub_host_to_target32 (header_size); +@@ -1350,58 +1372,47 @@ grub_install_generate_image (const char *dir, const char *prefix, + PE_OHDR (o32, o64, num_data_directories) = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); + + /* The sections. */ +- PE_OHDR (o32, o64, code_base) = grub_host_to_target32 (header_size); ++ PE_OHDR (o32, o64, code_base) = grub_host_to_target32 (vma); + PE_OHDR (o32, o64, code_size) = grub_host_to_target32 (layout.exec_size); +- text_section = sections; +- strcpy (text_section->name, ".text"); +- text_section->virtual_size = grub_host_to_target32 (layout.exec_size); +- text_section->virtual_address = grub_host_to_target32 (header_size); +- text_section->raw_data_size = grub_host_to_target32 (layout.exec_size); +- text_section->raw_data_offset = grub_host_to_target32 (header_size); +- text_section->characteristics = grub_cpu_to_le32_compile_time ( +- GRUB_PE32_SCN_CNT_CODE +- | GRUB_PE32_SCN_MEM_EXECUTE +- | GRUB_PE32_SCN_MEM_READ); ++ section = init_pe_section (image_target, section, ".text", ++ &vma, layout.exec_size, ++ image_target->section_align, ++ &raw_data, layout.exec_size, ++ GRUB_PE32_SCN_CNT_CODE | ++ GRUB_PE32_SCN_MEM_EXECUTE | ++ 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 (total_module_size, + GRUB_PE32_FILE_ALIGNMENT)); + +- data_section = text_section + 1; +- strcpy (data_section->name, ".data"); +- data_section->virtual_size = grub_host_to_target32 (layout.kernel_size - layout.exec_size); +- data_section->virtual_address = grub_host_to_target32 (header_size + layout.exec_size); +- data_section->raw_data_size = grub_host_to_target32 (layout.kernel_size - layout.exec_size); +- data_section->raw_data_offset = grub_host_to_target32 (header_size + layout.exec_size); +- data_section->characteristics +- = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA +- | GRUB_PE32_SCN_MEM_READ +- | GRUB_PE32_SCN_MEM_WRITE); +- +- mods_section = data_section + 1; +- strcpy (mods_section->name, "mods"); +- mods_section->virtual_size = grub_host_to_target32 (reloc_addr - layout.kernel_size - header_size); +- mods_section->virtual_address = grub_host_to_target32 (header_size + layout.kernel_size + layout.bss_size); +- mods_section->raw_data_size = grub_host_to_target32 (reloc_addr - layout.kernel_size - header_size); +- mods_section->raw_data_offset = grub_host_to_target32 (header_size + layout.kernel_size); +- mods_section->characteristics +- = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA +- | GRUB_PE32_SCN_MEM_READ +- | GRUB_PE32_SCN_MEM_WRITE); +- +- PE_OHDR (o32, o64, base_relocation_table.rva) = grub_host_to_target32 (reloc_addr); +- PE_OHDR (o32, o64, base_relocation_table.size) = grub_host_to_target32 (layout.reloc_size); +- reloc_section = mods_section + 1; +- strcpy (reloc_section->name, ".reloc"); +- reloc_section->virtual_size = grub_host_to_target32 (layout.reloc_size); +- reloc_section->virtual_address = grub_host_to_target32 (reloc_addr + layout.bss_size); +- reloc_section->raw_data_size = grub_host_to_target32 (layout.reloc_size); +- reloc_section->raw_data_offset = grub_host_to_target32 (reloc_addr); +- reloc_section->characteristics +- = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA +- | GRUB_PE32_SCN_MEM_DISCARDABLE +- | GRUB_PE32_SCN_MEM_READ); ++ section = init_pe_section (image_target, section, ".data", ++ &vma, scn_size, image_target->section_align, ++ &raw_data, scn_size, ++ GRUB_PE32_SCN_CNT_INITIALIZED_DATA | ++ GRUB_PE32_SCN_MEM_READ | ++ GRUB_PE32_SCN_MEM_WRITE); ++ ++ scn_size = pe_size - layout.reloc_size - raw_data; ++ section = init_pe_section (image_target, section, "mods", ++ &vma, scn_size, image_target->section_align, ++ &raw_data, scn_size, ++ GRUB_PE32_SCN_CNT_INITIALIZED_DATA | ++ GRUB_PE32_SCN_MEM_READ | ++ GRUB_PE32_SCN_MEM_WRITE); ++ ++ 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); ++ memcpy (pe_img + raw_data, layout.reloc_section, scn_size); ++ init_pe_section (image_target, section, ".reloc", ++ &vma, scn_size, image_target->section_align, ++ &raw_data, scn_size, ++ GRUB_PE32_SCN_CNT_INITIALIZED_DATA | ++ GRUB_PE32_SCN_MEM_DISCARDABLE | ++ GRUB_PE32_SCN_MEM_READ); ++ + free (core_img); + core_img = pe_img; + core_size = pe_size; +-- +2.26.2 + diff --git a/0038-util-mkimage-Add-an-option-to-import-SBAT-metadata-i.patch b/0038-util-mkimage-Add-an-option-to-import-SBAT-metadata-i.patch new file mode 100644 index 0000000..4b49058 --- /dev/null +++ b/0038-util-mkimage-Add-an-option-to-import-SBAT-metadata-i.patch @@ -0,0 +1,263 @@ +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 + diff --git a/0039-grub-install-common-Add-sbat-option.patch b/0039-grub-install-common-Add-sbat-option.patch new file mode 100644 index 0000000..6e2e1dd --- /dev/null +++ b/0039-grub-install-common-Add-sbat-option.patch @@ -0,0 +1,84 @@ +From 427bbc05c7fe8c01872cdba3d1d59d27fc1b9e5b Mon Sep 17 00:00:00 2001 +From: Dimitri John Ledkov +Date: Mon, 22 Feb 2021 17:05:25 +0000 +Subject: [PATCH 39/46] grub-install-common: Add --sbat option + +Signed-off-by: Dimitri John Ledkov +Reviewed-by: Daniel Kiper +--- + include/grub/util/install.h | 5 ++++- + util/grub-install-common.c | 12 ++++++++++-- + 2 files changed, 14 insertions(+), 3 deletions(-) + +diff --git a/include/grub/util/install.h b/include/grub/util/install.h +index 6ee3b4516..2207b54d7 100644 +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -63,6 +63,8 @@ + /* TRANSLATORS: "embed" is a verb (command description). "*/ \ + { "pubkey", 'k', N_("FILE"), 0, \ + N_("embed FILE as public key for signature checking"), 0}, \ ++ { "sbat", GRUB_INSTALL_OPTIONS_SBAT, N_("FILE"), 0, \ ++ N_("SBAT metadata"), 0 }, \ + { "verbose", 'v', 0, 0, \ + N_("print verbose messages."), 1 } + +@@ -123,7 +125,8 @@ enum grub_install_options { + GRUB_INSTALL_OPTIONS_THEMES_DIRECTORY, + GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE, + GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS, +- GRUB_INSTALL_OPTIONS_DTB ++ GRUB_INSTALL_OPTIONS_DTB, ++ GRUB_INSTALL_OPTIONS_SBAT + }; + + extern char *grub_install_source_directory; +diff --git a/util/grub-install-common.c b/util/grub-install-common.c +index 052f3ef3d..4efee002f 100644 +--- a/util/grub-install-common.c ++++ b/util/grub-install-common.c +@@ -342,6 +342,7 @@ handle_install_list (struct install_list *il, const char *val, + + static char **pubkeys; + static size_t npubkeys; ++static char *sbat; + static grub_compression_t compression; + + int +@@ -372,6 +373,12 @@ grub_install_parse (int key, char *arg) + * (npubkeys + 1)); + pubkeys[npubkeys++] = xstrdup (arg); + return 1; ++ case GRUB_INSTALL_OPTIONS_SBAT: ++ if (sbat) ++ free (sbat); ++ ++ sbat = xstrdup (arg); ++ return 1; + + case GRUB_INSTALL_OPTIONS_VERBOSITY: + verbosity++; +@@ -533,9 +540,10 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, + grub_util_info ("grub-mkimage --directory '%s' --prefix '%s'" + " --output '%s' " + " --dtb '%s' " ++ "--sbat '%s' " + "--format '%s' --compression '%s' %s %s\n", + dir, prefix, +- outname, dtb ? : "", mkimage_target, ++ outname, dtb ? : "", sbat ? : "", mkimage_target, + compnames[compression], note ? "--note" : "", s); + free (s); + +@@ -546,7 +554,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, NULL); ++ note, compression, dtb, sbat); + while (dc--) + grub_install_pop_module (); + } +-- +2.26.2 + diff --git a/0040-shim_lock-Only-skip-loading-shim_lock-verifier-with-.patch b/0040-shim_lock-Only-skip-loading-shim_lock-verifier-with-.patch new file mode 100644 index 0000000..855fdbf --- /dev/null +++ b/0040-shim_lock-Only-skip-loading-shim_lock-verifier-with-.patch @@ -0,0 +1,268 @@ +From d9f12b9f37280aa54e8ef4b8c2a2163721d28360 Mon Sep 17 00:00:00 2001 +From: Dimitri John Ledkov +Date: Sat, 20 Feb 2021 17:10:34 +0000 +Subject: [PATCH 40/46] shim_lock: Only skip loading shim_lock verifier with + explicit consent + +Commit 32ddc42c (efi: Only register shim_lock verifier if shim_lock +protocol is found and SB enabled) reintroduced CVE-2020-15705 which +previously only existed in the out-of-tree linuxefi patches and was +fixed as part of the BootHole patch series. + +Under Secure Boot enforce loading shim_lock verifier. Allow skipping +shim_lock verifier if SecureBoot/MokSBState EFI variables indicate +skipping validations, or if GRUB image is built with --disable-shim-lock. + +Fixes: 132ddc42c (efi: Only register shim_lock verifier if shim_lock + protocol is found and SB enabled) +Fixes: CVE-2020-15705 + +Reported-by: Dimitri John Ledkov +Signed-off-by: Dimitri John Ledkov +Reviewed-by: Daniel Kiper +--- + docs/grub.texi | 5 ++++- + grub-core/kern/efi/sb.c | 17 ++++++++++++++++- + include/grub/kernel.h | 3 ++- + include/grub/util/install.h | 7 +++++-- + util/grub-install-common.c | 12 +++++++++--- + util/grub-mkimage.c | 8 +++++++- + util/mkimage.c | 15 ++++++++++++++- + 7 files changed, 57 insertions(+), 10 deletions(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index fa0b49737..b82f32382 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -5783,7 +5783,10 @@ secure boot chain. + The GRUB, except the @command{chainloader} command, works with the UEFI secure + boot and the shim. This functionality is provided by the shim_lock verifier. It + is built into the @file{core.img} and is registered if the UEFI secure boot is +-enabled. ++enabled. The @samp{shim_lock} variable is set to @samp{y} when shim_lock verifier ++is registered. If it is desired to use UEFI secure boot without shim, one can ++disable shim_lock by disabling shim verification with MokSbState UEFI variable ++or by building grub image with @samp{--disable-shim-lock} option. + + All GRUB modules not stored in the @file{core.img}, OS kernels, ACPI tables, + Device Trees, etc. have to be signed, e.g, using PGP. Additionally, the commands +diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c +index 5d7210a82..41dadcd14 100644 +--- a/grub-core/kern/efi/sb.c ++++ b/grub-core/kern/efi/sb.c +@@ -21,9 +21,11 @@ + #include + #include + #include ++#include + #include + #include + #include ++#include + #include + #include + #include +@@ -160,14 +162,27 @@ struct grub_file_verifier shim_lock_verifier = + void + grub_shim_lock_verifier_setup (void) + { ++ struct grub_module_header *header; + grub_efi_shim_lock_protocol_t *sl = + grub_efi_locate_protocol (&shim_lock_guid, 0); + ++ /* shim_lock is missing, check if GRUB image is built with --disable-shim-lock. */ + if (!sl) +- return; ++ { ++ FOR_MODULES (header) ++ { ++ if (header->type == OBJ_TYPE_DISABLE_SHIM_LOCK) ++ return; ++ } ++ } + ++ /* Secure Boot is off. Do not load shim_lock. */ + if (grub_efi_get_secureboot () != GRUB_EFI_SECUREBOOT_MODE_ENABLED) + return; + ++ /* Enforce shim_lock_verifier. */ + grub_verifier_register (&shim_lock_verifier); ++ ++ grub_env_set ("shim_lock", "y"); ++ grub_env_export ("shim_lock"); + } +diff --git a/include/grub/kernel.h b/include/grub/kernel.h +index 133a37c8d..abbca5ea3 100644 +--- a/include/grub/kernel.h ++++ b/include/grub/kernel.h +@@ -29,7 +29,8 @@ enum + OBJ_TYPE_CONFIG, + OBJ_TYPE_PREFIX, + OBJ_TYPE_PUBKEY, +- OBJ_TYPE_DTB ++ OBJ_TYPE_DTB, ++ OBJ_TYPE_DISABLE_SHIM_LOCK + }; + + /* The module header. */ +diff --git a/include/grub/util/install.h b/include/grub/util/install.h +index 2207b54d7..0992aecbe 100644 +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -65,6 +65,8 @@ + N_("embed FILE as public key for signature checking"), 0}, \ + { "sbat", GRUB_INSTALL_OPTIONS_SBAT, N_("FILE"), 0, \ + N_("SBAT metadata"), 0 }, \ ++ { "disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, \ ++ N_("disable shim_lock verifier"), 0 }, \ + { "verbose", 'v', 0, 0, \ + N_("print verbose messages."), 1 } + +@@ -126,7 +128,8 @@ enum grub_install_options { + GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE, + GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS, + GRUB_INSTALL_OPTIONS_DTB, +- GRUB_INSTALL_OPTIONS_SBAT ++ GRUB_INSTALL_OPTIONS_SBAT, ++ GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK + }; + + extern char *grub_install_source_directory; +@@ -188,7 +191,7 @@ grub_install_generate_image (const char *dir, const char *prefix, + const struct grub_install_image_target_desc *image_target, + int note, + grub_compression_t comp, const char *dtb_file, +- const char *sbat_path); ++ const char *sbat_path, const int disable_shim_lock); + + const struct grub_install_image_target_desc * + grub_install_get_image_target (const char *arg); +diff --git a/util/grub-install-common.c b/util/grub-install-common.c +index 4efee002f..c7b824789 100644 +--- a/util/grub-install-common.c ++++ b/util/grub-install-common.c +@@ -343,6 +343,7 @@ handle_install_list (struct install_list *il, const char *val, + static char **pubkeys; + static size_t npubkeys; + static char *sbat; ++static int disable_shim_lock; + static grub_compression_t compression; + + int +@@ -379,6 +380,9 @@ grub_install_parse (int key, char *arg) + + sbat = xstrdup (arg); + return 1; ++ case GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK: ++ disable_shim_lock = 1; ++ return 1; + + case GRUB_INSTALL_OPTIONS_VERBOSITY: + verbosity++; +@@ -541,10 +545,11 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, + " --output '%s' " + " --dtb '%s' " + "--sbat '%s' " +- "--format '%s' --compression '%s' %s %s\n", ++ "--format '%s' --compression '%s' %s %s %s\n", + dir, prefix, + outname, dtb ? : "", sbat ? : "", mkimage_target, +- compnames[compression], note ? "--note" : "", s); ++ compnames[compression], note ? "--note" : "", ++ disable_shim_lock ? "--disable-shim-lock" : "", s); + free (s); + + tgt = grub_install_get_image_target (mkimage_target); +@@ -554,7 +559,8 @@ 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, sbat); ++ note, compression, dtb, sbat, ++ disable_shim_lock); + while (dc--) + grub_install_pop_module (); + } +diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c +index 75b884710..c0d559937 100644 +--- a/util/grub-mkimage.c ++++ b/util/grub-mkimage.c +@@ -82,6 +82,7 @@ static struct argp_option options[] = { + {"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}, ++ {"disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, N_("disable shim_lock verifier"), 0}, + {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, + { 0, 0, 0, 0, 0, 0 } + }; +@@ -126,6 +127,7 @@ struct arguments + char *config; + char *sbat; + int note; ++ int disable_shim_lock; + const struct grub_install_image_target_desc *image_target; + grub_compression_t comp; + }; +@@ -233,6 +235,10 @@ argp_parser (int key, char *arg, struct argp_state *state) + arguments->sbat = xstrdup (arg); + break; + ++ case GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK: ++ arguments->disable_shim_lock = 1; ++ break; ++ + case 'v': + verbosity++; + break; +@@ -319,7 +325,7 @@ main (int argc, char *argv[]) + arguments.npubkeys, arguments.config, + arguments.image_target, arguments.note, + arguments.comp, arguments.dtb, +- arguments.sbat); ++ arguments.sbat, arguments.disable_shim_lock); + + if (grub_util_file_sync (fp) < 0) + grub_util_error (_("cannot sync `%s': %s"), arguments.output ? : "stdout", +diff --git a/util/mkimage.c b/util/mkimage.c +index b354ec1d9..a26cf76f7 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -870,7 +870,7 @@ 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, const char *dtb_path, +- const char *sbat_path) ++ const char *sbat_path, int disable_shim_lock) + { + char *kernel_img, *core_img; + size_t total_module_size, core_size; +@@ -929,6 +929,9 @@ grub_install_generate_image (const char *dir, const char *prefix, + if (sbat_path != NULL && image_target->id != IMAGE_EFI) + grub_util_error (_(".sbat section can be embedded into EFI images only")); + ++ if (disable_shim_lock) ++ total_module_size += sizeof (struct grub_module_header); ++ + if (config_path) + { + config_size = ALIGN_ADDR (grub_util_get_image_size (config_path) + 1); +@@ -1065,6 +1068,16 @@ grub_install_generate_image (const char *dir, const char *prefix, + offset += dtb_size; + } + ++ if (disable_shim_lock) ++ { ++ struct grub_module_header *header; ++ ++ header = (struct grub_module_header *) (kernel_img + offset); ++ header->type = grub_host_to_target32 (OBJ_TYPE_DISABLE_SHIM_LOCK); ++ header->size = grub_host_to_target32 (sizeof (*header)); ++ offset += sizeof (*header); ++ } ++ + if (config_path) + { + struct grub_module_header *header; +-- +2.26.2 + diff --git a/0041-squash-Add-secureboot-support-on-efi-chainloader.patch b/0041-squash-Add-secureboot-support-on-efi-chainloader.patch new file mode 100644 index 0000000..a38749e --- /dev/null +++ b/0041-squash-Add-secureboot-support-on-efi-chainloader.patch @@ -0,0 +1,92 @@ +From 50f063f61eec3a99565db5f964970a872b642b27 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Fri, 11 Dec 2020 22:33:52 +0800 +Subject: [PATCH 41/46] squash! Add secureboot support on efi chainloader + +Use grub_efi_get_secureboot to get secure boot status +--- + grub-core/loader/efi/chainloader.c | 54 ++---------------------------- + 1 file changed, 2 insertions(+), 52 deletions(-) + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index 8272df3cd..559247abf 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -46,6 +46,7 @@ + + #ifdef SUPPORT_SECURE_BOOT + #include ++#include + #endif + + GRUB_MOD_LICENSE ("GPLv3+"); +@@ -282,57 +283,6 @@ grub_secure_validate (void *data, grub_efi_uint32_t size) + return 0; + } + +-static grub_efi_boolean_t +-grub_secure_mode (void) +-{ +- grub_efi_guid_t efi_var_guid = GRUB_EFI_GLOBAL_VARIABLE_GUID; +- grub_uint8_t *data; +- grub_size_t datasize; +- +- data = grub_efi_get_variable ("SecureBoot", &efi_var_guid, &datasize); +- +- if (data) +- { +- grub_dprintf ("chain", "SecureBoot: %d, datasize %d\n", (int)*data, (int)datasize); +- } +- +- if (data && (datasize == 1)) +- { +- if (*data != 1) +- { +- grub_dprintf ("chain", "secure boot not enabled\n"); +- return 0; +- } +- } +- else +- { +- grub_dprintf ("chain", "unknown secure boot status\n"); +- return 0; +- } +- +- grub_free (data); +- +- data = grub_efi_get_variable ("SetupMode", &efi_var_guid, &datasize); +- +- if (data) +- { +- grub_dprintf ("chain", "SetupMode: %d, datasize %d\n", (int)*data, (int)datasize); +- } +- +- if (data && (datasize == 1)) +- { +- if (*data == 1) +- { +- grub_dprintf ("chain", "platform in setup mode\n"); +- return 0; +- } +- } +- +- grub_free (data); +- +- return 1; +-} +- + static grub_efi_boolean_t + read_header (void *data, grub_efi_uint32_t size, pe_coff_loader_image_context_t *context) + { +@@ -837,7 +787,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + + #ifdef SUPPORT_SECURE_BOOT + /* FIXME is secure boot possible also with universal binaries? */ +- if (debug_secureboot || (grub_secure_mode() && grub_secure_validate ((void *)address, fsize))) ++ if (debug_secureboot || (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED && grub_secure_validate ((void *)address, fsize))) + { + grub_file_close (file); + grub_loader_set (grub_secureboot_chainloader_boot, grub_secureboot_chainloader_unload, 0); +-- +2.26.2 + diff --git a/0042-squash-grub2-efi-chainload-harder.patch b/0042-squash-grub2-efi-chainload-harder.patch new file mode 100644 index 0000000..fcb8832 --- /dev/null +++ b/0042-squash-grub2-efi-chainload-harder.patch @@ -0,0 +1,26 @@ +From 5673c583f3987350a51e39b64260a84342d9592a Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Fri, 11 Dec 2020 22:39:54 +0800 +Subject: [PATCH 42/46] squash! grub2-efi-chainload-harder + +Use grub_efi_get_secureboot to get secure boot status +--- + grub-core/loader/efi/chainloader.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index 559247abf..7a910db44 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -799,7 +799,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + boot_image, fsize, + &image_handle); + #ifdef SUPPORT_SECURE_BOOT +- if (status == GRUB_EFI_SECURITY_VIOLATION && !grub_secure_mode()) ++ if (status == GRUB_EFI_SECURITY_VIOLATION && grub_efi_get_secureboot () != GRUB_EFI_SECUREBOOT_MODE_ENABLED) + { + /* If it failed with security violation while not in secure boot mode, + the firmware might be broken. We try to workaround on that by forcing +-- +2.26.2 + diff --git a/0043-squash-Don-t-allow-insmod-when-secure-boot-is-enable.patch b/0043-squash-Don-t-allow-insmod-when-secure-boot-is-enable.patch new file mode 100644 index 0000000..1ee7ca1 --- /dev/null +++ b/0043-squash-Don-t-allow-insmod-when-secure-boot-is-enable.patch @@ -0,0 +1,88 @@ +From 768ab190a7c0a412bbec6142d12000655324daa0 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Fri, 11 Dec 2020 23:01:59 +0800 +Subject: [PATCH 43/46] squash! Don't allow insmod when secure boot is enabled. + +Use grub_efi_get_secureboot to get secure boot status +--- + grub-core/kern/dl.c | 4 ++-- + grub-core/kern/efi/efi.c | 28 ---------------------------- + include/grub/efi/efi.h | 1 - + 3 files changed, 2 insertions(+), 31 deletions(-) + +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index e02f2afc5..93f08dfce 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -39,7 +39,7 @@ + #endif + + #ifdef GRUB_MACHINE_EFI +-#include ++#include + #endif + + +@@ -702,7 +702,7 @@ grub_dl_load_file (const char *filename) + grub_boot_time ("Loading module %s", filename); + + #ifdef GRUB_MACHINE_EFI +- if (grub_efi_secure_boot ()) ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) + { + #if 0 + /* This is an error, but grub2-mkconfig still generates a pile of +diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c +index 92e99b441..32f1b2ec7 100644 +--- a/grub-core/kern/efi/efi.c ++++ b/grub-core/kern/efi/efi.c +@@ -278,34 +278,6 @@ grub_efi_get_variable_with_attributes (const char *var, + return status; + } + +-grub_efi_boolean_t +-grub_efi_secure_boot (void) +-{ +- grub_efi_guid_t efi_var_guid = GRUB_EFI_GLOBAL_VARIABLE_GUID; +- grub_size_t datasize; +- char *secure_boot = NULL; +- char *setup_mode = NULL; +- grub_efi_boolean_t ret = 0; +- +- secure_boot = grub_efi_get_variable("SecureBoot", &efi_var_guid, &datasize); +- +- if (datasize != 1 || !secure_boot) +- goto out; +- +- setup_mode = grub_efi_get_variable("SetupMode", &efi_var_guid, &datasize); +- +- if (datasize != 1 || !setup_mode) +- goto out; +- +- if (*secure_boot && !*setup_mode) +- ret = 1; +- +- out: +- grub_free (secure_boot); +- grub_free (setup_mode); +- return ret; +-} +- + grub_efi_status_t + grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid, + grub_size_t *datasize_out, void **data_out) +diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h +index 568d80030..08f6ee00a 100644 +--- a/include/grub/efi/efi.h ++++ b/include/grub/efi/efi.h +@@ -91,7 +91,6 @@ EXPORT_FUNC (grub_efi_set_variable) (const char *var, + const grub_efi_guid_t *guid, + void *data, + grub_size_t datasize); +-grub_efi_boolean_t EXPORT_FUNC (grub_efi_secure_boot) (void); + int + EXPORT_FUNC (grub_efi_compare_device_paths) (const grub_efi_device_path_t *dp1, + const grub_efi_device_path_t *dp2); +-- +2.26.2 + diff --git a/0044-squash-kern-Add-lockdown-support.patch b/0044-squash-kern-Add-lockdown-support.patch new file mode 100644 index 0000000..639d75c --- /dev/null +++ b/0044-squash-kern-Add-lockdown-support.patch @@ -0,0 +1,115 @@ +From 3c612287086a5f590f80d874e8c5c6042bf7f6a0 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Wed, 24 Feb 2021 23:51:38 +0800 +Subject: [PATCH 44/46] squash! kern: Add lockdown support + +Since the lockdown feature is efi specific, the +grub_{command,extcmd}_lockdown functions can be removed from other +platform for not taking up space in kernel image. +--- + grub-core/commands/extcmd.c | 2 ++ + grub-core/kern/command.c | 2 ++ + include/grub/command.h | 11 +++++++++++ + include/grub/extcmd.h | 13 +++++++++++++ + 4 files changed, 28 insertions(+) + +diff --git a/grub-core/commands/extcmd.c b/grub-core/commands/extcmd.c +index 90a5ca24a..4ac111a99 100644 +--- a/grub-core/commands/extcmd.c ++++ b/grub-core/commands/extcmd.c +@@ -111,6 +111,7 @@ grub_register_extcmd (const char *name, grub_extcmd_func_t func, + summary, description, parser, 1); + } + ++#ifdef GRUB_MACHINE_EFI + static grub_err_t + grub_extcmd_lockdown (grub_extcmd_context_t ctxt __attribute__ ((unused)), + int argc __attribute__ ((unused)), +@@ -132,6 +133,7 @@ grub_register_extcmd_lockdown (const char *name, grub_extcmd_func_t func, + + return grub_register_extcmd (name, func, flags, summary, description, parser); + } ++#endif + + void + grub_unregister_extcmd (grub_extcmd_t ext) +diff --git a/grub-core/kern/command.c b/grub-core/kern/command.c +index 4aabcd4b5..17363af7b 100644 +--- a/grub-core/kern/command.c ++++ b/grub-core/kern/command.c +@@ -78,6 +78,7 @@ grub_register_command_prio (const char *name, + return cmd; + } + ++#ifdef GRUB_MACHINE_EFI + static grub_err_t + grub_cmd_lockdown (grub_command_t cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), +@@ -100,6 +101,7 @@ grub_register_command_lockdown (const char *name, + + return grub_register_command_prio (name, func, summary, description, 0); + } ++#endif + + void + grub_unregister_command (grub_command_t cmd) +diff --git a/include/grub/command.h b/include/grub/command.h +index 2a6f7f846..b518e262e 100644 +--- a/include/grub/command.h ++++ b/include/grub/command.h +@@ -86,11 +86,22 @@ EXPORT_FUNC(grub_register_command_prio) (const char *name, + const char *summary, + const char *description, + int prio); ++#ifdef GRUB_MACHINE_EFI + grub_command_t + EXPORT_FUNC(grub_register_command_lockdown) (const char *name, + grub_command_func_t func, + const char *summary, + const char *description); ++#else ++static inline grub_command_t ++grub_register_command_lockdown (const char *name, ++ grub_command_func_t func, ++ const char *summary, ++ const char *description) ++{ ++ return grub_register_command_prio (name, func, summary, description, 0); ++} ++#endif + void EXPORT_FUNC(grub_unregister_command) (grub_command_t cmd); + + static inline grub_command_t +diff --git a/include/grub/extcmd.h b/include/grub/extcmd.h +index fe9248b8b..fa1328ea5 100644 +--- a/include/grub/extcmd.h ++++ b/include/grub/extcmd.h +@@ -62,12 +62,25 @@ grub_extcmd_t EXPORT_FUNC(grub_register_extcmd) (const char *name, + const char *description, + const struct grub_arg_option *parser); + ++#ifdef GRUB_MACHINE_EFI + grub_extcmd_t EXPORT_FUNC(grub_register_extcmd_lockdown) (const char *name, + grub_extcmd_func_t func, + grub_command_flags_t flags, + const char *summary, + const char *description, + const struct grub_arg_option *parser); ++#else ++static inline grub_extcmd_t ++grub_register_extcmd_lockdown (const char *name, ++ grub_extcmd_func_t func, ++ grub_command_flags_t flags, ++ const char *summary, ++ const char *description, ++ const struct grub_arg_option *parser) ++{ ++ return grub_register_extcmd (name, func, flags, summary, description, parser); ++} ++#endif + + grub_extcmd_t EXPORT_FUNC(grub_register_extcmd_prio) (const char *name, + grub_extcmd_func_t func, +-- +2.26.2 + diff --git a/0045-squash-Add-support-for-Linux-EFI-stub-loading-on-aar.patch b/0045-squash-Add-support-for-Linux-EFI-stub-loading-on-aar.patch new file mode 100644 index 0000000..7c315ad --- /dev/null +++ b/0045-squash-Add-support-for-Linux-EFI-stub-loading-on-aar.patch @@ -0,0 +1,68 @@ +From 601c838c4cf3e6bd3e8e19b9e7aa4331cac0dc25 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 25 Feb 2021 20:44:58 +0800 +Subject: [PATCH 45/46] squash! Add support for Linux EFI stub loading on + aarch64. + +The efi shim_lock verifier has been moved to grub core so local +shim_lock protocol is no longer needed here for aarch64 efi to verify +the loaded kernel image. From now on the framework will take care the +verificaion, consolidating the integration of various security verifiers +like secure boot, gpg and tpm. +--- + grub-core/loader/arm64/efi/linux.c | 32 ------------------------------ + 1 file changed, 32 deletions(-) + +diff --git a/grub-core/loader/arm64/efi/linux.c b/grub-core/loader/arm64/efi/linux.c +index 8549e555b..b73105347 100644 +--- a/grub-core/loader/arm64/efi/linux.c ++++ b/grub-core/loader/arm64/efi/linux.c +@@ -49,32 +49,6 @@ static grub_uint32_t cmdline_size; + static grub_addr_t initrd_start; + static grub_addr_t initrd_end; + +-#define SHIM_LOCK_GUID \ +- { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} } +- +-struct grub_efi_shim_lock +-{ +- grub_efi_status_t (*verify) (void *buffer, grub_uint32_t size); +-}; +-typedef struct grub_efi_shim_lock grub_efi_shim_lock_t; +- +-static grub_efi_boolean_t +-grub_linuxefi_secure_validate (void *data, grub_uint32_t size) +-{ +- grub_efi_guid_t guid = SHIM_LOCK_GUID; +- grub_efi_shim_lock_t *shim_lock; +- +- shim_lock = grub_efi_locate_protocol(&guid, NULL); +- +- if (!shim_lock) +- return 1; +- +- if (shim_lock->verify(data, size) == GRUB_EFI_SUCCESS) +- return 1; +- +- return 0; +-} +- + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" + +@@ -443,12 +417,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + grub_dprintf ("linux", "kernel @ %p\n", kernel_addr); + +- if (!grub_linuxefi_secure_validate (kernel_addr, kernel_size)) +- { +- grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]); +- goto fail; +- } +- + pe = (void *)((unsigned long)kernel_addr + lh.hdr_offset); + handover_offset = pe->opt.entry_addr; + +-- +2.26.2 + diff --git a/0046-squash-verifiers-Move-verifiers-API-to-kernel-image.patch b/0046-squash-verifiers-Move-verifiers-API-to-kernel-image.patch new file mode 100644 index 0000000..e3ab92f --- /dev/null +++ b/0046-squash-verifiers-Move-verifiers-API-to-kernel-image.patch @@ -0,0 +1,153 @@ +From 59ac440754a43c6e964e924a086af066e04e753e Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Fri, 26 Feb 2021 19:43:14 +0800 +Subject: [PATCH 46/46] squash! verifiers: Move verifiers API to kernel image + +In case there's broken i386-pc setup running inconsistent installs for +module in filesystem and core image on the disk, keeping the verifiers +as module for i386-pc to avoid potential issue of looking up symbols. +--- + configure.ac | 1 + + grub-core/Makefile.am | 2 ++ + grub-core/Makefile.core.def | 8 +++++++- + grub-core/kern/main.c | 4 ++++ + grub-core/kern/verifiers.c | 11 +++++++++++ + include/grub/verify.h | 9 +++++++++ + 6 files changed, 34 insertions(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index c39e8379f..530da4b01 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1913,6 +1913,7 @@ AM_CONDITIONAL([COND_real_platform], [test x$platform != xnone]) + AM_CONDITIONAL([COND_emu], [test x$platform = xemu]) + AM_CONDITIONAL([COND_NOT_emu], [test x$platform != xemu]) + AM_CONDITIONAL([COND_i386_pc], [test x$target_cpu = xi386 -a x$platform = xpc]) ++AM_CONDITIONAL([COND_NOT_i386_pc], [test x$target_cpu != xi386 -o x$platform != xpc]) + AM_CONDITIONAL([COND_i386_efi], [test x$target_cpu = xi386 -a x$platform = xefi]) + AM_CONDITIONAL([COND_ia64_efi], [test x$target_cpu = xia64 -a x$platform = xefi]) + AM_CONDITIONAL([COND_i386_qemu], [test x$target_cpu = xi386 -a x$platform = xqemu]) +diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am +index 6b2e5e139..47c91e35d 100644 +--- a/grub-core/Makefile.am ++++ b/grub-core/Makefile.am +@@ -92,7 +92,9 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/parser.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/partition.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/term.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/time.h ++if COND_NOT_i386_pc + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/verify.h ++endif + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm_private.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/net.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/memory.h +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index eac42a7b7..893044538 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -141,7 +141,7 @@ kernel = { + common = kern/rescue_parser.c; + common = kern/rescue_reader.c; + common = kern/term.c; +- common = kern/verifiers.c; ++ nopc = kern/verifiers.c; + + noemu = kern/compiler-rt.c; + noemu = kern/mm.c; +@@ -946,6 +946,12 @@ module = { + cppflags = '-I$(srcdir)/lib/posix_wrap'; + }; + ++module = { ++ name = verifiers; ++ common = kern/verifiers.c; ++ enable = i386_pc; ++}; ++ + module = { + name = hdparm; + common = commands/hdparm.c; +diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c +index 73967e2f5..c7c6d2d0b 100644 +--- a/grub-core/kern/main.c ++++ b/grub-core/kern/main.c +@@ -29,7 +29,9 @@ + #include + #include + #include ++#ifndef GRUB_MACHINE_PCBIOS + #include ++#endif + + #ifdef GRUB_MACHINE_PCBIOS + #include +@@ -275,8 +277,10 @@ grub_main (void) + grub_printf ("Welcome to GRUB!\n\n"); + grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); + ++#ifndef GRUB_MACHINE_PCBIOS + /* Init verifiers API. */ + grub_verifiers_init (); ++#endif + + grub_load_config (); + +diff --git a/grub-core/kern/verifiers.c b/grub-core/kern/verifiers.c +index 3d19bffd1..479253351 100644 +--- a/grub-core/kern/verifiers.c ++++ b/grub-core/kern/verifiers.c +@@ -218,8 +218,19 @@ grub_verify_string (char *str, enum grub_verify_string_type type) + return GRUB_ERR_NONE; + } + ++#ifdef GRUB_MACHINE_PCBIOS ++GRUB_MOD_INIT(verifiers) ++#else + void + grub_verifiers_init (void) ++#endif + { + grub_file_filter_register (GRUB_FILE_FILTER_VERIFY, grub_verifiers_open); + } ++ ++#ifdef GRUB_MACHINE_PCBIOS ++GRUB_MOD_FINI(verifiers) ++{ ++ grub_file_filter_unregister (GRUB_FILE_FILTER_VERIFY); ++} ++#endif +diff --git a/include/grub/verify.h b/include/grub/verify.h +index cd129c398..6fde244fc 100644 +--- a/include/grub/verify.h ++++ b/include/grub/verify.h +@@ -64,10 +64,14 @@ struct grub_file_verifier + grub_err_t (*verify_string) (char *str, enum grub_verify_string_type type); + }; + ++#ifdef GRUB_MACHINE_PCBIOS ++extern struct grub_file_verifier *grub_file_verifiers; ++#else + extern struct grub_file_verifier *EXPORT_VAR (grub_file_verifiers); + + extern void + grub_verifiers_init (void); ++#endif + + static inline void + grub_verifier_register (struct grub_file_verifier *ver) +@@ -81,7 +85,12 @@ grub_verifier_unregister (struct grub_file_verifier *ver) + grub_list_remove (GRUB_AS_LIST (ver)); + } + ++#ifdef GRUB_MACHINE_PCBIOS ++grub_err_t ++grub_verify_string (char *str, enum grub_verify_string_type type); ++#else + extern grub_err_t + EXPORT_FUNC (grub_verify_string) (char *str, enum grub_verify_string_type type); ++#endif + + #endif /* ! GRUB_VERIFY_HEADER */ +-- +2.26.2 + diff --git a/grub2.changes b/grub2.changes index d801dd1..d4d30b4 100644 --- a/grub2.changes +++ b/grub2.changes @@ -1,3 +1,67 @@ +------------------------------------------------------------------- +Fri Feb 26 06:52:18 UTC 2021 - Michael Chang + +- VUL-0: grub2,shim: implement new SBAT method (bsc#1182057) + * 0031-util-mkimage-Remove-unused-code-to-add-BSS-section.patch + * 0032-util-mkimage-Use-grub_host_to_target32-instead-of-gr.patch + * 0033-util-mkimage-Always-use-grub_host_to_target32-to-ini.patch + * 0034-util-mkimage-Unify-more-of-the-PE32-and-PE32-header-.patch + * 0035-util-mkimage-Reorder-PE-optional-header-fields-set-u.patch + * 0036-util-mkimage-Improve-data_size-value-calculation.patch + * 0037-util-mkimage-Refactor-section-setup-to-use-a-helper.patch + * 0038-util-mkimage-Add-an-option-to-import-SBAT-metadata-i.patch + * 0039-grub-install-common-Add-sbat-option.patch +- Fix CVE-2021-20225 (bsc#1182262) + * 0022-lib-arg-Block-repeated-short-options-that-require-an.patch +- Fix CVE-2020-27749 (bsc#1179264) + * 0024-kern-parser-Fix-resource-leak-if-argc-0.patch + * 0025-kern-parser-Fix-a-memory-leak.patch + * 0026-kern-parser-Introduce-process_char-helper.patch + * 0027-kern-parser-Introduce-terminate_arg-helper.patch + * 0028-kern-parser-Refactor-grub_parser_split_cmdline-clean.patch + * 0029-kern-buffer-Add-variable-sized-heap-buffer.patch + * 0030-kern-parser-Fix-a-stack-buffer-overflow.patch +- Fix CVE-2021-20233 (bsc#1182263) + * 0023-commands-menuentry-Fix-quoting-in-setparams_prefix.patch +- Fix CVE-2020-25647 (bsc#1177883) + * 0021-usb-Avoid-possible-out-of-bound-accesses-caused-by-m.patch +- Fix CVE-2020-25632 (bsc#1176711) + * 0020-dl-Only-allow-unloading-modules-that-are-not-depende.patch +- Fix CVE-2020-27779, CVE-2020-14372 (bsc#1179265) (bsc#1175970) + * 0001-include-grub-i386-linux.h-Include-missing-grub-types.patch + * 0002-efi-Make-shim_lock-GUID-and-protocol-type-public.patch + * 0003-efi-Return-grub_efi_status_t-from-grub_efi_get_varia.patch + * 0004-efi-Add-a-function-to-read-EFI-variables-with-attrib.patch + * 0005-efi-Add-secure-boot-detection.patch + * 0006-efi-Only-register-shim_lock-verifier-if-shim_lock-pr.patch + * 0007-verifiers-Move-verifiers-API-to-kernel-image.patch + * 0008-efi-Move-the-shim_lock-verifier-to-the-GRUB-core.patch + * 0009-kern-Add-lockdown-support.patch + * 0010-kern-lockdown-Set-a-variable-if-the-GRUB-is-locked-d.patch + * 0011-efi-Lockdown-the-GRUB-when-the-UEFI-Secure-Boot-is-e.patch + * 0012-efi-Use-grub_is_lockdown-instead-of-hardcoding-a-dis.patch + * 0013-acpi-Don-t-register-the-acpi-command-when-locked-dow.patch + * 0014-mmap-Don-t-register-cutmem-and-badram-commands-when-.patch + * 0015-commands-Restrict-commands-that-can-load-BIOS-or-DT-.patch + * 0016-commands-setpci-Restrict-setpci-command-when-locked-.patch + * 0017-commands-hdparm-Restrict-hdparm-command-when-locked-.patch + * 0018-gdb-Restrict-GDB-access-when-locked-down.patch + * 0019-loader-xnu-Don-t-allow-loading-extension-and-package.patch + * 0040-shim_lock-Only-skip-loading-shim_lock-verifier-with-.patch + * 0041-squash-Add-secureboot-support-on-efi-chainloader.patch + * 0042-squash-grub2-efi-chainload-harder.patch + * 0043-squash-Don-t-allow-insmod-when-secure-boot-is-enable.patch + * 0044-squash-kern-Add-lockdown-support.patch + * 0045-squash-Add-support-for-Linux-EFI-stub-loading-on-aar.patch + * 0046-squash-verifiers-Move-verifiers-API-to-kernel-image.patch +- Drop patch supersceded by the new backport + * 0001-linuxefi-fail-kernel-validation-without-shim-protoco.patch + * 0001-shim_lock-Disable-GRUB_VERIFY_FLAGS_DEFER_AUTH-if-se.patch + * 0007-linuxefi-fail-kernel-validation-without-shim-protoco.patch +- Add SBAT metadata section to grub.efi +- Drop shim_lock module as it is part of core of grub.efi + * grub2.spec + ------------------------------------------------------------------- Mon Feb 22 12:49:48 UTC 2021 - Michael Chang diff --git a/grub2.spec b/grub2.spec index f9bd1b4..b1ad19c 100644 --- a/grub2.spec +++ b/grub2.spec @@ -321,16 +321,12 @@ Patch712: 0009-script-Avoid-a-use-after-free-when-redefining-a-func.patch # overflows in initrd size handling Patch713: 0010-linux-Fix-integer-overflows-in-initrd-size-handling.patch Patch714: 0001-kern-mm.c-Make-grub_calloc-inline.patch -# bsc#1174421 VUL-0: CVE-2020-15705: grub2: linuxefi: fail kernel validation -# without shim protocol -Patch715: 0001-linuxefi-fail-kernel-validation-without-shim-protoco.patch Patch716: 0002-cmdline-Provide-cmdline-functions-as-module.patch # bsc#1172745 L3: SLES 12 SP4 - Slow boot of system after updated kernel - # takes 45 minutes after grub to start loading kernel Patch717: 0001-ieee1275-powerpc-implements-fibre-channel-discovery-.patch Patch718: 0002-ieee1275-powerpc-enables-device-mapper-discovery.patch Patch719: 0001-Unify-the-check-to-enable-btrfs-relative-path.patch -Patch720: 0001-shim_lock-Disable-GRUB_VERIFY_FLAGS_DEFER_AUTH-if-se.patch Patch721: 0001-efi-linux-provide-linux-command.patch # Improve the error handling when grub2-install fails with short mbr gap # (bsc#1176062) @@ -343,11 +339,57 @@ Patch732: 0003-Make-grub_error-more-verbose.patch Patch733: 0004-arm-arm64-loader-Better-memory-allocation-and-error-.patch Patch734: 0005-Make-linux_arm_kernel_header.hdr_offset-be-at-the-ri.patch Patch735: 0006-efi-Set-image-base-address-before-jumping-to-the-PE-.patch -Patch736: 0007-linuxefi-fail-kernel-validation-without-shim-protoco.patch Patch737: 0008-squash-Add-support-for-Linux-EFI-stub-loading-on-aar.patch Patch738: 0009-squash-Add-support-for-linuxefi.patch Patch739: 0001-Fix-build-error-in-binutils-2.36.patch Patch740: 0001-emu-fix-executable-stack-marking.patch +# Boothole2 +Patch741: 0001-include-grub-i386-linux.h-Include-missing-grub-types.patch +Patch742: 0002-efi-Make-shim_lock-GUID-and-protocol-type-public.patch +Patch743: 0003-efi-Return-grub_efi_status_t-from-grub_efi_get_varia.patch +Patch744: 0004-efi-Add-a-function-to-read-EFI-variables-with-attrib.patch +Patch745: 0005-efi-Add-secure-boot-detection.patch +Patch746: 0006-efi-Only-register-shim_lock-verifier-if-shim_lock-pr.patch +Patch747: 0007-verifiers-Move-verifiers-API-to-kernel-image.patch +Patch748: 0008-efi-Move-the-shim_lock-verifier-to-the-GRUB-core.patch +Patch749: 0009-kern-Add-lockdown-support.patch +Patch750: 0010-kern-lockdown-Set-a-variable-if-the-GRUB-is-locked-d.patch +Patch751: 0011-efi-Lockdown-the-GRUB-when-the-UEFI-Secure-Boot-is-e.patch +Patch752: 0012-efi-Use-grub_is_lockdown-instead-of-hardcoding-a-dis.patch +Patch753: 0013-acpi-Don-t-register-the-acpi-command-when-locked-dow.patch +Patch754: 0014-mmap-Don-t-register-cutmem-and-badram-commands-when-.patch +Patch755: 0015-commands-Restrict-commands-that-can-load-BIOS-or-DT-.patch +Patch756: 0016-commands-setpci-Restrict-setpci-command-when-locked-.patch +Patch757: 0017-commands-hdparm-Restrict-hdparm-command-when-locked-.patch +Patch758: 0018-gdb-Restrict-GDB-access-when-locked-down.patch +Patch759: 0019-loader-xnu-Don-t-allow-loading-extension-and-package.patch +Patch760: 0020-dl-Only-allow-unloading-modules-that-are-not-depende.patch +Patch761: 0021-usb-Avoid-possible-out-of-bound-accesses-caused-by-m.patch +Patch762: 0022-lib-arg-Block-repeated-short-options-that-require-an.patch +Patch763: 0023-commands-menuentry-Fix-quoting-in-setparams_prefix.patch +Patch764: 0024-kern-parser-Fix-resource-leak-if-argc-0.patch +Patch765: 0025-kern-parser-Fix-a-memory-leak.patch +Patch766: 0026-kern-parser-Introduce-process_char-helper.patch +Patch767: 0027-kern-parser-Introduce-terminate_arg-helper.patch +Patch768: 0028-kern-parser-Refactor-grub_parser_split_cmdline-clean.patch +Patch769: 0029-kern-buffer-Add-variable-sized-heap-buffer.patch +Patch770: 0030-kern-parser-Fix-a-stack-buffer-overflow.patch +Patch771: 0031-util-mkimage-Remove-unused-code-to-add-BSS-section.patch +Patch772: 0032-util-mkimage-Use-grub_host_to_target32-instead-of-gr.patch +Patch773: 0033-util-mkimage-Always-use-grub_host_to_target32-to-ini.patch +Patch774: 0034-util-mkimage-Unify-more-of-the-PE32-and-PE32-header-.patch +Patch775: 0035-util-mkimage-Reorder-PE-optional-header-fields-set-u.patch +Patch776: 0036-util-mkimage-Improve-data_size-value-calculation.patch +Patch777: 0037-util-mkimage-Refactor-section-setup-to-use-a-helper.patch +Patch778: 0038-util-mkimage-Add-an-option-to-import-SBAT-metadata-i.patch +Patch779: 0039-grub-install-common-Add-sbat-option.patch +Patch780: 0040-shim_lock-Only-skip-loading-shim_lock-verifier-with-.patch +Patch781: 0041-squash-Add-secureboot-support-on-efi-chainloader.patch +Patch782: 0042-squash-grub2-efi-chainload-harder.patch +Patch783: 0043-squash-Don-t-allow-insmod-when-secure-boot-is-enable.patch +Patch784: 0044-squash-kern-Add-lockdown-support.patch +Patch785: 0045-squash-Add-support-for-Linux-EFI-stub-loading-on-aar.patch +Patch786: 0046-squash-verifiers-Move-verifiers-API-to-kernel-image.patch Requires: gettext-runtime %if 0%{?suse_version} >= 1140 @@ -664,12 +706,10 @@ swap partition while in resuming %patch712 -p1 %patch713 -p1 %patch714 -p1 -%patch715 -p1 %patch716 -p1 %patch717 -p1 %patch718 -p1 %patch719 -p1 -%patch720 -p1 %patch721 -p1 %patch722 -p1 %patch723 -p1 @@ -679,11 +719,56 @@ swap partition while in resuming %patch733 -p1 %patch734 -p1 %patch735 -p1 -%patch736 -p1 %patch737 -p1 %patch738 -p1 %patch739 -p1 %patch740 -p1 +%patch741 -p1 +%patch742 -p1 +%patch743 -p1 +%patch744 -p1 +%patch745 -p1 +%patch746 -p1 +%patch747 -p1 +%patch748 -p1 +%patch749 -p1 +%patch750 -p1 +%patch751 -p1 +%patch752 -p1 +%patch753 -p1 +%patch754 -p1 +%patch755 -p1 +%patch756 -p1 +%patch757 -p1 +%patch758 -p1 +%patch759 -p1 +%patch760 -p1 +%patch761 -p1 +%patch762 -p1 +%patch763 -p1 +%patch764 -p1 +%patch765 -p1 +%patch766 -p1 +%patch767 -p1 +%patch768 -p1 +%patch769 -p1 +%patch770 -p1 +%patch771 -p1 +%patch772 -p1 +%patch773 -p1 +%patch774 -p1 +%patch775 -p1 +%patch776 -p1 +%patch777 -p1 +%patch778 -p1 +%patch779 -p1 +%patch780 -p1 +%patch781 -p1 +%patch782 -p1 +%patch783 -p1 +%patch784 -p1 +%patch785 -p1 +%patch786 -p1 %build # collect evidence to debug spurious build failure on SLE15 @@ -789,16 +874,30 @@ PXE_MODULES="efinet tftp http" CRYPTO_MODULES="luks gcry_rijndael gcry_sha1 gcry_sha256" %ifarch x86_64 -CD_MODULES="${CD_MODULES} shim_lock linuxefi" +CD_MODULES="${CD_MODULES} linuxefi" %else CD_MODULES="${CD_MODULES} linux" %endif +# SBAT metadata +%if 0%{?is_opensuse} == 1 +distro_id="opensuse" +distro_name="The openSUSE Project" +%else +distro_id="sle" +distro_name="SUSE Linux Enterprise" +%endif +upstream_sbat=1 +distro_sbat=1 +echo "sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md" > sbat.csv +echo "grub,${upstream_sbat},Free Software Foundation,grub,%{version},https://www.gnu.org/software/grub/" >> sbat.csv +echo "grub.${distro_id},${distro_sbat},${distro_name},%{name},%{version},mail:security-team@suse.de" >> sbat.csv + GRUB_MODULES="${CD_MODULES} ${FS_MODULES} ${PXE_MODULES} ${CRYPTO_MODULES} mdraid09 mdraid1x lvm serial" -./grub-mkimage -O %{grubefiarch} -o grub.efi --prefix= \ +./grub-mkimage -O %{grubefiarch} -o grub.efi --prefix= --sbat sbat.csv \ -d grub-core ${GRUB_MODULES} %ifarch x86_64 -./grub-mkimage -O %{grubefiarch} -o grub-tpm.efi --prefix= \ +./grub-mkimage -O %{grubefiarch} -o grub-tpm.efi --prefix= --sbat sbat.csv \ -d grub-core ${GRUB_MODULES} tpm %endif