Hi All,
I've been working on rebasing Fedora's secure boot approach to using the secure_module patches Matthew Garrett posted upstream. Below are the changes to do this.
Things to note:
1) Most people won't even notice a change as the impacts to userspace remain the same.
2) We're dropping the pekey patches. It's a large chunk of code that is dead upstream and has no usage within Fedora.
3) The kexec patch should likely get reworked to prevent loading, and that has been noted upstream.
4) At some point we'll look at adding support for hibernate likely via the patches that OpenSUSE has introduced.
5) This falls back to using the upstream .modsign_keyring instead of .system_keyring. The concept of a system keyring is decent, but at the moment it isn't going anywhere upstream. We can look at switching back at some point in the future.
josh
From 17832506ee9b52bc8e00c2ec89b49257998171ed Mon Sep 17 00:00:00 2001
From: Matthew Garrett matthew.garrett@nebula.com Date: Mon, 19 Aug 2013 13:26:02 -0400 Subject: [PATCH 01/13] Add secure_modules() call
Provide a single call to allow kernel code to determine whether the system has been configured to either disable module loading entirely or to load only modules signed with a trusted key.
Signed-off-by: Matthew Garrett matthew.garrett@nebula.com --- include/linux/module.h | 7 +++++++ kernel/module.c | 10 ++++++++++ 2 files changed, 17 insertions(+)
diff --git a/include/linux/module.h b/include/linux/module.h index 46f1ea0..0c266b2 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -509,6 +509,8 @@ int unregister_module_notifier(struct notifier_block * nb);
extern void print_modules(void);
+extern bool secure_modules(void); + #else /* !CONFIG_MODULES... */
/* Given an address, look for it in the exception tables. */ @@ -619,6 +621,11 @@ static inline int unregister_module_notifier(struct notifier_block * nb) static inline void print_modules(void) { } + +static inline bool secure_modules(void) +{ + return false; +} #endif /* CONFIG_MODULES */
#ifdef CONFIG_SYSFS diff --git a/kernel/module.c b/kernel/module.c index 2069158..499ee57 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -3852,3 +3852,13 @@ void module_layout(struct module *mod, } EXPORT_SYMBOL(module_layout); #endif + +bool secure_modules(void) +{ +#ifdef CONFIG_MODULE_SIG + return (sig_enforce || modules_disabled); +#else + return modules_disabled; +#endif +} +EXPORT_SYMBOL_GPL(secure_modules);
From e347503648ace6a4b71dfb566365f1aa19657746 Mon Sep 17 00:00:00 2001
From: Matthew Garrett matthew.garrett@nebula.com Date: Mon, 19 Aug 2013 13:26:03 -0400 Subject: [PATCH 02/13] PCI: Lock down BAR access when module security is enabled
Any hardware that can potentially generate DMA has to be locked down from userspace in order to avoid it being possible for an attacker to modify kernel code, allowing them to circumvent disabled module loading or module signing. Default to paranoid - in future we can potentially relax this for sufficiently IOMMU-isolated devices.
Signed-off-by: Matthew Garrett matthew.garrett@nebula.com --- drivers/pci/pci-sysfs.c | 10 ++++++++++ drivers/pci/proc.c | 8 +++++++- drivers/pci/syscall.c | 3 ++- 3 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index c0dbe1f..cd4e35f 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -29,6 +29,7 @@ #include <linux/slab.h> #include <linux/vgaarb.h> #include <linux/pm_runtime.h> +#include <linux/module.h> #include "pci.h"
static int sysfs_initialized; /* = 0 */ @@ -624,6 +625,9 @@ pci_write_config(struct file* filp, struct kobject *kobj, loff_t init_off = off; u8 *data = (u8*) buf;
+ if (secure_modules()) + return -EPERM; + if (off > dev->cfg_size) return 0; if (off + count > dev->cfg_size) { @@ -930,6 +934,9 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, resource_size_t start, end; int i;
+ if (secure_modules()) + return -EPERM; + for (i = 0; i < PCI_ROM_RESOURCE; i++) if (res == &pdev->resource[i]) break; @@ -1037,6 +1044,9 @@ pci_write_resource_io(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { + if (secure_modules()) + return -EPERM; + return pci_resource_io(filp, kobj, attr, buf, off, count, true); }
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index cdc7836..e3d498b 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -117,6 +117,9 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof int size = dev->cfg_size; int cnt;
+ if (secure_modules()) + return -EPERM; + if (pos >= size) return 0; if (nbytes >= size) @@ -196,6 +199,9 @@ static long proc_bus_pci_ioctl(struct file *file, unsigned int cmd, #endif /* HAVE_PCI_MMAP */ int ret = 0;
+ if (secure_modules()) + return -EPERM; + switch (cmd) { case PCIIOC_CONTROLLER: ret = pci_domain_nr(dev->bus); @@ -234,7 +240,7 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma) struct pci_filp_private *fpriv = file->private_data; int i, ret;
- if (!capable(CAP_SYS_RAWIO)) + if (!capable(CAP_SYS_RAWIO) || secure_modules()) return -EPERM;
/* Make sure the caller is mapping a real resource for this device */ diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c index e1c1ec5..bffbf71 100644 --- a/drivers/pci/syscall.c +++ b/drivers/pci/syscall.c @@ -10,6 +10,7 @@ #include <linux/errno.h> #include <linux/pci.h> #include <linux/syscalls.h> +#include <linux/module.h> #include <asm/uaccess.h> #include "pci.h"
@@ -92,7 +93,7 @@ SYSCALL_DEFINE5(pciconfig_write, unsigned long, bus, unsigned long, dfn, u32 dword; int err = 0;
- if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN) || secure_modules()) return -EPERM;
dev = pci_get_bus_and_slot(bus, dfn);
From b846e3958d3f4ff875ec958efba8b681ccbae04e Mon Sep 17 00:00:00 2001
From: Matthew Garrett matthew.garrett@nebula.com Date: Mon, 19 Aug 2013 13:26:04 -0400 Subject: [PATCH 03/13] x86: Lock down IO port access when module security is enabled
IO port access would permit users to gain access to PCI configuration registers, which in turn (on a lot of hardware) give access to MMIO register space. This would potentially permit root to trigger arbitrary DMA, so lock it down by default.
Signed-off-by: Matthew Garrett matthew.garrett@nebula.com --- arch/x86/kernel/ioport.c | 5 +++-- drivers/char/mem.c | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kernel/ioport.c b/arch/x86/kernel/ioport.c index 4ddaf66..00b4403 100644 --- a/arch/x86/kernel/ioport.c +++ b/arch/x86/kernel/ioport.c @@ -15,6 +15,7 @@ #include <linux/thread_info.h> #include <linux/syscalls.h> #include <linux/bitmap.h> +#include <linux/module.h> #include <asm/syscalls.h>
/* @@ -28,7 +29,7 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on)
if ((from + num <= from) || (from + num > IO_BITMAP_BITS)) return -EINVAL; - if (turn_on && !capable(CAP_SYS_RAWIO)) + if (turn_on && (!capable(CAP_SYS_RAWIO) || secure_modules())) return -EPERM;
/* @@ -103,7 +104,7 @@ SYSCALL_DEFINE1(iopl, unsigned int, level) return -EINVAL; /* Trying to gain more privileges? */ if (level > old) { - if (!capable(CAP_SYS_RAWIO)) + if (!capable(CAP_SYS_RAWIO) || secure_modules()) return -EPERM; } regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) | (level << 12); diff --git a/drivers/char/mem.c b/drivers/char/mem.c index f895a8c..1af8664 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -28,6 +28,7 @@ #include <linux/export.h> #include <linux/io.h> #include <linux/aio.h> +#include <linux/module.h>
#include <asm/uaccess.h>
@@ -563,6 +564,9 @@ static ssize_t write_port(struct file *file, const char __user *buf, unsigned long i = *ppos; const char __user *tmp = buf;
+ if (secure_modules()) + return -EPERM; + if (!access_ok(VERIFY_READ, buf, count)) return -EFAULT; while (count-- > 0 && i < 65536) {
From 8c11e2cc989eece2d4978cfbc83f9b898f3cd1aa Mon Sep 17 00:00:00 2001
From: Matthew Garrett matthew.garrett@nebula.com Date: Mon, 19 Aug 2013 13:26:05 -0400 Subject: [PATCH 04/13] ACPI: Limit access to custom_method
custom_method effectively allows arbitrary access to system memory, making it possible for an attacker to circumvent restrictions on module loading. Disable it if any such restrictions have been enabled.
Signed-off-by: Matthew Garrett matthew.garrett@nebula.com --- drivers/acpi/custom_method.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/acpi/custom_method.c b/drivers/acpi/custom_method.c index 12b62f2..55a013f 100644 --- a/drivers/acpi/custom_method.c +++ b/drivers/acpi/custom_method.c @@ -7,6 +7,7 @@ #include <linux/kernel.h> #include <linux/uaccess.h> #include <linux/debugfs.h> +#include <linux/module.h> #include <acpi/acpi_drivers.h>
#include "internal.h" @@ -29,6 +30,9 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf, struct acpi_table_header table; acpi_status status;
+ if (secure_modules()) + return -EPERM; + if (!(*ppos)) { /* parse the table header to get the table length */ if (count <= sizeof(struct acpi_table_header))
From 968ccfb32df5d5c9673c57641ebf90b25c0df880 Mon Sep 17 00:00:00 2001
From: Matthew Garrett matthew.garrett@nebula.com Date: Mon, 19 Aug 2013 13:26:06 -0400 Subject: [PATCH 05/13] asus-wmi: Restrict debugfs interface when module loading is restricted
We have no way of validating what all of the Asus WMI methods do on a given machine, and there's a risk that some will allow hardware state to be manipulated in such a way that arbitrary code can be executed in the kernel, circumventing module loading restrictions. Prevent that if any of these features are enabled.
Signed-off-by: Matthew Garrett matthew.garrett@nebula.com --- drivers/platform/x86/asus-wmi.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 19c313b..db18ef66 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -1618,6 +1618,9 @@ static int show_dsts(struct seq_file *m, void *data) int err; u32 retval = -1;
+ if (secure_modules()) + return -EPERM; + err = asus_wmi_get_devstate(asus, asus->debug.dev_id, &retval);
if (err < 0) @@ -1634,6 +1637,9 @@ static int show_devs(struct seq_file *m, void *data) int err; u32 retval = -1;
+ if (secure_modules()) + return -EPERM; + err = asus_wmi_set_devstate(asus->debug.dev_id, asus->debug.ctrl_param, &retval);
@@ -1658,6 +1664,9 @@ static int show_call(struct seq_file *m, void *data) union acpi_object *obj; acpi_status status;
+ if (secure_modules()) + return -EPERM; + status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 1, asus->debug.method_id, &input, &output);
From e492d0a80bb591c34391757f97fc5aa8eb198e4f Mon Sep 17 00:00:00 2001
From: Matthew Garrett matthew.garrett@nebula.com Date: Mon, 19 Aug 2013 13:26:07 -0400 Subject: [PATCH 06/13] Restrict /dev/mem and /dev/kmem when module loading is restricted
Allowing users to write to address space makes it possible for the kernel to be subverted, avoiding module loading restrictions. Prevent this when any restrictions have been imposed on loading modules.
Signed-off-by: Matthew Garrett matthew.garrett@nebula.com --- drivers/char/mem.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 1af8664..61406c8 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -159,6 +159,9 @@ static ssize_t write_mem(struct file *file, const char __user *buf, unsigned long copied; void *ptr;
+ if (secure_modules()) + return -EPERM; + if (!valid_phys_addr_range(p, count)) return -EFAULT;
@@ -497,6 +500,9 @@ static ssize_t write_kmem(struct file *file, const char __user *buf, char *kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */ int err = 0;
+ if (secure_modules()) + return -EPERM; + if (p < (unsigned long) high_memory) { unsigned long to_write = min_t(unsigned long, count, (unsigned long)high_memory - p);
From 145913d656bfe8216032b38a576ac150699521e5 Mon Sep 17 00:00:00 2001
From: Josh Boyer jwboyer@redhat.com Date: Mon, 19 Aug 2013 13:26:08 -0400 Subject: [PATCH 07/13] acpi: Ignore acpi_rsdp kernel parameter when module loading is restricted
This option allows userspace to pass the RSDP address to the kernel, which makes it possible for a user to circumvent any restrictions imposed on loading modules. Disable it in that case.
Signed-off-by: Josh Boyer jwboyer@redhat.com --- drivers/acpi/osl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 6ab2c35..e4c4410 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -45,6 +45,7 @@ #include <linux/list.h> #include <linux/jiffies.h> #include <linux/semaphore.h> +#include <linux/module.h>
#include <asm/io.h> #include <asm/uaccess.h> @@ -245,7 +246,7 @@ early_param("acpi_rsdp", setup_acpi_rsdp); acpi_physical_address __init acpi_os_get_root_pointer(void) { #ifdef CONFIG_KEXEC - if (acpi_rsdp) + if (acpi_rsdp && !secure_modules()) return acpi_rsdp; #endif
From 012ac79f54ab746114d8276d8858a3df18b10e22 Mon Sep 17 00:00:00 2001
From: Matthew Garrett matthew.garrett@nebula.com Date: Mon, 19 Aug 2013 13:26:10 -0400 Subject: [PATCH 08/13] x86: Restrict MSR access when module loading is restricted
Writing to MSRs should not be allowed if module loading is restricted, since it could lead to execution of arbitrary code in kernel mode. Based on a patch by Kees Cook.
Cc: Kees Cook keescook@chromium.org Signed-off-by: Matthew Garrett matthew.garrett@nebula.com --- arch/x86/kernel/msr.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c index 88458fa..d08f7e3 100644 --- a/arch/x86/kernel/msr.c +++ b/arch/x86/kernel/msr.c @@ -103,6 +103,9 @@ static ssize_t msr_write(struct file *file, const char __user *buf, int err = 0; ssize_t bytes = 0;
+ if (secure_modules()) + return -EPERM; + if (count % 8) return -EINVAL; /* Invalid chunk size */
@@ -150,6 +153,10 @@ static long msr_ioctl(struct file *file, unsigned int ioc, unsigned long arg) err = -EBADF; break; } + if (secure_modules()) { + err = -EPERM; + break; + } if (copy_from_user(®s, uregs, sizeof regs)) { err = -EFAULT; break;
From a44d2968968fd667c8cbeba7c043f674d17e7ce7 Mon Sep 17 00:00:00 2001
From: Matthew Garrett matthew.garrett@nebula.com Date: Mon, 19 Aug 2013 13:26:09 -0400 Subject: [PATCH 09/13] kexec: Disable at runtime if the kernel enforces module loading restrictions
kexec permits the loading and execution of arbitrary code in ring 0, which is something that module signing enforcement is meant to prevent. It makes sense to disable kexec in this situation.
Signed-off-by: Matthew Garrett matthew.garrett@nebula.com --- kernel/kexec.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/kernel/kexec.c b/kernel/kexec.c index 59f7b55..1a7690f 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -32,6 +32,7 @@ #include <linux/vmalloc.h> #include <linux/swap.h> #include <linux/syscore_ops.h> +#include <linux/module.h>
#include <asm/page.h> #include <asm/uaccess.h> @@ -1645,6 +1646,9 @@ int kernel_kexec(void) goto Unlock; }
+ if (secure_modules()) + return -EPERM; + #ifdef CONFIG_KEXEC_JUMP if (kexec_image->preserve_context) { lock_system_sleep();
From f8f879da5dcc060a990a3b660aa5f340429cc4ed Mon Sep 17 00:00:00 2001
From: Matthew Garrett matthew.garrett@nebula.com Date: Mon, 19 Aug 2013 13:26:11 -0400 Subject: [PATCH 10/13] 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 Signed-off-by: Josh Boyer jwboyer@fedoraproject.org ---
V3: Make sure to include the bootparam_utils.h hunk so we don't clear the secure_boot flag (from Josh)
Documentation/x86/zero-page.txt | 2 ++ arch/x86/Kconfig | 10 ++++++++++ arch/x86/boot/compressed/eboot.c | 33 +++++++++++++++++++++++++++++++++ arch/x86/include/asm/bootparam_utils.h | 8 ++++++-- arch/x86/include/uapi/asm/bootparam.h | 3 ++- arch/x86/kernel/setup.c | 6 ++++++ include/linux/module.h | 6 ++++++ kernel/module.c | 7 +++++++ 8 files changed, 72 insertions(+), 3 deletions(-)
diff --git a/Documentation/x86/zero-page.txt b/Documentation/x86/zero-page.txt index 199f453..ec38acf 100644 --- a/Documentation/x86/zero-page.txt +++ b/Documentation/x86/zero-page.txt @@ -30,6 +30,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 b32ebf9..6a6c19b 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1581,6 +1581,16 @@ config EFI_STUB
See Documentation/x86/efi-stub.txt for more information.
+config EFI_SECURE_BOOT_SIG_ENFORCE + def_bool n + 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 b7388a4..145294d 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -861,6 +861,37 @@ fail: return status; }
+static int get_secure_boot(efi_system_table_t *_table) +{ + u8 sb, setup; + unsigned long datasize = sizeof(sb); + efi_guid_t var_guid = EFI_GLOBAL_VARIABLE_GUID; + efi_status_t status; + + status = efi_call_phys5(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_call_phys5(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; +} + + /* * Because the x86 boot code expects to be passed a boot_params we * need to create one ourselves (usually the bootloader would create @@ -1169,6 +1200,8 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table, if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) goto fail;
+ boot_params->secure_boot = get_secure_boot(sys_table); + setup_graphics(boot_params);
setup_efi_pci(boot_params); diff --git a/arch/x86/include/asm/bootparam_utils.h b/arch/x86/include/asm/bootparam_utils.h index 4a8cb8d..25f9cf1 100644 --- a/arch/x86/include/asm/bootparam_utils.h +++ b/arch/x86/include/asm/bootparam_utils.h @@ -38,9 +38,13 @@ static void sanitize_boot_params(struct boot_params *boot_params) memset(&boot_params->ext_ramdisk_image, 0, (char *)&boot_params->efi_info - (char *)&boot_params->ext_ramdisk_image); - memset(&boot_params->kbd_status, 0, + memset(&boot_params->kbd_status, 0, sizeof(boot_params->kbd_status)); + /* don't clear boot_params->secure_boot. we set that ourselves + * earlier. + */ + memset(&boot_params->_pad5[0], 0, (char *)&boot_params->hdr - - (char *)&boot_params->kbd_status); + (char *)&boot_params->_pad5[0]); memset(&boot_params->_pad7[0], 0, (char *)&boot_params->edd_mbr_sig_buffer[0] - (char *)&boot_params->_pad7[0]); diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h index c15ddaf..d35da96 100644 --- a/arch/x86/include/uapi/asm/bootparam.h +++ b/arch/x86/include/uapi/asm/bootparam.h @@ -131,7 +131,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]; /* 0x1ec */ /* * 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 f8ec578..deeb7bc 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -1129,6 +1129,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 0c266b2..5a6374a 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -184,6 +184,12 @@ const struct exception_table_entry *search_exception_tables(unsigned long add);
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 499ee57..bc7c987 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -3853,6 +3853,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
From b1604407fff69b17b598af03888a9efda0d58f2b Mon Sep 17 00:00:00 2001
From: Josh Boyer jwboyer@redhat.com Date: Tue, 5 Feb 2013 19:25:05 -0500 Subject: [PATCH 11/13] efi: Disable secure boot if shim is in insecure mode
A user can manually tell the shim boot loader to disable validation of images it loads. When a user does this, it creates a UEFI variable called MokSBState that does not have the runtime attribute set. Given that the user explicitly disabled validation, we can honor that and not enable secure boot mode if that variable is set.
Signed-off-by: Josh Boyer jwboyer@redhat.com --- arch/x86/boot/compressed/eboot.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index 145294d..545d4a6 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -863,8 +863,9 @@ fail:
static int get_secure_boot(efi_system_table_t *_table) { - u8 sb, setup; + u8 sb, setup, moksbstate; unsigned long datasize = sizeof(sb); + u32 attr; efi_guid_t var_guid = EFI_GLOBAL_VARIABLE_GUID; efi_status_t status;
@@ -888,6 +889,23 @@ static int get_secure_boot(efi_system_table_t *_table) if (setup == 1) return 0;
+ /* See if a user has put shim into insecure_mode. If so, and the variable + * doesn't have the runtime attribute set, we might as well honor that. + */ + var_guid = EFI_SHIM_LOCK_GUID; + status = efi_call_phys5(sys_table->runtime->get_variable, + L"MokSBState", &var_guid, &attr, &datasize, + &moksbstate); + + /* If it fails, we don't care why. Default to secure */ + if (status != EFI_SUCCESS) + return 1; + + if (!(attr & EFI_VARIABLE_RUNTIME_ACCESS)) { + if (moksbstate == 1) + return 0; + } + return 1; }
From 4d8b5cab923a2df15e1f33b3f0511366f9f98756 Mon Sep 17 00:00:00 2001
From: Josh Boyer jwboyer@fedoraproject.org Date: Tue, 27 Aug 2013 13:28:43 -0400 Subject: [PATCH 12/13] efi: Make EFI_SECURE_BOOT_SIG_ENFORCE depend on EFI
The functionality of the config option is dependent upon the platform being UEFI based. Reflect this in the config deps.
Signed-off-by: Josh Boyer jwboyer@fedoraproject.org --- arch/x86/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 6a6c19b..10498ec 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1582,7 +1582,8 @@ config EFI_STUB See Documentation/x86/efi-stub.txt for more information.
config EFI_SECURE_BOOT_SIG_ENFORCE - def_bool n + 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
From a87ca6498b8a9f8e3c1d7e6ef7ef4e233ec8639d Mon Sep 17 00:00:00 2001
From: Josh Boyer jwboyer@fedoraproject.org Date: Tue, 27 Aug 2013 13:33:03 -0400 Subject: [PATCH 13/13] efi: Add EFI_SECURE_BOOT bit
UEFI machines can be booted in Secure Boot mode. Add a EFI_SECURE_BOOT bit for use with efi_enabled.
Signed-off-by: Josh Boyer jwboyer@fedoraproject.org --- arch/x86/kernel/setup.c | 2 ++ include/linux/efi.h | 1 + 2 files changed, 3 insertions(+)
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index deeb7bc..08dc16e 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -1131,7 +1131,9 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_EFI_SECURE_BOOT_SIG_ENFORCE if (boot_params.secure_boot) { + set_bit(EFI_SECURE_BOOT, &x86_efi_facility); enforce_signed_modules(); + pr_info("Secure boot enabled\n"); } #endif
diff --git a/include/linux/efi.h b/include/linux/efi.h index 5f8f176..eed2202 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -634,6 +634,7 @@ extern int __init efi_setup_pcdp_console(char *); #define EFI_RUNTIME_SERVICES 3 /* Can we use runtime services? */ #define EFI_MEMMAP 4 /* Can we use EFI memory map? */ #define EFI_64BIT 5 /* Is the firmware 64-bit? */ +#define EFI_SECURE_BOOT 6 /* Are we in Secure Boot mode? */
#ifdef CONFIG_EFI # ifdef CONFIG_X86
From cff9d37c9529fca5ff853f0050c7f0de0e819ea7 Mon Sep 17 00:00:00 2001
From: Dave Howells dhowells@redhat.com Date: Tue, 23 Oct 2012 09:30:54 -0400 Subject: [PATCH 1/4] Add EFI signature data types
Add the data types that are used for containing hashes, keys and certificates for cryptographic verification.
Signed-off-by: David Howells dhowells@redhat.com --- include/linux/efi.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
diff --git a/include/linux/efi.h b/include/linux/efi.h index eed2202..1da1b3c 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -389,6 +389,12 @@ typedef efi_status_t efi_query_variable_store_t(u32 attributes, unsigned long si #define EFI_FILE_SYSTEM_GUID \ EFI_GUID( 0x964e5b22, 0x6459, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b )
+#define EFI_CERT_SHA256_GUID \ + EFI_GUID( 0xc1c41626, 0x504c, 0x4092, 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28 ) + +#define EFI_CERT_X509_GUID \ + EFI_GUID( 0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 ) + typedef struct { efi_guid_t guid; u64 table; @@ -524,6 +530,20 @@ typedef struct {
#define EFI_INVALID_TABLE_ADDR (~0UL)
+typedef struct { + efi_guid_t signature_owner; + u8 signature_data[]; +} efi_signature_data_t; + +typedef struct { + efi_guid_t signature_type; + u32 signature_list_size; + u32 signature_header_size; + u32 signature_size; + u8 signature_header[]; + /* efi_signature_data_t signatures[][] */ +} efi_signature_list_t; + /* * All runtime access to EFI goes through this structure: */
From 2ce1c1d0d7110c4b06d65e4c8506f6c54aa72628 Mon Sep 17 00:00:00 2001
From: Dave Howells dhowells@redhat.com Date: Tue, 23 Oct 2012 09:36:28 -0400 Subject: [PATCH 2/4] Add an EFI signature blob parser and key loader.
X.509 certificates are loaded into the specified keyring as asymmetric type keys.
Signed-off-by: David Howells dhowells@redhat.com --- crypto/asymmetric_keys/Kconfig | 8 +++ crypto/asymmetric_keys/Makefile | 1 + crypto/asymmetric_keys/efi_parser.c | 108 ++++++++++++++++++++++++++++++++++++ include/linux/efi.h | 4 ++ 4 files changed, 121 insertions(+) create mode 100644 crypto/asymmetric_keys/efi_parser.c
diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig index 6d2c2ea..ace9c30 100644 --- a/crypto/asymmetric_keys/Kconfig +++ b/crypto/asymmetric_keys/Kconfig @@ -35,4 +35,12 @@ config X509_CERTIFICATE_PARSER data and provides the ability to instantiate a crypto key from a public key packet found inside the certificate.
+config EFI_SIGNATURE_LIST_PARSER + bool "EFI signature list parser" + depends on EFI + select X509_CERTIFICATE_PARSER + help + This option provides support for parsing EFI signature lists for + X.509 certificates and turning them into keys. + endif # ASYMMETRIC_KEY_TYPE diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile index 0727204..cd8388e 100644 --- a/crypto/asymmetric_keys/Makefile +++ b/crypto/asymmetric_keys/Makefile @@ -8,6 +8,7 @@ asymmetric_keys-y := asymmetric_type.o signature.o
obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o +obj-$(CONFIG_EFI_SIGNATURE_LIST_PARSER) += efi_parser.o
# # X.509 Certificate handling diff --git a/crypto/asymmetric_keys/efi_parser.c b/crypto/asymmetric_keys/efi_parser.c new file mode 100644 index 0000000..636feb1 --- /dev/null +++ b/crypto/asymmetric_keys/efi_parser.c @@ -0,0 +1,108 @@ +/* EFI signature/key/certificate list parser + * + * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#define pr_fmt(fmt) "EFI: "fmt +#include <linux/module.h> +#include <linux/printk.h> +#include <linux/err.h> +#include <linux/efi.h> +#include <keys/asymmetric-type.h> + +static __initdata efi_guid_t efi_cert_x509_guid = EFI_CERT_X509_GUID; + +/** + * parse_efi_signature_list - Parse an EFI signature list for certificates + * @data: The data blob to parse + * @size: The size of the data blob + * @keyring: The keyring to add extracted keys to + */ +int __init parse_efi_signature_list(const void *data, size_t size, struct key *keyring) +{ + unsigned offs = 0; + size_t lsize, esize, hsize, elsize; + + pr_devel("-->%s(,%zu)\n", __func__, size); + + while (size > 0) { + efi_signature_list_t list; + const efi_signature_data_t *elem; + key_ref_t key; + + if (size < sizeof(list)) + return -EBADMSG; + + memcpy(&list, data, sizeof(list)); + pr_devel("LIST[%04x] guid=%pUl ls=%x hs=%x ss=%x\n", + offs, + list.signature_type.b, list.signature_list_size, + list.signature_header_size, list.signature_size); + + lsize = list.signature_list_size; + hsize = list.signature_header_size; + esize = list.signature_size; + elsize = lsize - sizeof(list) - hsize; + + if (lsize > size) { + pr_devel("<--%s() = -EBADMSG [overrun @%x]\n", + __func__, offs); + return -EBADMSG; + } + if (lsize < sizeof(list) || + lsize - sizeof(list) < hsize || + esize < sizeof(*elem) || + elsize < esize || + elsize % esize != 0) { + pr_devel("- bad size combo @%x\n", offs); + return -EBADMSG; + } + + if (efi_guidcmp(list.signature_type, efi_cert_x509_guid) != 0) { + data += lsize; + size -= lsize; + offs += lsize; + continue; + } + + data += sizeof(list) + hsize; + size -= sizeof(list) + hsize; + offs += sizeof(list) + hsize; + + for (; elsize > 0; elsize -= esize) { + elem = data; + + pr_devel("ELEM[%04x]\n", offs); + + key = key_create_or_update( + make_key_ref(keyring, 1), + "asymmetric", + NULL, + &elem->signature_data, + esize - sizeof(*elem), + (KEY_POS_ALL & ~KEY_POS_SETATTR) | + KEY_USR_VIEW, + KEY_ALLOC_NOT_IN_QUOTA); + + if (IS_ERR(key)) + pr_err("Problem loading in-kernel X.509 certificate (%ld)\n", + PTR_ERR(key)); + else + pr_notice("Loaded cert '%s' linked to '%s'\n", + key_ref_to_ptr(key)->description, + keyring->description); + + data += esize; + size -= esize; + offs += esize; + } + } + + return 0; +} diff --git a/include/linux/efi.h b/include/linux/efi.h index 1da1b3c..42a1d25 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -619,6 +619,10 @@ extern int efi_set_rtc_mmss(const struct timespec *now); extern void efi_reserve_boot_services(void); extern struct efi_memory_map memmap;
+struct key; +extern int __init parse_efi_signature_list(const void *data, size_t size, + struct key *keyring); + /** * efi_range_is_wc - check the WC bit on an address range * @start: starting kvirt address
From 0e4e8acfd0932bbf6b02112218092c810d9469a5 Mon Sep 17 00:00:00 2001
From: Josh Boyer jwboyer@fedoraproject.org Date: Fri, 26 Oct 2012 12:36:24 -0400 Subject: [PATCH 3/4] MODSIGN: Add module certificate blacklist keyring
This adds an additional keyring that is used to store certificates that are blacklisted. This keyring is searched first when loading signed modules and if the module's certificate is found, it will refuse to load. This is useful in cases where third party certificates are used for module signing.
Signed-off-by: Josh Boyer jwboyer@fedoraproject.org --- init/Kconfig | 8 ++++++++ kernel/modsign_pubkey.c | 14 ++++++++++++++ kernel/module-internal.h | 3 +++ kernel/module_signing.c | 12 ++++++++++++ 4 files changed, 37 insertions(+)
diff --git a/init/Kconfig b/init/Kconfig index fed81b5..b4fa2d1 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1772,6 +1772,14 @@ config MODULE_SIG_ALL comment "Do not forget to sign required modules with scripts/sign-file" depends on MODULE_SIG_FORCE && !MODULE_SIG_ALL
+config MODULE_SIG_BLACKLIST + bool "Support for blacklisting module signature certificates" + depends on MODULE_SIG + help + This adds support for keeping a blacklist of certificates that + should not pass module signature verification. If a module is + signed with something in this keyring, the load will be rejected. + choice prompt "Which hash algorithm should modules be signed with?" depends on MODULE_SIG diff --git a/kernel/modsign_pubkey.c b/kernel/modsign_pubkey.c index 2b6e699..4cd408d 100644 --- a/kernel/modsign_pubkey.c +++ b/kernel/modsign_pubkey.c @@ -17,6 +17,9 @@ #include "module-internal.h"
struct key *modsign_keyring; +#ifdef CONFIG_MODULE_SIG_BLACKLIST +struct key *modsign_blacklist; +#endif
extern __initdata const u8 modsign_certificate_list[]; extern __initdata const u8 modsign_certificate_list_end[]; @@ -43,6 +46,17 @@ static __init int module_verify_init(void) if (IS_ERR(modsign_keyring)) panic("Can't allocate module signing keyring\n");
+#ifdef CONFIG_MODULE_SIG_BLACKLIST + modsign_blacklist = keyring_alloc(".modsign_blacklist", + KUIDT_INIT(0), KGIDT_INIT(0), + current_cred(), + (KEY_POS_ALL & ~KEY_POS_SETATTR) | + KEY_USR_VIEW | KEY_USR_READ, + KEY_ALLOC_NOT_IN_QUOTA, NULL); + if (IS_ERR(modsign_blacklist)) + panic("Can't allocate module signing blacklist keyring\n"); +#endif + return 0; }
diff --git a/kernel/module-internal.h b/kernel/module-internal.h index 24f9247..51a8380 100644 --- a/kernel/module-internal.h +++ b/kernel/module-internal.h @@ -10,5 +10,8 @@ */
extern struct key *modsign_keyring; +#ifdef CONFIG_MODULE_SIG_BLACKLIST +extern struct key *modsign_blacklist; +#endif
extern int mod_verify_sig(const void *mod, unsigned long *_modlen); diff --git a/kernel/module_signing.c b/kernel/module_signing.c index f2970bd..5423195 100644 --- a/kernel/module_signing.c +++ b/kernel/module_signing.c @@ -157,6 +157,18 @@ static struct key *request_asymmetric_key(const char *signer, size_t signer_len,
pr_debug("Look up: "%s"\n", id);
+#ifdef CONFIG_MODULE_SIG_BLACKLIST + key = keyring_search(make_key_ref(modsign_blacklist, 1), + &key_type_asymmetric, id); + if (!IS_ERR(key)) { + /* module is signed with a cert in the blacklist. reject */ + pr_err("Module key '%s' is in blacklist\n", id); + key_ref_put(key); + kfree(id); + return ERR_PTR(-EKEYREJECTED); + } +#endif + key = keyring_search(make_key_ref(modsign_keyring, 1), &key_type_asymmetric, id); if (IS_ERR(key))
From c558b46370e850851a94795df67b7c57aecc48ea Mon Sep 17 00:00:00 2001
From: Josh Boyer jwboyer@fedoraproject.org Date: Fri, 26 Oct 2012 12:42:16 -0400 Subject: [PATCH 4/4] MODSIGN: Import certificates from UEFI Secure Boot
Secure Boot stores a list of allowed certificates in the 'db' variable. This imports those certificates into the module signing keyring. This allows for a third party signing certificate to be used in conjunction with signed modules. By importing the public certificate into the 'db' variable, a user can allow a module signed with that certificate to load. The shim UEFI bootloader has a similar certificate list stored in the 'MokListRT' variable. We import those as well.
In the opposite case, Secure Boot maintains a list of disallowed certificates in the 'dbx' variable. We load those certificates into the newly introduced module blacklist keyring and forbid any module signed with those from loading.
Signed-off-by: Josh Boyer jwboyer@fedoraproject.org --- include/linux/efi.h | 6 ++++ init/Kconfig | 9 +++++ kernel/Makefile | 3 ++ kernel/modsign_uefi.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 kernel/modsign_uefi.c
diff --git a/include/linux/efi.h b/include/linux/efi.h index 42a1d25..d3e6036 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -395,6 +395,12 @@ typedef efi_status_t efi_query_variable_store_t(u32 attributes, unsigned long si #define EFI_CERT_X509_GUID \ EFI_GUID( 0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 )
+#define EFI_IMAGE_SECURITY_DATABASE_GUID \ + EFI_GUID( 0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f ) + +#define EFI_SHIM_LOCK_GUID \ + EFI_GUID( 0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 ) + typedef struct { efi_guid_t guid; u64 table; diff --git a/init/Kconfig b/init/Kconfig index b4fa2d1..94ce526 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1780,6 +1780,15 @@ config MODULE_SIG_BLACKLIST should not pass module signature verification. If a module is signed with something in this keyring, the load will be rejected.
+config MODULE_SIG_UEFI + bool "Allow modules signed with certs stored in UEFI" + depends on MODULE_SIG && MODULE_SIG_BLACKLIST && EFI + select EFI_SIGNATURE_LIST_PARSER + help + This will import certificates stored in UEFI and allow modules + signed with those to be loaded. It will also disallow loading + of modules stored in the UEFI dbx variable. + choice prompt "Which hash algorithm should modules be signed with?" depends on MODULE_SIG diff --git a/kernel/Makefile b/kernel/Makefile index 35ef118..6ca1fea 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_PROVE_LOCKING) += spinlock.o obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_MODULE_SIG) += module_signing.o modsign_pubkey.o modsign_certificate.o +obj-$(CONFIG_MODULE_SIG_UEFI) += modsign_uefi.o obj-$(CONFIG_KALLSYMS) += kallsyms.o obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o obj-$(CONFIG_KEXEC) += kexec.o @@ -114,6 +115,8 @@ obj-$(CONFIG_CONTEXT_TRACKING) += context_tracking.o
$(obj)/configs.o: $(obj)/config_data.h
+$(obj)/modsign_uefi.o: KBUILD_CFLAGS += -fshort-wchar + # config_data.h contains the same information as ikconfig.h but gzipped. # Info from config_data can be extracted from /proc/config* targets += config_data.gz diff --git a/kernel/modsign_uefi.c b/kernel/modsign_uefi.c new file mode 100644 index 0000000..7eae5b4 --- /dev/null +++ b/kernel/modsign_uefi.c @@ -0,0 +1,91 @@ +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/cred.h> +#include <linux/err.h> +#include <linux/efi.h> +#include <linux/slab.h> +#include <keys/asymmetric-type.h> +#include "module-internal.h" + +static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid, unsigned long *size) +{ + efi_status_t status; + unsigned long lsize = 4; + unsigned long tmpdb[4]; + void *db = NULL; + + status = efi.get_variable(name, guid, NULL, &lsize, &tmpdb); + if (status != EFI_BUFFER_TOO_SMALL) { + pr_err("Couldn't get size: 0x%lx\n", status); + return NULL; + } + + db = kmalloc(lsize, GFP_KERNEL); + if (!db) { + pr_err("Couldn't allocate memory for uefi cert list\n"); + goto out; + } + + status = efi.get_variable(name, guid, NULL, &lsize, db); + if (status != EFI_SUCCESS) { + kfree(db); + db = NULL; + pr_err("Error reading db var: 0x%lx\n", status); + } +out: + *size = lsize; + return db; +} + +/* + * * Load the certs contained in the UEFI databases + * */ +static int __init load_uefi_certs(void) +{ + efi_guid_t secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID; + efi_guid_t mok_var = EFI_SHIM_LOCK_GUID; + void *db = NULL, *dbx = NULL, *mok = NULL; + unsigned long dbsize = 0, dbxsize = 0, moksize = 0; + int rc = 0; + + /* Check if SB is enabled and just return if not */ + if (!efi_enabled(EFI_SECURE_BOOT)) + return 0; + + /* Get db, MokListRT, and dbx. They might not exist, so it isn't + * an error if we can't get them. + */ + db = get_cert_list(L"db", &secure_var, &dbsize); + if (!db) { + pr_err("MODSIGN: Couldn't get UEFI db list\n"); + } else { + rc = parse_efi_signature_list(db, dbsize, modsign_keyring); + if (rc) + pr_err("Couldn't parse db signatures: %d\n", rc); + kfree(db); + } + + mok = get_cert_list(L"MokListRT", &mok_var, &moksize); + if (!mok) { + pr_info("MODSIGN: Couldn't get UEFI MokListRT\n"); + } else { + rc = parse_efi_signature_list(mok, moksize, modsign_keyring); + if (rc) + pr_err("Couldn't parse MokListRT signatures: %d\n", rc); + kfree(mok); + } + + dbx = get_cert_list(L"dbx", &secure_var, &dbxsize); + if (!dbx) { + pr_info("MODSIGN: Couldn't get UEFI dbx list\n"); + } else { + rc = parse_efi_signature_list(dbx, dbxsize, + modsign_blacklist); + if (rc) + pr_err("Couldn't parse dbx signatures: %d\n", rc); + kfree(dbx); + } + + return rc; +} +late_initcall(load_uefi_certs);
From 4fe6d11d21b548d6e8272cc8cad5fcc6150ef081 Mon Sep 17 00:00:00 2001
From: Josh Boyer jwboyer@fedoraproject.org Date: Fri, 26 Oct 2012 14:02:09 -0400 Subject: [PATCH] hibernate: Disable in a signed modules environment
There is currently no way to verify the resume image when returning from hibernate. This might compromise the signed modules trust model, so until we can work with signed hibernate images we disable it in a secure modules environment.
Signed-off-by: Josh Boyer jwboyer@fedoraproject.com --- kernel/power/hibernate.c | 16 +++++++++++++++- kernel/power/main.c | 7 ++++++- kernel/power/user.c | 5 +++++ 3 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index b26f5f1..e65228b 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -28,6 +28,8 @@ #include <linux/syscore_ops.h> #include <linux/ctype.h> #include <linux/genhd.h> +#include <linux/efi.h> +#include <linux/module.h>
#include "power.h"
@@ -632,6 +634,10 @@ int hibernate(void) { int error;
+ if (secure_modules()) { + return -EPERM; + } + lock_system_sleep(); /* The snapshot device should not be opened while we're running */ if (!atomic_add_unless(&snapshot_device_available, -1, 0)) { @@ -723,7 +729,7 @@ static int software_resume(void) /* * If the user said "noresume".. bail out early. */ - if (noresume) + if (noresume || secure_modules()) return 0;
/* @@ -889,6 +895,11 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr, int i; char *start = buf;
+ if (efi_enabled(EFI_SECURE_BOOT)) { + buf += sprintf(buf, "[%s]\n", "disabled"); + return buf-start; + } + for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) { if (!hibernation_modes[i]) continue; @@ -923,6 +934,9 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr, char *p; int mode = HIBERNATION_INVALID;
+ if (secure_modules()) + return -EPERM; + p = memchr(buf, '\n', n); len = p ? p - buf : n;
diff --git a/kernel/power/main.c b/kernel/power/main.c index 1d1bf63..300f300 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -15,6 +15,7 @@ #include <linux/workqueue.h> #include <linux/debugfs.h> #include <linux/seq_file.h> +#include <linux/efi.h>
#include "power.h"
@@ -301,7 +302,11 @@ static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, } #endif #ifdef CONFIG_HIBERNATION - s += sprintf(s, "%s\n", "disk"); + if (!efi_enabled(EFI_SECURE_BOOT)) { + s += sprintf(s, "%s\n", "disk"); + } else { + s += sprintf(s, "\n"); + } #else if (s != buf) /* convert the last space to a newline */ diff --git a/kernel/power/user.c b/kernel/power/user.c index 4ed81e7..b714ee6 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c @@ -24,6 +24,8 @@ #include <linux/console.h> #include <linux/cpu.h> #include <linux/freezer.h> +#include <linux/efi.h> +#include <linux/module.h>
#include <asm/uaccess.h>
@@ -48,6 +50,9 @@ static int snapshot_open(struct inode *inode, struct file *filp) struct snapshot_data *data; int error;
+ if (secure_modules()) + return -EPERM; + lock_system_sleep();
if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
diff --git a/config-x86-generic b/config-x86-generic index f2a071e..64f5a2f 100644 --- a/config-x86-generic +++ b/config-x86-generic @@ -441,14 +441,14 @@ CONFIG_VMWARE_VMCI_VSOCKETS=m CONFIG_XZ_DEC_X86=y
CONFIG_MPILIB=y -CONFIG_PKCS7_MESSAGE_PARSER=y -CONFIG_PE_FILE_PARSER=y CONFIG_MODULE_SIG=y CONFIG_MODULE_SIG_ALL=y # CONFIG_MODULE_SIG_SHA1 is not set CONFIG_MODULE_SIG_SHA256=y # CONFIG_MODULE_SIG_FORCE is not set -CONFIG_SYSTEM_BLACKLIST_KEYRING=y +CONFIG_MODULE_SIG_BLACKLIST=y +CONFIG_EFI_SECURE_BOOT_SIG_ENFORCE=y +CONFIG_EFI_SIGNATURE_LIST_PARSER=y
CONFIG_MODULE_SIG_UEFI=y
diff --git a/kernel.spec b/kernel.spec index 4f2f076..c6f3918 100644 --- a/kernel.spec +++ b/kernel.spec @@ -62,7 +62,7 @@ Summary: The Linux kernel # For non-released -rc kernels, this will be appended after the rcX and # gitX tags, so a 3 here would become part of release "0.rcX.gitX.3" # -%global baserelease 1 +%global baserelease 4 %global fedora_build %{baserelease}
# base_sublevel is the kernel version we're starting with and patching @@ -647,8 +647,10 @@ Patch800: crash-driver.patch # crypto/
# secure boot -Patch1000: devel-pekey-secure-boot-20130820.patch -Patch1001: devel-sysrq-secure-boot-20130717.patch +Patch1000: secure-modules.patch +Patch1001: modsign-uefi.patch +Patch1002: sb-hibernate.patch +Patch1003: devel-sysrq-secure-boot-20130717.patch
# virt + ksm patches
@@ -1371,8 +1373,10 @@ ApplyPatch crash-driver.patch # crypto/
# secure boot -ApplyPatch devel-pekey-secure-boot-20130820.patch -ApplyPatch devel-sysrq-secure-boot-20130717.patch +ApplyPatch secure-modules.patch +ApplyPatch modsign-uefi.patch +ApplyPatch sb-hibernate.patch +#pplyPatch devel-sysrq-secure-boot-20130717.patch
# Assorted Virt Fixes
On Fri, Aug 30, 2013 at 08:40:31AM -0400, Josh Boyer wrote:
# secure boot -ApplyPatch devel-pekey-secure-boot-20130820.patch -ApplyPatch devel-sysrq-secure-boot-20130717.patch +ApplyPatch secure-modules.patch +ApplyPatch modsign-uefi.patch +ApplyPatch sb-hibernate.patch +#pplyPatch devel-sysrq-secure-boot-20130717.patch
Oops, just noticed I have the sysrq patch still not applied. Not a big issue and I'll fix it up before I commit anything.
josh
On Fri, Aug 30, 2013 at 08:21:28AM -0400, Josh Boyer wrote:
I've been working on rebasing Fedora's secure boot approach to using the secure_module patches Matthew Garrett posted upstream. Below are the changes to do this.
Things to note:
- Most people won't even notice a change as the impacts to userspace
remain the same.
- We're dropping the pekey patches. It's a large chunk of code that is
dead upstream and has no usage within Fedora.
- The kexec patch should likely get reworked to prevent loading, and
that has been noted upstream.
- At some point we'll look at adding support for hibernate likely via
the patches that OpenSUSE has introduced.
- This falls back to using the upstream .modsign_keyring instead of
.system_keyring. The concept of a system keyring is decent, but at the moment it isn't going anywhere upstream. We can look at switching back at some point in the future.
ACK or something. ;-)
On 08/30/2013 08:21 AM, Josh Boyer wrote:
Hi All,
I've been working on rebasing Fedora's secure boot approach to using the secure_module patches Matthew Garrett posted upstream. Below are the changes to do this.
Things to note:
- Most people won't even notice a change as the impacts to userspace
remain the same.
- We're dropping the pekey patches. It's a large chunk of code that is
dead upstream and has no usage within Fedora.
- The kexec patch should likely get reworked to prevent loading, and
that has been noted upstream.
- At some point we'll look at adding support for hibernate likely via
the patches that OpenSUSE has introduced.
- This falls back to using the upstream .modsign_keyring instead of
.system_keyring. The concept of a system keyring is decent, but at the moment it isn't going anywhere upstream. We can look at switching back at some point in the future.
josh
Not-sure-if-supposed-to-acked-by: Prarit Bhargava prarit@redhat.com
:)
Looks good Josh ... thanks :)
P.
On Fri, Aug 30, 2013 at 08:58:14AM -0400, Prarit Bhargava wrote:
On 08/30/2013 08:21 AM, Josh Boyer wrote:
Hi All,
I've been working on rebasing Fedora's secure boot approach to using the secure_module patches Matthew Garrett posted upstream. Below are the changes to do this.
Things to note:
- Most people won't even notice a change as the impacts to userspace
remain the same.
- We're dropping the pekey patches. It's a large chunk of code that is
dead upstream and has no usage within Fedora.
- The kexec patch should likely get reworked to prevent loading, and
that has been noted upstream.
- At some point we'll look at adding support for hibernate likely via
the patches that OpenSUSE has introduced.
- This falls back to using the upstream .modsign_keyring instead of
.system_keyring. The concept of a system keyring is decent, but at the moment it isn't going anywhere upstream. We can look at switching back at some point in the future.
josh
Not-sure-if-supposed-to-acked-by: Prarit Bhargava prarit@redhat.com
Of course. More eyes always welcome.
:)
Looks good Josh ... thanks :)
Thanks.
josh
kernel@lists.fedoraproject.org