]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
net: don't allow CAP_NET_ADMIN to load non-netdev kernel modules
authorVasiliy Kulikov <segoon@openwall.com>
Tue, 1 Mar 2011 21:33:13 +0000 (00:33 +0300)
committerPaul Gortmaker <paul.gortmaker@windriver.com>
Sun, 17 Apr 2011 20:16:16 +0000 (16:16 -0400)
commit 8909c9ad8ff03611c9c96c9a92656213e4bb495b upstream.

Since a8f80e8ff94ecba629542d9b4b5f5a8ee3eb565c any process with
CAP_NET_ADMIN may load any module from /lib/modules/.  This doesn't mean
that CAP_NET_ADMIN is a superset of CAP_SYS_MODULE as modules are
limited to /lib/modules/**.  However, CAP_NET_ADMIN capability shouldn't
allow anybody load any module not related to networking.

This patch restricts an ability of autoloading modules to netdev modules
with explicit aliases.  This fixes CVE-2011-1019.

Arnd Bergmann suggested to leave untouched the old pre-v2.6.32 behavior
of loading netdev modules by name (without any prefix) for processes
with CAP_SYS_MODULE to maintain the compatibility with network scripts
that use autoloading netdev modules by aliases like "eth0", "wlan0".

Currently there are only three users of the feature in the upstream
kernel: ipip, ip_gre and sit.

    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

[PG: in 2.6.34, the bare MODULE_ALIAS for ipip/tunl0 and ip_gre/gre0
didn't exist, but this adds the limited scope MODULE_ALIAS_NETDEV ones]

Signed-off-by: Vasiliy Kulikov <segoon@openwall.com>
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
Acked-by: David S. Miller <davem@davemloft.net>
Acked-by: Kees Cook <kees.cook@canonical.com>
Signed-off-by: James Morris <jmorris@namei.org>
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
include/linux/netdevice.h
net/core/dev.c
net/ipv4/ip_gre.c
net/ipv4/ipip.c
net/ipv6/sit.c

index 473799698bc8a919407cc51af2f84930fae6ff44..0af14f2330f94af1c5a70fafbb1f1d6886a6ec8c 100644 (file)
@@ -2214,6 +2214,9 @@ do {                                                              \
 #define netif_info(priv, type, dev, fmt, args...)              \
        netif_printk(priv, type, KERN_INFO, (dev), fmt, ##args)
 
+#define MODULE_ALIAS_NETDEV(device) \
+       MODULE_ALIAS("netdev-" device)
+
 #if defined(DEBUG)
 #define netif_dbg(priv, type, dev, format, args...)            \
        netif_printk(priv, type, KERN_DEBUG, dev, format, ##args)
index f6641773944822ae0256e3528a78f6c2ae94e7d4..309593439ae476c6454c4d3a70877c6e46df635e 100644 (file)
@@ -1104,13 +1104,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);
 
index fe381d12ecdd4227e785ff54f6e0b97162914f55..6be6fe7c711454ae2644a3369ad5782024ed254d 100644 (file)
@@ -1709,3 +1709,4 @@ module_exit(ipgre_fini);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_RTNL_LINK("gre");
 MODULE_ALIAS_RTNL_LINK("gretap");
+MODULE_ALIAS_NETDEV("gre0");
index 0b27b14dcc9d65e6545327ef98a3ece61419214f..8900fdeb8294a40e34c1c21c863b982727b6516b 100644 (file)
@@ -853,3 +853,4 @@ static void __exit ipip_fini(void)
 module_init(ipip_init);
 module_exit(ipip_fini);
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_NETDEV("tunl0");
index 5abae10cd8844c8d2acb30ceced10055dbdf3856..5316ce5f77310189b32856c38fa36953e79c7104 100644 (file)
@@ -1241,4 +1241,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");