mirror of
https://github.com/adulau/aha.git
synced 2024-12-29 12:16:20 +00:00
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>
This commit is contained in:
parent
e80cf8537a
commit
7be69c0b9a
1 changed files with 18 additions and 4 deletions
|
@ -649,14 +649,28 @@ static int wireless_seq_show(struct seq_file *seq, void *v)
|
||||||
return 0;
|
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 = {
|
static const struct seq_operations wireless_seq_ops = {
|
||||||
.start = dev_seq_start,
|
.start = wireless_dev_seq_start,
|
||||||
.next = dev_seq_next,
|
.next = dev_seq_next,
|
||||||
.stop = dev_seq_stop,
|
.stop = wireless_dev_seq_stop,
|
||||||
.show = wireless_seq_show,
|
.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,
|
return seq_open_net(inode, file, &wireless_seq_ops,
|
||||||
sizeof(struct seq_net_private));
|
sizeof(struct seq_net_private));
|
||||||
|
@ -664,7 +678,7 @@ static int wireless_seq_open(struct inode *inode, struct file *file)
|
||||||
|
|
||||||
static const struct file_operations wireless_seq_fops = {
|
static const struct file_operations wireless_seq_fops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.open = wireless_seq_open,
|
.open = seq_open_wireless,
|
||||||
.read = seq_read,
|
.read = seq_read,
|
||||||
.llseek = seq_lseek,
|
.llseek = seq_lseek,
|
||||||
.release = seq_release_net,
|
.release = seq_release_net,
|
||||||
|
|
Loading…
Reference in a new issue