v2: Use grub_efi_get_secureboot to get secure boot status v3: Fix null sb_context->file_path due to missing assignment of chainloaded image's file_path (bsc#1216081) --- grub-core/loader/efi/chainloader.c | 62 +++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 26 deletions(-) --- a/grub-core/loader/efi/chainloader.c +++ b/grub-core/loader/efi/chainloader.c @@ -305,40 +305,41 @@ 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); + char *msdos = (char *)data; + struct grub_pe32_header_no_msdos_stub *pe32 = (struct grub_pe32_header_no_msdos_stub *)data; - if (!shim_lock) + if (size < sizeof (*pe32)) { - grub_error (GRUB_ERR_BAD_ARGUMENT, "no shim lock protocol"); + grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid image"); return 0; } - status = shim_lock->context (data, size, context); - - if (status == GRUB_EFI_SUCCESS) + if (grub_memcmp (msdos, "MZ", 2) == 0) { - grub_dprintf ("chain", "context success\n"); - return 1; + grub_uint32_t off = *((grub_uint32_t *) (msdos + 0x3c)); + pe32 = (struct grub_pe32_header_no_msdos_stub *) ((char *)data + off); } - switch (status) + if (grub_memcmp (pe32->signature, "PE\0\0", 4) != 0 || + pe32->coff_header.machine != GRUB_PE32_MACHINE_X86_64 || + pe32->optional_header.magic != GRUB_PE32_PE64_MAGIC) { - 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; + grub_error (GRUB_ERR_BAD_ARGUMENT, "Not supported image"); + return 0; } - return 0; + context->number_of_rva_and_sizes = pe32->optional_header.num_data_directories; + context->size_of_headers = pe32->optional_header.header_size; + context->image_size = pe32->optional_header.image_size; + context->image_address = pe32->optional_header.image_base; + context->entry_point = pe32->optional_header.entry_addr; + context->reloc_dir = &pe32->optional_header.base_relocation_table; + context->sec_dir = &pe32->optional_header.certificate_table; + context->number_of_sections = pe32->coff_header.num_sections; + context->pe_hdr = pe32; + context->first_section = (struct grub_pe32_section_table *)((char *)(&pe32->optional_header) + pe32->coff_header.optional_header_size); + + return 1; } static void* @@ -607,6 +608,9 @@ if (buffer) b->free_pool (buffer); + if (grub_errno) + grub_print_error (); + return 0; } @@ -825,6 +829,31 @@ status = b->load_image (0, grub_efi_image_handle, file_path, boot_image, size, &image_handle); +#ifdef SUPPORT_SECURE_BOOT + 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 + the SB method! (bsc#887793) */ + struct grub_secureboot_chainloader_context *sb_context; + + grub_dprintf ("chain", "Possible firmware flaw! Security violation while not in secure boot mode.\n"); + sb_context = grub_malloc (sizeof (*sb_context)); + if (!sb_context) + goto fail; + sb_context->cmdline = cmdline; + sb_context->cmdline_len = cmdline_len; + sb_context->fsize = size; + sb_context->dev_handle = dev_handle; + sb_context->address = address; + sb_context->pages = pages; + sb_context->file_path = file_path; + grub_file_close (file); + grub_loader_set_ex (grub_secureboot_chainloader_boot, + grub_secureboot_chainloader_unload, sb_context, 0); + return 0; + } +#endif if (status != GRUB_EFI_SUCCESS) { if (status == GRUB_EFI_OUT_OF_RESOURCES)