Thread (44 messages) 44 messages, 13 authors, 2011-03-26

Re: [PATCH v2] net: don't allow CAP_NET_ADMIN to load non-netdev kernel modules

From: Serge E. Hallyn <hidden>
Date: 2011-03-24 15:38:14
Also in: lkml

Quoting Eric Paris (eparis@parisplace.org):
On Tue, Mar 1, 2011 at 4:33 PM, Vasiliy Kulikov [off-list ref] wrote:
...
This patch is causing a bit of a problem in Fedora.  The problem lies
Sorry, what exactly is the problem it is causing?  I gather it's
spitting out printks?  What exactly do the printks say?  The patch
included at bottom checks for CAP_NET_ADMIN before checking for
CAP_SYS_MODULE, so these must be cases which historically always
quietly failed, and are now hitting the 'pr_err' which this patch
adds?

If it really is the capable(CAP_SYS_ADMIN) call itself, then there
must be a bug in the no_module logic in the patch.  Every
case where it's currently checking for capable(CAP_SYS_ADMIN)
(and potentially auditing a failure) should be one where in the past
it would have (and currently it still would) spit out an audit msg
for the capable(CAP_NET_ADMIN) failure anyway.

If it's just the pr_err that's causing problems, then perhaps we
can turn it into a warn_once?
mostly in the fact that we, by means of using SELinux, grant very very
few domains CAP_SYS_MODULE (and we record when domains attempt to use
this permission).  Unlike most other distros in which uid==0 is for
all intensive purposes == CAP_FULL_SET and there is no logging of
failures to use capabilities.  What happened is that as soon as we
instituted this change we started getting SELinux denials because lots
of domains (libvirt, udev, iw, NetworkManager) all the sudden started
trying to use CAP_SYS_MODULE.  It took me a minute to make sure this
patch was the problem because I wasn't seeing any printk messages.  I
had to make some changes to the patch to print every time a task got
into the CAP_SYS_MODULE case in order to get an idea what was causing
the problem.  I found on my machine I hit the problem 3 times trying
to load "reg", "wifi0", and "virbr0"    None of these are actual
modules in userspace so the upcall failed.

I'm trying to figure out how I should be dealing with this.

My first idea is changing the capable(CAP_SYS_MODULE) into a
has_capability_noaudit().  Which will not audit the access attempt.
I'm not sure I like that since it uses the read cred, it doesn't set
PF_SUPERPRIV, and it means we could likely miss recording a problem if
a task is doing this intentionally...

The next idea is I guess figuring out what's causing these and fix
them there, but I'm not certain a good way to debug it.  I know from
our audit logs that wpa_supplicant is calling SIOCGIFINDEX which is
causing one of these, libvirt is calling SIOCGIFFLAGS.  I'm not sure
what udev->iw is doing to trigger it's problem.....

If the name in question is not coming from direct userspace request I
guess I need help figuring out what is causing them....

So while this patch might not necessarily be breaking things it
certainly is not regression free and could potentially be breaking
systems with fine grained capabilities controls....

-Eric
quoted
   root@albatros:~# capsh --drop=$(seq -s, 0 11),$(seq -s, 13 34) --
   root@albatros:~# grep Cap /proc/$$/status
   CapInh:     0000000000000000
   CapPrm:     fffffff800001000
   CapEff:     fffffff800001000
   CapBnd:     fffffff800001000
   root@albatros:~# modprobe xfs
   FATAL: Error inserting xfs
   (/lib/modules/2.6.38-rc6-00001-g2bf4ca3/kernel/fs/xfs/xfs.ko): Operation not permitted
   root@albatros:~# lsmod | grep xfs
   root@albatros:~# ifconfig xfs
   xfs: error fetching interface information: Device not found
   root@albatros:~# lsmod | grep xfs
   root@albatros:~# lsmod | grep sit
   root@albatros:~# ifconfig sit
   sit: error fetching interface information: Device not found
   root@albatros:~# lsmod | grep sit
   root@albatros:~# ifconfig sit0
   sit0      Link encap:IPv6-in-IPv4
             NOARP  MTU:1480  Metric:1

   root@albatros:~# lsmod | grep sit
   sit                    10457  0
   tunnel4                 2957  1 sit

For CAP_SYS_MODULE module loading is still relaxed:

   root@albatros:~# grep Cap /proc/$$/status
   CapInh:     0000000000000000
   CapPrm:     ffffffffffffffff
   CapEff:     ffffffffffffffff
   CapBnd:     ffffffffffffffff
   root@albatros:~# ifconfig xfs
   xfs: error fetching interface information: Device not found
   root@albatros:~# lsmod | grep xfs
   xfs                   745319  0

Reference: https://lkml.org/lkml/2011/2/24/203

Signed-off-by: Vasiliy Kulikov <redacted>
---
 v2 - use pr_err()
   - don't try to load $name if netdev-$name is loaded

 include/linux/netdevice.h |    3 +++
 net/core/dev.c            |   12 ++++++++++--
 net/ipv4/ip_gre.c         |    2 +-
 net/ipv4/ipip.c           |    2 +-
 net/ipv6/sit.c            |    2 +-
 5 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index d971346..71caf7a 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2392,6 +2392,9 @@ extern int netdev_notice(const struct net_device *dev, const char *format, ...)
 extern int netdev_info(const struct net_device *dev, const char *format, ...)
       __attribute__ ((format (printf, 2, 3)));

+#define MODULE_ALIAS_NETDEV(device) \
+       MODULE_ALIAS("netdev-" device)
+
 #if defined(DEBUG)
 #define netdev_dbg(__dev, format, args...)                     \
       netdev_printk(KERN_DEBUG, __dev, format, ##args)
diff --git a/net/core/dev.c b/net/core/dev.c
index 8ae6631..6561021 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1114,13 +1114,21 @@ EXPORT_SYMBOL(netdev_bonding_change);
 void dev_load(struct net *net, const char *name)
 {
       struct net_device *dev;
+       int no_module;

       rcu_read_lock();
       dev = dev_get_by_name_rcu(net, name);
       rcu_read_unlock();

-       if (!dev && capable(CAP_NET_ADMIN))
-               request_module("%s", name);
+       no_module = !dev;
+       if (no_module && capable(CAP_NET_ADMIN))
+               no_module = request_module("netdev-%s", name);
+       if (no_module && capable(CAP_SYS_MODULE)) {
+               if (!request_module("%s", name))
+                       pr_err("Loading kernel module for a network device "
+"with CAP_SYS_MODULE (deprecated).  Use CAP_NET_ADMIN and alias netdev-%s "
+"instead\n", name);
+       }
 }
 EXPORT_SYMBOL(dev_load);
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 6613edf..d1d0e2c 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -1765,4 +1765,4 @@ module_exit(ipgre_fini);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_RTNL_LINK("gre");
 MODULE_ALIAS_RTNL_LINK("gretap");
-MODULE_ALIAS("gre0");
+MODULE_ALIAS_NETDEV("gre0");
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 988f52f..a5f58e7 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -913,4 +913,4 @@ static void __exit ipip_fini(void)
 module_init(ipip_init);
 module_exit(ipip_fini);
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("tunl0");
+MODULE_ALIAS_NETDEV("tunl0");
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 8ce38f1..d2c16e1 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -1290,4 +1290,4 @@ static int __init sit_init(void)
 module_init(sit_init);
 module_exit(sit_cleanup);
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("sit0");
+MODULE_ALIAS_NETDEV("sit0");
--
1.7.0.4
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Attachments

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help