net-2.6 : V2 - fix dev_get_valid_name

the commit:

commit d90310243f
Author: Octavian Purdila <opurdila@ixiacom.com>
Date:   Wed Nov 18 02:36:59 2009 +0000

    net: device name allocation cleanups

introduced a bug when there is a hash collision making impossible
to rename a device with eth%d. This bug is very hard to reproduce
and appears rarely.

The problem is coming from we don't pass a temporary buffer to
__dev_alloc_name but 'dev->name' which is modified by the function.

A detailed explanation is here:

http://marc.info/?l=linux-netdev&m=127417784011987&w=2

Changelog:
 V2 : replaced strings comparison by pointers comparison

Signed-off-by: Daniel Lezcano <daniel.lezcano@free.fr>
Reviewed-by: Octavian Purdila <opurdila@ixiacom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Daniel Lezcano 2010-05-19 10:12:19 +00:00 committed by David S. Miller
parent a4ed89cb92
commit 8ce6cebc2f

View File

@ -954,18 +954,22 @@ int dev_alloc_name(struct net_device *dev, const char *name)
}
EXPORT_SYMBOL(dev_alloc_name);
static int dev_get_valid_name(struct net *net, const char *name, char *buf,
bool fmt)
static int dev_get_valid_name(struct net_device *dev, const char *name, bool fmt)
{
struct net *net;
BUG_ON(!dev_net(dev));
net = dev_net(dev);
if (!dev_valid_name(name))
return -EINVAL;
if (fmt && strchr(name, '%'))
return __dev_alloc_name(net, name, buf);
return dev_alloc_name(dev, name);
else if (__dev_get_by_name(net, name))
return -EEXIST;
else if (buf != name)
strlcpy(buf, name, IFNAMSIZ);
else if (dev->name != name)
strlcpy(dev->name, name, IFNAMSIZ);
return 0;
}
@ -997,7 +1001,7 @@ int dev_change_name(struct net_device *dev, const char *newname)
memcpy(oldname, dev->name, IFNAMSIZ);
err = dev_get_valid_name(net, newname, dev->name, 1);
err = dev_get_valid_name(dev, newname, 1);
if (err < 0)
return err;
@ -4965,7 +4969,7 @@ int register_netdevice(struct net_device *dev)
}
}
ret = dev_get_valid_name(net, dev->name, dev->name, 0);
ret = dev_get_valid_name(dev, dev->name, 0);
if (ret)
goto err_uninit;
@ -5574,7 +5578,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
/* We get here if we can't use the current device name */
if (!pat)
goto out;
if (dev_get_valid_name(net, pat, dev->name, 1))
if (dev_get_valid_name(dev, pat, 1))
goto out;
}