wireless: Add missing locking to cfg80211_dev_rename

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>
This commit is contained in:
Eric W. Biederman 2008-05-08 14:30:18 -07:00 committed by John W. Linville
parent 601ae7f25a
commit 2940bb69fd

View File

@ -143,8 +143,11 @@ void cfg80211_put_dev(struct cfg80211_registered_device *drv)
int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
char *newname) char *newname)
{ {
struct cfg80211_registered_device *drv;
int idx, taken = -1, result, digits; int idx, taken = -1, result, digits;
mutex_lock(&cfg80211_drv_mutex);
/* prohibit calling the thing phy%d when %d is not its number */ /* prohibit calling the thing phy%d when %d is not its number */
sscanf(newname, PHY_NAME "%d%n", &idx, &taken); sscanf(newname, PHY_NAME "%d%n", &idx, &taken);
if (taken == strlen(newname) && idx != rdev->idx) { 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 * deny the name if it is phy<idx> where <idx> is printed
* without leading zeroes. taken == strlen(newname) here * without leading zeroes. taken == strlen(newname) here
*/ */
result = -EINVAL;
if (taken == strlen(PHY_NAME) + digits) if (taken == strlen(PHY_NAME) + digits)
return -EINVAL; goto out_unlock;
} }
/* this will check for collisions */
/* 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 only check for collisions in sysfs
* which is not even always compiled in.
*/
result = device_rename(&rdev->wiphy.dev, newname); result = device_rename(&rdev->wiphy.dev, newname);
if (result) if (result)
return result; goto out_unlock;
if (!debugfs_rename(rdev->wiphy.debugfsdir->d_parent, if (!debugfs_rename(rdev->wiphy.debugfsdir->d_parent,
rdev->wiphy.debugfsdir, 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", printk(KERN_ERR "cfg80211: failed to rename debugfs dir to %s!\n",
newname); 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 */ /* exported functions */