Skip to contentSkip to conversation

cfg80211: fix race between sysfs and cfg80211

RFC In review Maxime Bizon 3 participants 11 messages Jul 17, 2010 – Aug 16, 2010 802.11 (including cfg80211/NL80211)

lore
Share & tools
lore
#0 lore raw

RFC 1/1 cfg80211: fix race between sysfs and cfg80211

device_add() is called before adding the phy to the cfg80211 device list.

So if a userspace program uses sysfs uevents to detect new phy devices, and queries nl80211 to get phy info, it can get ENODEV even though the phy exists in sysfs.

An easy workaround is to hold the cfg80211 mutex until the phy is present both in sysfs and cfg80211 device list.

---
 net/wireless/core.c |   12 ++++++++----
 1 files changed, 8 insertions(+), 4 deletions(-)
net/wireless/core.c +8 -4
index 6ac70c1..8952ec4 100644
@@ -472,15 +472,19 @@ int wiphy_register(struct wiphy *wiphy)
 	/* check and set up bitrates */
 	ieee80211_set_bitrate_flags(wiphy);
 
+	mutex_lock(&cfg80211_mutex);
+
 	res = device_add(&rdev->wiphy.dev);
-	if (res)
+	if (res) {
+		mutex_unlock(&cfg80211_mutex);
 		return res;
+	}
 
 	res = rfkill_register(rdev->rfkill);
-	if (res)
+	if (res) {
+		mutex_unlock(&cfg80211_mutex);
 		goto out_rm_dev;
-
-	mutex_lock(&cfg80211_mutex);
+	}
 
 	/* set up regulatory info */
 	wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
Signature · 6 lines
1.7.1



-- 
Maxime
maintainer
#1 lore raw
Quoted 9 lines · Maxime Bizon

device_add() is called before adding the phy to the cfg80211 device list.

So if a userspace program uses sysfs uevents to detect new phy devices, and queries nl80211 to get phy info, it can get ENODEV even though the phy exists in sysfs.

An easy workaround is to hold the cfg80211 mutex until the phy is present both in sysfs and cfg80211 device list.

Maybe we should hold the mutex around the debugfs stuff as well? Then tools could even access that race-free, and we can simplify the code by having an "out_unlock" label.

johannes

#2 lore raw
Quoted 3 lines · Johannes Berg

Maybe we should hold the mutex around the debugfs stuff as well? Then tools could even access that race-free, and we can simplify the code by having an "out_unlock" label.

device_add() is called before adding the phy to the cfg80211 device list.

So if a userspace program uses sysfs uevents to detect new phy devices, and queries nl80211 to get phy info, it can get ENODEV even though the phy exists in sysfs.

An easy workaround is to hold the cfg80211 mutex until the phy is present both in sysfs and cfg80211 device list.

---
 net/wireless/core.c |   14 ++++++++------
 1 files changed, 8 insertions(+), 6 deletions(-)
net/wireless/core.c +8 -6
index 6ac70c1..fd164db 100644
@@ -472,24 +472,22 @@ int wiphy_register(struct wiphy *wiphy)
 	/* check and set up bitrates */
 	ieee80211_set_bitrate_flags(wiphy);
 
+	mutex_lock(&cfg80211_mutex);
+
 	res = device_add(&rdev->wiphy.dev);
 	if (res)
-		return res;
+		goto out_unlock;
 
 	res = rfkill_register(rdev->rfkill);
 	if (res)
 		goto out_rm_dev;
 
-	mutex_lock(&cfg80211_mutex);
-
 	/* set up regulatory info */
 	wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
 
 	list_add_rcu(&rdev->list, &cfg80211_rdev_list);
 	cfg80211_rdev_list_generation++;
 
-	mutex_unlock(&cfg80211_mutex);
-
 	/* add to debugfs */
 	rdev->wiphy.debugfsdir =
 		debugfs_create_dir(wiphy_name(&rdev->wiphy),
@@ -509,11 +507,15 @@ int wiphy_register(struct wiphy *wiphy)
 	}
 
 	cfg80211_debugfs_rdev_add(rdev);
