2010-11-08 01:24:04

by Dan Rosenberg

[permalink] [raw]
Subject: [PATCH RFC] Restrictions on module loading

A significant portion of kernel vulnerabilities do not affect core code,
but rather individual modules. Unfortunately, there is no global kernel
setting to restrict unprivileged users from triggering the automatic
loading of kernel modules, for example by creating a socket using a
packet family that is compiled as a module and not already loaded. On
most distributions, this creates a significant attack surface, and
requires maintenance of blacklists and other inelegant solutions to a
general problem.

The below patch replaces the existing "modules_disable" sysctl with a
finer-grained "modules_restrict" sysctl. By default, this is set at 0,
which results in no deviation from normal module loading behavior. When
set to 1, unprivileged users cannot trigger the automatic loading of
modules. This behavior is based on grsecurity's GRKERNSEC_MODHARDEN
setting. The current check is against current_uid(), since several
distributions explicitly remove CAP_SYS_MODULE from root processes, some
of which incidentally cause (and rely on) the automatic loading of
modules. I expect this to be a point of discussion.

When set to 2, modules may not be loaded or unloaded by anyone, and the
sysctl may not be changed from that point forward. This is designed to
provide protection against kernel module rootkits.

Signed-off-by: Dan Rosenberg <[email protected]>
---
Documentation/sysctl/kernel.txt | 16 +++++++++-------
include/linux/module.h | 5 ++++-
kernel/kmod.c | 4 ++++
kernel/module.c | 21 ++++++++++++++++++---
kernel/sysctl.c | 11 +++++------
5 files changed, 40 insertions(+), 17 deletions(-)

diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
index 3894eaa..e000214 100644
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -36,7 +36,7 @@ show up in /proc/sys/kernel:
- kstack_depth_to_print [ X86 only ]
- l2cr [ PPC only ]
- modprobe ==> Documentation/debugging-modules.txt
-- modules_disabled
+- modules_restrict
- msgmax
- msgmnb
- msgmni
@@ -254,13 +254,15 @@ kernel stack.

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

-modules_disabled:
+modules_restrict:

-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.
+A value indicating if module loading is restricted in an
+otherwise modular kernel. This value defaults to off (0),
+but can be set to (1) or (2). If set to (1), modules cannot
+be auto-loaded by non-root users, for example by creating a
+socket using a packet family that is compiled as a module and
+not already loaded. If set to (2), modules can neither be
+loaded nor unloaded, and the value can no longer be changed.

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

diff --git a/include/linux/module.h b/include/linux/module.h
index b29e745..869039a 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -175,7 +175,10 @@ struct notifier_block;

#ifdef CONFIG_MODULES

-extern int modules_disabled; /* for sysctl */
+int module_proc_update_handler(struct ctl_table *table, int write,
+ void __user *buffer, size_t *length, loff_t *ppos);
+
+extern int modules_restrict; /* for sysctl */
/* Get/put a kernel symbol (calls must be symmetric) */
void *__symbol_get(const char *symbol);
void *__symbol_get_gpl(const char *symbol);
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 9cd0591..e2ab82b 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -90,6 +90,10 @@ int __request_module(bool wait, const char *fmt, ...)
if (ret)
return ret;

+ /* Can non-root users cause auto-loading of modules? */
+ if (current_uid() && modules_restrict)
+ return -EPERM;
+
/* If modprobe needs a service that is in a module, we get a recursive
* loop. Limit the number of running kmod threads to max_threads/2 or
* MAX_KMOD_CONCURRENT, whichever is the smaller. A cleaner method
diff --git a/kernel/module.c b/kernel/module.c
index 437a74a..cdc5c8c 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -56,6 +56,7 @@
#include <linux/percpu.h>
#include <linux/kmemleak.h>
#include <linux/jump_label.h>
+#include <linux/sysctl.h>

#define CREATE_TRACE_POINTS
#include <trace/events/module.h>
@@ -88,7 +89,7 @@ struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */


/* Block module loading/unloading? */
-int modules_disabled = 0;
+int modules_restrict = 0;

