|
@@ -180,11 +180,12 @@ static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
|
|
|
static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
|
|
|
int destroy);
|
|
|
#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);
|
|
|
#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)
|
|
|
{
|
|
@@ -232,6 +233,7 @@ EXPORT_SYMBOL(in_dev_finish_destroy);
|
|
|
static struct in_device *inetdev_init(struct net_device *dev)
|
|
|
{
|
|
|
struct in_device *in_dev;
|
|
|
+ int err = -ENOMEM;
|
|
|
|
|
|
ASSERT_RTNL();
|
|
|
|
|
@@ -252,7 +254,13 @@ static struct in_device *inetdev_init(struct net_device *dev)
|
|
|
/* Account for reference dev->ip_ptr (below) */
|
|
|
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);
|
|
|
if (dev->flags & IFF_UP)
|
|
|
ip_mc_up(in_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 */
|
|
|
rcu_assign_pointer(dev->ip_ptr, in_dev);
|
|
|
out:
|
|
|
- return in_dev;
|
|
|
+ return in_dev ?: ERR_PTR(err);
|
|
|
out_kfree:
|
|
|
kfree(in_dev);
|
|
|
in_dev = NULL;
|
|
@@ -1347,8 +1355,8 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
|
|
|
if (!in_dev) {
|
|
|
if (event == NETDEV_REGISTER) {
|
|
|
in_dev = inetdev_init(dev);
|
|
|
- if (!in_dev)
|
|
|
- return notifier_from_errno(-ENOMEM);
|
|
|
+ if (IS_ERR(in_dev))
|
|
|
+ return notifier_from_errno(PTR_ERR(in_dev));
|
|
|
if (dev->flags & IFF_LOOPBACK) {
|
|
|
IN_DEV_CONF_SET(in_dev, NOXFRM, 1);
|
|
|
IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);
|
|
@@ -2182,11 +2190,21 @@ static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf)
|
|
|
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);
|
|
|
- __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
|
|
|
+ int err;
|
|
|
+
|
|
|
+ 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);
|
|
|
+ if (err)
|
|
|
+ neigh_sysctl_unregister(idev->arp_parms);
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
static void devinet_sysctl_unregister(struct in_device *idev)
|