Skip to content

Commit 2ee5c10

Browse files
jasowangdavem330
authored andcommitted
tun: fix use after free for ptr_ring
We used to initialize ptr_ring during TUNSETIFF, this is because its size depends on the tx_queue_len of netdevice. And we try to clean it up when socket were detached from netdevice. A race were spotted when trying to do uninit during a read which will lead a use after free for pointer ring. Solving this by always initialize a zero size ptr_ring in open() and do resizing during TUNSETIFF, and then we can safely do cleanup during close(). With this, there's no need for the workaround that was introduced by commit 14d4a88 ("tun: fix a memory leak for tfile->tx_array"). Reported-by: [email protected] Cc: Eric Dumazet <[email protected]> Cc: Cong Wang <[email protected]> Cc: Michael S. Tsirkin <[email protected]> Fixes: 078ba52 ("tun: switch to use skb array for tx") Signed-off-by: Jason Wang <[email protected]> Acked-by: Michael S. Tsirkin <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 9fd8ff1 commit 2ee5c10

File tree

1 file changed

+12
-15
lines changed

1 file changed

+12
-15
lines changed

drivers/net/tun.c

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -681,15 +681,6 @@ static void tun_queue_purge(struct tun_file *tfile)
681681
skb_queue_purge(&tfile->sk.sk_error_queue);
682682
}
683683

684-
static void tun_cleanup_tx_ring(struct tun_file *tfile)
685-
{
686-
if (tfile->tx_ring.queue) {
687-
ptr_ring_cleanup(&tfile->tx_ring, tun_ptr_free);
688-
xdp_rxq_info_unreg(&tfile->xdp_rxq);
689-
memset(&tfile->tx_ring, 0, sizeof(tfile->tx_ring));
690-
}
691-
}
692-
693684
static void __tun_detach(struct tun_file *tfile, bool clean)
694685
{
695686
struct tun_file *ntfile;
@@ -736,7 +727,8 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
736727
tun->dev->reg_state == NETREG_REGISTERED)
737728
unregister_netdevice(tun->dev);
738729
}
739-
tun_cleanup_tx_ring(tfile);
730+
if (tun)
731+
xdp_rxq_info_unreg(&tfile->xdp_rxq);
740732
sock_put(&tfile->sk);
741733
}
742734
}
@@ -783,14 +775,14 @@ static void tun_detach_all(struct net_device *dev)
783775
tun_napi_del(tun, tfile);
784776
/* Drop read queue */
785777
tun_queue_purge(tfile);
778+
xdp_rxq_info_unreg(&tfile->xdp_rxq);
786779
sock_put(&tfile->sk);
787-
tun_cleanup_tx_ring(tfile);
788780
}
789781
list_for_each_entry_safe(tfile, tmp, &tun->disabled, next) {
790782
tun_enable_queue(tfile);
791783
tun_queue_purge(tfile);
784+
xdp_rxq_info_unreg(&tfile->xdp_rxq);
792785
sock_put(&tfile->sk);
793-
tun_cleanup_tx_ring(tfile);
794786
}
795787
BUG_ON(tun->numdisabled != 0);
796788

@@ -834,7 +826,8 @@ static int tun_attach(struct tun_struct *tun, struct file *file,
834826
}
835827

836828
if (!tfile->detached &&
837-
ptr_ring_init(&tfile->tx_ring, dev->tx_queue_len, GFP_KERNEL)) {
829+
ptr_ring_resize(&tfile->tx_ring, dev->tx_queue_len,
830+
GFP_KERNEL, tun_ptr_free)) {
838831
err = -ENOMEM;
839832
goto out;
840833
}
@@ -3219,6 +3212,11 @@ static int tun_chr_open(struct inode *inode, struct file * file)
32193212
&tun_proto, 0);
32203213
if (!tfile)
32213214
return -ENOMEM;
3215+
if (ptr_ring_init(&tfile->tx_ring, 0, GFP_KERNEL)) {
3216+
sk_free(&tfile->sk);
3217+
return -ENOMEM;
3218+
}
3219+
32223220
RCU_INIT_POINTER(tfile->tun, NULL);
32233221
tfile->flags = 0;
32243222
tfile->ifindex = 0;
@@ -3239,8 +3237,6 @@ static int tun_chr_open(struct inode *inode, struct file * file)
32393237

32403238
sock_set_flag(&tfile->sk, SOCK_ZEROCOPY);
32413239

3242-
memset(&tfile->tx_ring, 0, sizeof(tfile->tx_ring));
3243-
32443240
return 0;
32453241
}
32463242

@@ -3249,6 +3245,7 @@ static int tun_chr_close(struct inode *inode, struct file *file)
32493245
struct tun_file *tfile = file->private_data;
32503246

32513247
tun_detach(tfile, true);
3248+
ptr_ring_cleanup(&tfile->tx_ring, tun_ptr_free);
32523249

32533250
return 0;
32543251
}

0 commit comments

Comments
 (0)