Commit 20e61da7 authored by WANG Cong's avatar WANG Cong Committed by David S. Miller

ipv4: fail early when creating netdev named all or default

We create a proc dir for each network device, this will cause
conflicts when the devices have name "all" or "default".

Rather than emitting an ugly kernel warning, we could just
fail earlier by checking the device name.
Reported-by: default avatarStephane Chazelas <stephane.chazelas@gmail.com>
Cc: "David S. Miller" <davem@davemloft.net>
Signed-off-by: default avatarCong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9d7e3ea7
...@@ -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)
{ {
......
...@@ -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)
......
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