| From 6b6203b92cfb457a0669a9c87a29b360405bffc6 Mon Sep 17 00:00:00 2001 |
| From: Matthew Garrett <matthew.garrett@nebula.com> |
| Date: Fri, 9 Aug 2013 18:36:30 -0400 |
| Subject: [PATCH 10/20] Add option to automatically enforce module signatures |
| when in Secure Boot mode |
| |
| UEFI Secure Boot provides a mechanism for ensuring that the firmware will |
| only load signed bootloaders and kernels. Certain use cases may also |
| require that all kernel modules also be signed. Add a configuration option |
| that enforces this automatically when enabled. |
| |
| Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com> |
| |
| Documentation/x86/zero-page.txt | 2 ++ |
| arch/x86/Kconfig | 11 ++++++ |
| arch/x86/boot/compressed/eboot.c | 66 +++++++++++++++++++++++++++++++++++ |
| arch/x86/include/uapi/asm/bootparam.h | 3 +- |
| arch/x86/kernel/setup.c | 6 ++++ |
| include/linux/module.h | 6 ++++ |
| kernel/module.c | 7 ++++ |
| 7 files changed, 100 insertions(+), 1 deletion(-) |
| |
| diff --git a/Documentation/x86/zero-page.txt b/Documentation/x86/zero-page.txt |
| index 95a4d34af3fd..b8527c6b7646 100644 |
| |
| |
| @@ -31,6 +31,8 @@ Offset Proto Name Meaning |
| 1E9/001 ALL eddbuf_entries Number of entries in eddbuf (below) |
| 1EA/001 ALL edd_mbr_sig_buf_entries Number of entries in edd_mbr_sig_buffer |
| (below) |
| +1EB/001 ALL kbd_status Numlock is enabled |
| +1EC/001 ALL secure_boot Secure boot is enabled in the firmware |
| 1EF/001 ALL sentinel Used to detect broken bootloaders |
| 290/040 ALL edd_mbr_sig_buffer EDD MBR signatures |
| 2D0/A00 ALL e820_map E820 memory map table |
| diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig |
| index bada636d1065..d666ef8b616c 100644 |
| |
| |
| @@ -1786,6 +1786,17 @@ config EFI_MIXED |
| |
| If unsure, say N. |
| |
| +config EFI_SECURE_BOOT_SIG_ENFORCE |
| + def_bool n |
| + depends on EFI |
| + prompt "Force module signing when UEFI Secure Boot is enabled" |
| + ---help--- |
| + UEFI Secure Boot provides a mechanism for ensuring that the |
| + firmware will only load signed bootloaders and kernels. Certain |
| + use cases may also require that all kernel modules also be signed. |
| + Say Y here to automatically enable module signature enforcement |
| + when a system boots with UEFI Secure Boot enabled. |
| + |
| config SECCOMP |
| def_bool y |
| prompt "Enable seccomp to safely compute untrusted bytecode" |
| diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c |
| index cc69e37548db..ebc85c1eefd6 100644 |
| |
| |
| @@ -12,6 +12,7 @@ |
| #include <asm/efi.h> |
| #include <asm/setup.h> |
| #include <asm/desc.h> |
| +#include <asm/bootparam_utils.h> |
| |
| #include "../string.h" |
| #include "eboot.h" |
| @@ -537,6 +538,67 @@ static void setup_efi_pci(struct boot_params *params) |
| efi_call_early(free_pool, pci_handle); |
| } |
| |
| +static int get_secure_boot(void) |
| +{ |
| + u8 sb, setup; |
| + unsigned long datasize = sizeof(sb); |
| + efi_guid_t var_guid = EFI_GLOBAL_VARIABLE_GUID; |
| + efi_status_t status; |
| + |
| + status = efi_early->call((unsigned long)sys_table->runtime->get_variable, |
| + L"SecureBoot", &var_guid, NULL, &datasize, &sb); |
| + |
| + if (status != EFI_SUCCESS) |
| + return 0; |
| + |
| + if (sb == 0) |
| + return 0; |
| + |
| + |
| + status = efi_early->call((unsigned long)sys_table->runtime->get_variable, |
| + L"SetupMode", &var_guid, NULL, &datasize, |
| + &setup); |
| + |
| + if (status != EFI_SUCCESS) |
| + return 0; |
| + |
| + if (setup == 1) |
| + return 0; |
| + |
| + return 1; |
| +} |
| + |
| + |
| +/* |
| + * See if we have Graphics Output Protocol |
| + */ |
| +static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto, |
| + unsigned long size) |
| +{ |
| + efi_status_t status; |
| + void **gop_handle = NULL; |
| + |
| + status = efi_call_early(allocate_pool, EFI_LOADER_DATA, |
| + size, (void **)&gop_handle); |
| + if (status != EFI_SUCCESS) |
| + return status; |
| + |
| + status = efi_call_early(locate_handle, |
| + EFI_LOCATE_BY_PROTOCOL, |
| + proto, NULL, &size, gop_handle); |
| + if (status != EFI_SUCCESS) |
| + goto free_handle; |
| + |
| + if (efi_early->is64) |
| + status = setup_gop64(si, proto, size, gop_handle); |
| + else |
| + status = setup_gop32(si, proto, size, gop_handle); |
| + |
| +free_handle: |
| + efi_call_early(free_pool, gop_handle); |
| + return status; |
| +} |
| + |
| static efi_status_t |
| setup_uga32(void **uga_handle, unsigned long size, u32 *width, u32 *height) |
| { |
| @@ -1094,6 +1156,10 @@ struct boot_params *efi_main(struct efi_config *c, |
| else |
| setup_boot_services32(efi_early); |
| |
| + sanitize_boot_params(boot_params); |
| + |
| + boot_params->secure_boot = get_secure_boot(); |
| + |
| setup_graphics(boot_params); |
| |
| setup_efi_pci(boot_params); |
| diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h |
| index c18ce67495fa..2b3e5427097b 100644 |
| |
| |
| @@ -134,7 +134,8 @@ struct boot_params { |
| __u8 eddbuf_entries; /* 0x1e9 */ |
| __u8 edd_mbr_sig_buf_entries; /* 0x1ea */ |
| __u8 kbd_status; /* 0x1eb */ |
| - __u8 _pad5[3]; /* 0x1ec */ |
| + __u8 secure_boot; /* 0x1ec */ |
| + __u8 _pad5[2]; /* 0x1ed */ |
| /* |
| * The sentinel is set to a nonzero value (0xff) in header.S. |
| * |
| diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c |
| index bbfbca5fea0c..d40e961753c9 100644 |
| |
| |
| @@ -1160,6 +1160,12 @@ void __init setup_arch(char **cmdline_p) |
| |
| io_delay_init(); |
| |
| +#ifdef CONFIG_EFI_SECURE_BOOT_SIG_ENFORCE |
| + if (boot_params.secure_boot) { |
| + enforce_signed_modules(); |
| + } |
| +#endif |
| + |
| /* |
| * Parse the ACPI tables for possible boot-time SMP configuration. |
| */ |
| diff --git a/include/linux/module.h b/include/linux/module.h |
| index 05bd6c989a0c..32327704e18d 100644 |
| |
| |
| @@ -260,6 +260,12 @@ extern const typeof(name) __mod_##type##__##name##_device_table \ |
| |
| struct notifier_block; |
| |
| +#ifdef CONFIG_MODULE_SIG |
| +extern void enforce_signed_modules(void); |
| +#else |
| +static inline void enforce_signed_modules(void) {}; |
| +#endif |
| + |
| #ifdef CONFIG_MODULES |
| |
| extern int modules_disabled; /* for sysctl */ |
| diff --git a/kernel/module.c b/kernel/module.c |
| index cb864505d020..cb1f1da69bf4 100644 |
| |
| |
| @@ -4285,6 +4285,13 @@ void module_layout(struct module *mod, |
| EXPORT_SYMBOL(module_layout); |
| #endif |
| |
| +#ifdef CONFIG_MODULE_SIG |
| +void enforce_signed_modules(void) |
| +{ |
| + sig_enforce = true; |
| +} |
| +#endif |
| + |
| bool secure_modules(void) |
| { |
| #ifdef CONFIG_MODULE_SIG |
| -- |
| 2.9.3 |
| |