/* Waiting for a module to finish initializing? */
static DECLARE_WAIT_QUEUE_HEAD(module_wq);
@@ -125,6 +126,20 @@ struct load_info {
} index;
};

+/* Proc update handler for modules_restrict sysctl */
+int module_proc_update_handler(struct ctl_table *table, int write,
+ void __user *buffer, size_t *length, loff_t *ppos)
+{
+
+ /* If module loading is entirely disabled, do not allow
+ * it to be re-enabled. */
+ if (modules_restrict == 2)
+ return -EPERM;
+
+ return proc_dointvec_minmax(table, write, buffer, length, ppos);
+
+}
+
/* We require a truly strong try_module_get(): 0 means failure due to
ongoing or failed initialization etc. */
static inline int strong_try_module_get(struct module *mod)
@@ -734,7 +749,7 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
char name[MODULE_NAME_LEN];
int ret, forced = 0;

- if (!capable(CAP_SYS_MODULE) || modules_disabled)
+ if (!capable(CAP_SYS_MODULE) || (modules_restrict == 2))
return -EPERM;

if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0)
@@ -2699,7 +2714,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
int ret = 0;

/* Must have permission */
- if (!capable(CAP_SYS_MODULE) || modules_disabled)
+ if (!capable(CAP_SYS_MODULE) || (modules_restrict == 2))
return -EPERM;

/* Do all the hard work */
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index c33a1ed..37b7964 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -552,14 +552,13 @@ static struct ctl_table kern_table[] = {
.proc_handler = proc_dostring,
},
{
- .procname = "modules_disabled",
- .data = &modules_disabled,
+ .procname = "modules_restrict",
+ .data = &modules_restrict,
.maxlen = sizeof(int),
.mode = 0644,
- /* only handle a transition from default "0" to "1" */
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &one,
- .extra2 = &one,
+ .proc_handler = module_proc_update_handler,
+ .extra1 = &zero,
+ .extra2 = &two,
},
#endif
#ifdef CONFIG_HOTPLUG


2010-11-08 05:14:10

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH RFC] Restrictions on module loading

On Sun, Nov 07, 2010 at 08:23:59PM -0500, Dan Rosenberg wrote:
> A significant portion of kernel vulnerabilities do not affect core code,
> but rather individual modules. Unfortunately, there is no global kernel
> setting to restrict unprivileged users from triggering the automatic
> loading of kernel modules, for example by creating a socket using a
> packet family that is compiled as a module and not already loaded. On
> most distributions, this creates a significant attack surface, and
> requires maintenance of blacklists and other inelegant solutions to a
> general problem.
>
> The below patch replaces the existing "modules_disable" sysctl with a
> finer-grained "modules_restrict" sysctl. By default, this is set at 0,
> which results in no deviation from normal module loading behavior. When
> set to 1, unprivileged users cannot trigger the automatic loading of
> modules. This behavior is based on grsecurity's GRKERNSEC_MODHARDEN
> setting. The current check is against current_uid(), since several
> distributions explicitly remove CAP_SYS_MODULE from root processes, some
> of which incidentally cause (and rely on) the automatic loading of
> modules. I expect this to be a point of discussion.
>
> When set to 2, modules may not be loaded or unloaded by anyone, and the
> sysctl may not be changed from that point forward. This is designed to
> provide protection against kernel module rootkits.
>
> Signed-off-by: Dan Rosenberg <[email protected]>

Acked-by: Kees Cook <[email protected]>

This looks great to me. There will be a small amount of pain for people
that are already using modules_disabled=1, but I think the audience is so
small that it won't be a problem to switch to modules_restrict=2.

-Kees

--
Kees Cook
Ubuntu Security Team

2010-11-08 08:30:53

by Bodo Eggert

[permalink] [raw]
Subject: Re: [PATCH RFC] Restrictions on module loading

Dan Rosenberg <[email protected]> wrote:

