dect
/
linux-2.6
Archived
13
0
Fork 0

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
1 changed files with 12 additions and 8 deletions

View File

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