878 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			878 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| Bugzilla: N/A
 | |
| Upstream-status: Fedora mustard.  Replaced by securelevels, but that was nak'd
 | |
| 
 | |
| From 0f81a4461431941c17ff26fd3d5e284ede4a368a Mon Sep 17 00:00:00 2001
 | |
| From: Matthew Garrett <matthew.garrett@nebula.com>
 | |
| Date: Fri, 9 Aug 2013 17:58:15 -0400
 | |
| Subject: [PATCH 01/14] 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 f520a767c86c..fc9b54eb779e 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 11869408f79b..2b9204fe055f 100644
 | |
| --- a/kernel/module.c
 | |
| +++ b/kernel/module.c
 | |
| @@ -3835,3 +3835,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);
 | |
| -- 
 | |
| 1.8.5.3
 | |
| 
 | |
| 
 | |
| From 806c4ee0e6484b529b88b3d0ceb49f6edf96ae11 Mon Sep 17 00:00:00 2001
 | |
| From: Matthew Garrett <matthew.garrett@nebula.com>
 | |
| Date: Thu, 8 Mar 2012 10:10:38 -0500
 | |
| Subject: [PATCH 02/14] 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 4e0acefb7565..01b56d13d021 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 */
 | |
| @@ -652,6 +653,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) {
 | |
| @@ -958,6 +962,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;
 | |
| @@ -1065,6 +1072,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 46d1378f2e9e..294fe7b34af0 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 24750a1b39b6..fa57896b97dd 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);
 | |
| -- 
 | |
| 1.8.5.3
 | |
| 
 | |
| 
 | |
| From 16ee82e2add8684e374451e6ba34be3ee41e4ef1 Mon Sep 17 00:00:00 2001
 | |
| From: Matthew Garrett <matthew.garrett@nebula.com>
 | |
| Date: Thu, 8 Mar 2012 10:35:59 -0500
 | |
| Subject: [PATCH 03/14] 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 4ddaf66ea35f..00b440307419 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 917403fe10da..cdf839f9defe 100644
 | |
| --- a/drivers/char/mem.c
 | |
| +++ b/drivers/char/mem.c
 | |
| @@ -27,6 +27,7 @@
 | |
|  #include <linux/export.h>
 | |
|  #include <linux/io.h>
 | |
|  #include <linux/aio.h>
 | |
| +#include <linux/module.h>
 | |
|  
 | |
|  #include <asm/uaccess.h>
 | |
|  
 | |
| @@ -568,6 +569,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) {
 | |
| -- 
 | |
| 1.8.5.3
 | |
| 
 | |
| 
 | |
| From 2fd4b35393b19cde87e4770d3b85d12760e72f6a Mon Sep 17 00:00:00 2001
 | |
| From: Matthew Garrett <matthew.garrett@nebula.com>
 | |
| Date: Fri, 9 Mar 2012 08:39:37 -0500
 | |
| Subject: [PATCH 04/14] 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 | 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))
 | |
| -- 
 | |
| 1.8.5.3
 | |
| 
 | |
| 
 | |
| From 543d64276237adb782ec30a5dab67d0b21afc1d4 Mon Sep 17 00:00:00 2001
 | |
| From: Matthew Garrett <matthew.garrett@nebula.com>
 | |
| Date: Fri, 9 Mar 2012 08:46:50 -0500
 | |
| Subject: [PATCH 05/14] 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 c5e082fb82fa..03c57fc8de8a 100644
 | |
| --- a/drivers/platform/x86/asus-wmi.c
 | |
| +++ b/drivers/platform/x86/asus-wmi.c
 | |
| @@ -1595,6 +1595,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)
 | |
| @@ -1611,6 +1614,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);
 | |
|  
 | |
| @@ -1635,6 +1641,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);
 | |
| -- 
 | |
| 1.8.5.3
 | |
| 
 | |
| 
 | |
| From 6e2fec5547b597c43ca72e34729b8a402660a7c1 Mon Sep 17 00:00:00 2001
 | |
| From: Matthew Garrett <matthew.garrett@nebula.com>
 | |
| Date: Fri, 9 Mar 2012 09:28:15 -0500
 | |
| Subject: [PATCH 06/14] 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 cdf839f9defe..c63cf93b00eb 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;
 | |
|  
 | |
| @@ -502,6 +505,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);
 | |
| -- 
 | |
| 1.8.5.3
 | |
| 
 | |
| 
 | |
| From 358cea0a54f726fa61839b411f3f54284d4588bf Mon Sep 17 00:00:00 2001
 | |
