Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Dmitry Vyukov <dvyukov@google.com>
Fixes: 1576d9860599 ("tun: switch to use skb array for tx")
Cc: Jason Wang <jasowang@redhat.com>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Cong Wang and committed by
David S. Miller
4df0bfc7 8cbab92d

+13 -2
+13 -2
drivers/net/tun.c
··· 611 611 skb_queue_purge(&tfile->sk.sk_error_queue); 612 612 } 613 613 614 + static void tun_cleanup_tx_array(struct tun_file *tfile) 615 + { 616 + if (tfile->tx_array.ring.queue) { 617 + skb_array_cleanup(&tfile->tx_array); 618 + memset(&tfile->tx_array, 0, sizeof(tfile->tx_array)); 619 + } 620 + } 621 + 614 622 static void __tun_detach(struct tun_file *tfile, bool clean) 615 623 { 616 624 struct tun_file *ntfile; ··· 665 657 tun->dev->reg_state == NETREG_REGISTERED) 666 658 unregister_netdevice(tun->dev); 667 659 } 668 - if (tun) 669 - skb_array_cleanup(&tfile->tx_array); 660 + tun_cleanup_tx_array(tfile); 670 661 sock_put(&tfile->sk); 671 662 } 672 663 } ··· 707 700 /* Drop read queue */ 708 701 tun_queue_purge(tfile); 709 702 sock_put(&tfile->sk); 703 + tun_cleanup_tx_array(tfile); 710 704 } 711 705 list_for_each_entry_safe(tfile, tmp, &tun->disabled, next) { 712 706 tun_enable_queue(tfile); 713 707 tun_queue_purge(tfile); 714 708 sock_put(&tfile->sk); 709 + tun_cleanup_tx_array(tfile); 715 710 } 716 711 BUG_ON(tun->numdisabled != 0); 717 712 ··· 2859 2850 INIT_LIST_HEAD(&tfile->next); 2860 2851 2861 2852 sock_set_flag(&tfile->sk, SOCK_ZEROCOPY); 2853 + 2854 + memset(&tfile->tx_array, 0, sizeof(tfile->tx_array)); 2862 2855 2863 2856 return 0; 2864 2857 }