> The below patch replaces the existing "modules_disable" sysctl with a
> finer-grained "modules_restrict" sysctl. By default, this is set at 0,
> which results in no deviation from normal module loading behavior. When
> set to 1, unprivileged users cannot trigger the automatic loading of
> modules. This behavior is based on grsecurity's GRKERNSEC_MODHARDEN
> setting. The current check is against current_uid(), since several
> distributions explicitly remove CAP_SYS_MODULE from root processes, some
> of which incidentally cause (and rely on) the automatic loading of
> modules. I expect this to be a point of discussion.

- Why don't you offer both?

- What about task switches or work queues?

- It might be more like the expected behavior if you'd used:
0: off, 1: modules completely disabled, 2: CAP_SYS_MODULE, 3: uid==0

Many users will forget to look into the documentation or find the current,
stale documentation or just assume a boolean value.

2010-11-08 10:21:37

by Alan

[permalink] [raw]
Subject: Re: [PATCH RFC] Restrictions on module loading

> loading of kernel modules, for example by creating a socket using a
> packet family that is compiled as a module and not already loaded. On
> most distributions, this creates a significant attack surface, and
> requires maintenance of blacklists and other inelegant solutions to a
> general problem.

Those inelegant solutions work rather better in a lot of situations
because most distributions will fall flat on their face if auto loading
isn't active and they are more flexible.

> The below patch replaces the existing "modules_disable" sysctl with a

NAK - Its a long standing ABI.

> When set to 2, modules may not be loaded or unloaded by anyone, and the
> sysctl may not be changed from that point forward. This is designed to
> provide protection against kernel module rootkits.

I've no objection to modules_restrict although I doubt it'll ever get
used in the real world, but better to extend the meaning of the existing
interface, not remove stuff.

If you have "security" in your address the please think like a security
person - users with security relying upon writing to modules_disable are
*not* going to notice a one line log entry somewhere about unable to open
{filename that doesn't look important}.

So your change is actually *bad* for security in its current form, you
remove the facilities they rely upon.

Alan

2010-11-08 11:34:11

by Andi Kleen

[permalink] [raw]
Subject: Re: [PATCH RFC] Restrictions on module loading

Bodo Eggert <[email protected]> writes:
>
> - What about task switches or work queues?

That's indeed a problem. All request_module()s would need auditing
and if there's any triggered from a workqueue a new interface
that passes the credentials around.

-Andi
--
[email protected] -- Speaking for myself only.

2010-11-08 12:23:43

by Dan Rosenberg

[permalink] [raw]
Subject: Re: [PATCH RFC] Restrictions on module loading


> NAK - Its a long standing ABI.

As far as I can tell, modules_disabled was first included in 2.6.31, so
it's hardly what I'd call "long standing". However, I see your point -
it's definitely not my intention to surprise anyone by changing security
features out from under them.

I do think merging the features makes sense in this case. I'll rework
this to keep the "modules_disabled" name, where a value of "0" means
default behavior, a value of "1" means no loading or unloading (and no
changing it back), and the new value of "2" incorporates the
restrictions I'm intending to enforce.

>
> I've no objection to modules_restrict although I doubt it'll ever get
> used in the real world, but better to extend the meaning of the existing
> interface, not remove stuff.
>

There has been interest in improving the ease with which users can
enforce restrictions on automatic module loading. No one is being
forced to use it.

-Dan

2010-11-08 14:01:01

by Alan

[permalink] [raw]
Subject: Re: [PATCH RFC] Restrictions on module loading

> As far as I can tell, modules_disabled was first included in 2.6.31, so
> it's hardly what I'd call "long standing". However, I see your point -

One year, two months, plus shipped in numerous major distributions.
That's long standing in the Linux world.

Alan

2010-11-09 05:43:01

by Eugene Teo

[permalink] [raw]
Subject: Re: [Security] [PATCH RFC] Restrictions on module loading

On Mon, Nov 8, 2010 at 9:23 AM, Dan Rosenberg <[email protected]> wrote:
[...]
> The below patch replaces the existing "modules_disable" sysctl with a
> finer-grained "modules_restrict" sysctl. ?By default, this is set at 0,

I suggest that we either keep the existing "modules_disable" sysctl
variable and build on top of it, or use another sysctl variable.

Thanks, Eugene