aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2009-04-19 18:35:50 -0400
committerDavid S. Miller <davem@davemloft.net>2009-04-20 06:01:48 -0400
commitc40af84a6726f63e35740d26f841992e8f31f92c (patch)
treedbb8271908d537817915814735cfc2a86130e2f6 /drivers/net
parent9c3fea6ab04a7bd9298e635bf29b4a5379f6c476 (diff)
tun: Fix sk_sleep races when attaching/detaching
As the sk_sleep wait queue actually lives in tfile, which may be detached from the tun device, bad things will happen when we use sk_sleep after detaching. Since the tun device is the persistent data structure here (when requested by the user), it makes much more sense to have the wait queue live there. There is no reason to have it in tfile at all since the only time we can wait is if we have a tun attached. In fact we already have a wait queue in tun_struct, so we might as well use it. Reported-by: Eric W. Biederman <ebiederm@xmission.com> Tested-by: Christian Borntraeger <borntraeger@de.ibm.com> Tested-by: Patrick McHardy <kaber@trash.net> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/tun.c15
1 files changed, 6 insertions, 9 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 95ae40ab8718..735bf41c654a 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -93,7 +93,6 @@ struct tun_file {
93 atomic_t count; 93 atomic_t count;
94 struct tun_struct *tun; 94 struct tun_struct *tun;
95 struct net *net; 95 struct net *net;
96 wait_queue_head_t read_wait;
97}; 96};
98 97
99struct tun_sock; 98struct tun_sock;
@@ -331,7 +330,7 @@ static void tun_net_uninit(struct net_device *dev)
331 /* Inform the methods they need to stop using the dev. 330 /* Inform the methods they need to stop using the dev.
332 */ 331 */
333 if (tfile) { 332 if (tfile) {
334 wake_up_all(&tfile->read_wait); 333 wake_up_all(&tun->socket.wait);
335 if (atomic_dec_and_test(&tfile->count)) 334 if (atomic_dec_and_test(&tfile->count))
336 __tun_detach(tun); 335 __tun_detach(tun);
337 } 336 }
@@ -398,7 +397,7 @@ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
398 /* Notify and wake up reader process */ 397 /* Notify and wake up reader process */
399 if (tun->flags & TUN_FASYNC) 398 if (tun->flags & TUN_FASYNC)
400 kill_fasync(&tun->fasync, SIGIO, POLL_IN); 399 kill_fasync(&tun->fasync, SIGIO, POLL_IN);
401 wake_up_interruptible(&tun->tfile->read_wait); 400 wake_up_interruptible(&tun->socket.wait);
402 return 0; 401 return 0;
403 402
404drop: 403drop:
@@ -495,7 +494,7 @@ static unsigned int tun_chr_poll(struct file *file, poll_table * wait)
495 494
496 DBG(KERN_INFO "%s: tun_chr_poll\n", tun->dev->name); 495 DBG(KERN_INFO "%s: tun_chr_poll\n", tun->dev->name);
497 496
498 poll_wait(file, &tfile->read_wait, wait); 497 poll_wait(file, &tun->socket.wait, wait);
499 498
500 if (!skb_queue_empty(&tun->readq)) 499 if (!skb_queue_empty(&tun->readq))
501 mask |= POLLIN | POLLRDNORM; 500 mask |= POLLIN | POLLRDNORM;
@@ -768,7 +767,7 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
768 goto out; 767 goto out;
769 } 768 }
770 769
771 add_wait_queue(&tfile->read_wait, &wait); 770 add_wait_queue(&tun->socket.wait, &wait);
772 while (len) { 771 while (len) {
773 current->state = TASK_INTERRUPTIBLE; 772 current->state = TASK_INTERRUPTIBLE;
774 773
@@ -799,7 +798,7 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
799 } 798 }
800 799
801 current->state = TASK_RUNNING; 800 current->state = TASK_RUNNING;
802 remove_wait_queue(&tfile->read_wait, &wait); 801 remove_wait_queue(&tun->socket.wait, &wait);
803 802
804out: 803out:
805 tun_put(tun); 804 tun_put(tun);
@@ -867,7 +866,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
867 struct sock *sk; 866 struct sock *sk;
868 struct tun_struct *tun; 867 struct tun_struct *tun;
869 struct net_device *dev; 868 struct net_device *dev;
870 struct tun_file *tfile = file->private_data;
871 int err; 869 int err;
872 870
873 dev = __dev_get_by_name(net, ifr->ifr_name); 871 dev = __dev_get_by_name(net, ifr->ifr_name);
@@ -925,10 +923,10 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
925 if (!sk) 923 if (!sk)
926 goto err_free_dev; 924 goto err_free_dev;
927 925
926 init_waitqueue_head(&tun->socket.wait);
928 sock_init_data(&tun->socket, sk); 927 sock_init_data(&tun->socket, sk);
929 sk->sk_write_space = tun_sock_write_space; 928 sk->sk_write_space = tun_sock_write_space;
930 sk->sk_sndbuf = INT_MAX; 929 sk->sk_sndbuf = INT_MAX;
931 sk->sk_sleep = &tfile->read_wait;
932 930
933 tun->sk = sk; 931 tun->sk = sk;
934 container_of(sk, struct tun_sock, sk)->tun = tun; 932 container_of(sk, struct tun_sock, sk)->tun = tun;
@@ -1270,7 +1268,6 @@ static int tun_chr_open(struct inode *inode, struct file * file)
1270 atomic_set(&tfile->count, 0); 1268 atomic_set(&tfile->count, 0);
1271 tfile->tun = NULL; 1269 tfile->tun = NULL;
1272 tfile->net = get_net(current->nsproxy->net_ns); 1270 tfile->net = get_net(current->nsproxy->net_ns);
1273 init_waitqueue_head(&tfile->read_wait);
1274 file->private_data = tfile; 1271 file->private_data = tfile;
1275 return 0; 1272 return 0;
1276} 1273}