[PATCH v2] kexec: add sysctl to disable kexec

Kees Cook
2013-12-10T00:18:24Z

For general-purpose (i.e. distro) kernel builds it makes sense to build with
CONFIG_KEXEC to allow end users to choose what kind of things they want to do
with kexec. However, in the face of trying to lock down a system with such
a kernel, there needs to be a way to disable kexec (much like module loading
can be disabled). Without this, it is too easy for the root user to modify
kernel memory even when CONFIG_STRICT_DEVMEM and modules_disabled are set.

Signed-off-by: Kees Cook <keescook@chromium.org>
Acked-by: Rik van Riel <riel@redhat.com>
---
v2:
- updated sysctl documentation; akpm
---
Documentation/sysctl/kernel.txt | 13 ++++++++++++-
include/linux/kexec.h | 1 +
kernel/kexec.c | 3 ++-
kernel/sysctl.c | 13 +++++++++++++
4 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
index 26b7ee491df8..ca153f958a30 100644
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -33,6 +33,7 @@ show up in /proc/sys/kernel:
- domainname
- hostname
- hotplug
+- kexec_disabled
- kptr_restrict
- kstack_depth_to_print [ X86 only ]
- l2cr [ PPC only ]
@@ -287,6 +288,16 @@ Default value is "/sbin/hotplug".

==============================================================

+kexec_disabled:
+
+A toggle indicating if the kexec_load syscall has been disabled. This
+value defaults to 0 (false: kexec_load enabled), but can be set to 1
+(true: kexec_load disabled). Once true, kexec can no longer be used, and
+the toggle cannot be set back to false. Generally used together with the
+"modules_disabled" sysctl.
+
+==============================================================
+
kptr_restrict:

This toggle indicates whether restrictions are placed on
@@ -331,7 +342,7 @@ A toggle value indicating if modules are allowed to be loaded
in an otherwise modular kernel. This toggle defaults to off
(0), but can be set true (1). Once true, modules can be
neither loaded nor unloaded, and the toggle cannot be set back
-to false.
+to false. Generally used with the "kexec_disabled" toggle.

==============================================================

diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index d78d28a733b1..a1503ed4dde5 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -170,6 +170,7 @@ unsigned long paddr_vmcoreinfo_note(void);

extern struct kimage *kexec_image;
extern struct kimage *kexec_crash_image;
+extern int kexec_disabled;

#ifndef kexec_flush_icache_page
#define kexec_flush_icache_page(page)
diff --git a/kernel/kexec.c b/kernel/kexec.c
index 490afc03627e..9d44ed203ee7 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -929,6 +929,7 @@ static int kimage_load_segment(struct kimage *image,
*/
struct kimage *kexec_image;
struct kimage *kexec_crash_image;
+int kexec_disabled;

static DEFINE_MUTEX(kexec_mutex);

@@ -939,7 +940,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) || kexec_disabled)
return -EPERM;

/*
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 34a604726d0b..07869ce3642d 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -62,6 +62,7 @@
#include <linux/capability.h>
#include <linux/binfmts.h>
#include <linux/sched/sysctl.h>
+#include <linux/kexec.h>

#include <asm/uaccess.h>
#include <asm/processor.h>
@@ -614,6 +615,18 @@ static struct ctl_table kern_table[] = {
.proc_handler = proc_dointvec,
},
#endif
+#ifdef CONFIG_KEXEC
+ {
+ .procname = "kexec_disabled",
+ .data = &kexec_disabled,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ /* only handle a transition from default "0" to "1" */
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &one,
+ .extra2 = &one,
+ },
+#endif
#ifdef CONFIG_MODULES
{
.procname = "modprobe",
--
1.7.9.5

--
Kees Cook
Chrome OS Security