From df7d76ae50f18d4465e59fdf7f19d3df44906cb5 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Mon, 21 Nov 2016 23:55:55 +0000 Subject: [PATCH 07/32] efi: Add EFI_SECURE_BOOT bit UEFI machines can be booted in Secure Boot mode. Add a EFI_SECURE_BOOT bit that can be passed to efi_enabled() to find out whether secure boot is enabled. This will be used by the SysRq+x handler, registered by the x86 arch, to find out whether secure boot mode is enabled so that it can be disabled. Signed-off-by: Josh Boyer Signed-off-by: David Howells --- arch/x86/kernel/setup.c | 1 + include/linux/efi.h | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 69780ed..447905e 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -1182,6 +1182,7 @@ void __init setup_arch(char **cmdline_p) pr_info("Secure boot disabled\n"); break; case efi_secureboot_mode_enabled: + set_bit(EFI_SECURE_BOOT, &efi.flags); pr_info("Secure boot enabled\n"); break; default: diff --git a/include/linux/efi.h b/include/linux/efi.h index 94d34e0..6049600 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -1069,6 +1069,7 @@ extern int __init efi_setup_pcdp_console(char *); #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_MEM_ATTR 10 /* Did firmware publish an EFI_MEMORY_ATTRIBUTES table? */ +#define EFI_SECURE_BOOT 11 /* Are we in Secure Boot mode? */ #ifdef CONFIG_EFI /* -- 2.7.4 From 0f9281e3b77bf5f767f1993d52b152a1ef317a0a Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 25 Nov 2016 11:52:05 +0000 Subject: [PATCH 08/32] efi: Handle secure boot from UEFI-2.6 UEFI-2.6 adds a new variable, DeployedMode. If it exists, this must be 1 if we're to engage lockdown mode. Reported-by: James Bottomley Signed-off-by: David Howells --- drivers/firmware/efi/libstub/secureboot.c | 16 +++++++++++++++- include/linux/efi.h | 4 ++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/efi/libstub/secureboot.c b/drivers/firmware/efi/libstub/secureboot.c index 6def402..77af519 100644 --- a/drivers/firmware/efi/libstub/secureboot.c +++ b/drivers/firmware/efi/libstub/secureboot.c @@ -20,6 +20,9 @@ static const efi_char16_t const efi_SecureBoot_name[] = { static const efi_char16_t const efi_SetupMode_name[] = { 'S', 'e', 't', 'u', 'p', 'M', 'o', 'd', 'e', 0 }; +static const efi_char16_t const efi_DeployedMode_name[] = { + 'D', 'e', 'p', 'l', 'o', 'y', 'e', 'd', 'M', 'o', 'd', 'e', 0 +}; /* SHIM variables */ static const efi_guid_t shim_guid = EFI_SHIM_LOCK_GUID; @@ -38,7 +41,7 @@ static efi_char16_t const shim_MokSBState_name[] = { enum efi_secureboot_mode efi_get_secureboot(efi_system_table_t *sys_table_arg) { u32 attr; - u8 secboot, setupmode, moksbstate; + u8 secboot, setupmode, deployedmode, moksbstate; unsigned long size; efi_status_t status; @@ -57,6 +60,17 @@ enum efi_secureboot_mode efi_get_secureboot(efi_system_table_t *sys_table_arg) if (secboot == 0 || setupmode == 1) return efi_secureboot_mode_disabled; + /* UEFI-2.6 requires DeployedMode to be 1. */ + if (sys_table_arg->hdr.revision >= EFI_2_60_SYSTEM_TABLE_REVISION) { + size = sizeof(deployedmode); + status = get_efi_var(efi_DeployedMode_name, &efi_variable_guid, + NULL, &size, &deployedmode); + if (status != EFI_SUCCESS) + goto out_efi_err; + if (deployedmode == 0) + return efi_secureboot_mode_disabled; + } + /* * See if a user has put the shim into insecure mode. If so, and if the * variable doesn't have the runtime attribute set, we might as well diff --git a/include/linux/efi.h b/include/linux/efi.h index 6049600..784a276 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -646,6 +646,10 @@ typedef struct { #define EFI_SYSTEM_TABLE_SIGNATURE ((u64)0x5453595320494249ULL) +#define EFI_2_60_SYSTEM_TABLE_REVISION ((2 << 16) | (60)) +#define EFI_2_50_SYSTEM_TABLE_REVISION ((2 << 16) | (50)) +#define EFI_2_40_SYSTEM_TABLE_REVISION ((2 << 16) | (40)) +#define EFI_2_31_SYSTEM_TABLE_REVISION ((2 << 16) | (31)) #define EFI_2_30_SYSTEM_TABLE_REVISION ((2 << 16) | (30)) #define EFI_2_20_SYSTEM_TABLE_REVISION ((2 << 16) | (20)) #define EFI_2_10_SYSTEM_TABLE_REVISION ((2 << 16) | (10)) -- 2.7.4 From f05a90c19a9613d8d50597319ed91f691e25b689 Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 21 Nov 2016 23:36:17 +0000 Subject: [PATCH 09/32] Add the ability to lock down access to the running kernel image Provide a single call to allow kernel code to determine whether the system should be locked down, thereby disallowing various accesses that might allow the running kernel image to be changed including the loading of modules that aren't validly signed with a key we recognise, fiddling with MSR registers and disallowing hibernation, Signed-off-by: David Howells --- include/linux/kernel.h | 9 +++++++++ include/linux/security.h | 11 +++++++++++ security/Kconfig | 15 +++++++++++++++ security/Makefile | 3 +++ security/lock_down.c | 40 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 78 insertions(+) create mode 100644 security/lock_down.c diff --git a/include/linux/kernel.h b/include/linux/kernel.h index cb09238..3cd3be9 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -273,6 +273,15 @@ extern int oops_may_print(void); void do_exit(long error_code) __noreturn; void complete_and_exit(struct completion *, long) __noreturn; +#ifdef CONFIG_LOCK_DOWN_KERNEL +extern bool kernel_is_locked_down(void); +#else +static inline bool kernel_is_locked_down(void) +{ + return false; +} +#endif + /* Internal, do not use. */ int __must_check _kstrtoul(const char *s, unsigned int base, unsigned long *res); int __must_check _kstrtol(const char *s, unsigned int base, long *res); diff --git a/include/linux/security.h b/include/linux/security.h index d3868f2..187b74b 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1679,5 +1679,16 @@ static inline void free_secdata(void *secdata) { } #endif /* CONFIG_SECURITY */ +#ifdef CONFIG_LOCK_DOWN_KERNEL +extern void lock_kernel_down(void); +#ifdef CONFIG_ALLOW_LOCKDOWN_LIFT +extern void lift_kernel_lockdown(void); +#endif +#else +static inline void lock_kernel_down(void) +{ +} +#endif + #endif /* ! __LINUX_SECURITY_H */ diff --git a/security/Kconfig b/security/Kconfig index d900f47..d9b391d 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -193,6 +193,21 @@ config STATIC_USERMODEHELPER_PATH If you wish for all usermode helper programs to be disabled, specify an empty string here (i.e. ""). +config LOCK_DOWN_KERNEL + bool "Allow the kernel to be 'locked down'" + help + Allow the kernel to be locked down under certain circumstances, for + instance if UEFI secure boot is enabled. Locking down the kernel + turns off various features that might otherwise allow access to the + kernel image (eg. setting MSR registers). + +config ALLOW_LOCKDOWN_LIFT + bool + help + Allow the lockdown on a kernel to be lifted, thereby restoring the + ability of userspace to access the kernel image (eg. by SysRq+x under + x86). + source security/selinux/Kconfig source security/smack/Kconfig source security/tomoyo/Kconfig diff --git a/security/Makefile b/security/Makefile index f2d71cd..8c4a43e 100644 --- a/security/Makefile +++ b/security/Makefile @@ -29,3 +29,6 @@ obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o # Object integrity file lists subdir-$(CONFIG_INTEGRITY) += integrity obj-$(CONFIG_INTEGRITY) += integrity/ + +# Allow the kernel to be locked down +obj-$(CONFIG_LOCK_DOWN_KERNEL) += lock_down.o diff --git a/security/lock_down.c b/security/lock_down.c new file mode 100644 index 0000000..5788c60 --- /dev/null +++ b/security/lock_down.c @@ -0,0 +1,40 @@ +/* Lock down the kernel + * + * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#include +#include + +static __read_mostly bool kernel_locked_down; + +/* + * Put the kernel into lock-down mode. + */ +void lock_kernel_down(void) +{ + kernel_locked_down = true; +} + +/* + * Take the kernel out of lockdown mode. + */ +void lift_kernel_lockdown(void) +{ + kernel_locked_down = false; +} + +/** + * kernel_is_locked_down - Find out if the kernel is locked down + */ +bool kernel_is_locked_down(void) +{ + return kernel_locked_down; +} +EXPORT_SYMBOL(kernel_is_locked_down); -- 2.7.4 From fb6feb38e297260d050fc477c72683ac51d07ae3 Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 21 Nov 2016 23:55:55 +0000 Subject: [PATCH 10/32] efi: Lock down the kernel if booted 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 to lock down the kernel - which includes requiring validly signed modules - if the kernel is secure-booted. Signed-off-by: David Howells --- arch/x86/Kconfig | 12 ++++++++++++ arch/x86/kernel/setup.c | 8 +++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 874c123..a315974 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1816,6 +1816,18 @@ config EFI_MIXED If unsure, say N. +config EFI_SECURE_BOOT_LOCK_DOWN + def_bool n + depends on EFI + prompt "Lock down the kernel 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 and that + userspace is prevented from directly changing the running kernel + image. Say Y here to automatically lock down the kernel 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/kernel/setup.c b/arch/x86/kernel/setup.c index 447905e..d44e60e 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -69,6 +69,7 @@ #include #include #include +#include #include