| From 8909c9ad8ff03611c9c96c9a92656213e4bb495b Mon Sep 17 00:00:00 2001 |
| From: Vasiliy Kulikov <segoon@openwall.com> |
| Date: Wed, 2 Mar 2011 00:33:13 +0300 |
| Subject: net: don't allow CAP_NET_ADMIN to load non-netdev kernel modules |
| |
| From: Vasiliy Kulikov <segoon@openwall.com> |
| |
| 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 |
| |
| 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: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| include/linux/netdevice.h | 4 ++++ |
| net/core/dev.c | 12 ++++++++++-- |
| net/ipv4/ip_gre.c | 1 + |
| net/ipv4/ipip.c | 1 + |
| net/ipv6/sit.c | 2 +- |
| 5 files changed, 17 insertions(+), 3 deletions(-) |
| |
| --- a/include/linux/netdevice.h |
| +++ b/include/linux/netdevice.h |
| @@ -2015,6 +2015,10 @@ static inline u32 dev_ethtool_get_flags( |
| return 0; |
| return dev->ethtool_ops->get_flags(dev); |
| } |
| + |
| +#define MODULE_ALIAS_NETDEV(device) \ |
| + MODULE_ALIAS("netdev-" device) |
| + |
| #endif /* __KERNEL__ */ |
| |
| #endif /* _LINUX_NETDEVICE_H */ |
| --- a/net/core/dev.c |
| +++ b/net/core/dev.c |
| @@ -1037,13 +1037,21 @@ EXPORT_SYMBOL(netdev_bonding_change); |
| void dev_load(struct net *net, const char *name) |
| { |
| struct net_device *dev; |
| + int no_module; |
| |
| read_lock(&dev_base_lock); |
| dev = __dev_get_by_name(net, name); |
| read_unlock(&dev_base_lock); |
| |
| - 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); |
| |
| --- a/net/ipv4/ip_gre.c |
| +++ b/net/ipv4/ip_gre.c |
| @@ -1708,3 +1708,4 @@ module_exit(ipgre_fini); |
| MODULE_LICENSE("GPL"); |
| MODULE_ALIAS_RTNL_LINK("gre"); |
| MODULE_ALIAS_RTNL_LINK("gretap"); |
| +MODULE_ALIAS_NETDEV("gre0"); |
| --- a/net/ipv4/ipip.c |
| +++ b/net/ipv4/ipip.c |
| @@ -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"); |
| --- a/net/ipv6/sit.c |
| +++ b/net/ipv6/sit.c |
| @@ -1101,4 +1101,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"); |