| From: Josh Boyer <jwboyer@redhat.com>
 | |
| Date: Mon, 25 Jun 2012 19:57:30 -0400
 | |
| Subject: [PATCH 07/14] 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 f7fd72ac69cf..ccdae1c8c386 100644
 | |
| --- a/drivers/acpi/osl.c
 | |
| +++ b/drivers/acpi/osl.c
 | |
| @@ -44,6 +44,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>
 | |
| @@ -244,7 +245,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
 | |
|  
 | |
| -- 
 | |
| 1.8.5.3
 | |
| 
 | |
| 
 | |
| From 89751b3ad4dea7cf5b806cd14126dd70657a9148 Mon Sep 17 00:00:00 2001
 | |
| From: Matthew Garrett <matthew.garrett@nebula.com>
 | |
| Date: Fri, 9 Aug 2013 03:33:56 -0400
 | |
| Subject: [PATCH 08/14] 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 | 8 ++++++++
 | |
|  1 file changed, 8 insertions(+)
 | |
| 
 | |
| diff --git a/kernel/kexec.c b/kernel/kexec.c
 | |
| index c8380ad203bc..e6eb239f567a 100644
 | |
| --- a/kernel/kexec.c
 | |
| +++ b/kernel/kexec.c
 | |
| @@ -33,6 +33,7 @@
 | |
|  #include <linux/swap.h>
 | |
|  #include <linux/syscore_ops.h>
 | |
|  #include <linux/compiler.h>
 | |
| +#include <linux/module.h>
 | |
|  
 | |
|  #include <asm/page.h>
 | |
|  #include <asm/uaccess.h>
 | |
| @@ -948,6 +949,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.
 | |
|  	 */
 | |
| -- 
 | |
| 1.8.5.3
 | |
| 
 | |
| 
 | |
| From 31174421a7103571a1c3faf7ba27d4045e5fbc18 Mon Sep 17 00:00:00 2001
 | |
| From: Matthew Garrett <matthew.garrett@nebula.com>
 | |
| Date: Tue, 3 Sep 2013 11:23:29 -0400
 | |
| Subject: [PATCH 09/14] uswsusp: Disable when module loading is restricted
 | |
| 
 | |
| uswsusp allows a user process to dump and then restore kernel state, which
 | |
| makes it possible to avoid module loading restrictions. Prevent this when
 | |
| any restrictions have been imposed on loading modules.
 | |
| 
 | |
| Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
 | |
| ---
 | |
|  kernel/power/user.c | 4 ++++
 | |
|  1 file changed, 4 insertions(+)
 | |
| 
 | |
| diff --git a/kernel/power/user.c b/kernel/power/user.c
 | |
| index 98d357584cd6..efe99dee9510 100644
 | |
| --- a/kernel/power/user.c
 | |
| +++ b/kernel/power/user.c
 | |
| @@ -24,6 +24,7 @@
 | |
|  #include <linux/console.h>
 | |
|  #include <linux/cpu.h>
 | |
|  #include <linux/freezer.h>
 | |
| +#include <linux/module.h>
 | |
|  
 | |
|  #include <asm/uaccess.h>
 | |
|  
 | |
| @@ -49,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)) {
 | |
| -- 
 | |
| 1.8.5.3
 | |
| 
 | |
| 
 | |
| From ea5cf8801db979fa7d5f90ab3faf72eb22490f9b Mon Sep 17 00:00:00 2001
 | |
| From: Matthew Garrett <matthew.garrett@nebula.com>
 | |
| Date: Fri, 8 Feb 2013 11:12:13 -0800
 | |
| Subject: [PATCH 10/14] 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 c9603ac80de5..8bef43fc3f40 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;
 | |
| -- 
 | |
| 1.8.5.3
 | |
| 
 | |
| 
 | |
| From 2985684ff78972bde7ebf1e295b52afd9bea29e0 Mon Sep 17 00:00:00 2001
 | |
| From: Matthew Garrett <matthew.garrett@nebula.com>
 | |
| Date: Fri, 9 Aug 2013 18:36:30 -0400
 | |
| Subject: [PATCH 11/14] Add option to automatically enforce module signatures
 | |
|  when in Secure Boot mode
 | |
| 
 | |
| UEFI Secure Boot provides a mechanism for ensuring that the firmware will
 | |
| only load signed bootloaders and kernels. Certain use cases may also
 | |
| require that all kernel modules also be signed. Add a configuration option
 | |
| that enforces this automatically when enabled.
 | |
| 
 | |
| Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
 | |
| ---
 | |
|  Documentation/x86/zero-page.txt       |  2 ++
 | |
|  arch/x86/Kconfig                      | 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 199f453cb4de..ec38acf00b40 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 5b8ec0f53b57..085d5eb36361 100644
 | |
| --- a/arch/x86/Kconfig
 | |
| +++ b/arch/x86/Kconfig
 | |
| @@ -1534,6 +1534,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 1e6146137f8e..b00745ff398a 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>
 | |
|  
 | |
|  #undef memcpy			/* Use memcpy from misc.c */
 | |
|  
 | |
| @@ -809,6 +810,37 @@ out:
 | |
|  	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_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;
 | |
| +}
 | |
