dbc4a9b
From: Matthew Garrett <matthew.garrett@nebula.com>
dbc4a9b
Date: Fri, 9 Aug 2013 18:36:30 -0400
dbc4a9b
Subject: [PATCH] Add option to automatically enforce module signatures when in
dbc4a9b
 Secure Boot mode
dbc4a9b
dbc4a9b
UEFI Secure Boot provides a mechanism for ensuring that the firmware will
dbc4a9b
only load signed bootloaders and kernels. Certain use cases may also
dbc4a9b
require that all kernel modules also be signed. Add a configuration option
dbc4a9b
that enforces this automatically when enabled.
dbc4a9b
dbc4a9b
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
dbc4a9b
---
dbc4a9b
 Documentation/x86/zero-page.txt       |  2 ++
dbc4a9b
 arch/x86/Kconfig                      | 10 ++++++++++
dbc4a9b
 arch/x86/boot/compressed/eboot.c      | 36 +++++++++++++++++++++++++++++++++++
dbc4a9b
 arch/x86/include/uapi/asm/bootparam.h |  3 ++-
dbc4a9b
 arch/x86/kernel/setup.c               |  6 ++++++
dbc4a9b
 include/linux/module.h                |  6 ++++++
dbc4a9b
 kernel/module.c                       |  7 +++++++
dbc4a9b
 7 files changed, 69 insertions(+), 1 deletion(-)
dbc4a9b
dbc4a9b
diff --git a/Documentation/x86/zero-page.txt b/Documentation/x86/zero-page.txt
dbc4a9b
index 199f453cb4de..ec38acf00b40 100644
dbc4a9b
--- a/Documentation/x86/zero-page.txt
dbc4a9b
+++ b/Documentation/x86/zero-page.txt
dbc4a9b
@@ -30,6 +30,8 @@ Offset	Proto	Name		Meaning
dbc4a9b
 1E9/001	ALL	eddbuf_entries	Number of entries in eddbuf (below)
dbc4a9b
 1EA/001	ALL	edd_mbr_sig_buf_entries	Number of entries in edd_mbr_sig_buffer
dbc4a9b
 				(below)
dbc4a9b
+1EB/001	ALL     kbd_status      Numlock is enabled
dbc4a9b
+1EC/001	ALL     secure_boot	Secure boot is enabled in the firmware
dbc4a9b
 1EF/001	ALL	sentinel	Used to detect broken bootloaders
dbc4a9b
 290/040	ALL	edd_mbr_sig_buffer EDD MBR signatures
dbc4a9b
 2D0/A00	ALL	e820_map	E820 memory map table
dbc4a9b
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
dbc4a9b
index 36327438caf0..61542c282e70 100644
dbc4a9b
--- a/arch/x86/Kconfig
dbc4a9b
+++ b/arch/x86/Kconfig
dbc4a9b
@@ -1566,6 +1566,16 @@ config EFI_MIXED
dbc4a9b
 
dbc4a9b
 	   If unsure, say N.
dbc4a9b
 
dbc4a9b
+config EFI_SECURE_BOOT_SIG_ENFORCE
dbc4a9b
+        def_bool n
dbc4a9b
+	prompt "Force module signing when UEFI Secure Boot is enabled"
dbc4a9b
+	---help---
dbc4a9b
+	  UEFI Secure Boot provides a mechanism for ensuring that the
dbc4a9b
+	  firmware will only load signed bootloaders and kernels. Certain
dbc4a9b
+	  use cases may also require that all kernel modules also be signed.
dbc4a9b
+	  Say Y here to automatically enable module signature enforcement
dbc4a9b
+	  when a system boots with UEFI Secure Boot enabled.
dbc4a9b
+
dbc4a9b
 config SECCOMP
dbc4a9b
 	def_bool y
dbc4a9b
 	prompt "Enable seccomp to safely compute untrusted bytecode"
dbc4a9b
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
dbc4a9b
index de8eebd6f67c..975d11bfaf5b 100644
dbc4a9b
--- a/arch/x86/boot/compressed/eboot.c
dbc4a9b
+++ b/arch/x86/boot/compressed/eboot.c
dbc4a9b
@@ -12,6 +12,7 @@
dbc4a9b
 #include <asm/efi.h>
dbc4a9b
 #include <asm/setup.h>
dbc4a9b
 #include <asm/desc.h>
dbc4a9b
+#include <asm/bootparam_utils.h>
dbc4a9b
 
dbc4a9b
 #undef memcpy			/* Use memcpy from misc.c */
dbc4a9b
 
dbc4a9b
@@ -814,6 +815,37 @@ out:
dbc4a9b
 	return status;
dbc4a9b
 }
dbc4a9b
 
