[PATCH 01/24] Add the ability to lock down access to the running kernel image
From: David Howells
Date: Wed Apr 11 2018 - 12:24:54 EST
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:
- /dev/mem and similar
- Loading of unauthorised modules
- Fiddling with MSR registers
- Suspend to disk managed by the kernel
- Use of device DMA
Two kernel configuration options are provided:
(*) CONFIG_LOCK_DOWN_KERNEL
This makes lockdown available and applies it to all the points that
need to be locked down if the mode is set. Lockdown mode can be
enabled by providing:
lockdown=1
on the command line.
(*) CONFIG_LOCK_DOWN_MANDATORY
This forces lockdown on at compile time, overriding the command line
option.
init_lockdown() is used as a hook from which lockdown can be managed in
future. It has to be called from arch setup code before things like ACPI
are enabled.
Note that, with the other changes in this series, if lockdown mode is
enabled, the kernel will not be able to use certain drivers as the ability
to manually configure hardware parameters would then be prohibited. This
primarily applies to ISA hardware devices.
Signed-off-by: David Howells <dhowells@xxxxxxxxxx>
---
arch/x86/kernel/setup.c | 2 +
include/linux/kernel.h | 32 +++++++++++++++++++++++
security/Kconfig | 23 ++++++++++++++++-
security/Makefile | 3 ++
security/lock_down.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 124 insertions(+), 1 deletion(-)
create mode 100644 security/lock_down.c
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 6285697b6e56..566f0f447053 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -996,6 +996,8 @@ void __init setup_arch(char **cmdline_p)
if (efi_enabled(EFI_BOOT))
efi_init();
+ init_lockdown();
+
dmi_scan_machine();
dmi_memdev_walk();
dmi_set_dump_stack_arch_desc();
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 4ae1dfd9bf05..7d085cca9cee 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -306,6 +306,38 @@ static inline void refcount_error_report(struct pt_regs *regs, const char *err)
{ }
#endif
+#ifdef CONFIG_LOCK_DOWN_KERNEL
+extern void __init init_lockdown(void);
+extern bool __kernel_is_locked_down(const char *what, bool first);
+
+#ifndef CONFIG_LOCK_DOWN_MANDATORY
+#define kernel_is_locked_down(what) \
+ ({ \
+ static bool message_given; \
+ bool locked_down = __kernel_is_locked_down(what, !message_given); \
+ message_given = true; \
+ locked_down; \
+ })
+#else
+#define kernel_is_locked_down(what) \
+ ({ \
+ static bool message_given; \
+ __kernel_is_locked_down(what, !message_given); \
+ message_given = true; \
+ true; \
+ })
+#endif
+#else
+static inline void __init init_lockdown(void)
+{
+}
+static inline bool __kernel_is_locked_down(const char *what, bool first)
+{
+ return false;
+}
+#define kernel_is_locked_down(what) ({ 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/security/Kconfig b/security/Kconfig
index c4302067a3ad..a68e5bdebad5 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -231,6 +231,28 @@ 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. Locking down the kernel turns
+ off various features that might otherwise allow access to the kernel
+ image (eg. setting MSR registers).
+
+ Note, however, that locking down your kernel will prevent some
+ drivers from functioning because allowing manual configuration of
+ hardware parameters is forbidden, lest a device be used to access the
+ kernel by DMA. This mostly applies to ISA devices.
+
+ The kernel lockdown can be triggered by adding lockdown=1 to the
+ kernel command line.
+
+config LOCK_DOWN_MANDATORY
+ bool "Make kernel lockdown mandatory"
+ depends on LOCK_DOWN_KERNEL
+ help
+ Makes the lockdown non-negotiable. It is always on and cannot be
+ disabled.
+
source security/selinux/Kconfig
source security/smack/Kconfig
source security/tomoyo/Kconfig
@@ -278,4 +300,3 @@ config DEFAULT_SECURITY
default "" if DEFAULT_SECURITY_DAC
endmenu
-
diff --git a/security/Makefile b/security/Makefile
index 4d2d3782ddef..507ac8c520ce 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -30,3 +30,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 000000000000..f35ffdd096ad
--- /dev/null
+++ b/security/lock_down.c
@@ -0,0 +1,65 @@
+/* Lock down the kernel
+ *
+ * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@xxxxxxxxxx)
+ *
+ * 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 <linux/export.h>
+#include <linux/sched.h>
+
+#ifndef CONFIG_LOCK_DOWN_MANDATORY
+static __ro_after_init bool kernel_locked_down;
+#else
+#define kernel_locked_down true
+#endif
+
+/*
+ * Put the kernel into lock-down mode.
+ */
+static void __init lock_kernel_down(const char *where)
+{
+#ifndef CONFIG_LOCK_DOWN_MANDATORY
+ if (!kernel_locked_down) {
+ kernel_locked_down = true;
+ pr_notice("Kernel is locked down from %s; see man kernel_lockdown.7\n",
+ where);
+ }
+#endif
+}
+
+static int __init lockdown_param(char *ignored)
+{
+ lock_kernel_down("command line");
+ return 0;
+}
+
+early_param("lockdown", lockdown_param);
+
+/*
+ * Lock the kernel down from very early in the arch setup. This must happen
+ * prior to things like ACPI being initialised.
+ */
+void __init init_lockdown(void)
+{
+#ifdef CONFIG_LOCK_DOWN_MANDATORY
+ pr_notice("Kernel is locked down from config; see man kernel_lockdown.7\n");
+#endif
+}
+
+/**
+ * kernel_is_locked_down - Find out if the kernel is locked down
+ * @what: Tag to use in notice generated if lockdown is in effect
+ */
+bool __kernel_is_locked_down(const char *what, bool first)
+{
+ if (what && first && kernel_locked_down)
+ pr_notice("Lockdown: %s: %s is restricted; see man kernel_lockdown.7\n",
+ current->comm, what);
+ return kernel_locked_down;
+}
+EXPORT_SYMBOL(__kernel_is_locked_down);