Commit 4df0bfc7 authored by Cong Wang's avatar Cong Wang Committed by David S. Miller

tun: fix a memory leak for tfile->tx_array

tfile->tun could be detached before we close the tun fd,
via tun_detach_all(), so it should not be used to check for
tfile->tx_array.

As Jason suggested, we probably have to clean it up
unconditionally both in __tun_deatch() and tun_detach_all(),
but this requires to check if it is initialized or not.
Currently skb_array_cleanup() doesn't have such a check,
so I check it in the caller and introduce a helper function,
it is a bit ugly but we can always improve it in net-next.
Reported-by: default avatarDmitry Vyukov <dvyukov@google.com>
Fixes: 1576d986 ("tun: switch to use skb array for tx")
Cc: Jason Wang <jasowang@redhat.com>
Signed-off-by: default avatarCong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8cbab92d
...@@ -611,6 +611,14 @@ static void tun_queue_purge(struct tun_file *tfile) ...@@ -611,6 +611,14 @@ static void tun_queue_purge(struct tun_file *tfile)
skb_queue_purge(&tfile->sk.sk_error_queue); skb_queue_purge(&tfile->sk.sk_error_queue);
} }
static void tun_cleanup_tx_array(struct tun_file *tfile)
{
if (tfile->tx_array.ring.queue) {
skb_array_cleanup(&tfile->tx_array);
memset(&tfile->tx_array, 0, sizeof(tfile->tx_array));
}
}
static void __tun_detach(struct tun_file *tfile, bool clean) static void __tun_detach(struct tun_file *tfile, bool clean)
{ {
struct tun_file *ntfile; struct tun_file *ntfile;
...@@ -657,8 +665,7 @@ static void __tun_detach(struct tun_file *tfile, bool clean) ...@@ -657,8 +665,7 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
tun->dev->reg_state == NETREG_REGISTERED) tun->dev->reg_state == NETREG_REGISTERED)
unregister_netdevice(tun->dev); unregister_netdevice(tun->dev);
} }
if (tun) tun_cleanup_tx_array(tfile);
skb_array_cleanup(&tfile->tx_array);
sock_put(&tfile->sk); sock_put(&tfile->sk);
} }
} }
...@@ -700,11 +707,13 @@ static void tun_detach_all(struct net_device *dev) ...@@ -700,11 +707,13 @@ static void tun_detach_all(struct net_device *dev)
/* Drop read queue */ /* Drop read queue */
tun_queue_purge(tfile); tun_queue_purge(tfile);
sock_put(&tfile->sk); sock_put(&tfile->sk);
tun_cleanup_tx_array(tfile);
} }
list_for_each_entry_safe(tfile, tmp, &tun->disabled, next) { list_for_each_entry_safe(tfile, tmp, &tun->disabled, next) {
tun_enable_queue(tfile); tun_enable_queue(tfile);
tun_queue_purge(tfile); tun_queue_purge(tfile);
sock_put(&tfile->sk); sock_put(&tfile->sk);
tun_cleanup_tx_array(tfile);
} }
BUG_ON(tun->numdisabled != 0); BUG_ON(tun->numdisabled != 0);
...@@ -2851,6 +2860,8 @@ static int tun_chr_open(struct inode *inode, struct file * file) ...@@ -2851,6 +2860,8 @@ static int tun_chr_open(struct inode *inode, struct file * file)
sock_set_flag(&tfile->sk, SOCK_ZEROCOPY); sock_set_flag(&tfile->sk, SOCK_ZEROCOPY);
memset(&tfile->tx_array, 0, sizeof(tfile->tx_array));
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment