[kernel] Update secure boot support for UEFI cert importing

Josh Boyer jwboyer at fedoraproject.org
Sat Oct 27 13:29:51 UTC 2012


commit 5e72ee302b9b69fafdab16730f979e73b808f9ec
Author: Josh Boyer <jwboyer at redhat.com>
Date:   Sat Oct 27 09:26:27 2012 -0400

    Update secure boot support for UEFI cert importing

 config-x86-generic         |    2 +
 kernel.spec                |    9 +-
 secure-boot-20120924.patch |  713 -----------------------
 secure-boot-20121026.patch | 1388 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 1396 insertions(+), 716 deletions(-)
---
diff --git a/config-x86-generic b/config-x86-generic
index b209e66..228ad8a 100644
--- a/config-x86-generic
+++ b/config-x86-generic
@@ -430,3 +430,5 @@ CONFIG_MODULE_SIG=y
 # CONFIG_MODULE_SIG_SHA1 is not set
 CONFIG_MODULE_SIG_SHA256=y
 # CONFIG_MODULE_SIG_FORCE is not set
+CONFIG_MODULE_SIG_BLACKLIST=y
+CONFIG_MODULE_SIG_UEFI=y
diff --git a/kernel.spec b/kernel.spec
index 79bde35..c56b1f5 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -62,7 +62,7 @@ Summary: The Linux kernel
 # For non-released -rc kernels, this will be appended after the rcX and
 # gitX tags, so a 3 here would become part of release "0.rcX.gitX.3"
 #
-%global baserelease 1
+%global baserelease 2
 %global fedora_build %{baserelease}
 
 # base_sublevel is the kernel version we're starting with and patching
@@ -688,7 +688,7 @@ Patch800: linux-2.6-crash-driver.patch
 Patch900: modsign-post-KS-jwb.patch
 
 # secure boot
-Patch1000: secure-boot-20120924.patch
+Patch1000: secure-boot-20121026.patch
 
 # Improve PCI support on UEFI
 Patch1100: handle-efi-roms.patch
@@ -1406,7 +1406,7 @@ ApplyPatch linux-2.6-e1000-ich9-montevina.patch
 ApplyPatch modsign-post-KS-jwb.patch
 
 # secure boot
-ApplyPatch secure-boot-20120924.patch
+ApplyPatch secure-boot-20121026.patch
 
 # Improved PCI support for UEFI
 ApplyPatch handle-efi-roms.patch
@@ -2317,6 +2317,9 @@ fi
 #                 ||----w |
 #                 ||     ||
 %changelog
+* Sat Oct 27 2012 Josh Boyer <jwboyer at redhat.com>
+- Update secure boot support for UEFI cert importing
+
 * Fri Oct 26 2012 Peter Robinson <pbrobinson at fedoraproject.org>
 - The initial ARM unified kernel support (vexpress, highbank, mvebu to begin). WOO HOO!!!
 
diff --git a/secure-boot-20121026.patch b/secure-boot-20121026.patch
new file mode 100644
index 0000000..36ef7ba
--- /dev/null
+++ b/secure-boot-20121026.patch
@@ -0,0 +1,1388 @@
+From 57c0dbcbafaa724313c672830ff0087f56a84c47 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg at redhat.com>
+Date: Thu, 20 Sep 2012 10:40:56 -0400
+Subject: [PATCH 01/14] Secure boot: Add new capability
+
+Secure boot adds certain policy requirements, including that root must not
+be able to do anything that could cause the kernel to execute arbitrary code.
+The simplest way to handle this would seem to be to add a new capability
+and gate various functionality on that. We'll then strip it from the initial
+capability set if required.
+
+Signed-off-by: Matthew Garrett <mjg at redhat.com>
+---
+ include/uapi/linux/capability.h | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/include/linux/capability.h b/include/linux/capability.h
+index d10b7ed..4345bc8 100644
+--- a/include/uapi/linux/capability.h
++++ b/include/uapi/linux/capability.h
+@@ -364,7 +364,11 @@ struct cpu_vfs_cap_data {
+ 
+ #define CAP_BLOCK_SUSPEND    36
+ 
+-#define CAP_LAST_CAP         CAP_BLOCK_SUSPEND
++/* Allow things that trivially permit root to modify the running kernel */
++
++#define CAP_COMPROMISE_KERNEL  37
++
++#define CAP_LAST_CAP         CAP_COMPROMISE_KERNEL
+ 
+ #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
+ 
+-- 
+1.7.11.4
+
+
+From 95fd8148be46036e20fc64c480104d2a2b454e27 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg at redhat.com>
+Date: Thu, 20 Sep 2012 10:40:57 -0400
+Subject: [PATCH 02/14] PCI: Lock down BAR access in secure boot environments
+
+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 cause
+arbitrary kernel behaviour. Default to paranoid - in future we can
+potentially relax this for sufficiently IOMMU-isolated devices.
+
+Signed-off-by: Matthew Garrett <mjg at redhat.com>
+---
+ drivers/pci/pci-sysfs.c | 9 +++++++++
+ drivers/pci/proc.c      | 8 +++++++-
+ drivers/pci/syscall.c   | 2 +-
+ 3 files changed, 17 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
+index 6869009..c03fb85 100644
+--- a/drivers/pci/pci-sysfs.c
++++ b/drivers/pci/pci-sysfs.c
+@@ -542,6 +542,9 @@ pci_write_config(struct file* filp, struct kobject *kobj,
+ 	loff_t init_off = off;
+ 	u8 *data = (u8*) buf;
+ 
++	if (!capable(CAP_COMPROMISE_KERNEL))
++		return -EPERM;
++
+ 	if (off > dev->cfg_size)
+ 		return 0;
+ 	if (off + count > dev->cfg_size) {
+@@ -844,6 +847,9 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
+ 	resource_size_t start, end;
+ 	int i;
+ 
++	if (!capable(CAP_COMPROMISE_KERNEL))
++		return -EPERM;
++
+ 	for (i = 0; i < PCI_ROM_RESOURCE; i++)
+ 		if (res == &pdev->resource[i])
+ 			break;
+@@ -951,6 +957,9 @@ pci_write_resource_io(struct file *filp, struct kobject *kobj,
+ 		      struct bin_attribute *attr, char *buf,
+ 		      loff_t off, size_t count)
+ {
++	if (!capable(CAP_COMPROMISE_KERNEL))
++		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 27911b5..ac8c9a5 100644
+--- a/drivers/pci/proc.c
++++ b/drivers/pci/proc.c
+@@ -135,6 +135,9 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof
+ 	int size = dp->size;
+ 	int cnt;
+ 
++	if (!capable(CAP_COMPROMISE_KERNEL))
++		return -EPERM;
++
+ 	if (pos >= size)
+ 		return 0;
+ 	if (nbytes >= size)
+@@ -211,6 +214,9 @@ static long proc_bus_pci_ioctl(struct file *file, unsigned int cmd,
+ #endif /* HAVE_PCI_MMAP */
+ 	int ret = 0;
+ 
++	if (!capable(CAP_COMPROMISE_KERNEL))
++		return -EPERM;
++
+ 	switch (cmd) {
+ 	case PCIIOC_CONTROLLER:
+ 		ret = pci_domain_nr(dev->bus);
+@@ -251,7 +257,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) || !capable(CAP_COMPROMISE_KERNEL))
+ 		return -EPERM;
+ 
+ 	/* Make sure the caller is mapping a real resource for this device */
+diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c
+index e1c1ec5..97e785f 100644
+--- a/drivers/pci/syscall.c
++++ b/drivers/pci/syscall.c
+@@ -92,7 +92,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) || !capable(CAP_COMPROMISE_KERNEL))
+ 		return -EPERM;
+ 
+ 	dev = pci_get_bus_and_slot(bus, dfn);
+-- 
+1.7.11.4
+
+
+From 2d23d2726583d79062e58abcc32c7dd027d312aa Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg at redhat.com>
+Date: Thu, 20 Sep 2012 10:40:58 -0400
+Subject: [PATCH 03/14] x86: Lock down IO port access in secure boot
+ environments
+
+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 <mjg at redhat.com>
+---
+ arch/x86/kernel/ioport.c | 4 ++--
+ drivers/char/mem.c       | 3 +++
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/arch/x86/kernel/ioport.c b/arch/x86/kernel/ioport.c
+index 8c96897..a2578c4 100644
+--- a/arch/x86/kernel/ioport.c
++++ b/arch/x86/kernel/ioport.c
+@@ -28,7 +28,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) || !capable(CAP_COMPROMISE_KERNEL)))
+ 		return -EPERM;
+ 
+ 	/*
+@@ -102,7 +102,7 @@ long sys_iopl(unsigned int level, struct pt_regs *regs)
+ 		return -EINVAL;
+ 	/* Trying to gain more privileges? */
+ 	if (level > old) {
+-		if (!capable(CAP_SYS_RAWIO))
++		if (!capable(CAP_SYS_RAWIO) || !capable(CAP_COMPROMISE_KERNEL))
+ 			return -EPERM;
+ 	}
+ 	regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) | (level << 12);
+diff --git a/drivers/char/mem.c b/drivers/char/mem.c
+index e5eedfa..1e0a660 100644
+--- a/drivers/char/mem.c
++++ b/drivers/char/mem.c
+@@ -597,6 +597,9 @@ static ssize_t write_port(struct file *file, const char __user *buf,
+ 	unsigned long i = *ppos;
+ 	const char __user * tmp = buf;
+ 
++	if (!capable(CAP_COMPROMISE_KERNEL))
++		return -EPERM;
++
+ 	if (!access_ok(VERIFY_READ, buf, count))
+ 		return -EFAULT;
+ 	while (count-- > 0 && i < 65536) {
+-- 
+1.7.11.4
+
+
+From e063cb2f3a667d2540682d4bdbef91fdb23b1a84 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg at redhat.com>
+Date: Thu, 20 Sep 2012 10:40:59 -0400
+Subject: [PATCH 04/14] ACPI: Limit access to custom_method
+
+It must be impossible for even root to get code executed in kernel context
+under a secure boot environment. custom_method effectively allows arbitrary
+access to system memory, so it needs to have a capability check here.
+
+Signed-off-by: Matthew Garrett <mjg at redhat.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 5d42c24..247d58b 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 (!capable(CAP_COMPROMISE_KERNEL))
++		return -EPERM;
++
+ 	if (!(*ppos)) {
+ 		/* parse the table header to get the table length */
+ 		if (count <= sizeof(struct acpi_table_header))
+-- 
+1.7.11.4
+
+
+From a1cccbd084c7355dcb2be7ae2934f168ce9ba9d5 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg at redhat.com>
+Date: Thu, 20 Sep 2012 10:41:00 -0400
+Subject: [PATCH 05/14] asus-wmi: Restrict debugfs interface
+
+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. Add a capability check to prevent that.
+
+Signed-off-by: Matthew Garrett <mjg at redhat.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 2eb9fe8..61e055d 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -1523,6 +1523,9 @@ static int show_dsts(struct seq_file *m, void *data)
+ 	int err;
+ 	u32 retval = -1;
+ 
++	if (!capable(CAP_COMPROMISE_KERNEL))
++		return -EPERM;
++
+ 	err = asus_wmi_get_devstate(asus, asus->debug.dev_id, &retval);
+ 
+ 	if (err < 0)
+@@ -1539,6 +1542,9 @@ static int show_devs(struct seq_file *m, void *data)
+ 	int err;
+ 	u32 retval = -1;
+ 
++	if (!capable(CAP_COMPROMISE_KERNEL))
++		return -EPERM;
++
+ 	err = asus_wmi_set_devstate(asus->debug.dev_id, asus->debug.ctrl_param,
+ 				    &retval);
+ 
+@@ -1563,6 +1569,9 @@ static int show_call(struct seq_file *m, void *data)
+ 	union acpi_object *obj;
+ 	acpi_status status;
+ 
++	if (!capable(CAP_COMPROMISE_KERNEL))
++		return -EPERM;
++
+ 	status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID,
+ 				     1, asus->debug.method_id,
+ 				     &input, &output);
+-- 
+1.7.11.4
+
+
+From 1c9e53b626268f82509062751eda14e8572717cf Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg at redhat.com>
+Date: Thu, 20 Sep 2012 10:41:01 -0400
+Subject: [PATCH 06/14] Restrict /dev/mem and /dev/kmem in secure boot setups
+
+Allowing users to write to address space makes it possible for the kernel
+to be subverted. Restrict this when we need to protect the kernel.
+
+Signed-off-by: Matthew Garrett <mjg at redhat.com>
+---
+ drivers/char/mem.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/drivers/char/mem.c b/drivers/char/mem.c
+index 1e0a660..33eb947 100644
+--- a/drivers/char/mem.c
++++ b/drivers/char/mem.c
+@@ -158,6 +158,9 @@ static ssize_t write_mem(struct file *file, const char __user *buf,
+ 	unsigned long copied;
+ 	void *ptr;
+ 
++	if (!capable(CAP_COMPROMISE_KERNEL))
++		return -EPERM;
++
+ 	if (!valid_phys_addr_range(p, count))
+ 		return -EFAULT;
+ 
+@@ -530,6 +533,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 (!capable(CAP_COMPROMISE_KERNEL))
++		return -EPERM;
++
+ 	if (p < (unsigned long) high_memory) {
+ 		unsigned long to_write = min_t(unsigned long, count,
+ 					       (unsigned long)high_memory - p);
+-- 
+1.7.11.4
+
+
+From fbf919bf372b9a7a08bdacac8129d47ced1b1f19 Mon Sep 17 00:00:00 2001
+From: Josh Boyer <jwboyer at redhat.com>
+Date: Thu, 20 Sep 2012 10:41:02 -0400
+Subject: [PATCH 07/14] Secure boot: Add a dummy kernel parameter that will
+ switch on Secure Boot mode
+
+This forcibly drops CAP_COMPROMISE_KERNEL from both cap_permitted and cap_bset
+in the init_cred struct, which everything else inherits from.  This works on
+any machine and can be used to develop even if the box doesn't have UEFI.
+
+Signed-off-by: Josh Boyer <jwboyer at redhat.com>
+---
+ Documentation/kernel-parameters.txt |  7 +++++++
+ kernel/cred.c                       | 17 +++++++++++++++++
+ 2 files changed, 24 insertions(+)
+
+diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
+index 9b2b8d3..93978d5 100644
+--- a/Documentation/kernel-parameters.txt
++++ b/Documentation/kernel-parameters.txt
+@@ -2562,6 +2562,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
+ 			Note: increases power consumption, thus should only be
+ 			enabled if running jitter sensitive (HPC/RT) workloads.
+ 
++	secureboot_enable=
++			[KNL] Enables an emulated UEFI Secure Boot mode.  This
++			locks down various aspects of the kernel guarded by the
++			CAP_COMPROMISE_KERNEL capability.  This includes things
++			like /dev/mem, IO port access, and other areas.  It can
++			be used on non-UEFI machines for testing purposes.
++
+ 	security=	[SECURITY] Choose a security module to enable at boot.
+ 			If this boot parameter is not specified, only the first
+ 			security module asking for security registration will be
+diff --git a/kernel/cred.c b/kernel/cred.c
+index de728ac..7e6e83f 100644
+--- a/kernel/cred.c
++++ b/kernel/cred.c
+@@ -623,6 +623,23 @@ void __init cred_init(void)
+ 				     0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
+ }
+ 
++void __init secureboot_enable()
++{
++	pr_info("Secure boot enabled\n");
++	cap_lower((&init_cred)->cap_bset, CAP_COMPROMISE_KERNEL);
++	cap_lower((&init_cred)->cap_permitted, CAP_COMPROMISE_KERNEL);
++}
++
++/* Dummy Secure Boot enable option to fake out UEFI SB=1 */
++static int __init secureboot_enable_opt(char *str)
++{
++	int sb_enable = !!simple_strtol(str, NULL, 0);
++	if (sb_enable)
++		secureboot_enable();
++	return 1;
++}
++__setup("secureboot_enable=", secureboot_enable_opt);
++
+ /**
+  * prepare_kernel_cred - Prepare a set of credentials for a kernel service
+  * @daemon: A userspace daemon to be used as a reference
+-- 
+1.7.11.4
+
+
+From 43ed7865d867ae692e30227d66fa58cdecbd9269 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg at redhat.com>
+Date: Thu, 20 Sep 2012 10:41:03 -0400
+Subject: [PATCH 08/14] efi: Enable secure boot lockdown automatically when
+ enabled in firmware
+
+The firmware has a set of flags that indicate whether secure boot is enabled
+and enforcing. Use them to indicate whether the kernel should lock itself
+down.
+
+Signed-off-by: Matthew Garrett <mjg at redhat.com>
+---
+ Documentation/x86/zero-page.txt  |  2 ++
+ arch/x86/boot/compressed/eboot.c | 32 ++++++++++++++++++++++++++++++++
+ arch/x86/include/asm/bootparam.h |  3 ++-
+ arch/x86/kernel/setup.c          |  3 +++
+ include/linux/cred.h             |  2 ++
+ 5 files changed, 41 insertions(+), 1 deletion(-)
+
+diff --git a/Documentation/x86/zero-page.txt b/Documentation/x86/zero-page.txt
+index cf5437d..7f9ed48 100644
+--- a/Documentation/x86/zero-page.txt
++++ b/Documentation/x86/zero-page.txt
+@@ -27,6 +27,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	Kernel should enable secure boot lockdowns
+ 290/040	ALL	edd_mbr_sig_buffer EDD MBR signatures
+ 2D0/A00	ALL	e820_map	E820 memory map table
+ 				(array of struct e820entry)
+diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
+index b3e0227..3789356 100644
+--- a/arch/x86/boot/compressed/eboot.c
++++ b/arch/x86/boot/compressed/eboot.c
+@@ -724,6 +724,36 @@ fail:
+ 	return status;
+ }
+ 
++static int get_secure_boot(efi_system_table_t *_table)
++{
++	u8 sb, setup;
++	unsigned long datasize = sizeof(sb);
++	efi_guid_t var_guid = EFI_GLOBAL_VARIABLE_GUID;
++	efi_status_t status;
++
++	status = efi_call_phys5(sys_table->runtime->get_variable,
++				L"SecureBoot", &var_guid, NULL, &datasize, &sb);
++
++	if (status != EFI_SUCCESS)
++		return 0;
++
++	if (sb == 0)
++		return 0;
++
++
++	status = efi_call_phys5(sys_table->runtime->get_variable,
++				L"SetupMode", &var_guid, NULL, &datasize,
++				&setup);
++
++	if (status != EFI_SUCCESS)
++		return 0;
++
++	if (setup == 1)
++		return 0;
++
++	return 1;
++}
++
+ /*
+  * Because the x86 boot code expects to be passed a boot_params we
+  * need to create one ourselves (usually the bootloader would create
+@@ -1018,6 +1048,8 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
+ 	if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
+ 		goto fail;
+ 
++	boot_params->secure_boot = get_secure_boot(sys_table);
++
+ 	setup_graphics(boot_params);
+ 
+ 	status = efi_call_phys3(sys_table->boottime->allocate_pool,
+diff --git a/arch/x86/include/asm/bootparam.h b/arch/x86/include/asm/bootparam.h
+index 2ad874c..c7338e0 100644
+--- a/arch/x86/include/asm/bootparam.h
++++ b/arch/x86/include/asm/bootparam.h
+@@ -114,7 +114,8 @@ struct boot_params {
+ 	__u8  eddbuf_entries;				/* 0x1e9 */
+ 	__u8  edd_mbr_sig_buf_entries;			/* 0x1ea */
+ 	__u8  kbd_status;				/* 0x1eb */
+-	__u8  _pad6[5];					/* 0x1ec */
++	__u8  secure_boot;				/* 0x1ec */
++	__u8  _pad6[4];					/* 0x1ed */
+ 	struct setup_header hdr;    /* setup header */	/* 0x1f1 */
+ 	__u8  _pad7[0x290-0x1f1-sizeof(struct setup_header)];
+ 	__u32 edd_mbr_sig_buffer[EDD_MBR_SIG_MAX];	/* 0x290 */
+diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
+index f4b9b80..239bf2a 100644
+--- a/arch/x86/kernel/setup.c
++++ b/arch/x86/kernel/setup.c
+@@ -947,6 +947,9 @@ void __init setup_arch(char **cmdline_p)
+ 
+ 	io_delay_init();
+ 
++	if (boot_params.secure_boot)
++		secureboot_enable();
++
+ 	/*
+ 	 * Parse the ACPI tables for possible boot-time SMP configuration.
+ 	 */
+diff --git a/include/linux/cred.h b/include/linux/cred.h
+index ebbed2c..a24faf1 100644
+--- a/include/linux/cred.h
++++ b/include/linux/cred.h
+@@ -170,6 +170,8 @@ extern int set_security_override_from_ctx(struct cred *, const char *);
+ extern int set_create_files_as(struct cred *, struct inode *);
+ extern void __init cred_init(void);
+ 
++extern void secureboot_enable(void);
++
+ /*
+  * check for validity of credentials
+  */
+-- 
+1.7.11.4
+
+
+From 3acf1ceb5f6f3be9103c9da16ddc24afc6d8b02a Mon Sep 17 00:00:00 2001
+From: Josh Boyer <jwboyer at redhat.com>
+Date: Thu, 20 Sep 2012 10:41:04 -0400
+Subject: [PATCH 09/14] acpi: Ignore acpi_rsdp kernel parameter in a secure
+ boot environment
+
+This option allows userspace to pass the RSDP address to the kernel.  This
+could potentially be used to circumvent the secure boot trust model.
+We ignore the setting if we don't have the CAP_COMPROMISE_KERNEL capability.
+
+Signed-off-by: Josh Boyer <jwboyer at redhat.com>
+---
+ drivers/acpi/osl.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
+index 9eaf708..f94341b 100644
+--- a/drivers/acpi/osl.c
++++ b/drivers/acpi/osl.c
+@@ -246,7 +246,7 @@ early_param("acpi_rsdp", setup_acpi_rsdp);
+ acpi_physical_address __init acpi_os_get_root_pointer(void)
+ {
+ #ifdef CONFIG_KEXEC
+-	if (acpi_rsdp)
++	if (acpi_rsdp && capable(CAP_COMPROMISE_KERNEL))
+ 		return acpi_rsdp;
+ #endif
+ 
+-- 
+1.7.11.4
+
+
+From 03fb06d272ddc1062e610521c5cfdbe42f251209 Mon Sep 17 00:00:00 2001
+From: Josh Boyer <jwboyer at redhat.com>
+Date: Thu, 20 Sep 2012 10:41:05 -0400
+Subject: [PATCH 10/14] SELinux: define mapping for new Secure Boot capability
+
+Add the name of the new Secure Boot capability.  This allows SELinux
+policies to properly map CAP_COMPROMISE_KERNEL to the appropriate
+capability class.
+
+Signed-off-by: Josh Boyer <jwboyer at redhat.com>
+---
+ security/selinux/include/classmap.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
+index df2de54..70e2834 100644
+--- a/security/selinux/include/classmap.h
++++ b/security/selinux/include/classmap.h
+@@ -146,8 +146,8 @@ struct security_class_mapping secclass_map[] = {
+ 	{ "memprotect", { "mmap_zero", NULL } },
+ 	{ "peer", { "recv", NULL } },
+ 	{ "capability2",
+-	  { "mac_override", "mac_admin", "syslog", "wake_alarm", "block_suspend",
+-	    NULL } },
++	  { "mac_override", "mac_admin", "syslog", "wake_alarm",
++	    "block_suspend", "compromise_kernel", NULL } },
+ 	{ "kernel_service", { "use_as_override", "create_files_as", NULL } },
+ 	{ "tun_socket",
+ 	  { COMMON_SOCK_PERMS, NULL } },
+-- 
+1.7.11.4
+
+
+From 0cfaa5ecf01f8eaaa2a84d88b7258a94ac9a1bfe Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg at redhat.com>
+Date: Tue, 4 Sep 2012 11:55:13 -0400
+Subject: [PATCH 11/14] kexec: Disable in a secure boot environment
+
+kexec could be used as a vector for a malicious user to use a signed kernel
+to circumvent the secure boot trust model. In the long run we'll want to
+support signed kexec payloads, but for the moment we should just disable
+loading entirely in that situation.
+
+Signed-off-by: Matthew Garrett <mjg at redhat.com>
+---
+ kernel/kexec.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/kernel/kexec.c b/kernel/kexec.c
+index 0668d58..8b976a5 100644
+--- a/kernel/kexec.c
++++ b/kernel/kexec.c
+@@ -944,7 +944,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))
++	if (!capable(CAP_SYS_BOOT) || !capable(CAP_COMPROMISE_KERNEL))
+ 		return -EPERM;
+ 
+ 	/*
+-- 
+1.7.11.4
+
+
+From 895c46276788b3711aee05a1a1d685eff69d48b9 Mon Sep 17 00:00:00 2001
+From: Josh Boyer <jwboyer at redhat.com>
+Date: Mon, 25 Jun 2012 21:29:46 -0400
+Subject: [PATCH 12/14] Documentation: kernel-parameters.txt remove
+ capability.disable
+
+Remove the documentation for capability.disable.  The code supporting this
+parameter was removed with:
+
+	commit 5915eb53861c5776cfec33ca4fcc1fd20d66dd27
+	Author: Miklos Szeredi <mszeredi at suse.cz>
+	Date:   Thu Jul 3 20:56:05 2008 +0200
+
+    	security: remove dummy module
+
+Signed-off-by: Josh Boyer <jwboyer at redhat.com>
+---
+ Documentation/kernel-parameters.txt | 6 ------
+ 1 file changed, 6 deletions(-)
+
+diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
+index 93978d5..e3e5f8c 100644
+--- a/Documentation/kernel-parameters.txt
++++ b/Documentation/kernel-parameters.txt
+@@ -446,12 +446,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
+ 			possible to determine what the correct size should be.
+ 			This option provides an override for these situations.
+ 
+-	capability.disable=
+-			[SECURITY] Disable capabilities.  This would normally
+-			be used only if an alternative security model is to be
+-			configured.  Potentially dangerous and should only be
+-			used if you are entirely sure of the consequences.
+-
+ 	ccw_timeout_log [S390]
+ 			See Documentation/s390/CommonIO for details.
+ 
+-- 
+1.7.11.4
+
+
+From 1cc529e97756554953187fe48b9b8cf0e24b9bc7 Mon Sep 17 00:00:00 2001
+From: Josh Boyer <jwboyer at redhat.com>
+Date: Fri, 5 Oct 2012 10:12:48 -0400
+Subject: [PATCH] modsign: Always enforce module signing in a Secure Boot
+ environment
+
+If a machine is booted into a Secure Boot environment, we need to
+protect the trust model.  This requires that all modules be signed
+with a key that is in the kernel's _modsign keyring.  The checks for
+this are already done via the 'sig_enforce' module parameter.  Make
+this visible within the kernel and force it to be true.
+
+Signed-off-by: Josh Boyer <jwboyer at redhat.com>
+---
+ kernel/cred.c   | 8 ++++++++
+ kernel/module.c | 4 ++--
+ 2 files changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/kernel/cred.c b/kernel/cred.c
+index 7e6e83f..2b0b980 100644
+--- a/kernel/cred.c
++++ b/kernel/cred.c
+@@ -623,11 +623,19 @@ void __init cred_init(void)
+ 				     0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
+ }
+ 
++#ifdef CONFIG_MODULE_SIG
++extern bool sig_enforce;
++#endif
++
+ void __init secureboot_enable()
+ {
+ 	pr_info("Secure boot enabled\n");
+ 	cap_lower((&init_cred)->cap_bset, CAP_COMPROMISE_KERNEL);
+ 	cap_lower((&init_cred)->cap_permitted, CAP_COMPROMISE_KERNEL);
++#ifdef CONFIG_MODULE_SIG
++	/* Enable module signature enforcing */
++	sig_enforce = true;
++#endif
+ }
+ 
+ /* Dummy Secure Boot enable option to fake out UEFI SB=1 */
+diff --git a/kernel/module.c b/kernel/module.c
+index de16959..7d4c50a 100644
+--- a/kernel/module.c
++++ b/kernel/module.c
+@@ -106,9 +106,9 @@ struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
+ 
+ #ifdef CONFIG_MODULE_SIG
+ #ifdef CONFIG_MODULE_SIG_FORCE
+-static bool sig_enforce = true;
++bool sig_enforce = true;
+ #else
+-static bool sig_enforce = false;
++bool sig_enforce = false;
+ 
+ static int param_set_bool_enable_only(const char *val,
+ 				      const struct kernel_param *kp)
+-- 
+1.7.11.4
+
+From 945f3829d0d376c5e0c790b57c4fa9e875d602d3 Mon Sep 17 00:00:00 2001
+From: Dave Howells <dhowells at redhat.com>
+Date: Tue, 23 Oct 2012 09:30:54 -0400
+Subject: [PATCH 1/2] Add EFI signature data types, such as are used for
+ containing hashes, keys and certificates for
+ cryptographic verification.
+
+Signed-off-by: David Howells <dhowells at redhat.com>
+---
+ include/linux/efi.h | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+diff --git a/include/linux/efi.h b/include/linux/efi.h
+index 8670eb1..836c797 100644
+--- a/include/linux/efi.h
++++ b/include/linux/efi.h
+@@ -312,6 +312,12 @@ typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **capsules,
+ #define EFI_FILE_SYSTEM_GUID \
+     EFI_GUID(  0x964e5b22, 0x6459, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b )
+ 
++#define EFI_CERT_SHA256_GUID \
++    EFI_GUID(  0xc1c41626, 0x504c, 0x4092, 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28 )
++
++#define EFI_CERT_X509_GUID \
++    EFI_GUID(  0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 )
++
+ typedef struct {
+ 	efi_guid_t guid;
+ 	u64 table;
+@@ -447,6 +453,20 @@ typedef struct {
+ 
+ #define EFI_INVALID_TABLE_ADDR		(~0UL)
+ 
++typedef struct  {
++	efi_guid_t signature_owner;
++	u8 signature_data[];
++} efi_signature_data_t;
++
++typedef struct {
++	efi_guid_t signature_type;
++	u32 signature_list_size;
++	u32 signature_header_size;
++	u32 signature_size;
++	u8 signature_header[];
++	/* efi_signature_data_t signatures[][] */
++} efi_signature_list_t;
++
+ /*
+  * All runtime access to EFI goes through this structure:
+  */
+-- 
+1.7.12.1
+
+
+From 5934634101936bc4ee4636df7269e00c4979911c Mon Sep 17 00:00:00 2001
+From: Dave Howells <dhowells at redhat.com>
+Date: Tue, 23 Oct 2012 09:36:28 -0400
+Subject: [PATCH 2/2] Add an EFI signature blob parser and key loader.  X.509
+ certificates are loaded into the specified keyring as
+ asymmetric type keys.
+
+Signed-off-by: David Howells <dhowells at redhat.com>
+---
+ crypto/asymmetric_keys/Kconfig      |   7 +++
+ crypto/asymmetric_keys/Makefile     |   1 +
+ crypto/asymmetric_keys/efi_parser.c | 107 ++++++++++++++++++++++++++++++++++++
+ include/linux/efi.h                 |   4 ++
+ 4 files changed, 119 insertions(+)
+ create mode 100644 crypto/asymmetric_keys/efi_parser.c
+
+diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
+index 6d2c2ea..eb53fc3 100644
+--- a/crypto/asymmetric_keys/Kconfig
++++ b/crypto/asymmetric_keys/Kconfig
+@@ -35,4 +35,11 @@ config X509_CERTIFICATE_PARSER
+ 	  data and provides the ability to instantiate a crypto key from a
+ 	  public key packet found inside the certificate.
+ 
++config EFI_SIGNATURE_LIST_PARSER
++	bool "EFI signature list parser"
++	select X509_CERTIFICATE_PARSER
++	help
++	  This option provides support for parsing EFI signature lists for
++	  X.509 certificates and turning them into keys.
++
+ endif # ASYMMETRIC_KEY_TYPE
+diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
+index 0727204..cd8388e 100644
+--- a/crypto/asymmetric_keys/Makefile
++++ b/crypto/asymmetric_keys/Makefile
+@@ -8,6 +8,7 @@ asymmetric_keys-y := asymmetric_type.o signature.o
+ 
+ obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o
+ obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o
++obj-$(CONFIG_EFI_SIGNATURE_LIST_PARSER) += efi_parser.o
+ 
+ #
+ # X.509 Certificate handling
+diff --git a/crypto/asymmetric_keys/efi_parser.c b/crypto/asymmetric_keys/efi_parser.c
+new file mode 100644
+index 0000000..59b859a
+--- /dev/null
++++ b/crypto/asymmetric_keys/efi_parser.c
+@@ -0,0 +1,107 @@
++/* EFI signature/key/certificate list parser
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells at 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);
++			continue;
++		}
++
++		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'\n",
++					  key_ref_to_ptr(key)->description);
++
++			data += esize;
++			size -= esize;
++			offs += esize;
++		}
++	}
++
++	return 0;
++}
+diff --git a/include/linux/efi.h b/include/linux/efi.h
+index 836c797..9cc3250 100644
+--- a/include/linux/efi.h
++++ b/include/linux/efi.h
+@@ -536,6 +536,10 @@ extern int efi_set_rtc_mmss(unsigned long nowtime);
+ extern void efi_reserve_boot_services(void);
+ extern struct efi_memory_map memmap;
+ 
++struct key;
++extern int __init parse_efi_signature_list(const void *data, size_t size,
++					   struct key *keyring);
++
+ /**
+  * efi_range_is_wc - check the WC bit on an address range
+  * @start: starting kvirt address
+-- 
+1.7.12.1
+
+From 84d11d541cc039e8561d06deab5f9b700f12f246 Mon Sep 17 00:00:00 2001
+From: Josh Boyer <jwboyer at redhat.com>
+Date: Fri, 26 Oct 2012 12:29:49 -0400
+Subject: [PATCH 1/3] EFI: Add in-kernel variable to determine if Secure Boot
+ is enabled
+
+There are a few cases where in-kernel functions may need to know if
+Secure Boot is enabled.  The added capability check cannot be used as the
+kernel can't drop it's own capabilites, so we add a global variable
+similar to efi_enabled so they can determine if Secure Boot is enabled.
+
+Signed-off-by: Josh Boyer <jwboyer at redhat.com>
+---
+ arch/x86/kernel/setup.c     | 4 +++-
+ arch/x86/platform/efi/efi.c | 2 ++
+ include/linux/efi.h         | 3 +++
+ 3 files changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
+index 51f6970..d5b9548 100644
+--- a/arch/x86/kernel/setup.c
++++ b/arch/x86/kernel/setup.c
+@@ -961,8 +961,10 @@ void __init setup_arch(char **cmdline_p)
+ 
+ 	io_delay_init();
+ 
+-	if (boot_params.secure_boot)
++	if (boot_params.secure_boot) {
+ 		secureboot_enable();
++		secure_boot_enabled = 1;
++	}
+ 
+ 	/*
+ 	 * Parse the ACPI tables for possible boot-time SMP configuration.
+diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
+index aded2a9..e57320b 100644
+--- a/arch/x86/platform/efi/efi.c
++++ b/arch/x86/platform/efi/efi.c
+@@ -54,6 +54,8 @@
+ int efi_enabled;
+ EXPORT_SYMBOL(efi_enabled);
+ 
++int secure_boot_enabled;
++
+ struct efi __read_mostly efi = {
+ 	.mps        = EFI_INVALID_TABLE_ADDR,
+ 	.acpi       = EFI_INVALID_TABLE_ADDR,
+diff --git a/include/linux/efi.h b/include/linux/efi.h
+index 9cc3250..ff72468 100644
+--- a/include/linux/efi.h
++++ b/include/linux/efi.h
+@@ -573,11 +573,14 @@ extern int __init efi_setup_pcdp_console(char *);
+ # ifdef CONFIG_X86
+    extern int efi_enabled;
+    extern bool efi_64bit;
++   extern int secure_boot_enabled;
+ # else
+ #  define efi_enabled 1
++#  define secure_boot_enabled 0
+ # endif
+ #else
+ # define efi_enabled 0
++# define secure_boot_enabled 0
+ #endif
+ 
+ /*
+-- 
+1.7.12.1
+
+
+From 2a5f33b264daffd717b509bc5ac3cdc060b5573e Mon Sep 17 00:00:00 2001
+From: Josh Boyer <jwboyer at redhat.com>
+Date: Fri, 26 Oct 2012 12:36:24 -0400
+Subject: [PATCH 2/3] MODSIGN: Add module certificate blacklist keyring
+
+This adds an additional keyring that is used to store certificates that
+are blacklisted.  This keyring is searched first when loading signed modules
+and if the module's certificate is found, it will refuse to load.  This is
+useful in cases where third party certificates are used for module signing.
+
+Signed-off-by: Josh Boyer <jwboyer at redhat.com>
+---
+ init/Kconfig             |  8 ++++++++
+ kernel/modsign_pubkey.c  | 17 +++++++++++++++++
+ kernel/module-internal.h |  3 +++
+ kernel/module_signing.c  | 14 +++++++++++++-
+ 4 files changed, 41 insertions(+), 1 deletion(-)
+
+diff --git a/init/Kconfig b/init/Kconfig
+index 6fdd6e3..7a9bf00 100644
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1602,6 +1602,14 @@ config MODULE_SIG_FORCE
+ 	  Reject unsigned modules or signed modules for which we don't have a
+ 	  key.  Without this, such modules will simply taint the kernel.
+ 
++config MODULE_SIG_BLACKLIST
++	bool "Support for blacklisting module signature certificates"
++	depends on MODULE_SIG
++	help
++	  This adds support for keeping a blacklist of certificates that
++	  should not pass module signature verification.  If a module is
++	  signed with something in this keyring, the load will be rejected.
++
+ choice
+ 	prompt "Which hash algorithm should modules be signed with?"
+ 	depends on MODULE_SIG
+diff --git a/kernel/modsign_pubkey.c b/kernel/modsign_pubkey.c
+index 4646eb2..6d70783 100644
+--- a/kernel/modsign_pubkey.c
++++ b/kernel/modsign_pubkey.c
+@@ -17,6 +17,9 @@
+ #include "module-internal.h"
+ 
+ struct key *modsign_keyring;
++#ifdef CONFIG_MODULE_SIG_BLACKLIST
++struct key *modsign_blacklist;
++#endif
+ 
+ extern __initdata const u8 modsign_certificate_list[];
+ extern __initdata const u8 modsign_certificate_list_end[];
+@@ -52,6 +55,20 @@ static __init int module_verify_init(void)
+ 	if (key_instantiate_and_link(modsign_keyring, NULL, 0, NULL, NULL) < 0)
+ 		panic("Can't instantiate module signing keyring\n");
+ 
++#ifdef CONFIG_MODULE_SIG_BLACKLIST
++	modsign_blacklist = key_alloc(&key_type_keyring, ".modsign_blacklist",
++				    KUIDT_INIT(0), KGIDT_INIT(0),
++				    current_cred(),
++				    (KEY_POS_ALL & ~KEY_POS_SETATTR) |
++				    KEY_USR_VIEW | KEY_USR_READ,
++				    KEY_ALLOC_NOT_IN_QUOTA);
++	if (IS_ERR(modsign_blacklist))
++		panic("Can't allocate module signing blacklist keyring\n");
++
++	if (key_instantiate_and_link(modsign_blacklist, NULL, 0, NULL, NULL) < 0)
++		panic("Can't instantiate module signing blacklist keyring\n");
++#endif
++
+ 	return 0;
+ }
+ 
+diff --git a/kernel/module-internal.h b/kernel/module-internal.h
+index 24f9247..51a8380 100644
+--- a/kernel/module-internal.h
++++ b/kernel/module-internal.h
+@@ -10,5 +10,8 @@
+  */
+ 
+ extern struct key *modsign_keyring;
++#ifdef CONFIG_MODULE_SIG_BLACKLIST
++extern struct key *modsign_blacklist;
++#endif
+ 
+ extern int mod_verify_sig(const void *mod, unsigned long *_modlen);
+diff --git a/kernel/module_signing.c b/kernel/module_signing.c
+index ea1b1df..602aa24 100644
+--- a/kernel/module_signing.c
++++ b/kernel/module_signing.c
+@@ -132,7 +132,7 @@ static int mod_extract_mpi_array(struct public_key_signature *pks,
+ static struct key *request_asymmetric_key(const char *signer, size_t signer_len,
+ 					  const u8 *key_id, size_t key_id_len)
+ {
+-	key_ref_t key;
++	key_ref_t key, blacklist;
+ 	size_t i;
+ 	char *id, *q;
+ 
+@@ -157,6 +157,18 @@ static struct key *request_asymmetric_key(const char *signer, size_t signer_len,
+ 
+ 	pr_debug("Look up: \"%s\"\n", id);
+ 
++#ifdef CONFIG_MODULE_SIG_BLACKLIST
++	blacklist = keyring_search(make_key_ref(modsign_blacklist, 1),
++				   &key_type_asymmetric, id);
++	if (!IS_ERR(blacklist)) {
++		/* module is signed with a cert in the blacklist.  reject */
++		pr_err("Module key '%s' is in blacklist\n", id);
++		/*key_put(blacklist);*/
++		kfree(id);
++		return ERR_PTR(-EKEYREJECTED);
++	}
++#endif
++	
+ 	key = keyring_search(make_key_ref(modsign_keyring, 1),
+ 			     &key_type_asymmetric, id);
+ 	if (IS_ERR(key))
+-- 
+1.7.12.1
+
+
+
+From ddd5e2e1b775fb19aeec7fb842e707fc35347bc0 Mon Sep 17 00:00:00 2001
+From: Josh Boyer <jwboyer at redhat.com>
+Date: Fri, 26 Oct 2012 12:42:16 -0400
+Subject: [PATCH] MODSIGN: Import certificates from UEFI Secure Boot
+
+Secure Boot stores a list of allowed certificates in the 'db' variable.
+This imports those certificates into the module signing keyring.  This
+allows for a third party signing certificate to be used in conjunction
+with signed modules.  By importing the public certificate into the 'db'
+variable, a user can allow a module signed with that certificate to
+load.
+
+In the opposite case, Secure Boot maintains a list of disallowed
+certificates in the 'dbx' variable.  We load those certificates into
+the newly introduced module blacklist keyring and forbid any module
+signed with those from loading.
+
+Signed-off-by: Josh Boyer <jwboyer at redhat.com>
+---
+ include/linux/efi.h   |  3 ++
+ init/Kconfig          |  9 ++++++
+ kernel/Makefile       |  3 ++
+ kernel/modsign_uefi.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 99 insertions(+)
+ create mode 100644 kernel/modsign_uefi.c
+
+diff --git a/include/linux/efi.h b/include/linux/efi.h
+index ff72468..509755e 100644
+--- a/include/linux/efi.h
++++ b/include/linux/efi.h
+@@ -318,6 +318,9 @@ typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **capsules,
+ #define EFI_CERT_X509_GUID \
+     EFI_GUID(  0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 )
+ 
++#define EFI_IMAGE_SECURITY_DATABASE_GUID \
++    EFI_GUID(  0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f )
++
+ typedef struct {
+ 	efi_guid_t guid;
+ 	u64 table;
+diff --git a/init/Kconfig b/init/Kconfig
+index 7a9bf00..9c4c529 100644
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1610,6 +1610,15 @@ config MODULE_SIG_BLACKLIST
+ 	  should not pass module signature verification.  If a module is
+ 	  signed with something in this keyring, the load will be rejected.
+ 
++config MODULE_SIG_UEFI
++	bool "Allow modules signed with certs stored in UEFI"
++	depends on MODULE_SIG && MODULE_SIG_BLACKLIST && EFI
++	select EFI_SIGNATURE_LIST_PARSER
++	help
++	  This will import certificates stored in UEFI and allow modules
++	  signed with those to be loaded.  It will also disallow loading
++	  of modules stored in the UEFI dbx variable.
++
+ choice
+ 	prompt "Which hash algorithm should modules be signed with?"
+ 	depends on MODULE_SIG
+diff --git a/kernel/Makefile b/kernel/Makefile
+index 0dfeca4..ff1468f 100644
+--- a/kernel/Makefile
++++ b/kernel/Makefile
+@@ -55,6 +55,7 @@ obj-$(CONFIG_PROVE_LOCKING) += spinlock.o
+ obj-$(CONFIG_UID16) += uid16.o
+ obj-$(CONFIG_MODULES) += module.o
+ obj-$(CONFIG_MODULE_SIG) += module_signing.o modsign_pubkey.o
++obj-$(CONFIG_MODULE_SIG_UEFI) += modsign_uefi.o
+ obj-$(CONFIG_KALLSYMS) += kallsyms.o
+ obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
+ obj-$(CONFIG_KEXEC) += kexec.o
+@@ -113,6 +114,8 @@ obj-$(CONFIG_JUMP_LABEL) += jump_label.o
+ 
+ $(obj)/configs.o: $(obj)/config_data.h
+ 
++$(obj)/modsign_uefi.o: KBUILD_CFLAGS += -fshort-wchar
++
+ # config_data.h contains the same information as ikconfig.h but gzipped.
+ # Info from config_data can be extracted from /proc/config*
+ targets += config_data.gz
+diff --git a/kernel/modsign_uefi.c b/kernel/modsign_uefi.c
+new file mode 100644
+index 0000000..049669d
+--- /dev/null
++++ b/kernel/modsign_uefi.c
+@@ -0,0 +1,84 @@
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/cred.h>
++#include <linux/err.h>
++#include <linux/efi.h>
++#include <keys/asymmetric-type.h>
++#include "module-internal.h"
++
++static 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;
++	void *db = NULL, *dbx = NULL;
++	unsigned long dbsize = 0, dbxsize = 0;
++	int rc = 0;
++
++	/* Check if SB is enabled and just return if not */
++	if (!secure_boot_enabled)
++		return 0;
++
++	db = get_cert_list(L"db", &secure_var, &dbsize);
++	if (!db) {
++		pr_err("Couldn't get db list\n");
++		rc = -1;
++		goto err;
++	}
++
++	/* Get dbx.  It might not exist, so it isn't an error if we can't
++	 * get it.
++	 */
++	dbx = get_cert_list(L"dbx", &secure_var, &dbxsize);
++	if (!dbx) {
++		pr_err("Couldn't get dbx list\n");
++	}
++
++	rc = parse_efi_signature_list(db, dbsize, modsign_keyring);
++	if (rc)
++		pr_err("Couldn't parse db signatures: %d\n", rc);
++
++	if (dbx) {
++		rc = parse_efi_signature_list(dbx, dbxsize,
++			modsign_blacklist);
++		if (rc)
++			pr_err("Couldn't parse dbx signatures: %d\n", rc);
++	}
++
++err:
++	kfree(db);
++	kfree(dbx);
++	return rc;
++}
++late_initcall(load_uefi_certs);
+-- 
+1.7.12.1
+
+From d037dc552a62b1dd39b457e10c133a4509b0efc3 Mon Sep 17 00:00:00 2001
+From: Josh Boyer <jwboyer at redhat.com>
+Date: Fri, 26 Oct 2012 14:02:09 -0400
+Subject: [PATCH] hibernate: Disable in a Secure Boot environment
+
+There is currently no way to verify the resume image when returning
+from hibernate.  This might compromise the secure boot trust model,
+so until we can work with signed hibernate images we disable it in
+a Secure Boot environment.
+
+Signed-off-by: Josh Boyer <jwboyer at redhat.com>
+---
+ kernel/power/hibernate.c | 14 +++++++++++++-
+ kernel/power/main.c      |  4 +++-
+ 2 files changed, 16 insertions(+), 2 deletions(-)
+
+diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
+index b26f5f1..f04343b 100644
+--- a/kernel/power/hibernate.c
++++ b/kernel/power/hibernate.c
+@@ -632,6 +632,10 @@ int hibernate(void)
+ {
+ 	int error;
+ 
++	if (!capable(CAP_COMPROMISE_KERNEL)) {
++		return -EPERM;
++	}
++
+ 	lock_system_sleep();
+ 	/* The snapshot device should not be opened while we're running */
+ 	if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
+@@ -723,7 +727,7 @@ static int software_resume(void)
+ 	/*
+ 	 * If the user said "noresume".. bail out early.
+ 	 */
+-	if (noresume)
++	if (noresume || !capable(CAP_COMPROMISE_KERNEL))
+ 		return 0;
+ 
+ 	/*
+@@ -889,6 +893,11 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
+ 	int i;
+ 	char *start = buf;
+ 
++	if (!capable(CAP_COMPROMISE_KERNEL)) {
++		buf += sprintf(buf, "[%s]\n", "disabled");
++		return buf-start;
++	}
++
+ 	for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
+ 		if (!hibernation_modes[i])
+ 			continue;
+@@ -923,6 +932,9 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
+ 	char *p;
+ 	int mode = HIBERNATION_INVALID;
+ 
++	if (!capable(CAP_COMPROMISE_KERNEL))
++		return -EPERM;
++
+ 	p = memchr(buf, '\n', n);
+ 	len = p ? p - buf : n;
+ 
+diff --git a/kernel/power/main.c b/kernel/power/main.c
+index f458238..72580c1 100644
+--- a/kernel/power/main.c
++++ b/kernel/power/main.c
+@@ -301,7 +301,9 @@ static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
+ 	}
+ #endif
+ #ifdef CONFIG_HIBERNATION
+-	s += sprintf(s, "%s\n", "disk");
++	if (capable(CAP_COMPROMISE_KERNEL)) {
++		s += sprintf(s, "%s\n", "disk");
++	}
+ #else
+ 	if (s != buf)
+ 		/* convert the last space to a newline */
+-- 
+1.7.12.1
+


More information about the scm-commits mailing list