wireless: Add missing locking to cfg80211_dev_rename
authorEric W. Biederman <ebiederm@xmission.com>
Thu, 8 May 2008 21:30:18 +0000 (14:30 -0700)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 14 May 2008 20:29:49 +0000 (16:29 -0400)
device_rename only performs useful and race free validity
checking at the optional sysfs level so depending on it
for all of the validity checking in cfg80211_dev_rename
is racy.

Instead implement all of the needed validity checking
and locking in cfg80211_dev_rename.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Acked-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
net/wireless/core.c

index 80afacd..f1da0b9 100644 (file)
@@ -143,8 +143,11 @@ void cfg80211_put_dev(struct cfg80211_registered_device *drv)
 int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
                        char *newname)
 {
+       struct cfg80211_registered_device *drv;
        int idx, taken = -1, result, digits;
 
+       mutex_lock(&cfg80211_drv_mutex);
+
        /* prohibit calling the thing phy%d when %d is not its number */
        sscanf(newname, PHY_NAME "%d%n", &idx, &taken);
        if (taken == strlen(newname) && idx != rdev->idx) {
@@ -156,14 +159,30 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
                 * deny the name if it is phy<idx> where <idx> is printed
                 * without leading zeroes. taken == strlen(newname) here
                 */
+               result = -EINVAL;
                if (taken == strlen(PHY_NAME) + digits)
-                       return -EINVAL;
+                       goto out_unlock;
+       }
+
+
+       /* Ignore nop renames */
+       result = 0;
+       if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0)
+               goto out_unlock;
+
+       /* Ensure another device does not already have this name. */
+       list_for_each_entry(drv, &cfg80211_drv_list, list) {
+               result = -EINVAL;
+               if (strcmp(newname, dev_name(&drv->wiphy.dev)) == 0)
+                       goto out_unlock;
        }
 
-       /* this will check for collisions */
+       /* this will only check for collisions in sysfs
+        * which is not even always compiled in.
+        */
        result = device_rename(&rdev->wiphy.dev, newname);
        if (result)
-               return result;
+               goto out_unlock;
 
        if (!debugfs_rename(rdev->wiphy.debugfsdir->d_parent,
                            rdev->wiphy.debugfsdir,
@@ -172,9 +191,13 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
                printk(KERN_ERR "cfg80211: failed to rename debugfs dir to %s!\n",
                       newname);
 
-       nl80211_notify_dev_rename(rdev);
+       result = 0;
+out_unlock:
+       mutex_unlock(&cfg80211_drv_mutex);
+       if (result == 0)
+               nl80211_notify_dev_rename(rdev);
 
-       return 0;
+       return result;
 }
 
 /* exported functions */