From 02edef7def11ef45c9dca82382f4d5037b359ce6 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Fri, 9 Aug 2013 17:58:15 -0400 Subject: [PATCH 01/21] 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. Bugzilla: N/A Upstream-status: Fedora mustard. Replaced by securelevels, but that was nak'd Signed-off-by: Matthew Garrett --- 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 2bb0c308570672..ab1300986415bb 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -630,6 +630,8 @@ static inline bool module_requested_async_probing(struct module *module) return module && module->async_probe_requested; } +extern bool secure_modules(void); + #else /* !CONFIG_MODULES... */ /* Given an address, look for it in the exception tables. */ @@ -746,6 +748,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 794ebe8e878d55..7dfb91b87ac526 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -4112,3 +4112,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 4f9bf3ce823a63e72687fa331bdcfd9050f00b54 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Thu, 8 Mar 2012 10:10:38 -0500 Subject: [PATCH 02/21] 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 --- 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 95d9e7bd933bc8..0e249f1ddbbf82 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "pci.h" static int sysfs_initialized; /* = 0 */ @@ -711,6 +712,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) { @@ -998,6 +1002,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; @@ -1098,6 +1105,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 3f155e78513fd4..4265ea07e3b066 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; - 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 b91c4da6836574..98f5637304d1ba 100644 --- a/drivers/pci/syscall.c +++ b/drivers/pci/syscall.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #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 fbcd2f7543b10fb9ff7075eab04aafc8ced67761 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Thu, 8 Mar 2012 10:35:59 -0500 Subject: [PATCH 03/21] 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 --- 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 37dae792dbbed0..1ecc03ca3c1503 100644 --- a/arch/x86/kernel/ioport.c +++ b/arch/x86/kernel/ioport.c @@ -15,6 +15,7 @@ #include #include #include +#include #include /* @@ -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 4f6f94c43412c0..9d53d66819ea06 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -577,6 +578,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 c84966668b5d607812d3f3788dcfa7fbcab400a3 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Fri, 9 Mar 2012 08:39:37 -0500 Subject: [PATCH 04/21] 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 --- 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 c68e72414a67a9..4277938af700d1 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 aafea7dbb04999694c5d7514a8ade6dffc80b6a8 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Fri, 9 Mar 2012 08:46:50 -0500 Subject: [PATCH 05/21] 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 --- 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 a96630d5234674..92bf6b1e967736 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -1867,6 +1867,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) @@ -1883,6 +1886,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); @@ -1907,6 +1913,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 e1a26d978277b78e5f0f393018cecc2e6f6660ab Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Fri, 9 Mar 2012 09:28:15 -0500 Subject: [PATCH 06/21] 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 --- drivers/char/mem.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 9d53d66819ea06..918f43a69b73a1 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -167,6 +167,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; @@ -513,6 +516,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 2d464f9da317e687e5fa03b7a079ad811192f491 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Mon, 25 Jun 2012 19:57:30 -0400 Subject: [PATCH 07/21] 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 --- 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 67da6fb722740b..e02776126f11cb 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -254,7 +255,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 e6288d2d10780371525b4fadaabc8c2d5ac87ad8 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Thu, 19 Nov 2015 18:55:53 -0800 Subject: [PATCH 08/21] 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 --- kernel/kexec.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/kexec.c b/kernel/kexec.c index ee70aef5cd81df..755198b28253b1 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "kexec_internal.h" @@ -131,7 +132,7 @@ SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments, int result; /* We only trust the superuser with rebooting the system. */ - if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) + if (!capable(CAP_SYS_BOOT) || kexec_load_disabled || secure_modules()) return -EPERM; /* From 0cf91ec9a013fe36fc934519e02d5ac3a281b907 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Fri, 8 Feb 2013 11:12:13 -0800 Subject: [PATCH 09/21] 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 Signed-off-by: Matthew Garrett --- 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 64f9616f93f1ec..7fde0152f52b75 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 6e0533e9784929c426d8b9b8566f28d7b79aa109 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Fri, 9 Aug 2013 18:36:30 -0400 Subject: [PATCH 10/21] 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 --- Documentation/x86/zero-page.txt | 2 ++ arch/x86/Kconfig | 10 ++++++++ arch/x86/boot/compressed/eboot.c | 36 +++++++++++++++++++++++++++ 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, 69 insertions(+), 1 deletion(-) diff --git a/Documentation/x86/zero-page.txt b/Documentation/x86/zero-page.txt index 95a4d34af3fdd7..b8527c6b76461c 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 c46662f64c3920..a10f771d251302 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1754,6 +1754,16 @@ config EFI_MIXED If unsure, say N. +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 583d539a41977a..ca120ac1d78380 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "../string.h" #include "eboot.h" @@ -847,6 +848,37 @@ setup_gop64(struct screen_info *si, efi_guid_t *proto, return status; } +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 */ @@ -1432,6 +1464,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 329254373479ad..b61f8533c0fdaf 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 d3d80e6d42a20e..94eb7dd1ec195d 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -1145,6 +1145,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 ab1300986415bb..e072b84c3453e3 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -273,6 +273,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 7dfb91b87ac526..6eb3c6c38c1b8a 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -4113,6 +4113,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 635479012d1f2ecc3109f8d026286ed54e429e89 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Tue, 27 Aug 2013 13:28:43 -0400 Subject: [PATCH 11/21] 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 --- arch/x86/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index a10f771d251302..36a2818234cc6f 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1755,7 +1755,8 @@ config EFI_MIXED If unsure, say N. 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 a3ac48fab6c056a4857dcb1adea99871d5846cd8 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Tue, 27 Aug 2013 13:33:03 -0400 Subject: [PATCH 12/21] 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 --- 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 94eb7dd1ec195d..7c9fc347e35778 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -1147,7 +1147,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 47be3ad7d3e5ba..9bf95e82d3d9ea 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -980,6 +980,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 /* From 4483ccc2fb447291aaafe690570437e72b54a396 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Fri, 20 Jun 2014 08:53:24 -0400 Subject: [PATCH 13/21] 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 --- 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 b7342a24f55921..8a6b21875381fd 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include "power.h" @@ -66,7 +67,7 @@ static const struct platform_hibernation_ops *hibernation_ops; bool hibernation_available(void) { - return (nohibernate == 0); + return ((nohibernate == 0) && !secure_modules()); } /** From 5b5cf4e83fc167101790192e8f6711fb9f879101 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 16 Jun 2015 14:14:31 +0100 Subject: [PATCH 14/21] Security: Provide copy-up security hooks for unioned files Provide two new security hooks for use with security files that are used when a file is copied up between layers: (1) security_inode_copy_up(). This is called so that the security label on the destination file can be set appropriately. (2) security_inode_copy_up_xattr(). This is called so that each xattr being copied up can be vetted - including modification and discard. Signed-off-by: David Howells --- include/linux/lsm_hooks.h | 23 +++++++++++++++++++++++ include/linux/security.h | 14 ++++++++++++++ security/security.c | 17 +++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 71969de4058c99..f5b726706dd782 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -401,6 +401,24 @@ * @inode contains a pointer to the inode. * @secid contains a pointer to the location where result will be saved. * In case of failure, @secid will be set to zero. + * @inode_copy_up: + * Appropriately label the destination inode when a unioned file is copied + * up from a lower layer to the union/overlay layer. + * @src indicates the file that is being copied up. + * @dst indicates the file that has being created by the copy up. + * Returns 0 on success or a negative error code on error. + * @inode_copy_up_xattr: + * Filter/modify the xattrs being copied up when a unioned file is copied + * up from a lower layer to the union/overlay layer. + * @src indicates the file that is being copied up. + * @dst indicates the file that has being created by the copy up. + * @name indicates the name of the xattr. + * @value, *@size indicate the payload of the xattr. + * Returns 0 to accept the xattr, 1 to discard the xattr or a negative + * error code to abort the copy up. The xattr buffer must be at least + * XATTR_SIZE_MAX in capacity and the contents may be modified and *@size + * changed appropriately. Note that the caller is responsible for reading + * and writing the xattrs as this hook is merely a filter. * * Security hooks for file operations * @@ -1425,6 +1443,9 @@ union security_list_options { int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size); void (*inode_getsecid)(struct inode *inode, u32 *secid); + int (*inode_copy_up) (struct dentry *src, struct dentry *dst); + int (*inode_copy_up_xattr) (struct dentry *src, struct dentry *dst, + const char *name, void *value, size_t *size); int (*file_permission)(struct file *file, int mask); int (*file_alloc_security)(struct file *file); @@ -1694,6 +1715,8 @@ struct security_hook_heads { struct list_head inode_setsecurity; struct list_head inode_listsecurity; struct list_head inode_getsecid; + struct list_head inode_copy_up; + struct list_head inode_copy_up_xattr; struct list_head file_permission; struct list_head file_alloc_security; struct list_head file_free_security; diff --git a/include/linux/security.h b/include/linux/security.h index 4824a4ccaf1c37..1f9ea4061f30ef 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -274,6 +274,10 @@ int security_inode_getsecurity(struct inode *inode, const char *name, void **buf int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags); int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size); void security_inode_getsecid(struct inode *inode, u32 *secid); +int security_inode_copy_up(struct dentry *src, struct dentry *dst); +int security_inode_copy_up_xattr(struct dentry *src, struct dentry *dst, + const char *name, void *value, size_t *size); + int security_file_permission(struct file *file, int mask); int security_file_alloc(struct file *file); void security_file_free(struct file *file); @@ -740,6 +744,16 @@ static inline void security_inode_getsecid(struct inode *inode, u32 *secid) *secid = 0; } +static inline int security_inode_copy_up(struct dentry *src, struct dentry *dst) +{ + return 0; +} +static inline int security_inode_copy_up_xattr(struct dentry *src, struct dentry *dst, + const char *name, const void *value, size_t *size) +{ + return 0; +} + static inline int security_file_permission(struct file *file, int mask) { return 0; diff --git a/security/security.c b/security/security.c index e8ffd92ae2eb5a..f1a1dbf96c729a 100644 --- a/security/security.c +++ b/security/security.c @@ -726,6 +726,19 @@ void security_inode_getsecid(struct inode *inode, u32 *secid) call_void_hook(inode_getsecid, inode, secid); } +int security_inode_copy_up(struct dentry *src, struct dentry *dst) +{ + return call_int_hook(inode_copy_up, 0, src, dst); +} +EXPORT_SYMBOL(security_inode_copy_up); + +int security_inode_copy_up_xattr(struct dentry *src, struct dentry *dst, + const char *name, void *value, size_t *size) +{ + return call_int_hook(inode_copy_up_xattr, 0, src, dst, name, value, size); +} +EXPORT_SYMBOL(security_inode_copy_up_xattr); + int security_file_permission(struct file *file, int mask) { int ret; @@ -1660,6 +1673,10 @@ struct security_hook_heads security_hook_heads = { LIST_HEAD_INIT(security_hook_heads.inode_listsecurity), .inode_getsecid = LIST_HEAD_INIT(security_hook_heads.inode_getsecid), + .inode_copy_up = + LIST_HEAD_INIT(security_hook_heads.inode_copy_up), + .inode_copy_up_xattr = + LIST_HEAD_INIT(security_hook_heads.inode_copy_up_xattr), .file_permission = LIST_HEAD_INIT(security_hook_heads.file_permission), .file_alloc_security = From eabd104a61199840d5dfe65a8a6eb353fc112600 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 16 Jun 2015 14:14:31 +0100 Subject: [PATCH 15/21] Overlayfs: Use copy-up security hooks Use the copy-up security hooks previously provided to allow an LSM to adjust the security on a newly created copy and to filter the xattrs copied to that file copy. Signed-off-by: David Howells --- fs/overlayfs/copy_up.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index d894e7cd9a8642..41ca95d9babdd4 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -70,6 +70,14 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new) value_size = size; goto retry; } + error = security_inode_copy_up_xattr(old, new, + name, value, &size); + if (error < 0) + break; + if (error == 1) { + error = 0; + continue; /* Discard */ + } error = vfs_setxattr(new, name, value, size, 0); if (error) @@ -233,6 +241,10 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir, if (err) goto out2; + err = security_inode_copy_up(lowerpath->dentry, newdentry); + if (err < 0) + goto out_cleanup; + if (S_ISREG(stat->mode)) { struct path upperpath; ovl_path_upper(dentry, &upperpath); From 798fc50146e1c819932435bb2e0d92ef180fad81 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 16 Jun 2015 14:14:32 +0100 Subject: [PATCH 16/21] SELinux: Stub in copy-up handling Provide stubs for union/overlay copy-up handling. The xattr copy up stub discards lower SELinux xattrs rather than letting them be copied up so that the security label on the copy doesn't get corrupted. Signed-off-by: David Howells --- security/selinux/hooks.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index f1ab71504e1d59..d361b744b870e8 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3253,6 +3253,24 @@ static void selinux_inode_getsecid(struct inode *inode, u32 *secid) *secid = isec->sid; } +static int selinux_inode_copy_up(struct dentry *src, struct dentry *dst) +{ + return 0; +} + +static int selinux_inode_copy_up_xattr(struct dentry *src, struct dentry *dst, + const char *name, void *value, + size_t *size) +{ + /* The copy_up hook above sets the initial context on an inode, but we + * don't then want to overwrite it by blindly copying all the lower + * xattrs up. Instead, we have to filter out SELinux-related xattrs. + */ + if (strcmp(name, XATTR_NAME_SELINUX) == 0) + return 1; /* Discard */ + return 0; +} + /* file security operations */ static int selinux_revalidate_file_permission(struct file *file, int mask) @@ -5996,6 +6014,8 @@ static struct security_hook_list selinux_hooks[] = { LSM_HOOK_INIT(inode_setsecurity, selinux_inode_setsecurity), LSM_HOOK_INIT(inode_listsecurity, selinux_inode_listsecurity), LSM_HOOK_INIT(inode_getsecid, selinux_inode_getsecid), + LSM_HOOK_INIT(inode_copy_up, selinux_inode_copy_up), + LSM_HOOK_INIT(inode_copy_up_xattr, selinux_inode_copy_up_xattr), LSM_HOOK_INIT(file_permission, selinux_file_permission), LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security), From 7c5c4e06a08f0f397e44bd88e8aff169fa407af6 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 16 Jun 2015 14:14:32 +0100 Subject: [PATCH 17/21] SELinux: Handle opening of a unioned file Handle the opening of a unioned file by trying to derive the label that would be attached to the union-layer inode if it doesn't exist. If the union-layer inode does exist (as it necessarily does in overlayfs, but not in unionmount), we assume that it has the right label and use that. Otherwise we try to get it from the superblock. If the superblock has a globally-applied label, we use that, otherwise we try to transition to an appropriate label. This union label is then stored in the file_security_struct. We then perform an additional check to make sure that the calling task is granted permission by the union-layer inode label to open the file in addition to a check to make sure that the task is granted permission to open the lower file with the lower inode label. Signed-off-by: David Howells --- security/selinux/hooks.c | 69 +++++++++++++++++++++++++++++++ security/selinux/include/objsec.h | 1 + 2 files changed, 70 insertions(+) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index d361b744b870e8..7186928dd41673 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3584,10 +3584,72 @@ static int selinux_file_receive(struct file *file) return file_has_perm(cred, file, file_to_av(file)); } +/* + * We have a file opened on a unioned file system that falls through to a file + * on a lower layer. If there is a union inode, we try to get the label from + * that, otherwise we need to get it from the superblock. + * + * file->f_path points to the union layer and file->f_inode points to the lower + * layer. + */ +static int selinux_file_open_union(struct file *file, + struct file_security_struct *fsec, + const struct cred *cred) +{ + const struct superblock_security_struct *sbsec; + const struct inode_security_struct *isec, *dsec, *fisec; + const struct task_security_struct *tsec = current_security(); + struct common_audit_data ad; + struct dentry *union_dentry = file->f_path.dentry; + const struct inode *union_inode = d_inode(union_dentry); + const struct inode *lower_inode = file_inode(file); + struct dentry *dir; + int rc; + + sbsec = union_dentry->d_sb->s_security; + + if (union_inode) { + isec = union_inode->i_security; + fsec->union_isid = isec->sid; + } else if ((sbsec->flags & SE_SBINITIALIZED) && + (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) { + fsec->union_isid = sbsec->mntpoint_sid; + } else { + dir = dget_parent(union_dentry); + dsec = d_inode(dir)->i_security; + + rc = security_transition_sid( + tsec->sid, dsec->sid, + inode_mode_to_security_class(lower_inode->i_mode), + &union_dentry->d_name, + &fsec->union_isid); + dput(dir); + if (rc) { + pr_warn("%s: security_transition_sid failed, rc=%d (name=%pD)\n", + __func__, -rc, file); + return rc; + } + } + + /* We need to check that the union file is allowed to be opened as well + * as checking that the lower file is allowed to be opened. + */ + if (unlikely(IS_PRIVATE(lower_inode))) + return 0; + + ad.type = LSM_AUDIT_DATA_PATH; + ad.u.path = file->f_path; + + fisec = lower_inode->i_security; + return avc_has_perm(cred_sid(cred), fsec->union_isid, fisec->sclass, + open_file_to_av(file), &ad); +} + static int selinux_file_open(struct file *file, const struct cred *cred) { struct file_security_struct *fsec; struct inode_security_struct *isec; + int rc; fsec = file->f_security; isec = inode_security(file_inode(file)); @@ -3608,6 +3670,13 @@ static int selinux_file_open(struct file *file, const struct cred *cred) * new inode label or new policy. * This check is not redundant - do not remove. */ + + if (d_inode(file->f_path.dentry) != file->f_inode) { + rc = selinux_file_open_union(file, fsec, cred); + if (rc < 0) + return rc; + } + return file_path_has_perm(cred, file, open_file_to_av(file)); } diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index a2ae05414ba191..54cce84e081ccd 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -60,6 +60,7 @@ struct file_security_struct { u32 sid; /* SID of open file description */ u32 fown_sid; /* SID of file owner (for SIGIO) */ u32 isid; /* SID of inode at the time of file open */ + u32 union_isid; /* SID of would-be inodes in union top (or 0) */ u32 pseqno; /* Policy seqno at the time of file open */ }; From 92ca3f0e63d46f131f75f57ef2b6a44bd8acd2ab Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 16 Jun 2015 14:14:32 +0100 Subject: [PATCH 18/21] SELinux: Check against union label for file operations File operations (eg. read, write) issued against a file that is attached to the lower layer of a union file needs to be checked against the union-layer label not the lower layer label. The union label is stored in the file_security_struct rather than being retrieved from one of the inodes. Signed-off-by: David Howells --- security/selinux/hooks.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 7186928dd41673..a44cca77007885 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1745,6 +1745,7 @@ static int file_has_perm(const struct cred *cred, struct file *file, u32 av) { + struct inode_security_struct *isec; struct file_security_struct *fsec = file->f_security; struct inode *inode = file_inode(file); struct common_audit_data ad; @@ -1765,8 +1766,15 @@ static int file_has_perm(const struct cred *cred, /* av is zero if only checking access to the descriptor. */ rc = 0; - if (av) - rc = inode_has_perm(cred, inode, av, &ad); + if (av && likely(!IS_PRIVATE(inode))) { + if (fsec->union_isid) { + isec = inode->i_security; + rc = avc_has_perm(sid, fsec->union_isid, isec->sclass, + av, &ad); + } + if (!rc) + rc = inode_has_perm(cred, inode, av, &ad); + } out: return rc; From cb9ecb801b14c59df0a34717eb7ff4e5caff44e4 Mon Sep 17 00:00:00 2001 From: Vito Caputo Date: Wed, 25 Nov 2015 02:59:45 -0800 Subject: [PATCH 19/21] kbuild: derive relative path for KBUILD_SRC from CURDIR This enables relocating source and build trees to different roots, provided they stay reachable relative to one another. Useful for builds done within a sandbox where the eventual root is prefixed by some undesirable path component. --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7b3ecdcdc6c181..7d950e42c91b8b 100644 --- a/Makefile +++ b/Makefile @@ -143,7 +143,8 @@ $(filter-out _all sub-make $(CURDIR)/Makefile, $(MAKECMDGOALS)) _all: sub-make @: sub-make: FORCE - $(Q)$(MAKE) -C $(KBUILD_OUTPUT) KBUILD_SRC=$(CURDIR) \ + $(Q)$(MAKE) -C $(KBUILD_OUTPUT) \ + KBUILD_SRC=$(shell realpath --relative-to=$(KBUILD_OUTPUT) $(CURDIR)) \ -f $(CURDIR)/Makefile $(filter-out _all sub-make,$(MAKECMDGOALS)) # Leave processing to above invocation of make From a19700db885d083eebff877f9b14e387d824f812 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Tue, 22 Dec 2015 07:43:52 +0000 Subject: [PATCH 20/21] Don't verify write permissions on lower inodes on overlayfs If a user opens a file r/w on overlayfs, and if the underlying inode is currently still on the lower fs, right now we're verifying whether selinux policy permits writes to the selinux context on the underlying inode. This is suboptimal, since we don't want confined processes to be able to write to these files if they're able to escape from a container and so don't want to permit this in policy. Have overlayfs pass down an additional flag when verifying the permission on lower inodes, and mask off the write bits in the selinux permissions check if that flag is set. --- fs/overlayfs/inode.c | 3 +++ include/linux/fs.h | 1 + security/selinux/hooks.c | 9 +++++++++ 3 files changed, 13 insertions(+) diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index a4ff5d0d7db916..6ba3443cdf7755 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -163,6 +163,9 @@ int ovl_permission(struct inode *inode, int mask) goto out_dput; } + if (!is_upper) + mask |= MAY_OPEN_LOWER; + err = __inode_permission(realinode, mask); out_dput: dput(alias); diff --git a/include/linux/fs.h b/include/linux/fs.h index ae681002100a1f..fb6e94b61e77e5 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -83,6 +83,7 @@ typedef void (dax_iodone_t)(struct buffer_head *bh_map, int uptodate); #define MAY_CHDIR 0x00000040 /* called from RCU mode, don't block */ #define MAY_NOT_BLOCK 0x00000080 +#define MAY_OPEN_LOWER 0x00000100 /* * flags in file.f_mode. Note that FMODE_READ and FMODE_WRITE must correspond diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index a44cca77007885..f5ca93cf21f314 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2967,6 +2967,15 @@ static int selinux_inode_permission(struct inode *inode, int mask) u32 audited, denied; from_access = mask & MAY_ACCESS; + + /* + * If we're trying to open the lower layer of an overlay mount, don't + * worry about write or append permissions - these will be verified + * against the upper context + */ + if (mask & MAY_OPEN_LOWER) + mask &= ~(MAY_WRITE|MAY_APPEND); + mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND); /* No permission to check. Existence test. */ From 86ecc1a1941cb41b49bc16628d11bb5ef7f2cb43 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Tue, 1 Mar 2016 15:00:15 -0800 Subject: [PATCH 21/21] Fix unallocated memory access in TPM eventlog code COmmit 0cc698 added support for handling endian fixups in the event log code but broke the binary log file in the process. Keep the endian code, but read the event data from the actual event rather than from unallocated RAM. Signed-off-by: Matthew Garrett Cc: stable@kernel.org --- drivers/char/tpm/tpm_eventlog.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm_eventlog.c b/drivers/char/tpm/tpm_eventlog.c index bd72fb04225e43..e47092c61827b7 100644 --- a/drivers/char/tpm/tpm_eventlog.c +++ b/drivers/char/tpm/tpm_eventlog.c @@ -244,7 +244,12 @@ static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v) tempPtr = (char *)&temp_event; - for (i = 0; i < sizeof(struct tcpa_event) + temp_event.event_size; i++) + for (i = 0; i < sizeof(struct tcpa_event); i++) + seq_putc(m, tempPtr[i]); + + tempPtr = (char *)&event->event_data; + + for (i = 0; i < temp_event.event_size; i++) seq_putc(m, tempPtr[i]); return 0;