+	mutex_unlock(&cfg80211_mutex);
 
 	return 0;
 
- out_rm_dev:
+out_rm_dev:
 	device_del(&rdev->wiphy.dev);
+
+out_unlock:
+	mutex_unlock(&cfg80211_mutex);
 	return res;
 }
 EXPORT_SYMBOL(wiphy_register);
Signature · 7 lines
1.7.1




-- 
Maxime
#3 lore raw
In reply to Johannes Berg

On Sat, 2010-07-17 at 21:29 +0200, Johannes Berg wrote:

Hi Johannes,

Quoted 3 lines

Maybe we should hold the mutex around the debugfs stuff as well? Then tools could even access that race-free, and we can simplify the code by having an "out_unlock" label.

Any comment on the last patch I sent ?

Thanks !

Signature · 1 line
Maxime
#4 lore raw

PATCH 1/1 cfg80211: fix race between sysfs and cfg80211

In reply to Johannes Berg

From: Maxime Bizon <[email protected]>

device_add() is called before adding the phy to the cfg80211 device list.

So if a userspace program uses sysfs uevents to detect new phy devices, and queries nl80211 to get phy info, it can get ENODEV even though the phy exists in sysfs.

An easy workaround is to hold the cfg80211 mutex until the phy is present in sysfs/cfg80211/debugfs.

---
 net/wireless/core.c |   14 ++++++++------
 1 files changed, 8 insertions(+), 6 deletions(-)
net/wireless/core.c +8 -6
index 6ac70c1..fd164db 100644
@@ -472,24 +472,22 @@ int wiphy_register(struct wiphy *wiphy)
 	/* check and set up bitrates */
 	ieee80211_set_bitrate_flags(wiphy);
 
+	mutex_lock(&cfg80211_mutex);
+
 	res = device_add(&rdev->wiphy.dev);
 	if (res)
-		return res;
+		goto out_unlock;
 
 	res = rfkill_register(rdev->rfkill);
 	if (res)
 		goto out_rm_dev;
 
-	mutex_lock(&cfg80211_mutex);
-
 	/* set up regulatory info */
 	wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
 
 	list_add_rcu(&rdev->list, &cfg80211_rdev_list);
 	cfg80211_rdev_list_generation++;
 
-	mutex_unlock(&cfg80211_mutex);
-
 	/* add to debugfs */
 	rdev->wiphy.debugfsdir =
 		debugfs_create_dir(wiphy_name(&rdev->wiphy),
@@ -509,11 +507,15 @@ int wiphy_register(struct wiphy *wiphy)
 	}
 
 	cfg80211_debugfs_rdev_add(rdev);
+	mutex_unlock(&cfg80211_mutex);
 
 	return 0;
 
- out_rm_dev:
+out_rm_dev:
 	device_del(&rdev->wiphy.dev);
+
+out_unlock:
+	mutex_unlock(&cfg80211_mutex);
 	return res;
 }
 EXPORT_SYMBOL(wiphy_register);
Signature · 6 lines
1.7.1



-- 
Maxime
#5 lore raw
Quoted 9 lines · Maxime Bizon

From: Maxime Bizon <[email protected]>

device_add() is called before adding the phy to the cfg80211 device list.

So if a userspace program uses sysfs uevents to detect new phy devices, and queries nl80211 to get phy info, it can get ENODEV even though the phy exists in sysfs.

Quoted 5 lines

An easy workaround is to hold the cfg80211 mutex until the phy is present in sysfs/cfg80211/debugfs.

---

You should resubmit as a new e-mail with a subject of [PATCH v2].

Luis

#6 lore raw

PATCH v2 1/1 cfg80211: fix race between sysfs and cfg80211

In reply to Johannes Berg

From: Maxime Bizon <[email protected]>

device_add() is called before adding the phy to the cfg80211 device list.

