aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-05-11 10:06:36 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-05-11 15:24:07 -0400
commit7be69c0b9aa93ef655db4d46e5654996489d62f5 (patch)
treeae00a8c366c7cb3d8aad35acc9b16f8e2d355b02 /net
parente80cf8537ae54ec96c389055d6e9b0ef630c042d (diff)
wext: fix get_wireless_stats locking
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@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/wireless/wext.c22
1 files changed, 18 insertions, 4 deletions
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
index cb6a5bb85d80..dc5b47e84a3d 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext.c
@@ -649,14 +649,28 @@ static int wireless_seq_show(struct seq_file *seq, void *v)
649 return 0; 649 return 0;
650} 650}
651 651
652static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos)
653 __acquires(dev_base_lock)
654{
655 rtnl_lock();
656 return dev_seq_start(seq, pos);
657}
658
659static void wireless_dev_seq_stop(struct seq_file *seq, void *v)
660 __releases(dev_base_lock)
661{
662 dev_seq_stop(seq, v);
663 rtnl_unlock();
664}
665
652static const struct seq_operations wireless_seq_ops = { 666static const struct seq_operations wireless_seq_ops = {
653 .start = dev_seq_start, 667 .start = wireless_dev_seq_start,
654 .next = dev_seq_next, 668 .next = dev_seq_next,
655 .stop = dev_seq_stop, 669 .stop = wireless_dev_seq_stop,
656 .show = wireless_seq_show, 670 .show = wireless_seq_show,
657}; 671};
658 672
659static int wireless_seq_open(struct inode *inode, struct file *file) 673static int seq_open_wireless(struct inode *inode, struct file *file)
660{ 674{
661 return seq_open_net(inode, file, &wireless_seq_ops, 675 return seq_open_net(inode, file, &wireless_seq_ops,
662 sizeof(struct seq_net_private)); 676 sizeof(struct seq_net_private));
@@ -664,7 +678,7 @@ static int wireless_seq_open(struct inode *inode, struct file *file)
664 678
665static const struct file_operations wireless_seq_fops = { 679static const struct file_operations wireless_seq_fops = {
666 .owner = THIS_MODULE, 680 .owner = THIS_MODULE,
667 .open = wireless_seq_open, 681 .open = seq_open_wireless,
668 .read = seq_read, 682 .read = seq_read,
669 .llseek = seq_lseek, 683 .llseek = seq_lseek,
670 .release = seq_release_net, 684 .release = seq_release_net,