Commit 772e7023 authored by David S. Miller's avatar David S. Miller

Merge branch 'netdev-name'

Cong Wang says:

====================
net: forbid net devices named "all" "default" or "config"

/proc/sys/net/ipv[46]/conf/<dev> could conflict with
/proc/sys/net/ipv[46]/conf/(all|default). And /proc/net/vlan/<dev>
could conflict with /proc/net/vlan/config. Besides kernel warnings,
undefined behavior such as duplicated proc files also appears, therefore
we should forbid these names.

v2: introduce a helper function, suggested by Florian
    fix error handling for ipv6_add_dev() in addrconf_init()
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9d7e3ea7 9c5ff24f
...@@ -216,6 +216,12 @@ static inline int inet_is_local_reserved_port(struct net *net, int port) ...@@ -216,6 +216,12 @@ static inline int inet_is_local_reserved_port(struct net *net, int port)
return 0; return 0;
return test_bit(port, net->ipv4.sysctl_local_reserved_ports); return test_bit(port, net->ipv4.sysctl_local_reserved_ports);
} }
static inline bool sysctl_dev_name_is_allowed(const char *name)
{
return strcmp(name, "default") != 0 && strcmp(name, "all") != 0;
}
#else #else
static inline int inet_is_local_reserved_port(struct net *net, int port) static inline int inet_is_local_reserved_port(struct net *net, int port)
{ {
......
...@@ -325,23 +325,24 @@ static void vlan_transfer_features(struct net_device *dev, ...@@ -325,23 +325,24 @@ static void vlan_transfer_features(struct net_device *dev,
netdev_update_features(vlandev); netdev_update_features(vlandev);
} }
static void __vlan_device_event(struct net_device *dev, unsigned long event) static int __vlan_device_event(struct net_device *dev, unsigned long event)
{ {
int err = 0;
switch (event) { switch (event) {
case NETDEV_CHANGENAME: case NETDEV_CHANGENAME:
vlan_proc_rem_dev(dev); vlan_proc_rem_dev(dev);
if (vlan_proc_add_dev(dev) < 0) err = vlan_proc_add_dev(dev);
pr_warn("failed to change proc name for %s\n",
dev->name);
break; break;
case NETDEV_REGISTER: case NETDEV_REGISTER:
if (vlan_proc_add_dev(dev) < 0) err = vlan_proc_add_dev(dev);
pr_warn("failed to add proc entry for %s\n", dev->name);
break; break;
case NETDEV_UNREGISTER: case NETDEV_UNREGISTER:
vlan_proc_rem_dev(dev); vlan_proc_rem_dev(dev);
break; break;
} }
return err;
} }
static int vlan_device_event(struct notifier_block *unused, unsigned long event, static int vlan_device_event(struct notifier_block *unused, unsigned long event,
...@@ -356,8 +357,12 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, ...@@ -356,8 +357,12 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
bool last = false; bool last = false;
LIST_HEAD(list); LIST_HEAD(list);
if (is_vlan_dev(dev)) if (is_vlan_dev(dev)) {
__vlan_device_event(dev, event); int err = __vlan_device_event(dev, event);
if (err)
return notifier_from_errno(err);
}
if ((event == NETDEV_UP) && if ((event == NETDEV_UP) &&
(dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) { (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) {
......
...@@ -171,6 +171,8 @@ int vlan_proc_add_dev(struct net_device *vlandev) ...@@ -171,6 +171,8 @@ int vlan_proc_add_dev(struct net_device *vlandev)
struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev); struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev);
struct vlan_net *vn = net_generic(dev_net(vlandev), vlan_net_id); struct vlan_net *vn = net_generic(dev_net(vlandev), vlan_net_id);
if (!strcmp(vlandev->name, name_conf))
return -EINVAL;
vlan->dent = vlan->dent =
proc_create_data(vlandev->name, S_IFREG|S_IRUSR|S_IWUSR, proc_create_data(vlandev->name, S_IFREG|S_IRUSR|S_IWUSR,
vn->proc_vlan_dir, &vlandev_fops, vlandev); vn->proc_vlan_dir, &vlandev_fops, vlandev);
......
...@@ -180,11 +180,12 @@ static BLOCKING_NOTIFIER_HEAD(inetaddr_chain); ...@@ -180,11 +180,12 @@ static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
int destroy); int destroy);
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
static void devinet_sysctl_register(struct in_device *idev); static int devinet_sysctl_register(struct in_device *idev);
static void devinet_sysctl_unregister(struct in_device *idev); static void devinet_sysctl_unregister(struct in_device *idev);
#else #else
static void devinet_sysctl_register(struct in_device *idev) static int devinet_sysctl_register(struct in_device *idev)
{ {
return 0;
} }
static void devinet_sysctl_unregister(struct in_device *idev) static void devinet_sysctl_unregister(struct in_device *idev)
{ {
...@@ -232,6 +233,7 @@ EXPORT_SYMBOL(in_dev_finish_destroy); ...@@ -232,6 +233,7 @@ EXPORT_SYMBOL(in_dev_finish_destroy);
static struct in_device *inetdev_init(struct net_device *dev) static struct in_device *inetdev_init(struct net_device *dev)
{ {
struct in_device *in_dev; struct in_device *in_dev;
int err = -ENOMEM;
ASSERT_RTNL(); ASSERT_RTNL();
...@@ -252,7 +254,13 @@ static struct in_device *inetdev_init(struct net_device *dev) ...@@ -252,7 +254,13 @@ static struct in_device *inetdev_init(struct net_device *dev)
/* Account for reference dev->ip_ptr (below) */ /* Account for reference dev->ip_ptr (below) */
in_dev_hold(in_dev); in_dev_hold(in_dev);
devinet_sysctl_register(in_dev); err = devinet_sysctl_register(in_dev);
if (err) {
in_dev->dead = 1;
in_dev_put(in_dev);
in_dev = NULL;
goto out;
}
ip_mc_init_dev(in_dev); ip_mc_init_dev(in_dev);
if (dev->flags & IFF_UP) if (dev->flags & IFF_UP)
ip_mc_up(in_dev); ip_mc_up(in_dev);
...@@ -260,7 +268,7 @@ static struct in_device *inetdev_init(struct net_device *dev) ...@@ -260,7 +268,7 @@ static struct in_device *inetdev_init(struct net_device *dev)
/* we can receive as soon as ip_ptr is set -- do this last */ /* we can receive as soon as ip_ptr is set -- do this last */
rcu_assign_pointer(dev->ip_ptr, in_dev); rcu_assign_pointer(dev->ip_ptr, in_dev);
out: out:
return in_dev; return in_dev ?: ERR_PTR(err);
out_kfree: out_kfree:
kfree(in_dev); kfree(in_dev);
in_dev = NULL; in_dev = NULL;
...@@ -1347,8 +1355,8 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, ...@@ -1347,8 +1355,8 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
if (!in_dev) { if (!in_dev) {
if (event == NETDEV_REGISTER) { if (event == NETDEV_REGISTER) {
in_dev = inetdev_init(dev); in_dev = inetdev_init(dev);
if (!in_dev) if (IS_ERR(in_dev))
return notifier_from_errno(-ENOMEM); return notifier_from_errno(PTR_ERR(in_dev));
if (dev->flags & IFF_LOOPBACK) { if (dev->flags & IFF_LOOPBACK) {
IN_DEV_CONF_SET(in_dev, NOXFRM, 1); IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
IN_DEV_CONF_SET(in_dev, NOPOLICY, 1); IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
...@@ -2182,11 +2190,21 @@ static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf) ...@@ -2182,11 +2190,21 @@ static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf)
kfree(t); kfree(t);
} }
static void devinet_sysctl_register(struct in_device *idev) static int devinet_sysctl_register(struct in_device *idev)
{ {
neigh_sysctl_register(idev->dev, idev->arp_parms, NULL); int err;
__devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
if (!sysctl_dev_name_is_allowed(idev->dev->name))
return -EINVAL;
err = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL);
if (err)
return err;
err = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
&idev->cnf); &idev->cnf);
if (err)
neigh_sysctl_unregister(idev->arp_parms);
return err;
} }
static void devinet_sysctl_unregister(struct in_device *idev) static void devinet_sysctl_unregister(struct in_device *idev)
......
...@@ -108,11 +108,12 @@ static inline u32 cstamp_delta(unsigned long cstamp) ...@@ -108,11 +108,12 @@ static inline u32 cstamp_delta(unsigned long cstamp)
} }
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
static void addrconf_sysctl_register(struct inet6_dev *idev); static int addrconf_sysctl_register(struct inet6_dev *idev);
static void addrconf_sysctl_unregister(struct inet6_dev *idev); static void addrconf_sysctl_unregister(struct inet6_dev *idev);
#else #else
static inline void addrconf_sysctl_register(struct inet6_dev *idev) static inline int addrconf_sysctl_register(struct inet6_dev *idev)
{ {
return 0;
} }
static inline void addrconf_sysctl_unregister(struct inet6_dev *idev) static inline void addrconf_sysctl_unregister(struct inet6_dev *idev)
...@@ -310,16 +311,16 @@ static int snmp6_alloc_dev(struct inet6_dev *idev) ...@@ -310,16 +311,16 @@ static int snmp6_alloc_dev(struct inet6_dev *idev)
static struct inet6_dev *ipv6_add_dev(struct net_device *dev) static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
{ {
struct inet6_dev *ndev; struct inet6_dev *ndev;
int err = -ENOMEM;
ASSERT_RTNL(); ASSERT_RTNL();
if (dev->mtu < IPV6_MIN_MTU) if (dev->mtu < IPV6_MIN_MTU)
return NULL; return ERR_PTR(-EINVAL);
ndev = kzalloc(sizeof(struct inet6_dev), GFP_KERNEL); ndev = kzalloc(sizeof(struct inet6_dev), GFP_KERNEL);
if (ndev == NULL) if (ndev == NULL)
return NULL; return ERR_PTR(err);
rwlock_init(&ndev->lock); rwlock_init(&ndev->lock);
ndev->dev = dev; ndev->dev = dev;
...@@ -332,7 +333,7 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) ...@@ -332,7 +333,7 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl); ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl);
if (ndev->nd_parms == NULL) { if (ndev->nd_parms == NULL) {
kfree(ndev); kfree(ndev);
return NULL; return ERR_PTR(err);
} }
if (ndev->cnf.forwarding) if (ndev->cnf.forwarding)
dev_disable_lro(dev); dev_disable_lro(dev);
...@@ -346,17 +347,14 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) ...@@ -346,17 +347,14 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
neigh_parms_release(&nd_tbl, ndev->nd_parms); neigh_parms_release(&nd_tbl, ndev->nd_parms);
dev_put(dev); dev_put(dev);
kfree(ndev); kfree(ndev);
return NULL; return ERR_PTR(err);
} }
if (snmp6_register_dev(ndev) < 0) { if (snmp6_register_dev(ndev) < 0) {
ADBG(KERN_WARNING ADBG(KERN_WARNING
"%s: cannot create /proc/net/dev_snmp6/%s\n", "%s: cannot create /proc/net/dev_snmp6/%s\n",
__func__, dev->name); __func__, dev->name);
neigh_parms_release(&nd_tbl, ndev->nd_parms); goto err_release;
ndev->dead = 1;
in6_dev_finish_destroy(ndev);
return NULL;
} }
/* One reference from device. We must do this before /* One reference from device. We must do this before
...@@ -394,7 +392,12 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) ...@@ -394,7 +392,12 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
ipv6_mc_init_dev(ndev); ipv6_mc_init_dev(ndev);
ndev->tstamp = jiffies; ndev->tstamp = jiffies;
addrconf_sysctl_register(ndev); err = addrconf_sysctl_register(ndev);
if (err) {
ipv6_mc_destroy_dev(ndev);
del_timer(&ndev->regen_timer);
goto err_release;
}
/* protected by rtnl_lock */ /* protected by rtnl_lock */
rcu_assign_pointer(dev->ip6_ptr, ndev); rcu_assign_pointer(dev->ip6_ptr, ndev);
...@@ -409,6 +412,12 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev) ...@@ -409,6 +412,12 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters); ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters);
return ndev; return ndev;
err_release:
neigh_parms_release(&nd_tbl, ndev->nd_parms);
ndev->dead = 1;
in6_dev_finish_destroy(ndev);
return ERR_PTR(err);
} }
static struct inet6_dev *ipv6_find_idev(struct net_device *dev) static struct inet6_dev *ipv6_find_idev(struct net_device *dev)
...@@ -420,7 +429,7 @@ static struct inet6_dev *ipv6_find_idev(struct net_device *dev) ...@@ -420,7 +429,7 @@ static struct inet6_dev *ipv6_find_idev(struct net_device *dev)
idev = __in6_dev_get(dev); idev = __in6_dev_get(dev);
if (!idev) { if (!idev) {
idev = ipv6_add_dev(dev); idev = ipv6_add_dev(dev);
if (!idev) if (IS_ERR(idev))
return NULL; return NULL;
} }
...@@ -2830,8 +2839,8 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, ...@@ -2830,8 +2839,8 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
case NETDEV_REGISTER: case NETDEV_REGISTER:
if (!idev && dev->mtu >= IPV6_MIN_MTU) { if (!idev && dev->mtu >= IPV6_MIN_MTU) {
idev = ipv6_add_dev(dev); idev = ipv6_add_dev(dev);
if (!idev) if (IS_ERR(idev))
return notifier_from_errno(-ENOMEM); return notifier_from_errno(PTR_ERR(idev));
} }
break; break;
...@@ -2851,7 +2860,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, ...@@ -2851,7 +2860,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
if (!idev && dev->mtu >= IPV6_MIN_MTU) if (!idev && dev->mtu >= IPV6_MIN_MTU)
idev = ipv6_add_dev(dev); idev = ipv6_add_dev(dev);
if (idev) { if (!IS_ERR_OR_NULL(idev)) {
idev->if_flags |= IF_READY; idev->if_flags |= IF_READY;
run_pending = 1; run_pending = 1;
} }
...@@ -2894,7 +2903,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, ...@@ -2894,7 +2903,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
break; break;
} }
if (idev) { if (!IS_ERR_OR_NULL(idev)) {
if (run_pending) if (run_pending)
addrconf_dad_run(idev); addrconf_dad_run(idev);
...@@ -2929,7 +2938,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, ...@@ -2929,7 +2938,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
if (!idev && dev->mtu >= IPV6_MIN_MTU) { if (!idev && dev->mtu >= IPV6_MIN_MTU) {
idev = ipv6_add_dev(dev); idev = ipv6_add_dev(dev);
if (idev) if (!IS_ERR(idev))
break; break;
} }
...@@ -2950,10 +2959,14 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, ...@@ -2950,10 +2959,14 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
if (idev) { if (idev) {
snmp6_unregister_dev(idev); snmp6_unregister_dev(idev);
addrconf_sysctl_unregister(idev); addrconf_sysctl_unregister(idev);
addrconf_sysctl_register(idev); err = addrconf_sysctl_register(idev);
err = snmp6_register_dev(idev);
if (err) if (err)
return notifier_from_errno(err); return notifier_from_errno(err);
err = snmp6_register_dev(idev);
if (err) {
addrconf_sysctl_unregister(idev);
return notifier_from_errno(err);
}
} }
break; break;
...@@ -5248,12 +5261,23 @@ static void __addrconf_sysctl_unregister(struct ipv6_devconf *p) ...@@ -5248,12 +5261,23 @@ static void __addrconf_sysctl_unregister(struct ipv6_devconf *p)
kfree(t); kfree(t);
} }
static void addrconf_sysctl_register(struct inet6_dev *idev) static int addrconf_sysctl_register(struct inet6_dev *idev)
{ {
neigh_sysctl_register(idev->dev, idev->nd_parms, int err;
if (!sysctl_dev_name_is_allowed(idev->dev->name))
return -EINVAL;
err = neigh_sysctl_register(idev->dev, idev->nd_parms,
&ndisc_ifinfo_sysctl_change); &ndisc_ifinfo_sysctl_change);
__addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name, if (err)
return err;
err = __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name,
idev, &idev->cnf); idev, &idev->cnf);
if (err)
neigh_sysctl_unregister(idev->nd_parms);
return err;
} }
static void addrconf_sysctl_unregister(struct inet6_dev *idev) static void addrconf_sysctl_unregister(struct inet6_dev *idev)
...@@ -5338,6 +5362,7 @@ static struct rtnl_af_ops inet6_ops = { ...@@ -5338,6 +5362,7 @@ static struct rtnl_af_ops inet6_ops = {
int __init addrconf_init(void) int __init addrconf_init(void)
{ {
struct inet6_dev *idev;
int i, err; int i, err;
err = ipv6_addr_label_init(); err = ipv6_addr_label_init();
...@@ -5376,11 +5401,12 @@ int __init addrconf_init(void) ...@@ -5376,11 +5401,12 @@ int __init addrconf_init(void)
* device and it being up should be removed. * device and it being up should be removed.
*/ */
rtnl_lock(); rtnl_lock();
if (!ipv6_add_dev(init_net.loopback_dev)) idev = ipv6_add_dev(init_net.loopback_dev);
err = -ENOMEM;
rtnl_unlock(); rtnl_unlock();
if (err) if (IS_ERR(idev)) {
err = PTR_ERR(idev);
goto errlo; goto errlo;
}
for (i = 0; i < IN6_ADDR_HSIZE; i++) for (i = 0; i < IN6_ADDR_HSIZE; i++)
INIT_HLIST_HEAD(&inet6_addr_lst[i]); INIT_HLIST_HEAD(&inet6_addr_lst[i]);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment