代码拉取完成,页面将自动刷新
同步操作将从 src-openEuler/grub2 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
From 06ff1079788fedac5e3f1f12ed7bbe69228a7ae0 Mon Sep 17 00:00:00 2001
From: Michael Chang <[email protected]>
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.
v1:
Use grub_efi_get_secureboot to get secure boot status
Signed-off-by: Michael Chang <[email protected]>
---
grub-core/loader/efi/chainloader.c | 538 +++++++++++++++++++++++++++++++++--
1 files changed, 507 insertions(+), 31 deletions(-)
--- a/grub-core/loader/efi/chainloader.c
+++ b/grub-core/loader/efi/chainloader.c
@@ -41,10 +41,24 @@
#include <grub/i386/macho.h>
#endif
+#ifdef __x86_64__
+#define SUPPORT_SECURE_BOOT
+#endif
+
+#ifdef SUPPORT_SECURE_BOOT
+#include <grub/efi/pe32.h>
+#include <grub/efi/sb.h>
+#endif
+
GRUB_MOD_LICENSE ("GPLv3+");
static grub_dl_t my_mod;
+#ifdef SUPPORT_SECURE_BOOT
+static grub_efi_boolean_t debug_secureboot = 0;
+static grub_efi_status_t (__grub_efi_api *entry_point) (grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table);
+#endif
+
static grub_err_t
grub_chainloader_unload (void *context)
{
@@ -209,6 +223,421 @@
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;
+};
+
+struct grub_secureboot_chainloader_context
+{
+ grub_efi_physical_address_t address;
+ grub_efi_uintn_t pages;
+ grub_ssize_t fsize;
+ grub_efi_device_path_t *file_path;
+ grub_efi_char16_t *cmdline;
+ grub_ssize_t cmdline_len;
+ grub_efi_handle_t dev_handle;
+};
+
+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_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
+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_uint8_t subtype;
+
+ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
+ break;
+
+ type = GRUB_EFI_DEVICE_PATH_TYPE (dp);
+ subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp);
+
+ 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 (struct grub_secureboot_chainloader_context *load_context)
+{
+ grub_efi_boot_services_t *b;
+ grub_efi_loaded_image_t *li, li_bak;
+ grub_efi_status_t efi_status;
+ void *data = (void *)(unsigned long)load_context->address;
+ grub_efi_uint32_t datasize = load_context->fsize;
+ 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 = b->allocate_pool (GRUB_EFI_LOADER_DATA,
+ buffer_size, (void**)&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_UP ((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 = load_context->cmdline;
+ li->load_options_size = load_context->cmdline_len;
+ li->file_path = grub_efi_get_media_file_path (load_context->file_path);
+ li->device_handle = load_context->dev_handle;
+ 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 = entry_point (grub_efi_image_handle, grub_efi_system_table);
+
+ grub_memcpy (li, &li_bak, sizeof (grub_efi_loaded_image_t));
+ efi_status = b->free_pool (buffer);
+
+ return 1;
+
+error_exit:
+ if (buffer)
+ b->free_pool (buffer);
+
+ return 0;
+
+}
+
+static grub_err_t
+grub_secureboot_chainloader_unload (void* context)
+{
+ grub_efi_boot_services_t *b;
+ struct grub_secureboot_chainloader_context *sb_context = (struct grub_secureboot_chainloader_context *)context;
+
+ b = grub_efi_system_table->boot_services;
+ b->free_pages (sb_context->address, sb_context->pages);
+ grub_free (sb_context->file_path);
+ grub_free (sb_context->cmdline);
+ grub_free (sb_context);
+
+ grub_dl_unref (my_mod);
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_secureboot_chainloader_boot (void *context)
+{
+ struct grub_secureboot_chainloader_context *sb_context = (struct grub_secureboot_chainloader_context *)context;
+
+ handle_image (sb_context);
+ grub_loader_unset ();
+ return grub_errno;
+}
+#endif
+
static grub_err_t
grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
@@ -222,11 +651,12 @@
grub_efi_loaded_image_t *loaded_image;
char *filename;
void *boot_image = 0;
- grub_efi_handle_t dev_handle = 0;
grub_efi_physical_address_t address = 0;
grub_efi_uintn_t pages = 0;
grub_efi_char16_t *cmdline = NULL;
grub_efi_handle_t image_handle = NULL;
+ grub_ssize_t cmdline_len = 0;
+ grub_efi_handle_t dev_handle = 0;
if (argc == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
@@ -236,12 +666,39 @@
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, GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE);
if (! file)
goto fail;
- /* Get the root device's device path. */
- dev = grub_device_open (0);
+ /* Get the device path from filename. */
+ char *devname = grub_file_get_device_name (filename);
+ dev = grub_device_open (devname);
if (dev == NULL)
;
else if (dev->disk)
@@ -343,6 +800,28 @@
}
#endif
+#ifdef SUPPORT_SECURE_BOOT
+ /* FIXME is secure boot possible also with universal binaries? */
+ if (debug_secureboot || (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED && grub_secure_validate ((void *)address, size)))
+ {
+ struct grub_secureboot_chainloader_context *sb_context;
+
+ 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
+
status = b->load_image (0, grub_efi_image_handle, file_path,
boot_image, size,
&image_handle);
@@ -368,33 +847,10 @@
loaded_image->device_handle = dev_handle;
/* Build load options with arguments from chainloader command line. */
- 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_file_close (file);
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。