diff options
author | Daniel Lezcano <daniel.lezcano@free.fr> | 2010-05-19 06:12:19 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-05-24 02:24:36 -0400 |
commit | 8ce6cebc2f126f3ecf2d80746ea54245adf18057 (patch) | |
tree | 6efcd84b0a8d00aede2c52944bc8eaecc02e67de /net | |
parent | a4ed89cb92f93d406ac45fe5507228a2475e32ba (diff) |
net-2.6 : V2 - fix dev_get_valid_name
the commit:
commit d90310243fd750240755e217c5faa13e24f41536
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>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/dev.c | 20 |
1 files changed, 12 insertions, 8 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 0aab66d68b19..07a48e2bf7db 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -954,18 +954,22 @@ int dev_alloc_name(struct net_device *dev, const char *name) | |||
954 | } | 954 | } |
955 | EXPORT_SYMBOL(dev_alloc_name); | 955 | EXPORT_SYMBOL(dev_alloc_name); |
956 | 956 | ||
957 | static int dev_get_valid_name(struct net *net, const char *name, char *buf, | 957 | static int dev_get_valid_name(struct net_device *dev, const char *name, bool fmt) |
958 | bool fmt) | ||
959 | { | 958 | { |
959 | struct net *net; | ||
960 | |||
961 | BUG_ON(!dev_net(dev)); | ||
962 | net = dev_net(dev); | ||
963 | |||
960 | if (!dev_valid_name(name)) | 964 | if (!dev_valid_name(name)) |
961 | return -EINVAL; | 965 | return -EINVAL; |
962 | 966 | ||
963 | if (fmt && strchr(name, '%')) | 967 | if (fmt && strchr(name, '%')) |
964 | return __dev_alloc_name(net, name, buf); | 968 | return dev_alloc_name(dev, name); |
965 | else if (__dev_get_by_name(net, name)) | 969 | else if (__dev_get_by_name(net, name)) |
966 | return -EEXIST; | 970 | return -EEXIST; |
967 | else if (buf != name) | 971 | else if (dev->name != name) |
968 | strlcpy(buf, name, IFNAMSIZ); | 972 | strlcpy(dev->name, name, IFNAMSIZ); |
969 | 973 | ||
970 | return 0; | 974 | return 0; |
971 | } | 975 | } |
@@ -997,7 +1001,7 @@ int dev_change_name(struct net_device *dev, const char *newname) | |||
997 | 1001 | ||
998 | memcpy(oldname, dev->name, IFNAMSIZ); | 1002 | memcpy(oldname, dev->name, IFNAMSIZ); |
999 | 1003 | ||
1000 | err = dev_get_valid_name(net, newname, dev->name, 1); | 1004 | err = dev_get_valid_name(dev, newname, 1); |
1001 | if (err < 0) | 1005 | if (err < 0) |
1002 | return err; | 1006 | return err; |
1003 | 1007 | ||
@@ -4965,7 +4969,7 @@ int register_netdevice(struct net_device *dev) | |||
4965 | } | 4969 | } |
4966 | } | 4970 | } |
4967 | 4971 | ||
4968 | ret = dev_get_valid_name(net, dev->name, dev->name, 0); | 4972 | ret = dev_get_valid_name(dev, dev->name, 0); |
4969 | if (ret) | 4973 | if (ret) |
4970 | goto err_uninit; | 4974 | goto err_uninit; |
4971 | 4975 | ||
@@ -5574,7 +5578,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char | |||
5574 | /* We get here if we can't use the current device name */ | 5578 | /* We get here if we can't use the current device name */ |
5575 | if (!pat) | 5579 | if (!pat) |
5576 | goto out; | 5580 | goto out; |
5577 | if (dev_get_valid_name(net, pat, dev->name, 1)) | 5581 | if (dev_get_valid_name(dev, pat, 1)) |
5578 | goto out; | 5582 | goto out; |
5579 | } | 5583 | } |
5580 | 5584 | ||