diff options
author | Jason Wang <jasowang@redhat.com> | 2013-01-11 11:59:34 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-01-11 22:42:02 -0500 |
commit | dd38bd853082355641d0034aaf368e13ef2438f8 (patch) | |
tree | d30449d71cc6c1cbe9d5cc412c2046f4c1527c43 /drivers/net/tun.c | |
parent | 7c0c3b1a8a175437991ccc898ed66ec5e4a96208 (diff) |
tuntap: fix leaking reference count
Reference count leaking of both module and sock were found:
- When a detached file were closed, its sock refcnt from device were not
released, solving this by add the sock_put().
- The module were hold or drop unconditionally in TUNSETPERSIST, which means we
if we set the persist flag for N times, we need unset it for another N
times. Solving this by only hold or drop an reference when there's a flag
change and also drop the reference count when the persist device is deleted.
Signed-off-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r-- | drivers/net/tun.c | 12 |
1 files changed, 9 insertions, 3 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index a36b56f0940b..af372d0957fe 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -428,8 +428,10 @@ static void __tun_detach(struct tun_file *tfile, bool clean) | |||
428 | /* Drop read queue */ | 428 | /* Drop read queue */ |
429 | skb_queue_purge(&tfile->sk.sk_receive_queue); | 429 | skb_queue_purge(&tfile->sk.sk_receive_queue); |
430 | tun_set_real_num_queues(tun); | 430 | tun_set_real_num_queues(tun); |
431 | } else if (tfile->detached && clean) | 431 | } else if (tfile->detached && clean) { |
432 | tun = tun_enable_queue(tfile); | 432 | tun = tun_enable_queue(tfile); |
433 | sock_put(&tfile->sk); | ||
434 | } | ||
433 | 435 | ||
434 | if (clean) { | 436 | if (clean) { |
435 | if (tun && tun->numqueues == 0 && tun->numdisabled == 0 && | 437 | if (tun && tun->numqueues == 0 && tun->numdisabled == 0 && |
@@ -478,6 +480,9 @@ static void tun_detach_all(struct net_device *dev) | |||
478 | sock_put(&tfile->sk); | 480 | sock_put(&tfile->sk); |
479 | } | 481 | } |
480 | BUG_ON(tun->numdisabled != 0); | 482 | BUG_ON(tun->numdisabled != 0); |
483 | |||
484 | if (tun->flags & TUN_PERSIST) | ||
485 | module_put(THIS_MODULE); | ||
481 | } | 486 | } |
482 | 487 | ||
483 | static int tun_attach(struct tun_struct *tun, struct file *file) | 488 | static int tun_attach(struct tun_struct *tun, struct file *file) |
@@ -1874,10 +1879,11 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, | |||
1874 | /* Disable/Enable persist mode. Keep an extra reference to the | 1879 | /* Disable/Enable persist mode. Keep an extra reference to the |
1875 | * module to prevent the module being unprobed. | 1880 | * module to prevent the module being unprobed. |
1876 | */ | 1881 | */ |
1877 | if (arg) { | 1882 | if (arg && !(tun->flags & TUN_PERSIST)) { |
1878 | tun->flags |= TUN_PERSIST; | 1883 | tun->flags |= TUN_PERSIST; |
1879 | __module_get(THIS_MODULE); | 1884 | __module_get(THIS_MODULE); |
1880 | } else { | 1885 | } |
1886 | if (!arg && (tun->flags & TUN_PERSIST)) { | ||
1881 | tun->flags &= ~TUN_PERSIST; | 1887 | tun->flags &= ~TUN_PERSIST; |
1882 | module_put(THIS_MODULE); | 1888 | module_put(THIS_MODULE); |
1883 | } | 1889 | } |