Skip to content

Commit c617651

Browse files
committed
tun: avoid double free in tun_free_netdev
jira VULN-8777 cve CVE-2022-4744 commit-author George Kennedy <george.kennedy@oracle.com> commit 158b515 upstream-diff Content is the same as the upstream patch except s/dev->tstats/tun->pcpu_stats/g becuase the switch to tstats (497a575 "tun: switch to net core provided statistics counters") isn't in this kernel. This matches how this change was backported to 4.19.y. Avoid double free in tun_free_netdev() by moving the dev->tstats and tun->security allocs to a new ndo_init routine (tun_net_init()) that will be called by register_netdevice(). ndo_init is paired with the desctructor (tun_free_netdev()), so if there's an error in register_netdevice() the destructor will handle the frees. BUG: KASAN: double-free or invalid-free in selinux_tun_dev_free_security+0x1a/0x20 security/selinux/hooks.c:5605 CPU: 0 PID: 25750 Comm: syz-executor416 Not tainted 5.16.0-rc2-syzk #1 Hardware name: Red Hat KVM, BIOS Call Trace: <TASK> __dump_stack lib/dump_stack.c:88 [inline] dump_stack_lvl+0x89/0xb5 lib/dump_stack.c:106 print_address_description.constprop.9+0x28/0x160 mm/kasan/report.c:247 kasan_report_invalid_free+0x55/0x80 mm/kasan/report.c:372 ____kasan_slab_free mm/kasan/common.c:346 [inline] __kasan_slab_free+0x107/0x120 mm/kasan/common.c:374 kasan_slab_free include/linux/kasan.h:235 [inline] slab_free_hook mm/slub.c:1723 [inline] slab_free_freelist_hook mm/slub.c:1749 [inline] slab_free mm/slub.c:3513 [inline] kfree+0xac/0x2d0 mm/slub.c:4561 selinux_tun_dev_free_security+0x1a/0x20 security/selinux/hooks.c:5605 security_tun_dev_free_security+0x4f/0x90 security/security.c:2342 tun_free_netdev+0xe6/0x150 drivers/net/tun.c:2215 netdev_run_todo+0x4df/0x840 net/core/dev.c:10627 rtnl_unlock+0x13/0x20 net/core/rtnetlink.c:112 __tun_chr_ioctl+0x80c/0x2870 drivers/net/tun.c:3302 tun_chr_ioctl+0x2f/0x40 drivers/net/tun.c:3311 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:874 [inline] __se_sys_ioctl fs/ioctl.c:860 [inline] __x64_sys_ioctl+0x19d/0x220 fs/ioctl.c:860 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x3a/0x80 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x44/0xae Reported-by: syzkaller <syzkaller@googlegroups.com> Signed-off-by: George Kennedy <george.kennedy@oracle.com> Suggested-by: Jakub Kicinski <kuba@kernel.org> Link: https://lore.kernel.org/r/1639679132-19884-1-git-send-email-george.kennedy@oracle.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> (cherry picked from commit 158b515) Signed-off-by: Brett Mastbergen <bmastbergen@ciq.com>
1 parent 2d31b60 commit c617651

File tree

1 file changed

+59
-60
lines changed

1 file changed

+59
-60
lines changed

drivers/net/tun.c

Lines changed: 59 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -251,13 +251,19 @@ struct tun_struct {
251251
struct tun_prog __rcu *steering_prog;
252252
struct tun_prog __rcu *filter_prog;
253253
struct ethtool_link_ksettings link_ksettings;
254+
/* init args */
255+
struct file *file;
256+
struct ifreq *ifr;
254257
};
255258

256259
struct veth {
257260
__be16 h_vlan_proto;
258261
__be16 h_vlan_TCI;
259262
};
260263

264+
static void tun_flow_init(struct tun_struct *tun);
265+
static void tun_flow_uninit(struct tun_struct *tun);
266+
261267
static int tun_napi_receive(struct napi_struct *napi, int budget)
262268
{
263269
struct tun_file *tfile = container_of(napi, struct tun_file, napi);
@@ -996,6 +1002,49 @@ static int check_filter(struct tap_filter *filter, const struct sk_buff *skb)
9961002

9971003
static const struct ethtool_ops tun_ethtool_ops;
9981004

1005+
static int tun_net_init(struct net_device *dev)
1006+
{
1007+
struct tun_struct *tun = netdev_priv(dev);
1008+
struct ifreq *ifr = tun->ifr;
1009+
int err;
1010+
1011+
tun->pcpu_stats = netdev_alloc_pcpu_stats(struct tun_pcpu_stats);
1012+
if (!tun->pcpu_stats)
1013+
return -ENOMEM;
1014+
1015+
spin_lock_init(&tun->lock);
1016+
1017+
err = security_tun_dev_alloc_security(&tun->security);
1018+
if (err < 0) {
1019+
free_percpu(tun->pcpu_stats);
1020+
return err;
1021+
}
1022+
1023+
tun_flow_init(tun);
1024+
1025+
dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST |
1026+
TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |
1027+
NETIF_F_HW_VLAN_STAG_TX;
1028+
dev->features = dev->hw_features | NETIF_F_LLTX;
1029+
dev->vlan_features = dev->features &
1030+
~(NETIF_F_HW_VLAN_CTAG_TX |
1031+
NETIF_F_HW_VLAN_STAG_TX);
1032+
1033+
tun->flags = (tun->flags & ~TUN_FEATURES) |
1034+
(ifr->ifr_flags & TUN_FEATURES);
1035+
1036+
INIT_LIST_HEAD(&tun->disabled);
1037+
err = tun_attach(tun, tun->file, false, ifr->ifr_flags & IFF_NAPI,
1038+
ifr->ifr_flags & IFF_NAPI_FRAGS, false);
1039+
if (err < 0) {
1040+
tun_flow_uninit(tun);
1041+
security_tun_dev_free_security(tun->security);
1042+
free_percpu(tun->pcpu_stats);
1043+
return err;
1044+
}
1045+
return 0;
1046+
}
1047+
9991048
/* Net device detach from fd. */
10001049
static void tun_net_uninit(struct net_device *dev)
10011050
{
@@ -1274,6 +1323,7 @@ static int tun_net_change_carrier(struct net_device *dev, bool new_carrier)
12741323
}
12751324

12761325
static const struct net_device_ops tun_netdev_ops = {
1326+
.ndo_init = tun_net_init,
12771327
.ndo_uninit = tun_net_uninit,
12781328
.ndo_open = tun_net_open,
12791329
.ndo_stop = tun_net_close,
@@ -1360,6 +1410,7 @@ static int tun_xdp_tx(struct net_device *dev, struct xdp_buff *xdp)
13601410
}
13611411

13621412
static const struct net_device_ops tap_netdev_ops = {
1413+
.ndo_init = tun_net_init,
13631414
.ndo_uninit = tun_net_uninit,
13641415
.ndo_open = tun_net_open,
13651416
.ndo_stop = tun_net_close,
@@ -1403,7 +1454,7 @@ static void tun_flow_uninit(struct tun_struct *tun)
14031454
#define MAX_MTU 65535
14041455

14051456
/* Initialize net device. */
1406-
static void tun_net_init(struct net_device *dev)
1457+
static void tun_net_initialize(struct net_device *dev)
14071458
{
14081459
struct tun_struct *tun = netdev_priv(dev);
14091460

@@ -2324,13 +2375,7 @@ static void tun_free_netdev(struct net_device *dev)
23242375
struct tun_struct *tun = netdev_priv(dev);
23252376

23262377
BUG_ON(!(list_empty(&tun->disabled)));
2327-
23282378
free_percpu(tun->pcpu_stats);
2329-
/* We clear pcpu_stats so that tun_set_iff() can tell if
2330-
* tun_free_netdev() has been called from register_netdevice().
2331-
*/
2332-
tun->pcpu_stats = NULL;
2333-
23342379
tun_flow_uninit(tun);
23352380
security_tun_dev_free_security(tun->security);
23362381
__tun_set_ebpf(tun, &tun->steering_prog, NULL);
@@ -2825,9 +2870,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
28252870

28262871
if (!dev)
28272872
return -ENOMEM;
2828-
err = dev_get_valid_name(net, dev, name);
2829-
if (err < 0)
2830-
goto err_free_dev;
28312873

28322874
dev_net_set(dev, net);
28332875
dev->rtnl_link_ops = &tun_link_ops;
@@ -2846,41 +2888,16 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
28462888
tun->rx_batched = 0;
28472889
RCU_INIT_POINTER(tun->steering_prog, NULL);
28482890

2849-
tun->pcpu_stats = netdev_alloc_pcpu_stats(struct tun_pcpu_stats);
2850-
if (!tun->pcpu_stats) {
2851-
err = -ENOMEM;
2852-
goto err_free_dev;
2853-
}
2854-
2855-
spin_lock_init(&tun->lock);
2856-
2857-
err = security_tun_dev_alloc_security(&tun->security);
2858-
if (err < 0)
2859-
goto err_free_stat;
2860-
2861-
tun_net_init(dev);
2862-
tun_flow_init(tun);
2863-
2864-
dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST |
2865-
TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |
2866-
NETIF_F_HW_VLAN_STAG_TX;
2867-
dev->features = dev->hw_features | NETIF_F_LLTX;
2868-
dev->vlan_features = dev->features &
2869-
~(NETIF_F_HW_VLAN_CTAG_TX |
2870-
NETIF_F_HW_VLAN_STAG_TX);
2891+
tun->ifr = ifr;
2892+
tun->file = file;
28712893

2872-
tun->flags = (tun->flags & ~TUN_FEATURES) |
2873-
(ifr->ifr_flags & TUN_FEATURES);
2874-
2875-
INIT_LIST_HEAD(&tun->disabled);
2876-
err = tun_attach(tun, file, false, ifr->ifr_flags & IFF_NAPI,
2877-
ifr->ifr_flags & IFF_NAPI_FRAGS, false);
2878-
if (err < 0)
2879-
goto err_free_flow;
2894+
tun_net_initialize(dev);
28802895

28812896
err = register_netdevice(tun->dev);
2882-
if (err < 0)
2883-
goto err_detach;
2897+
if (err < 0) {
2898+
free_netdev(dev);
2899+
return err;
2900+
}
28842901
/* free_netdev() won't check refcnt, to aovid race
28852902
* with dev_put() we need publish tun after registration.
28862903
*/
@@ -2899,24 +2916,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
28992916

29002917
strcpy(ifr->ifr_name, tun->dev->name);
29012918
return 0;
2902-
2903-
err_detach:
2904-
tun_detach_all(dev);
2905-
/* We are here because register_netdevice() has failed.
2906-
* If register_netdevice() already called tun_free_netdev()
2907-
* while dealing with the error, tun->pcpu_stats has been cleared.
2908-
*/
2909-
if (!tun->pcpu_stats)
2910-
goto err_free_dev;
2911-
2912-
err_free_flow:
2913-
tun_flow_uninit(tun);
2914-
security_tun_dev_free_security(tun->security);
2915-
err_free_stat:
2916-
free_percpu(tun->pcpu_stats);
2917-
err_free_dev:
2918-
free_netdev(dev);
2919-
return err;
29202919
}
29212920

29222921
static void tun_get_iff(struct tun_struct *tun, struct ifreq *ifr)

0 commit comments

Comments
 (0)