So if a userspace program uses sysfs uevents to detect new phy devices, and queries nl80211 to get phy info, it can get ENODEV even though the phy exists in sysfs.

An easy workaround is to hold the cfg80211 mutex until the phy is present in sysfs/cfg80211/debugfs.

---
 net/wireless/core.c |   14 ++++++++------
 1 files changed, 8 insertions(+), 6 deletions(-)
net/wireless/core.c +8 -6
index 6ac70c1..fd164db 100644
@@ -472,24 +472,22 @@ int wiphy_register(struct wiphy *wiphy)
 	/* check and set up bitrates */
 	ieee80211_set_bitrate_flags(wiphy);
 
+	mutex_lock(&cfg80211_mutex);
+
 	res = device_add(&rdev->wiphy.dev);
 	if (res)
-		return res;
+		goto out_unlock;
 
 	res = rfkill_register(rdev->rfkill);
 	if (res)
 		goto out_rm_dev;
 
-	mutex_lock(&cfg80211_mutex);
-
 	/* set up regulatory info */
 	wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
 
 	list_add_rcu(&rdev->list, &cfg80211_rdev_list);
 	cfg80211_rdev_list_generation++;
 
-	mutex_unlock(&cfg80211_mutex);
-
 	/* add to debugfs */
 	rdev->wiphy.debugfsdir =
 		debugfs_create_dir(wiphy_name(&rdev->wiphy),
@@ -509,11 +507,15 @@ int wiphy_register(struct wiphy *wiphy)
 	}
 
 	cfg80211_debugfs_rdev_add(rdev);
+	mutex_unlock(&cfg80211_mutex);
 
 	return 0;
 
- out_rm_dev:
+out_rm_dev:
 	device_del(&rdev->wiphy.dev);
+
+out_unlock:
+	mutex_unlock(&cfg80211_mutex);
 	return res;
 }
 EXPORT_SYMBOL(wiphy_register);
Signature · 6 lines
1.7.1



-- 
Maxime
#7 lore raw

On Fri, 2010-07-23 at 04:29 +0200, Maxime Bizon wrote:

Hi,

Quoted 1 line

From: Maxime Bizon <[email protected]>

Any comment/ACK/NACK on this ?

Thanks,

Signature · 1 line
Maxime
maintainer
#8 lore raw
Quoted 7 lines · Maxime Bizon

On Fri, 2010-07-23 at 04:29 +0200, Maxime Bizon wrote:

Hi,

Quoted 1 line

From: Maxime Bizon <[email protected]>

Any comment/ACK/NACK on this ?

Err, it was merged a long time ago

johannes

#9 lore raw
Quoted 1 line · Johannes Berg

Err, it was merged a long time ago

I'm hitting another race now, it appeared after I disabled CONFIG_CRYPTO_MANAGER_TESTS (new option in 2.6.35.2).

I have a userspace daemon that listen for new phy event, and create and configure an AP interface just after it gets the event.

The driver is still inside ieee80211_register_hw(), but the userspace is able to create the AP interface before the call is over. Once wiphy_register() is done, no lock seems to prevent this from happening.

ieee80211_init_rate_ctrl_alg() then fails with EBUSY, and ieee80211_register_hw() starts unregistering the phy.

Is that expected ?

I was able to get past it by taking rtnl lock before wiphy_register()

Signature · 1 line
Maxime
maintainer
#10 lore raw
Quoted 8 lines · Maxime Bizon

The driver is still inside ieee80211_register_hw(), but the userspace is able to create the AP interface before the call is over. Once wiphy_register() is done, no lock seems to prevent this from happening.

ieee80211_init_rate_ctrl_alg() then fails with EBUSY, and ieee80211_register_hw() starts unregistering the phy.

Is that expected ?

Oops. No, not really, but I think the problem is that we do wiphy_register far too early. I think we should see if we can reorder the code in register_hw(). It won't be perfect wrt. debugfs, but I don't think that is a problem.

johannes