From 34c65f9278dafe341e0a47739150f8838b6e87d3a3c819813dd1d72ee0926efa Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Fri, 18 Jan 2013 08:24:02 +0000 Subject: [PATCH] Accepting request 148908 from home:michael-chang:branches:Base:System Sync from SLE 11 SP3 : - ship a Secure Boot UEFI compatible bootloader (fate#314485) - add grub2-secureboot-chainloader.patch, which expands the efi chainloader to be able to verify images via shim lock protocol. OBS-URL: https://build.opensuse.org/request/show/148908 OBS-URL: https://build.opensuse.org/package/show/Base:System/grub2?expand=0&rev=8 --- grub2-secureboot-chainloader.patch | 646 +++++++++++++++++++++++++++++ grub2.changes | 7 + grub2.spec | 2 + 3 files changed, 655 insertions(+) create mode 100644 grub2-secureboot-chainloader.patch diff --git a/grub2-secureboot-chainloader.patch b/grub2-secureboot-chainloader.patch new file mode 100644 index 0000000..7121229 --- /dev/null +++ b/grub2-secureboot-chainloader.patch @@ -0,0 +1,646 @@ +From 06ff1079788fedac5e3f1f12ed7bbe69228a7ae0 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Tue, 18 Dec 2012 16:54:03 +0800 +Subject: [PATCH] Add secureboot support on efi chainloader + +References: fate#314485 +Patch-Mainline: no + +Expand the chainloader to be able to verify the image by means of shim +lock protocol. The PE/COFF image is loaded and relocated by the +chainloader instead of calling LoadImage and StartImage UEFI boot +Service as they require positive verification result from keys enrolled +in KEK or DB. The shim will use MOK in addition to firmware enrolled +keys to verify the image. + +The chainloader module could be used to load other UEFI bootloaders, +such as xen.efi, and could be signed by any of MOK, KEK or DB. + +Signed-off-by: Michael Chang +--- + grub-core/loader/efi/chainloader.c | 538 +++++++++++++++++++++++++++++++++-- + 1 files changed, 507 insertions(+), 31 deletions(-) + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index 3f3e6e3..12e1aff 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -36,15 +36,30 @@ + #include + #include + ++#ifdef __x86_64__ ++#define SUPPORT_SECURE_BOOT ++#endif ++ ++#ifdef SUPPORT_SECURE_BOOT ++#include ++#endif ++ + GRUB_MOD_LICENSE ("GPLv3+"); + + static grub_dl_t my_mod; + + static grub_efi_physical_address_t address; + static grub_efi_uintn_t pages; ++static grub_ssize_t fsize; + static grub_efi_device_path_t *file_path; + static grub_efi_handle_t image_handle; + static grub_efi_char16_t *cmdline; ++static grub_ssize_t cmdline_len; ++ ++#ifdef SUPPORT_SECURE_BOOT ++static grub_efi_boolean_t debug_secureboot = 0; ++static grub_efi_status_t (*entry_point) (grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table); ++#endif + + static grub_err_t + grub_chainloader_unload (void) +@@ -186,12 +201,458 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename) + return file_path; + } + ++#ifdef SUPPORT_SECURE_BOOT ++#define SHIM_LOCK_GUID \ ++ { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} } ++ ++struct grub_pe32_header_no_msdos_stub ++{ ++ char signature[GRUB_PE32_SIGNATURE_SIZE]; ++ struct grub_pe32_coff_header coff_header; ++ struct grub_pe64_optional_header optional_header; ++}; ++ ++struct pe_coff_loader_image_context ++{ ++ grub_efi_uint64_t image_address; ++ grub_efi_uint64_t image_size; ++ grub_efi_uint64_t entry_point; ++ grub_efi_uintn_t size_of_headers; ++ grub_efi_uint16_t image_type; ++ grub_efi_uint16_t number_of_sections; ++ struct grub_pe32_section_table *first_section; ++ struct grub_pe32_data_directory *reloc_dir; ++ struct grub_pe32_data_directory *sec_dir; ++ grub_efi_uint64_t number_of_rva_and_sizes; ++ struct grub_pe32_header_no_msdos_stub *pe_hdr; ++}; ++ ++typedef struct pe_coff_loader_image_context pe_coff_loader_image_context_t; ++ ++struct grub_efi_shim_lock ++{ ++ grub_efi_status_t (*verify)(void *buffer, ++ grub_efi_uint32_t size); ++ grub_efi_status_t (*hash)(void *data, ++ grub_efi_int32_t datasize, ++ pe_coff_loader_image_context_t *context, ++ grub_efi_uint8_t *sha256hash, ++ grub_efi_uint8_t *sha1hash); ++ grub_efi_status_t (*context)(void *data, ++ grub_efi_uint32_t size, ++ pe_coff_loader_image_context_t *context); ++}; ++ ++typedef struct grub_efi_shim_lock grub_efi_shim_lock_t; ++ ++static grub_efi_boolean_t ++grub_secure_validate (void *data, grub_efi_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) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "no shim lock protocol"); ++ return 0; ++ } ++ ++ if (shim_lock->verify (data, size) == GRUB_EFI_SUCCESS) ++ { ++ grub_dprintf ("chain", "verify success\n"); ++ return 1; ++ } ++ ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "verify failed"); ++ 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) ++{ ++ 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); ++ ++ if (!shim_lock) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "no shim lock protocol"); ++ return 0; ++ } ++ ++ status = shim_lock->context (data, size, context); ++ ++ if (status == GRUB_EFI_SUCCESS) ++ { ++ grub_dprintf ("chain", "context success\n"); ++ return 1; ++ } ++ ++ switch (status) ++ { ++ case GRUB_EFI_UNSUPPORTED: ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "context error unsupported"); ++ break; ++ case GRUB_EFI_INVALID_PARAMETER: ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "context error invalid parameter"); ++ break; ++ default: ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "context error code"); ++ break; ++ } ++ ++ return 0; ++} ++ ++static void* ++image_address (void *image, grub_efi_uint64_t sz, grub_efi_uint64_t adr) ++{ ++ if (adr > sz) ++ return NULL; ++ ++ return ((grub_uint8_t*)image + adr); ++} ++ ++static grub_efi_status_t ++relocate_coff (pe_coff_loader_image_context_t *context, void *data) ++{ ++ struct grub_pe32_data_directory *reloc_base, *reloc_base_end; ++ grub_efi_uint64_t adjust; ++ grub_efi_uint16_t *reloc, *reloc_end; ++ char *fixup, *fixup_base, *fixup_data = NULL; ++ grub_efi_uint16_t *fixup_16; ++ grub_efi_uint32_t *fixup_32; ++ grub_efi_uint64_t *fixup_64; ++ ++ grub_efi_uint64_t size = context->image_size; ++ void *image_end = (char *)data + size; ++ ++ context->pe_hdr->optional_header.image_base = (grub_uint64_t)data; ++ ++ if (context->number_of_rva_and_sizes <= 5 || context->reloc_dir->size == 0) ++ { ++ grub_dprintf ("chain", "no need to reloc, we are done\n"); ++ return GRUB_EFI_SUCCESS; ++ } ++ ++ reloc_base = image_address (data, size, context->reloc_dir->rva); ++ reloc_base_end = image_address (data, size, context->reloc_dir->rva + context->reloc_dir->size -1); ++ ++ grub_dprintf ("chain", "reloc_base %p reloc_base_end %p\n", reloc_base, reloc_base_end); ++ ++ if (!reloc_base || !reloc_base_end) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "Reloc table overflows binary"); ++ return GRUB_EFI_UNSUPPORTED; ++ } ++ ++ adjust = (grub_uint64_t)data - context->image_address; ++ ++ while (reloc_base < reloc_base_end) ++ { ++ reloc = (grub_uint16_t *)((char*)reloc_base + sizeof (struct grub_pe32_data_directory)); ++ reloc_end = (grub_uint16_t *)((char*)reloc_base + reloc_base->size); ++ ++ if ((void *)reloc_end < data || (void *)reloc_end > image_end) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "Reloc table overflows binary"); ++ return GRUB_EFI_UNSUPPORTED; ++ } ++ ++ fixup_base = image_address(data, size, reloc_base->rva); ++ ++ if (!fixup_base) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid fixupbase"); ++ return GRUB_EFI_UNSUPPORTED; ++ } ++ ++ while (reloc < reloc_end) ++ { ++ fixup = fixup_base + (*reloc & 0xFFF); ++ switch ((*reloc) >> 12) ++ { ++ case GRUB_PE32_REL_BASED_ABSOLUTE: ++ break; ++ case GRUB_PE32_REL_BASED_HIGH: ++ fixup_16 = (grub_uint16_t *)fixup; ++ *fixup_16 = (grub_uint16_t) (*fixup_16 + ((grub_uint16_t)((grub_uint32_t)adjust >> 16))); ++ if (fixup_data != NULL) ++ { ++ *(grub_uint16_t *) fixup_data = *fixup_16; ++ fixup_data = fixup_data + sizeof (grub_uint16_t); ++ } ++ break; ++ case GRUB_PE32_REL_BASED_LOW: ++ fixup_16 = (grub_uint16_t *)fixup; ++ *fixup_16 = (grub_uint16_t) (*fixup_16 + (grub_uint16_t)adjust ); ++ if (fixup_data != NULL) ++ { ++ *(grub_uint16_t *) fixup_data = *fixup_16; ++ fixup_data = fixup_data + sizeof (grub_uint16_t); ++ } ++ break; ++ case GRUB_PE32_REL_BASED_HIGHLOW: ++ fixup_32 = (grub_uint32_t *)fixup; ++ *fixup_32 = *fixup_32 + (grub_uint32_t)adjust; ++ if (fixup_data != NULL) ++ { ++ fixup_data = (char *)ALIGN_UP ((grub_addr_t)fixup_data, sizeof (grub_uint32_t)); ++ *(grub_uint32_t *) fixup_data = *fixup_32; ++ fixup_data += sizeof (grub_uint32_t); ++ } ++ break; ++ case GRUB_PE32_REL_BASED_DIR64: ++ fixup_64 = (grub_uint64_t *)fixup; ++ *fixup_64 = *fixup_64 + (grub_uint64_t)adjust; ++ if (fixup_data != NULL) ++ { ++ fixup_data = (char *)ALIGN_UP ((grub_addr_t)fixup_data, sizeof (grub_uint64_t)); ++ *(grub_uint64_t *) fixup_data = *fixup_64; ++ fixup_data += sizeof (grub_uint64_t); ++ } ++ break; ++ default: ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown relocation"); ++ return GRUB_EFI_UNSUPPORTED; ++ } ++ reloc += 1; ++ } ++ reloc_base = (struct grub_pe32_data_directory *)reloc_end; ++ } ++ ++ return GRUB_EFI_SUCCESS; ++} ++ ++static grub_efi_device_path_t * ++grub_efi_get_media_file_path (grub_efi_device_path_t *dp) ++{ ++ while (1) ++ { ++ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); ++ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); ++ ++ if (type == GRUB_EFI_END_DEVICE_PATH_TYPE) ++ break; ++ else if (type == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE ++ && subtype == GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE) ++ return dp; ++ ++ dp = GRUB_EFI_NEXT_DEVICE_PATH (dp); ++ } ++ ++ return NULL; ++} ++ ++static grub_efi_boolean_t ++handle_image (void *data, grub_efi_uint32_t datasize) ++{ ++ grub_efi_boot_services_t *b; ++ grub_efi_loaded_image_t *li, li_bak; ++ grub_efi_status_t efi_status; ++ char *buffer = NULL; ++ char *buffer_aligned = NULL; ++ grub_efi_uint32_t i, size; ++ struct grub_pe32_section_table *section; ++ char *base, *end; ++ pe_coff_loader_image_context_t context; ++ grub_uint32_t section_alignment; ++ grub_uint32_t buffer_size; ++ ++ b = grub_efi_system_table->boot_services; ++ ++ if (read_header (data, datasize, &context)) ++ { ++ grub_dprintf ("chain", "Succeed to read header\n"); ++ } ++ else ++ { ++ grub_dprintf ("chain", "Failed to read header\n"); ++ goto error_exit; ++ } ++ ++ section_alignment = context.pe_hdr->optional_header.section_alignment; ++ buffer_size = context.image_size + section_alignment; ++ ++ efi_status = efi_call_3 (b->allocate_pool, GRUB_EFI_LOADER_DATA, ++ buffer_size, &buffer); ++ ++ if (efi_status != GRUB_EFI_SUCCESS) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ goto error_exit; ++ } ++ ++ buffer_aligned = (char *)ALIGN_DOWN ((grub_addr_t)buffer, section_alignment); ++ ++ grub_memcpy (buffer_aligned, data, context.size_of_headers); ++ ++ section = context.first_section; ++ for (i = 0; i < context.number_of_sections; i++) ++ { ++ size = section->virtual_size; ++ if (size > section->raw_data_size) ++ size = section->raw_data_size; ++ ++ base = image_address (buffer_aligned, context.image_size, section->virtual_address); ++ end = image_address (buffer_aligned, context.image_size, section->virtual_address + size - 1); ++ ++ if (!base || !end) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid section size"); ++ goto error_exit; ++ } ++ ++ if (section->raw_data_size > 0) ++ grub_memcpy (base, (grub_efi_uint8_t*)data + section->raw_data_offset, size); ++ ++ if (size < section->virtual_size) ++ grub_memset (base + size, 0, section->virtual_size - size); ++ ++ grub_dprintf ("chain", "copied section %s\n", section->name); ++ section += 1; ++ } ++ ++ efi_status = relocate_coff (&context, buffer_aligned); ++ ++ if (efi_status != GRUB_EFI_SUCCESS) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "relocation failed"); ++ goto error_exit; ++ } ++ ++ entry_point = image_address (buffer_aligned, context.image_size, context.entry_point); ++ ++ if (!entry_point) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid entry point"); ++ goto error_exit; ++ } ++ ++ li = grub_efi_get_loaded_image (grub_efi_image_handle); ++ if (!li) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "no loaded image available"); ++ goto error_exit; ++ } ++ ++ grub_memcpy (&li_bak, li, sizeof (grub_efi_loaded_image_t)); ++ li->image_base = buffer_aligned; ++ li->image_size = context.image_size; ++ li->load_options = cmdline; ++ li->load_options_size = cmdline_len; ++ li->file_path = grub_efi_get_media_file_path (file_path); ++ if (li->file_path) ++ { ++ grub_printf ("file path: "); ++ grub_efi_print_device_path (li->file_path); ++ } ++ else ++ { ++ grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching file path found"); ++ goto error_exit; ++ } ++ ++ efi_status = efi_call_2 (entry_point, grub_efi_image_handle, grub_efi_system_table); ++ ++ grub_memcpy (li, &li_bak, sizeof (grub_efi_loaded_image_t)); ++ efi_status = efi_call_1 (b->free_pool, buffer); ++ ++ return 1; ++ ++error_exit: ++ if (buffer) ++ efi_call_1 (b->free_pool, buffer); ++ ++ return 0; ++ ++} ++ ++static grub_err_t ++grub_secureboot_chainloader_unload (void) ++{ ++ grub_efi_boot_services_t *b; ++ ++ b = grub_efi_system_table->boot_services; ++ efi_call_2 (b->free_pages, address, pages); ++ grub_free (file_path); ++ grub_free (cmdline); ++ cmdline = 0; ++ file_path = 0; ++ ++ grub_dl_unref (my_mod); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_secureboot_chainloader_boot (void) ++{ ++ handle_image ((void *)address, fsize); ++ grub_loader_unset (); ++ return grub_errno; ++} ++#endif ++ + static grub_err_t + grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) + { + grub_file_t file = 0; +- grub_ssize_t size; + grub_efi_status_t status; + grub_efi_boot_services_t *b; + grub_device_t dev = 0; +@@ -213,6 +674,32 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + + b = grub_efi_system_table->boot_services; + ++ if (argc > 1) ++ { ++ int i; ++ grub_efi_char16_t *p16; ++ ++ for (i = 1, cmdline_len = 0; i < argc; i++) ++ cmdline_len += grub_strlen (argv[i]) + 1; ++ ++ cmdline_len *= sizeof (grub_efi_char16_t); ++ cmdline = p16 = grub_malloc (cmdline_len); ++ if (! cmdline) ++ goto fail; ++ ++ for (i = 1; i < argc; i++) ++ { ++ char *p8; ++ ++ p8 = argv[i]; ++ while (*p8) ++ *(p16++) = *(p8++); ++ ++ *(p16++) = ' '; ++ } ++ *(--p16) = 0; ++ } ++ + file = grub_file_open (filename); + if (! file) + goto fail; +@@ -258,14 +745,14 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_printf ("file path: "); + grub_efi_print_device_path (file_path); + +- size = grub_file_size (file); +- if (!size) ++ fsize = grub_file_size (file); ++ if (!fsize) + { + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), + filename); + goto fail; + } +- pages = (((grub_efi_uintn_t) size + ((1 << 12) - 1)) >> 12); ++ pages = (((grub_efi_uintn_t) fsize + ((1 << 12) - 1)) >> 12); + + status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ANY_PAGES, + GRUB_EFI_LOADER_CODE, +@@ -278,7 +765,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- if (grub_file_read (file, (void *) ((grub_addr_t) address), size) != size) ++ if (grub_file_read (file, (void *) ((grub_addr_t) address), fsize) != fsize) + { + if (grub_errno == GRUB_ERR_NONE) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), +@@ -287,8 +774,17 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + ++#ifdef SUPPORT_SECURE_BOOT ++ if (debug_secureboot || (grub_secure_mode() && grub_secure_validate ((void *)address, fsize))) ++ { ++ grub_file_close (file); ++ grub_loader_set (grub_secureboot_chainloader_boot, grub_secureboot_chainloader_unload, 0); ++ return 0; ++ } ++#endif ++ + status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path, +- (void *) ((grub_addr_t) address), size, ++ (void *) ((grub_addr_t) address), fsize, + &image_handle); + if (status != GRUB_EFI_SUCCESS) + { +@@ -313,33 +809,10 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + + grub_file_close (file); + +- if (argc > 1) ++ if (cmdline) + { +- int i, len; +- grub_efi_char16_t *p16; +- +- for (i = 1, len = 0; i < argc; i++) +- len += grub_strlen (argv[i]) + 1; +- +- len *= sizeof (grub_efi_char16_t); +- cmdline = p16 = grub_malloc (len); +- if (! cmdline) +- goto fail; +- +- for (i = 1; i < argc; i++) +- { +- char *p8; +- +- p8 = argv[i]; +- while (*p8) +- *(p16++) = *(p8++); +- +- *(p16++) = ' '; +- } +- *(--p16) = 0; +- + loaded_image->load_options = cmdline; +- loaded_image->load_options_size = len; ++ loaded_image->load_options_size = cmdline_len; + } + + grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0); +@@ -358,6 +831,9 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + if (address) + efi_call_2 (b->free_pages, address, pages); + ++ if (cmdline) ++ grub_free (cmdline); ++ + grub_dl_unref (my_mod); + + return grub_errno; +-- +1.7.3.4 + diff --git a/grub2.changes b/grub2.changes index 8155558..87a3f84 100644 --- a/grub2.changes +++ b/grub2.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Fri Jan 18 07:39:18 UTC 2013 - mchang@suse.com + +- ship a Secure Boot UEFI compatible bootloader (fate#314485) +- add grub2-secureboot-chainloader.patch, which expands the efi + chainloader to be able to verify images via shim lock protocol. + ------------------------------------------------------------------- Tue Jan 8 08:09:01 UTC 2013 - mchang@suse.com diff --git a/grub2.spec b/grub2.spec index 30900ec..6de126c 100644 --- a/grub2.spec +++ b/grub2.spec @@ -135,6 +135,7 @@ Patch25: 30_os-prober_UEFI_support.patch Patch26: grub2-fix-enumeration-of-extended-partition.patch Patch27: grub2-add-device-to-os_prober-linux-menuentry.patch Patch28: grub2-fix-unquoted-string-in-class.patch +Patch29: grub2-secureboot-chainloader.patch PreReq: perl-Bootloader Requires: gettext-runtime %if 0%{?suse_version} >= 1140 @@ -250,6 +251,7 @@ mv docs/grub.texi docs/grub2.texi %patch26 -p1 %patch27 -p1 %patch28 -p1 +%patch29 -p1 cd .. # README.openSUSE