The upstream 0-day bot found an issue with the existing patchset in the rawhide kernel. Everything builds fine as a whole, but if one were to bisect the patches, a build would break because the shim GUID is used in a patch before it is actually defined.
Fix this by inserting a patch in the series to explicitly define that and the image security database GUIDs. This posting is a refresh of the whole series, for completeness.
josh
From: Matthew Garrett matthew.garrett@nebula.com
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.
Bugzilla: N/A Upstream-status: Fedora mustard. Replaced by securelevels, but that was nak'd
Signed-off-by: Matthew Garrett matthew.garrett@nebula.com --- include/linux/module.h | 6 ++++++ kernel/module.c | 10 ++++++++++ 2 files changed, 16 insertions(+)
diff --git a/include/linux/module.h b/include/linux/module.h index 0c3207d26ac0..05bd6c989a0c 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -641,6 +641,8 @@ static inline bool is_livepatch_module(struct module *mod) } #endif /* CONFIG_LIVEPATCH */
+extern bool secure_modules(void); + #else /* !CONFIG_MODULES... */
static inline struct module *__module_address(unsigned long addr) @@ -750,6 +752,10 @@ static inline bool module_requested_async_probing(struct module *module) return false; }
+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 f57dd63186e6..cb864505d020 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -4284,3 +4284,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(secure_modules);
From: Matthew Garrett matthew.garrett@nebula.com
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 bcd10c795284..a950301496f3 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -30,6 +30,7 @@ #include <linux/vgaarb.h> #include <linux/pm_runtime.h> #include <linux/of.h> +#include <linux/module.h> #include "pci.h"
static int sysfs_initialized; /* = 0 */ @@ -716,6 +717,9 @@ static ssize_t 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) { @@ -1007,6 +1011,9 @@ static int 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; @@ -1106,6 +1113,9 @@ static ssize_t 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 2408abe4ee8c..59f321c56c18 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -116,6 +116,9 @@ static ssize_t proc_bus_pci_write(struct file *file, const char __user *buf, int size = dev->cfg_size; int cnt;
+ if (secure_modules()) + return -EPERM; + if (pos >= size) return 0; if (nbytes >= size) @@ -195,6 +198,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); @@ -233,7 +239,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, write_combine;
- 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 b91c4da68365..98f5637304d1 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: Matthew Garrett matthew.garrett@nebula.com
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 589b3193f102..ab8372443efb 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;
/* @@ -108,7 +109,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) | diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 5bb1985ec484..7f1a7ab5850d 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/uio.h> +#include <linux/module.h>
#include <linux/uaccess.h>
@@ -580,6 +581,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: Matthew Garrett matthew.garrett@nebula.com
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 | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/drivers/acpi/custom_method.c b/drivers/acpi/custom_method.c index c68e72414a67..4277938af700 100644 --- a/drivers/acpi/custom_method.c +++ b/drivers/acpi/custom_method.c @@ -29,6 +29,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: Matthew Garrett matthew.garrett@nebula.com
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 ce6ca31a2d09..55d23994d6a2 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -1872,6 +1872,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) @@ -1888,6 +1891,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);
@@ -1912,6 +1918,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: Matthew Garrett matthew.garrett@nebula.com
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 7f1a7ab5850d..d6a6f05fbc1c 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -164,6 +164,9 @@ static ssize_t write_mem(struct file *file, const char __user *buf, if (p != *ppos) return -EFBIG;
+ if (secure_modules()) + return -EPERM; + if (!valid_phys_addr_range(p, count)) return -EFAULT;
@@ -516,6 +519,9 @@ static ssize_t write_kmem(struct file *file, const char __user *buf, if (!pfn_valid(PFN_DOWN(p))) return -EIO;
+ 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: Josh Boyer jwboyer@redhat.com
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 416953a42510..4887e343c7fd 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -40,6 +40,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> @@ -191,7 +192,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: Matthew Garrett matthew.garrett@nebula.com
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 | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/kernel/kexec.c b/kernel/kexec.c index 980936a90ee6..fce28bf7d5d7 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -12,6 +12,7 @@ #include <linux/mm.h> #include <linux/file.h> #include <linux/kexec.h> +#include <linux/module.h> #include <linux/mutex.h> #include <linux/list.h> #include <linux/syscalls.h> @@ -194,6 +195,13 @@ SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments, return -EPERM;
/* + * kexec can be used to circumvent module loading restrictions, so + * prevent loading in that case + */ + if (secure_modules()) + return -EPERM; + + /* * Verify we have a legal set of flags * This leaves us room for future extensions. */
From: Matthew Garrett matthew.garrett@nebula.com
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 7f3550acde1b..963ba4011923 100644 --- a/arch/x86/kernel/msr.c +++ b/arch/x86/kernel/msr.c @@ -83,6 +83,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 */
@@ -130,6 +133,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: Matthew Garrett matthew.garrett@nebula.com
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 --- a/Documentation/x86/zero-page.txt +++ b/Documentation/x86/zero-page.txt @@ -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 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -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 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -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 --- a/arch/x86/include/uapi/asm/bootparam.h +++ b/arch/x86/include/uapi/asm/bootparam.h @@ -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 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -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 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -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 --- a/kernel/module.c +++ b/kernel/module.c @@ -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
Add the definitions for shim and image security database, both of which are used widely in various Linux distros.
Signed-off-by: Josh Boyer jwboyer@fedoraproject.org --- include/linux/efi.h | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/include/linux/efi.h b/include/linux/efi.h index 2d089487d2da..ce943d5accfd 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -592,6 +592,9 @@ void efi_native_runtime_setup(void); #define EFI_MEMORY_ATTRIBUTES_TABLE_GUID EFI_GUID(0xdcfa911d, 0x26eb, 0x469f, 0xa2, 0x20, 0x38, 0xb7, 0xdc, 0x46, 0x12, 0x20) #define EFI_CONSOLE_OUT_DEVICE_GUID EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4, 0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
+#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) + /* * This GUID is used to pass to the kernel proper the struct screen_info * structure that was populated by the stub based on the GOP protocol instance
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@fedoraproject.org --- 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 ebc85c1eefd6..50e027f388d8 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -540,8 +540,9 @@ static void setup_efi_pci(struct boot_params *params)
static int get_secure_boot(void) { - 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;
@@ -565,6 +566,23 @@ static int get_secure_boot(void) 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_early->call((unsigned long)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; }
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 d40e961753c9..b93183336674 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -1162,7 +1162,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, &efi.flags); enforce_signed_modules(); + pr_info("Secure boot enabled\n"); } #endif
diff --git a/include/linux/efi.h b/include/linux/efi.h index ce943d5accfd..5af91b58afae 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -1046,6 +1046,7 @@ extern int __init efi_setup_pcdp_console(char *); #define EFI_ARCH_1 7 /* First arch-specific bit */ #define EFI_DBG 8 /* Print additional debug info at runtime */ #define EFI_NX_PE_DATA 9 /* Can runtime data regions be mapped non-executable? */ +#define EFI_SECURE_BOOT 10 /* Are we in Secure Boot mode? */
#ifdef CONFIG_EFI /*
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.org --- kernel/power/hibernate.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index b26dbc48c75b..ab187ad3fc61 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -29,6 +29,7 @@ #include <linux/ctype.h> #include <linux/genhd.h> #include <linux/ktime.h> +#include <linux/module.h> #include <trace/events/power.h>
#include "power.h" @@ -67,7 +68,7 @@ static const struct platform_hibernation_ops *hibernation_ops;
bool hibernation_available(void) { - return (nohibernate == 0); + return ((nohibernate == 0) && !secure_modules()); }
/**
From: Dave Howells dhowells@redhat.com
Add the data types that are used for containing hashes, keys and certificates for cryptographic verification.
Bugzilla: N/A Upstream-status: Fedora mustard for now
Signed-off-by: David Howells dhowells@redhat.com --- include/linux/efi.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
diff --git a/include/linux/efi.h b/include/linux/efi.h index 5af91b58afae..190858d62fe3 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -603,6 +603,9 @@ void efi_native_runtime_setup(void); #define LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID EFI_GUID(0xe03fc20a, 0x85dc, 0x406e, 0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95) #define LINUX_EFI_LOADER_ENTRY_GUID EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf, 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f)
+#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; @@ -853,6 +856,20 @@ typedef struct { efi_memory_desc_t entry[0]; } efi_memory_attributes_table_t;
+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: Dave Howells dhowells@redhat.com
X.509 certificates are loaded into the specified keyring as asymmetric type keys.
[labbott@fedoraproject.org: Drop KEY_ALLOC_TRUSTED] 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 331f6baf2df8..5f9002d3192e 100644 --- a/crypto/asymmetric_keys/Kconfig +++ b/crypto/asymmetric_keys/Kconfig @@ -61,4 +61,12 @@ config SIGNED_PE_FILE_VERIFICATION This option provides support for verifying the signature(s) on a signed PE binary.
+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 6516855bec18..c099fe15ed6d 100644 --- a/crypto/asymmetric_keys/Makefile +++ b/crypto/asymmetric_keys/Makefile @@ -10,6 +10,7 @@ asymmetric_keys-y := \ signature.o
obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.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 000000000000..636feb18b733 --- /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 190858d62fe3..668aa1244885 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -1025,6 +1025,10 @@ extern int efi_memattr_apply_permissions(struct mm_struct *mm, char * __init efi_md_typeattr_format(char *buf, size_t size, const efi_memory_desc_t *md);
+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
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 --- certs/system_keyring.c | 22 ++++++++++++++++++++++ include/keys/system_keyring.h | 4 ++++ init/Kconfig | 9 +++++++++ 3 files changed, 35 insertions(+)
diff --git a/certs/system_keyring.c b/certs/system_keyring.c index 50979d6dcecd..787eeead2f57 100644 --- a/certs/system_keyring.c +++ b/certs/system_keyring.c @@ -22,6 +22,9 @@ static struct key *builtin_trusted_keys; #ifdef CONFIG_SECONDARY_TRUSTED_KEYRING static struct key *secondary_trusted_keys; #endif +#ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING +struct key *system_blacklist_keyring; +#endif
extern __initconst const u8 system_certificate_list[]; extern __initconst const unsigned long system_certificate_list_size; @@ -99,6 +102,16 @@ static __init int system_trusted_keyring_init(void) if (key_link(secondary_trusted_keys, builtin_trusted_keys) < 0) panic("Can't link trusted keyrings\n"); #endif +#ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING + system_blacklist_keyring = keyring_alloc(".system_blacklist_keyring", + KUIDT_INIT(0), KGIDT_INIT(0), current_cred(), + ((KEY_POS_ALL & ~KEY_POS_SETATTR) | + KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH), + KEY_ALLOC_NOT_IN_QUOTA, + NULL, NULL); + if (IS_ERR(system_blacklist_keyring)) + panic("Can't allocate system blacklist keyring\n"); +#endif
return 0; } @@ -214,6 +227,15 @@ int verify_pkcs7_signature(const void *data, size_t len, trusted_keys = builtin_trusted_keys; #endif } +#ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING + ret = pkcs7_validate_trust(pkcs7, system_blacklist_keyring); + if (!ret) { + /* module is signed with a cert in the blacklist. reject */ + pr_err("Module key is in the blacklist\n"); + ret = -EKEYREJECTED; + goto error; + } +#endif ret = pkcs7_validate_trust(pkcs7, trusted_keys); if (ret < 0) { if (ret == -ENOKEY) diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h index fbd4647767e9..5bc291a3d261 100644 --- a/include/keys/system_keyring.h +++ b/include/keys/system_keyring.h @@ -33,6 +33,10 @@ extern int restrict_link_by_builtin_and_secondary_trusted( #define restrict_link_by_builtin_and_secondary_trusted restrict_link_by_builtin_trusted #endif
+#ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING +extern struct key *system_blacklist_keyring; +#endif + #ifdef CONFIG_IMA_BLACKLIST_KEYRING extern struct key *ima_blacklist_keyring;
diff --git a/init/Kconfig b/init/Kconfig index 34407f15e6d3..461ad575a608 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1859,6 +1859,15 @@ config SYSTEM_DATA_VERIFICATION module verification, kexec image verification and firmware blob verification.
+config SYSTEM_BLACKLIST_KEYRING + bool "Provide system-wide ring of blacklisted keys" + depends on KEYS + help + Provide a system keyring to which blacklisted keys can be added. + Keys in the keyring are considered entirely untrusted. Keys in this + keyring are used by the module signature checking to reject loading + of modules signed with a blacklisted key. + config PROFILING bool "Profiling support" help
Secure Boot stores a list of allowed certificates in the 'db' variable. This imports those certificates into the system trusted 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 system blacklist keyring and forbid any module signed with those from loading.
Signed-off-by: Josh Boyer jwboyer@fedoraproject.org --- certs/system_keyring.c | 13 ++++++ include/keys/system_keyring.h | 1 + init/Kconfig | 9 ++++ kernel/Makefile | 3 ++ kernel/modsign_uefi.c | 99 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 125 insertions(+) create mode 100644 kernel/modsign_uefi.c
diff --git a/certs/system_keyring.c b/certs/system_keyring.c index 787eeead2f57..4d9123ed5c07 100644 --- a/certs/system_keyring.c +++ b/certs/system_keyring.c @@ -30,6 +30,19 @@ extern __initconst const u8 system_certificate_list[]; extern __initconst const unsigned long system_certificate_list_size;
/** + * get_system_keyring - Return a pointer to the system keyring + * + */ +struct key *get_system_keyring(void) +{ + struct key *system_keyring = NULL; + + system_keyring = builtin_trusted_keys; + return system_keyring; +} +EXPORT_SYMBOL_GPL(get_system_keyring); + +/** * restrict_link_to_builtin_trusted - Restrict keyring addition by built in CA * * Restrict the addition of keys into a keyring based on the key-to-be-added diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h index 5bc291a3d261..56ff5715ab67 100644 --- a/include/keys/system_keyring.h +++ b/include/keys/system_keyring.h @@ -36,6 +36,7 @@ extern int restrict_link_by_builtin_and_secondary_trusted( #ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING extern struct key *system_blacklist_keyring; #endif +extern struct key *get_system_keyring(void);
#ifdef CONFIG_IMA_BLACKLIST_KEYRING extern struct key *ima_blacklist_keyring; diff --git a/init/Kconfig b/init/Kconfig index 461ad575a608..93646fd7b1c8 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -2009,6 +2009,15 @@ 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_UEFI + bool "Allow modules signed with certs stored in UEFI" + depends on MODULE_SIG && SYSTEM_BLACKLIST_KEYRING && 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 eb26e12c6c2a..e0c2268cb97e 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -57,6 +57,7 @@ endif obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_MODULE_SIG) += module_signing.o +obj-$(CONFIG_MODULE_SIG_UEFI) += modsign_uefi.o obj-$(CONFIG_KALLSYMS) += kallsyms.o obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o obj-$(CONFIG_KEXEC_CORE) += kexec_core.o @@ -113,6 +114,8 @@ obj-$(CONFIG_MEMBARRIER) += membarrier.o
obj-$(CONFIG_HAS_IOMEM) += memremap.o
+$(obj)/modsign_uefi.o: KBUILD_CFLAGS += -fshort-wchar + $(obj)/configs.o: $(obj)/config_data.h
# config_data.h contains the same information as ikconfig.h but gzipped. diff --git a/kernel/modsign_uefi.c b/kernel/modsign_uefi.c new file mode 100644 index 000000000000..fe4a6f2bf10a --- /dev/null +++ b/kernel/modsign_uefi.c @@ -0,0 +1,99 @@ +#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 <keys/system_keyring.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; + struct key *keyring = NULL; + + /* Check if SB is enabled and just return if not */ + if (!efi_enabled(EFI_SECURE_BOOT)) + return 0; + + keyring = get_system_keyring(); + if (!keyring) { + pr_err("MODSIGN: Couldn't get system keyring\n"); + return -EINVAL; + } + + /* 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, 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, 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, + system_blacklist_keyring); + if (rc) + pr_err("Couldn't parse dbx signatures: %d\n", rc); + kfree(dbx); + } + + return rc; +} +late_initcall(load_uefi_certs);
If a user tells shim to not use the certs/hashes in the UEFI db variable for verification purposes, shim will set a UEFI variable called MokIgnoreDB. Have the uefi import code look for this and not import things from the db variable.
Signed-off-by: Josh Boyer jwboyer@fedoraproject.org --- kernel/modsign_uefi.c | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-)
diff --git a/kernel/modsign_uefi.c b/kernel/modsign_uefi.c index fe4a6f2bf10a..a41da14b1ffd 100644 --- a/kernel/modsign_uefi.c +++ b/kernel/modsign_uefi.c @@ -8,6 +8,23 @@ #include <keys/system_keyring.h> #include "module-internal.h"
+static __init int check_ignore_db(void) +{ + efi_status_t status; + unsigned int db = 0; + unsigned long size = sizeof(db); + efi_guid_t guid = EFI_SHIM_LOCK_GUID; + + /* Check and see if the MokIgnoreDB variable exists. If that fails + * then we don't ignore DB. If it succeeds, we do. + */ + status = efi.get_variable(L"MokIgnoreDB", &guid, NULL, &size, &db); + if (status != EFI_SUCCESS) + return 0; + + return 1; +} + static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid, unsigned long *size) { efi_status_t status; @@ -47,7 +64,7 @@ static int __init load_uefi_certs(void) 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; + int ignore_db, rc = 0; struct key *keyring = NULL;
/* Check if SB is enabled and just return if not */ @@ -60,17 +77,22 @@ static int __init load_uefi_certs(void) return -EINVAL; }
+ /* See if the user has setup Ignore DB mode */ + ignore_db = check_ignore_db(); + /* 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, keyring); - if (rc) - pr_err("Couldn't parse db signatures: %d\n", rc); - kfree(db); + if (!ignore_db) { + 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, keyring); + if (rc) + pr_err("Couldn't parse db signatures: %d\n", rc); + kfree(db); + } }
mok = get_cert_list(L"MokListRT", &mok_var, &moksize);
From: Kyle McMartin kyle@redhat.com
Bugzilla: N/A Upstream-status: Fedora mustard --- arch/x86/kernel/setup.c | 36 ++++++++++++++++++++++++++++++++++++ drivers/input/misc/uinput.c | 1 + drivers/tty/sysrq.c | 19 +++++++++++++------ include/linux/input.h | 5 +++++ include/linux/sysrq.h | 8 +++++++- kernel/debug/kdb/kdb_main.c | 2 +- kernel/module.c | 2 +- 7 files changed, 64 insertions(+), 9 deletions(-)
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index b93183336674..dab2882927c2 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -70,6 +70,11 @@ #include <linux/tboot.h> #include <linux/jiffies.h>
+#include <linux/fips.h> +#include <linux/cred.h> +#include <linux/sysrq.h> +#include <linux/init_task.h> + #include <video/edid.h>
#include <asm/mtrr.h> @@ -1286,6 +1291,37 @@ void __init i386_reserve_resources(void)
#endif /* CONFIG_X86_32 */
+#ifdef CONFIG_MAGIC_SYSRQ +#ifdef CONFIG_MODULE_SIG +extern bool sig_enforce; +#endif + +static void sysrq_handle_secure_boot(int key) +{ + if (!efi_enabled(EFI_SECURE_BOOT)) + return; + + pr_info("Secure boot disabled\n"); +#ifdef CONFIG_MODULE_SIG + sig_enforce = fips_enabled; +#endif +} +static struct sysrq_key_op secure_boot_sysrq_op = { + .handler = sysrq_handle_secure_boot, + .help_msg = "unSB(x)", + .action_msg = "Disabling Secure Boot restrictions", + .enable_mask = SYSRQ_DISABLE_USERSPACE, +}; +static int __init secure_boot_sysrq(void) +{ + if (efi_enabled(EFI_SECURE_BOOT)) + register_sysrq_key('x', &secure_boot_sysrq_op); + return 0; +} +late_initcall(secure_boot_sysrq); +#endif /*CONFIG_MAGIC_SYSRQ*/ + + static struct notifier_block kernel_offset_notifier = { .notifier_call = dump_kernel_offset }; diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 92595b98e7ed..894ed3f74f04 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -379,6 +379,7 @@ static int uinput_allocate_device(struct uinput_device *udev) if (!udev->dev) return -ENOMEM;
+ udev->dev->flags |= INPUTDEV_FLAGS_SYNTHETIC; udev->dev->event = uinput_dev_event; input_set_drvdata(udev->dev, udev);
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 52bbd27e93ae..594bd731253a 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -479,6 +479,7 @@ static struct sysrq_key_op *sysrq_key_table[36] = { /* x: May be registered on mips for TLB dump */ /* x: May be registered on ppc/powerpc for xmon */ /* x: May be registered on sparc64 for global PMU dump */ + /* x: May be registered on x86_64 for disabling secure boot */ NULL, /* x */ /* y: May be registered on sparc64 for global register dump */ NULL, /* y */ @@ -522,7 +523,7 @@ static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p) sysrq_key_table[i] = op_p; }
-void __handle_sysrq(int key, bool check_mask) +void __handle_sysrq(int key, int from) { struct sysrq_key_op *op_p; int orig_log_level; @@ -542,11 +543,15 @@ void __handle_sysrq(int key, bool check_mask)
op_p = __sysrq_get_key_op(key); if (op_p) { + /* Ban synthetic events from some sysrq functionality */ + if ((from == SYSRQ_FROM_PROC || from == SYSRQ_FROM_SYNTHETIC) && + op_p->enable_mask & SYSRQ_DISABLE_USERSPACE) + printk("This sysrq operation is disabled from userspace.\n"); /* * Should we check for enabled operations (/proc/sysrq-trigger * should not) and is the invoked operation enabled? */ - if (!check_mask || sysrq_on_mask(op_p->enable_mask)) { + if (from == SYSRQ_FROM_KERNEL || sysrq_on_mask(op_p->enable_mask)) { pr_cont("%s\n", op_p->action_msg); console_loglevel = orig_log_level; op_p->handler(key); @@ -578,7 +583,7 @@ void __handle_sysrq(int key, bool check_mask) void handle_sysrq(int key) { if (sysrq_on()) - __handle_sysrq(key, true); + __handle_sysrq(key, SYSRQ_FROM_KERNEL); } EXPORT_SYMBOL(handle_sysrq);
@@ -659,7 +664,7 @@ static void sysrq_do_reset(unsigned long _state) static void sysrq_handle_reset_request(struct sysrq_state *state) { if (state->reset_requested) - __handle_sysrq(sysrq_xlate[KEY_B], false); + __handle_sysrq(sysrq_xlate[KEY_B], SYSRQ_FROM_KERNEL);
if (sysrq_reset_downtime_ms) mod_timer(&state->keyreset_timer, @@ -810,8 +815,10 @@ static bool sysrq_handle_keypress(struct sysrq_state *sysrq,
default: if (sysrq->active && value && value != 2) { + int from = sysrq->handle.dev->flags & INPUTDEV_FLAGS_SYNTHETIC ? + SYSRQ_FROM_SYNTHETIC : 0; sysrq->need_reinject = false; - __handle_sysrq(sysrq_xlate[code], true); + __handle_sysrq(sysrq_xlate[code], from); } break; } @@ -1095,7 +1102,7 @@ static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf,
if (get_user(c, buf)) return -EFAULT; - __handle_sysrq(c, false); + __handle_sysrq(c, SYSRQ_FROM_PROC); }
return count; diff --git a/include/linux/input.h b/include/linux/input.h index a65e3b24fb18..8b0357175049 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -42,6 +42,7 @@ struct input_value { * @phys: physical path to the device in the system hierarchy * @uniq: unique identification code for the device (if device has it) * @id: id of the device (struct input_id) + * @flags: input device flags (SYNTHETIC, etc.) * @propbit: bitmap of device properties and quirks * @evbit: bitmap of types of events supported by the device (EV_KEY, * EV_REL, etc.) @@ -124,6 +125,8 @@ struct input_dev { const char *uniq; struct input_id id;
+ unsigned int flags; + unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];
unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; @@ -190,6 +193,8 @@ struct input_dev { }; #define to_input_dev(d) container_of(d, struct input_dev, dev)
+#define INPUTDEV_FLAGS_SYNTHETIC 0x000000001 + /* * Verify that we are in sync with input_device_id mod_devicetable.h #defines */ diff --git a/include/linux/sysrq.h b/include/linux/sysrq.h index 387fa7d05c98..4b07e30b3279 100644 --- a/include/linux/sysrq.h +++ b/include/linux/sysrq.h @@ -28,6 +28,8 @@ #define SYSRQ_ENABLE_BOOT 0x0080 #define SYSRQ_ENABLE_RTNICE 0x0100
+#define SYSRQ_DISABLE_USERSPACE 0x00010000 + struct sysrq_key_op { void (*handler)(int); char *help_msg; @@ -42,8 +44,12 @@ struct sysrq_key_op { * are available -- else NULL's). */
+#define SYSRQ_FROM_KERNEL 0x0001 +#define SYSRQ_FROM_PROC 0x0002 +#define SYSRQ_FROM_SYNTHETIC 0x0004 + void handle_sysrq(int key); -void __handle_sysrq(int key, bool check_mask); +void __handle_sysrq(int key, int from); int register_sysrq_key(int key, struct sysrq_key_op *op); int unregister_sysrq_key(int key, struct sysrq_key_op *op); struct sysrq_key_op *__sysrq_get_key_op(int key); diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index 2a20c0dfdafc..3d17205dab77 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c @@ -1968,7 +1968,7 @@ static int kdb_sr(int argc, const char **argv) return KDB_ARGCOUNT;
kdb_trap_printk++; - __handle_sysrq(*argv[1], check_mask); + __handle_sysrq(*argv[1], check_mask & SYSRQ_FROM_KERNEL); kdb_trap_printk--;
return 0; diff --git a/kernel/module.c b/kernel/module.c index cb1f1da69bf4..5933c27ba19e 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -270,7 +270,7 @@ static void module_assert_mutex_or_preempt(void) #endif }
-static bool sig_enforce = IS_ENABLED(CONFIG_MODULE_SIG_FORCE); +bool sig_enforce = IS_ENABLED(CONFIG_MODULE_SIG_FORCE); #ifndef CONFIG_MODULE_SIG_FORCE module_param(sig_enforce, bool_enable_only, 0644); #endif /* !CONFIG_MODULE_SIG_FORCE */
On 10/25/2016 10:24 AM, Josh Boyer wrote:
The upstream 0-day bot found an issue with the existing patchset in the rawhide kernel. Everything builds fine as a whole, but if one were to bisect the patches, a build would break because the shim GUID is used in a patch before it is actually defined.
Fix this by inserting a patch in the series to explicitly define that and the image security database GUIDs. This posting is a refresh of the whole series, for completeness.
josh
LGTM, go ahead and apply to rawhide.
Thanks, Laura
kernel@lists.fedoraproject.org