| +
 | |
| +
 | |
|  /*
 | |
|   * See if we have Graphics Output Protocol
 | |
|   */
 | |
| @@ -1372,6 +1404,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 225b0988043a..90dbfb73e11f 100644
 | |
| --- a/arch/x86/include/uapi/asm/bootparam.h
 | |
| +++ b/arch/x86/include/uapi/asm/bootparam.h
 | |
| @@ -133,7 +133,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 09c76d265550..5a61d732fd5c 100644
 | |
| --- a/arch/x86/kernel/setup.c
 | |
| +++ b/arch/x86/kernel/setup.c
 | |
| @@ -1142,6 +1142,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 fc9b54eb779e..7377bc851461 100644
 | |
| --- a/include/linux/module.h
 | |
| +++ b/include/linux/module.h
 | |
| @@ -188,6 +188,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 2b9204fe055f..2b8cc2d57c16 100644
 | |
| --- a/kernel/module.c
 | |
| +++ b/kernel/module.c
 | |
| @@ -3836,6 +3836,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
 | |
| -- 
 | |
| 1.8.5.3
 | |
| 
 | |
| 
 | |
| From b2e4ea728ccab2befbd5fe1bd834881a7dd8f34b Mon Sep 17 00:00:00 2001
 | |
| From: Josh Boyer <jwboyer@redhat.com>
 | |
| Date: Tue, 5 Feb 2013 19:25:05 -0500
 | |
| Subject: [PATCH 12/14] 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 b00745ff398a..bf42cc5f083d 100644
 | |
| --- a/arch/x86/boot/compressed/eboot.c
 | |
| +++ b/arch/x86/boot/compressed/eboot.c
 | |
| @@ -812,8 +812,9 @@ out:
 | |
|  
 | |
|  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;
 | |
|  
 | |
| @@ -837,6 +838,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_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;
 | |
|  }
 | |
|  
 | |
| -- 
 | |
| 1.8.5.3
 | |
| 
 | |
| 
 | |
| From fb418c682d01c447d30b5591a591fdbf33b1334e Mon Sep 17 00:00:00 2001
 | |
| From: Josh Boyer <jwboyer@fedoraproject.org>
 | |
| Date: Tue, 27 Aug 2013 13:28:43 -0400
 | |
| Subject: [PATCH 13/14] 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 085d5eb36361..3e8d398a976d 100644
 | |
| --- a/arch/x86/Kconfig
 | |
| +++ b/arch/x86/Kconfig
 | |
| @@ -1535,7 +1535,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
 | |
| -- 
 | |
| 1.8.5.3
 | |
| 
 | |
| 
 | |
| From 87bf357dd4589cfca043ec4b641b912a088b1234 Mon Sep 17 00:00:00 2001
 | |
| From: Josh Boyer <jwboyer@fedoraproject.org>
 | |
| Date: Tue, 27 Aug 2013 13:33:03 -0400
 | |
| Subject: [PATCH 14/14] 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 5a61d732fd5c..23fe9bf3c401 100644
 | |
| --- a/arch/x86/kernel/setup.c
 | |
| +++ b/arch/x86/kernel/setup.c
 | |
| @@ -1144,7 +1144,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 6c100ff0cae4..3a77a70fff27 100644
 | |
| --- a/include/linux/efi.h
 | |
| +++ b/include/linux/efi.h
 | |
| @@ -899,6 +899,7 @@ extern int __init efi_setup_pcdp_console(char *);
 | |
|  #define EFI_MEMMAP		4	/* Can we use EFI memory map? */
 | |
|  #define EFI_64BIT		5	/* Is the firmware 64-bit? */
 | |
|  #define EFI_ARCH_1		6	/* First arch-specific bit */
 | |
| +#define EFI_SECURE_BOOT		7 /* Are we in Secure Boot mode? */
 | |
|  
 | |
|  #ifdef CONFIG_EFI
 | |
|  /*
 | |
| -- 
 | |
| 1.8.5.3
 | |
| 
 |