1From 968de8c23c1cba0f18230f778ebcf6c412ec8ec5 Mon Sep 17 00:00:00 2001 2From: Dimitri John Ledkov <xnox@ubuntu.com> 3Date: Sat, 20 Feb 2021 17:10:34 +0000 4Subject: [PATCH] shim_lock: Only skip loading shim_lock verifier with explicit 5 consent 6 7Commit 32ddc42c (efi: Only register shim_lock verifier if shim_lock 8protocol is found and SB enabled) reintroduced CVE-2020-15705 which 9previously only existed in the out-of-tree linuxefi patches and was 10fixed as part of the BootHole patch series. 11 12Under Secure Boot enforce loading shim_lock verifier. Allow skipping 13shim_lock verifier if SecureBoot/MokSBState EFI variables indicate 14skipping validations, or if GRUB image is built with --disable-shim-lock. 15 16Fixes: 132ddc42c (efi: Only register shim_lock verifier if shim_lock 17 protocol is found and SB enabled) 18Fixes: CVE-2020-15705 19Fixes: CVE-2021-3418 20 21Reported-by: Dimitri John Ledkov <xnox@ubuntu.com> 22Signed-off-by: Dimitri John Ledkov <xnox@ubuntu.com> 23Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> 24Signed-off-by: Stefan Sørensen <stefan.sorensen@spectralink.com> 25--- 26 docs/grub.texi | 5 ++++- 27 grub-core/kern/efi/sb.c | 17 ++++++++++++++++- 28 include/grub/kernel.h | 3 ++- 29 include/grub/util/install.h | 7 +++++-- 30 util/grub-install-common.c | 12 +++++++++--- 31 util/grub-mkimage.c | 8 +++++++- 32 util/mkimage.c | 15 ++++++++++++++- 33 7 files changed, 57 insertions(+), 10 deletions(-) 34 35diff --git a/docs/grub.texi b/docs/grub.texi 36index bff6dfc..e302797 100644 37--- a/docs/grub.texi 38+++ b/docs/grub.texi 39@@ -5787,7 +5787,10 @@ secure boot chain. 40 The GRUB, except the @command{chainloader} command, works with the UEFI secure 41 boot and the shim. This functionality is provided by the shim_lock verifier. It 42 is built into the @file{core.img} and is registered if the UEFI secure boot is 43-enabled. 44+enabled. The @samp{shim_lock} variable is set to @samp{y} when shim_lock verifier 45+is registered. If it is desired to use UEFI secure boot without shim, one can 46+disable shim_lock by disabling shim verification with MokSbState UEFI variable 47+or by building grub image with @samp{--disable-shim-lock} option. 48 49 All GRUB modules not stored in the @file{core.img}, OS kernels, ACPI tables, 50 Device Trees, etc. have to be signed, e.g, using PGP. Additionally, the commands 51diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c 52index 5d7210a..41dadcd 100644 53--- a/grub-core/kern/efi/sb.c 54+++ b/grub-core/kern/efi/sb.c 55@@ -21,9 +21,11 @@ 56 #include <grub/efi/efi.h> 57 #include <grub/efi/pe32.h> 58 #include <grub/efi/sb.h> 59+#include <grub/env.h> 60 #include <grub/err.h> 61 #include <grub/file.h> 62 #include <grub/i386/linux.h> 63+#include <grub/kernel.h> 64 #include <grub/mm.h> 65 #include <grub/types.h> 66 #include <grub/verify.h> 67@@ -160,14 +162,27 @@ struct grub_file_verifier shim_lock_verifier = 68 void 69 grub_shim_lock_verifier_setup (void) 70 { 71+ struct grub_module_header *header; 72 grub_efi_shim_lock_protocol_t *sl = 73 grub_efi_locate_protocol (&shim_lock_guid, 0); 74 75+ /* shim_lock is missing, check if GRUB image is built with --disable-shim-lock. */ 76 if (!sl) 77- return; 78+ { 79+ FOR_MODULES (header) 80+ { 81+ if (header->type == OBJ_TYPE_DISABLE_SHIM_LOCK) 82+ return; 83+ } 84+ } 85 86+ /* Secure Boot is off. Do not load shim_lock. */ 87 if (grub_efi_get_secureboot () != GRUB_EFI_SECUREBOOT_MODE_ENABLED) 88 return; 89 90+ /* Enforce shim_lock_verifier. */ 91 grub_verifier_register (&shim_lock_verifier); 92+ 93+ grub_env_set ("shim_lock", "y"); 94+ grub_env_export ("shim_lock"); 95 } 96diff --git a/include/grub/kernel.h b/include/grub/kernel.h 97index 133a37c..abbca5e 100644 98--- a/include/grub/kernel.h 99+++ b/include/grub/kernel.h 100@@ -29,7 +29,8 @@ enum 101 OBJ_TYPE_CONFIG, 102 OBJ_TYPE_PREFIX, 103 OBJ_TYPE_PUBKEY, 104- OBJ_TYPE_DTB 105+ OBJ_TYPE_DTB, 106+ OBJ_TYPE_DISABLE_SHIM_LOCK 107 }; 108 109 /* The module header. */ 110diff --git a/include/grub/util/install.h b/include/grub/util/install.h 111index 8cb5056..11a8df8 100644 112--- a/include/grub/util/install.h 113+++ b/include/grub/util/install.h 114@@ -65,6 +65,8 @@ 115 N_("embed FILE as public key for signature checking"), 0}, \ 116 { "sbat", GRUB_INSTALL_OPTIONS_SBAT, N_("FILE"), 0, \ 117 N_("SBAT metadata"), 0 }, \ 118+ { "disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, \ 119+ N_("disable shim_lock verifier"), 0 }, \ 120 { "verbose", 'v', 0, 0, \ 121 N_("print verbose messages."), 1 } 122 123@@ -125,7 +127,8 @@ enum grub_install_options { 124 GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE, 125 GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS, 126 GRUB_INSTALL_OPTIONS_DTB, 127- GRUB_INSTALL_OPTIONS_SBAT 128+ GRUB_INSTALL_OPTIONS_SBAT, 129+ GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK 130 }; 131 132 extern char *grub_install_source_directory; 133@@ -187,7 +190,7 @@ grub_install_generate_image (const char *dir, const char *prefix, 134 const struct grub_install_image_target_desc *image_target, 135 int note, 136 grub_compression_t comp, const char *dtb_file, 137- const char *sbat_path); 138+ const char *sbat_path, const int disable_shim_lock); 139 140 const struct grub_install_image_target_desc * 141 grub_install_get_image_target (const char *arg); 142diff --git a/util/grub-install-common.c b/util/grub-install-common.c 143index 1fcccd2..13d9fe9 100644 144--- a/util/grub-install-common.c 145+++ b/util/grub-install-common.c 146@@ -308,6 +308,7 @@ handle_install_list (struct install_list *il, const char *val, 147 static char **pubkeys; 148 static size_t npubkeys; 149 static char *sbat; 150+static int disable_shim_lock; 151 static grub_compression_t compression; 152 153 int 154@@ -344,6 +345,9 @@ grub_install_parse (int key, char *arg) 155 156 sbat = xstrdup (arg); 157 return 1; 158+ case GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK: 159+ disable_shim_lock = 1; 160+ return 1; 161 162 case GRUB_INSTALL_OPTIONS_VERBOSITY: 163 verbosity++; 164@@ -506,10 +510,11 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, 165 " --output '%s' " 166 " --dtb '%s' " 167 "--sbat '%s' " 168- "--format '%s' --compression '%s' %s %s\n", 169+ "--format '%s' --compression '%s' %s %s %s\n", 170 dir, prefix, 171 outname, dtb ? : "", sbat ? : "", mkimage_target, 172- compnames[compression], note ? "--note" : "", s); 173+ compnames[compression], note ? "--note" : "", 174+ disable_shim_lock ? "--disable-shim-lock" : "", s); 175 free (s); 176 177 tgt = grub_install_get_image_target (mkimage_target); 178@@ -519,7 +524,8 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, 179 grub_install_generate_image (dir, prefix, fp, outname, 180 modules.entries, memdisk_path, 181 pubkeys, npubkeys, config_path, tgt, 182- note, compression, dtb, sbat); 183+ note, compression, dtb, sbat, 184+ disable_shim_lock); 185 while (dc--) 186 grub_install_pop_module (); 187 } 188diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c 189index 75b8847..c0d5599 100644 190--- a/util/grub-mkimage.c 191+++ b/util/grub-mkimage.c 192@@ -82,6 +82,7 @@ static struct argp_option options[] = { 193 {"format", 'O', N_("FORMAT"), 0, 0, 0}, 194 {"compression", 'C', "(xz|none|auto)", 0, N_("choose the compression to use for core image"), 0}, 195 {"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 0}, 196+ {"disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, N_("disable shim_lock verifier"), 0}, 197 {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, 198 { 0, 0, 0, 0, 0, 0 } 199 }; 200@@ -126,6 +127,7 @@ struct arguments 201 char *config; 202 char *sbat; 203 int note; 204+ int disable_shim_lock; 205 const struct grub_install_image_target_desc *image_target; 206 grub_compression_t comp; 207 }; 208@@ -233,6 +235,10 @@ argp_parser (int key, char *arg, struct argp_state *state) 209 arguments->sbat = xstrdup (arg); 210 break; 211 212+ case GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK: 213+ arguments->disable_shim_lock = 1; 214+ break; 215+ 216 case 'v': 217 verbosity++; 218 break; 219@@ -319,7 +325,7 @@ main (int argc, char *argv[]) 220 arguments.npubkeys, arguments.config, 221 arguments.image_target, arguments.note, 222 arguments.comp, arguments.dtb, 223- arguments.sbat); 224+ arguments.sbat, arguments.disable_shim_lock); 225 226 if (grub_util_file_sync (fp) < 0) 227 grub_util_error (_("cannot sync `%s': %s"), arguments.output ? : "stdout", 228diff --git a/util/mkimage.c b/util/mkimage.c 229index b354ec1..a26cf76 100644 230--- a/util/mkimage.c 231+++ b/util/mkimage.c 232@@ -870,7 +870,7 @@ grub_install_generate_image (const char *dir, const char *prefix, 233 size_t npubkeys, char *config_path, 234 const struct grub_install_image_target_desc *image_target, 235 int note, grub_compression_t comp, const char *dtb_path, 236- const char *sbat_path) 237+ const char *sbat_path, int disable_shim_lock) 238 { 239 char *kernel_img, *core_img; 240 size_t total_module_size, core_size; 241@@ -929,6 +929,9 @@ grub_install_generate_image (const char *dir, const char *prefix, 242 if (sbat_path != NULL && image_target->id != IMAGE_EFI) 243 grub_util_error (_(".sbat section can be embedded into EFI images only")); 244 245+ if (disable_shim_lock) 246+ total_module_size += sizeof (struct grub_module_header); 247+ 248 if (config_path) 249 { 250 config_size = ALIGN_ADDR (grub_util_get_image_size (config_path) + 1); 251@@ -1065,6 +1068,16 @@ grub_install_generate_image (const char *dir, const char *prefix, 252 offset += dtb_size; 253 } 254 255+ if (disable_shim_lock) 256+ { 257+ struct grub_module_header *header; 258+ 259+ header = (struct grub_module_header *) (kernel_img + offset); 260+ header->type = grub_host_to_target32 (OBJ_TYPE_DISABLE_SHIM_LOCK); 261+ header->size = grub_host_to_target32 (sizeof (*header)); 262+ offset += sizeof (*header); 263+ } 264+ 265 if (config_path) 266 { 267 struct grub_module_header *header; 268-- 2692.14.2 270 271