From 1c73650539c732fdf352f4a09eb1960874a72c54 Mon Sep 17 00:00:00 2001 From: madaidan <50278627+madaidan@users.noreply.github.com> Date: Sun, 5 Jan 2020 17:45:35 +0000 Subject: [PATCH] Restrict module auto-loading to CAP_SYS_MODULE This is modified from Brad Spengler/PaX Team's code in the last public patch of grsecurity/PaX based on my understanding of the code. Changes or omissions from the original code are mine and don't reflect the original grsecurity/PaX code. Module auto-loading in response to use of some feature implemented by an unloaded module will be restricted to CAP_SYS_MODULE. Enabling this option helps defend against attacks by unprivileged users who abuse the auto-loading behavior to cause a vulnerable module to load that is then exploited. --- .../admin-guide/kernel-parameters.txt | 4 ++++ Documentation/admin-guide/sysctl/kernel.rst | 18 ++++++++++++-- include/linux/kmod.h | 1 + kernel/kmod.c | 24 +++++++++++++++++++ kernel/sysctl.c | 9 +++++++ security/Kconfig | 22 +++++++++++++++++ 6 files changed, 76 insertions(+), 2 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 41f74d5830da5..862453c636e49 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2902,6 +2902,10 @@ log everything. Information is printed at KERN_DEBUG so loglevel=8 may also need to be specified. + modharden= [SECURITY] + on - Restrict module auto-loading to CAP_SYS_MODULE + off - Don't restrict module auto-loading + module.sig_enforce [KNL] When CONFIG_MODULE_SIG is set, this means that modules without (valid) signatures will fail to load. diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst index 59b1ee24aed4c..e822120f4fdc2 100644 --- a/Documentation/admin-guide/sysctl/kernel.rst +++ b/Documentation/admin-guide/sysctl/kernel.rst @@ -510,8 +510,22 @@ then the configured static usermode helper overrides this sysctl, except that the empty string is still accepted to completely disable module autoloading as described above. -modules_disabled -================ +modharden: +========== + +This toggle indicates whether unprivileged users are allowed to +auto-load kernel modules. + +When modharden is set to (0) there are no restrictions. When +modharden is set to (1), only users with ``CAP_SYS_MODULE`` are +permitted to load kernel modules + +The kernel config option ``CONFIG_SECURITY_MODHARDEN`` sets the +default value of modharden. + + +modules_disabled: +================= A toggle value indicating if modules are allowed to be loaded in an otherwise modular kernel. This toggle defaults to off diff --git a/include/linux/kmod.h b/include/linux/kmod.h index 68f69362d427c..6762f35c29eb9 100644 --- a/include/linux/kmod.h +++ b/include/linux/kmod.h @@ -22,6 +22,7 @@ extern char modprobe_path[]; /* for sysctl */ * usually useless though. */ extern __printf(2, 3) int __request_module(bool wait, const char *name, ...); +extern int modharden; #define request_module(mod...) __request_module(true, mod) #define request_module_nowait(mod...) __request_module(false, mod) #define try_then_request_module(x, mod...) \ diff --git a/kernel/kmod.c b/kernel/kmod.c index 3cd075ce2a1ef..32b62ed273c93 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -105,6 +105,25 @@ static int call_modprobe(char *module_name, int wait) return -ENOMEM; } +int modharden __read_mostly = IS_ENABLED(CONFIG_SECURITY_MODHARDEN); + + +static int __init enable_modharden(char *level) +{ + if (!level) + return -EINVAL; + + if (strcmp(level, "on") == 0) + modharden = 1; + else if (strcmp(level, "off") == 0) + modharden = 0; + else + return -EINVAL; + + return 0; +} +early_param("modharden", enable_modharden); + /** * __request_module - try to load a kernel module * @wait: wait (or not) for the operation to complete @@ -148,6 +167,11 @@ int __request_module(bool wait, const char *fmt, ...) if (ret) return ret; + if (modharden && !capable(CAP_SYS_MODULE)) { + printk(KERN_ALERT "denied attempt to auto-load module %s\n", module_name); + return -EPERM; + } + if (atomic_dec_if_positive(&kmod_concurrent_max) < 0) { pr_warn_ratelimited("request_module: kmod_concurrent_max (%u) close to 0 (max_modprobes: %u), for module %s, throttling...", atomic_read(&kmod_concurrent_max), diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 36470990b2e6e..1ae1be0fde473 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -2111,6 +2111,15 @@ static struct ctl_table kern_table[] = { .extra1 = SYSCTL_ONE, .extra2 = SYSCTL_ONE, }, + { + .procname = "modharden", + .data = &modharden, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE, + }, #endif #ifdef CONFIG_UEVENT_HELPER { diff --git a/security/Kconfig b/security/Kconfig index ccae931a1c6cf..7aad2565a37a3 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -42,6 +42,28 @@ config SECURITY_TIOCSTI_RESTRICT If you are unsure how to answer this question, answer N. +config SECURITY_MODHARDEN + bool "Harden module auto-loading" + default n + depends on MODULES + help + If you say Y here, module auto-loading in response to use of some + feature implemented by an unloaded module will be restricted to + CAP_SYS_MODULE. Enabling this option helps defend against attacks + by unprivileged users who abuse the auto-loading behavior to + cause a vulnerable module to load that is then exploited. + + If this option prevents a legitimate use of auto-loading for a + non-root user, the administrator can execute modprobe manually + with the exact name of the module mentioned in the alert log. + Alternatively, the administrator can add the module to the list + of modules loaded at boot by modifying init scripts. + + This setting can be overridden at runtime via the + kernel.modharden sysctl. + + If unsure say N. + config SECURITY bool "Enable different security models" depends on SYSFS