dbc4a9b
+static int get_secure_boot(void)
dbc4a9b
+{
dbc4a9b
+	u8 sb, setup;
dbc4a9b
+	unsigned long datasize = sizeof(sb);
dbc4a9b
+	efi_guid_t var_guid = EFI_GLOBAL_VARIABLE_GUID;
dbc4a9b
+	efi_status_t status;
dbc4a9b
+
dbc4a9b
+	status = efi_early->call((unsigned long)sys_table->runtime->get_variable,
dbc4a9b
+				L"SecureBoot", &var_guid, NULL, &datasize, &sb);
dbc4a9b
+
dbc4a9b
+	if (status != EFI_SUCCESS)
dbc4a9b
+		return 0;
dbc4a9b
+
dbc4a9b
+	if (sb == 0)
dbc4a9b
+		return 0;
dbc4a9b
+
dbc4a9b
+
dbc4a9b
+	status = efi_early->call((unsigned long)sys_table->runtime->get_variable,
dbc4a9b
+				L"SetupMode", &var_guid, NULL, &datasize,
dbc4a9b
+				&setup);
dbc4a9b
+
dbc4a9b
+	if (status != EFI_SUCCESS)
dbc4a9b
+		return 0;
dbc4a9b
+
dbc4a9b
+	if (setup == 1)
dbc4a9b
+		return 0;
dbc4a9b
+
dbc4a9b
+	return 1;
dbc4a9b
+}
dbc4a9b
+
dbc4a9b
+
dbc4a9b
 /*
dbc4a9b
  * See if we have Graphics Output Protocol
dbc4a9b
  */
dbc4a9b
@@ -1389,6 +1421,10 @@ struct boot_params *efi_main(struct efi_config *c,
dbc4a9b
 	else
dbc4a9b
 		setup_boot_services32(efi_early);
dbc4a9b
 
dbc4a9b
+	sanitize_boot_params(boot_params);
dbc4a9b
+
dbc4a9b
+	boot_params->secure_boot = get_secure_boot();
dbc4a9b
+
dbc4a9b
 	setup_graphics(boot_params);
dbc4a9b
 
dbc4a9b
 	setup_efi_pci(boot_params);
dbc4a9b
diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
dbc4a9b
index 225b0988043a..90dbfb73e11f 100644
dbc4a9b
--- a/arch/x86/include/uapi/asm/bootparam.h
dbc4a9b
+++ b/arch/x86/include/uapi/asm/bootparam.h
dbc4a9b
@@ -133,7 +133,8 @@ struct boot_params {
dbc4a9b
 	__u8  eddbuf_entries;				/* 0x1e9 */
dbc4a9b
 	__u8  edd_mbr_sig_buf_entries;			/* 0x1ea */
dbc4a9b
 	__u8  kbd_status;				/* 0x1eb */
dbc4a9b
-	__u8  _pad5[3];					/* 0x1ec */
dbc4a9b
+	__u8  secure_boot;				/* 0x1ec */
dbc4a9b
+	__u8  _pad5[2];					/* 0x1ed */
dbc4a9b
 	/*
dbc4a9b
 	 * The sentinel is set to a nonzero value (0xff) in header.S.
dbc4a9b
 	 *
dbc4a9b
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
dbc4a9b
index 41ead8d3bc0b..5a5cf7395724 100644
dbc4a9b
--- a/arch/x86/kernel/setup.c
dbc4a9b
+++ b/arch/x86/kernel/setup.c
dbc4a9b
@@ -1142,6 +1142,12 @@ void __init setup_arch(char **cmdline_p)
dbc4a9b
 
dbc4a9b
 	io_delay_init();
dbc4a9b
 
dbc4a9b
+#ifdef CONFIG_EFI_SECURE_BOOT_SIG_ENFORCE
dbc4a9b
+	if (boot_params.secure_boot) {
dbc4a9b
+		enforce_signed_modules();
dbc4a9b
+	}
dbc4a9b
+#endif
dbc4a9b
+
dbc4a9b
 	/*
dbc4a9b
 	 * Parse the ACPI tables for possible boot-time SMP configuration.
dbc4a9b
 	 */
dbc4a9b
diff --git a/include/linux/module.h b/include/linux/module.h
dbc4a9b
index 341a73ecea2e..cca08ac450e2 100644
dbc4a9b
--- a/include/linux/module.h
dbc4a9b
+++ b/include/linux/module.h
dbc4a9b
@@ -188,6 +188,12 @@ const struct exception_table_entry *search_exception_tables(unsigned long add);
dbc4a9b
 
dbc4a9b
 struct notifier_block;
dbc4a9b
 
dbc4a9b
+#ifdef CONFIG_MODULE_SIG
dbc4a9b
+extern void enforce_signed_modules(void);
dbc4a9b
+#else
dbc4a9b
+static inline void enforce_signed_modules(void) {};
dbc4a9b
+#endif
dbc4a9b
+
dbc4a9b
 #ifdef CONFIG_MODULES
dbc4a9b
 
dbc4a9b
 extern int modules_disabled; /* for sysctl */
dbc4a9b
diff --git a/kernel/module.c b/kernel/module.c
229fa32
index f1d78afbe29f..ec12c156ea61 100644
dbc4a9b
--- a/kernel/module.c
dbc4a9b
+++ b/kernel/module.c
229fa32
@@ -3845,6 +3845,13 @@ void module_layout(struct module *mod,
dbc4a9b
 EXPORT_SYMBOL(module_layout);
dbc4a9b
 #endif
dbc4a9b
 
dbc4a9b
+#ifdef CONFIG_MODULE_SIG
dbc4a9b
+void enforce_signed_modules(void)
dbc4a9b
+{
dbc4a9b
+	sig_enforce = true;
dbc4a9b
+}
dbc4a9b
+#endif
dbc4a9b
+
dbc4a9b
 bool secure_modules(void)
dbc4a9b
 {
dbc4a9b
 #ifdef CONFIG_MODULE_SIG
dbc4a9b
-- 
c47527a
2.1.0
dbc4a9b