Search Linux Wireless

[PATCH v2] wext: fix get_wireless_stats locking

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Currently, get_wireless_stats is racy by _design_. This is
because it returns a buffer, which needs to be statically
allocated since it cannot be freed if it was allocated
dynamically. Also, SIOCGIWSTATS and /proc/net/wireless use
no common lock, and /proc/net/wireless accesses are not
synchronised against each other. This is a design flaw in
get_wireless_stats since the beginning.

This patch fixes it by wrapping /proc/net/wireless accesses
with the RTNL so they are protected against each other and
SIOCGIWSTATS. The more correct method of fixing this would
be to pass in the buffer instead of returning it and have
the caller take care of synchronisation of the buffer, but
even then most drivers probably assume that their callback
is protected by the RTNL like all other wext callbacks.

Signed-off-by: Johannes Berg <johannes@xxxxxxxxxxxxxxxx>
---
v2: don't hold lock across open/release but rather start/stop

 net/wireless/wext.c |   22 ++++++++++++++++++----
 1 file changed, 18 insertions(+), 4 deletions(-)

--- wireless-testing.orig/net/wireless/wext.c	2009-05-11 13:34:00.000000000 +0200
+++ wireless-testing/net/wireless/wext.c	2009-05-11 16:02:31.000000000 +0200
@@ -649,14 +649,28 @@ static int wireless_seq_show(struct seq_
 	return 0;
 }
 
+static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos)
+	__acquires(dev_base_lock)
+{
+	rtnl_lock();
+	return dev_seq_start(seq, pos);
+}
+
+static void wireless_dev_seq_stop(struct seq_file *seq, void *v)
+	__releases(dev_base_lock)
+{
+	dev_seq_stop(seq, v);
+	rtnl_unlock();
+}
+
 static const struct seq_operations wireless_seq_ops = {
-	.start = dev_seq_start,
+	.start = wireless_dev_seq_start,
 	.next  = dev_seq_next,
-	.stop  = dev_seq_stop,
+	.stop  = wireless_dev_seq_stop,
 	.show  = wireless_seq_show,
 };
 
-static int wireless_seq_open(struct inode *inode, struct file *file)
+static int seq_open_wireless(struct inode *inode, struct file *file)
 {
 	return seq_open_net(inode, file, &wireless_seq_ops,
 			    sizeof(struct seq_net_private));
@@ -664,7 +678,7 @@ static int wireless_seq_open(struct inod
 
 static const struct file_operations wireless_seq_fops = {
 	.owner	 = THIS_MODULE,
-	.open    = wireless_seq_open,
+	.open    = seq_open_wireless,
 	.read    = seq_read,
 	.llseek  = seq_lseek,
 	.release = seq_release_net,


--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux