Skip to content

Commit 8b17a4f

Browse files
committed
tun: avoid double free in tun_free_netdev
jira LE-1907 cve CVE-2022-4744 Rebuild_History Non-Buildable kernel-rt-5.14.0-284.30.1.rt14.315.el9_2 commit-author George Kennedy <[email protected]> commit 158b515 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 ctrliq#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 <[email protected]> Signed-off-by: George Kennedy <[email protected]> Suggested-by: Jakub Kicinski <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]> (cherry picked from commit 158b515) Signed-off-by: Jonathan Maple <[email protected]>
1 parent 61c33bb commit 8b17a4f

File tree

1 file changed

+59
-56
lines changed

1 file changed

+59
-56
lines changed

drivers/net/tun.c

Lines changed: 59 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -209,13 +209,19 @@ struct tun_struct {
209209
struct tun_prog __rcu *steering_prog;
210210
struct tun_prog __rcu *filter_prog;
211211
struct ethtool_link_ksettings link_ksettings;
212+
/* init args */
213+
struct file *file;
214+
struct ifreq *ifr;
212215
};
213216

214217
struct veth {
215218
__be16 h_vlan_proto;
216219
__be16 h_vlan_TCI;
217220
};
218221

222+
static void tun_flow_init(struct tun_struct *tun);
223+
static void tun_flow_uninit(struct tun_struct *tun);
224+
219225
static int tun_napi_receive(struct napi_struct *napi, int budget)
220226
{
221227
struct tun_file *tfile = container_of(napi, struct tun_file, napi);
@@ -952,6 +958,49 @@ static int check_filter(struct tap_filter *filter, const struct sk_buff *skb)
952958

953959
static const struct ethtool_ops tun_ethtool_ops;
954960

961+
static int tun_net_init(struct net_device *dev)
962+
{
963+
struct tun_struct *tun = netdev_priv(dev);
964+
struct ifreq *ifr = tun->ifr;
965+
int err;
966+
967+
dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
968+
if (!dev->tstats)
969+
return -ENOMEM;
970+
971+
spin_lock_init(&tun->lock);
972+
973+
err = security_tun_dev_alloc_security(&tun->security);
974+
if (err < 0) {
975+
free_percpu(dev->tstats);
976+
return err;
977+
}
978+
979+
tun_flow_init(tun);
980+
981+
dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST |
982+
TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |
983+
NETIF_F_HW_VLAN_STAG_TX;
984+
dev->features = dev->hw_features | NETIF_F_LLTX;
985+
dev->vlan_features = dev->features &
986+
~(NETIF_F_HW_VLAN_CTAG_TX |
987+
NETIF_F_HW_VLAN_STAG_TX);
988+
989+
tun->flags = (tun->flags & ~TUN_FEATURES) |
990+
(ifr->ifr_flags & TUN_FEATURES);
991+
992+
INIT_LIST_HEAD(&tun->disabled);
993+
err = tun_attach(tun, tun->file, false, ifr->ifr_flags & IFF_NAPI,
994+
ifr->ifr_flags & IFF_NAPI_FRAGS, false);
995+
if (err < 0) {
996+
tun_flow_uninit(tun);
997+
security_tun_dev_free_security(tun->security);
998+
free_percpu(dev->tstats);
999+
return err;
1000+
}
1001+
return 0;
1002+
}
1003+
9551004
/* Net device detach from fd. */
9561005
static void tun_net_uninit(struct net_device *dev)
9571006
{
@@ -1186,6 +1235,7 @@ static int tun_net_change_carrier(struct net_device *dev, bool new_carrier)
11861235
}
11871236

11881237
static const struct net_device_ops tun_netdev_ops = {
1238+
.ndo_init = tun_net_init,
11891239
.ndo_uninit = tun_net_uninit,
11901240
.ndo_open = tun_net_open,
11911241
.ndo_stop = tun_net_close,
@@ -1269,6 +1319,7 @@ static int tun_xdp_tx(struct net_device *dev, struct xdp_buff *xdp)
12691319
}
12701320

12711321
static const struct net_device_ops tap_netdev_ops = {
1322+
.ndo_init = tun_net_init,
12721323
.ndo_uninit = tun_net_uninit,
12731324
.ndo_open = tun_net_open,
12741325
.ndo_stop = tun_net_close,
@@ -1309,7 +1360,7 @@ static void tun_flow_uninit(struct tun_struct *tun)
13091360
#define MAX_MTU 65535
13101361

13111362
/* Initialize net device. */
1312-
static void tun_net_init(struct net_device *dev)
1363+
static void tun_net_initialize(struct net_device *dev)
13131364
{
13141365
struct tun_struct *tun = netdev_priv(dev);
13151366

@@ -2227,11 +2278,6 @@ static void tun_free_netdev(struct net_device *dev)
22272278
BUG_ON(!(list_empty(&tun->disabled)));
22282279

22292280
free_percpu(dev->tstats);
2230-
/* We clear tstats so that tun_set_iff() can tell if
2231-
* tun_free_netdev() has been called from register_netdevice().
2232-
*/
2233-
dev->tstats = NULL;
2234-
22352281
tun_flow_uninit(tun);
22362282
security_tun_dev_free_security(tun->security);
22372283
__tun_set_ebpf(tun, &tun->steering_prog, NULL);
@@ -2737,41 +2783,16 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
27372783
tun->rx_batched = 0;
27382784
RCU_INIT_POINTER(tun->steering_prog, NULL);
27392785

2740-
dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
2741-
if (!dev->tstats) {
2742-
err = -ENOMEM;
2743-
goto err_free_dev;
2744-
}
2745-
2746-
spin_lock_init(&tun->lock);
2747-
2748-
err = security_tun_dev_alloc_security(&tun->security);
2749-
if (err < 0)
2750-
goto err_free_stat;
2751-
2752-
tun_net_init(dev);
2753-
tun_flow_init(tun);
2786+
tun->ifr = ifr;
2787+
tun->file = file;
27542788

2755-
dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST |
2756-
TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |
2757-
NETIF_F_HW_VLAN_STAG_TX;
2758-
dev->features = dev->hw_features | NETIF_F_LLTX;
2759-
dev->vlan_features = dev->features &
2760-
~(NETIF_F_HW_VLAN_CTAG_TX |
2761-
NETIF_F_HW_VLAN_STAG_TX);
2762-
2763-
tun->flags = (tun->flags & ~TUN_FEATURES) |
2764-
(ifr->ifr_flags & TUN_FEATURES);
2765-
2766-
INIT_LIST_HEAD(&tun->disabled);
2767-
err = tun_attach(tun, file, false, ifr->ifr_flags & IFF_NAPI,
2768-
ifr->ifr_flags & IFF_NAPI_FRAGS, false);
2769-
if (err < 0)
2770-
goto err_free_flow;
2789+
tun_net_initialize(dev);
27712790

27722791
err = register_netdevice(tun->dev);
2773-
if (err < 0)
2774-
goto err_detach;
2792+
if (err < 0) {
2793+
free_netdev(dev);
2794+
return err;
2795+
}
27752796
/* free_netdev() won't check refcnt, to avoid race
27762797
* with dev_put() we need publish tun after registration.
27772798
*/
@@ -2788,24 +2809,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
27882809

27892810
strcpy(ifr->ifr_name, tun->dev->name);
27902811
return 0;
2791-
2792-
err_detach:
2793-
tun_detach_all(dev);
2794-
/* We are here because register_netdevice() has failed.
2795-
* If register_netdevice() already called tun_free_netdev()
2796-
* while dealing with the error, dev->stats has been cleared.
2797-
*/
2798-
if (!dev->tstats)
2799-
goto err_free_dev;
2800-
2801-
err_free_flow:
2802-
tun_flow_uninit(tun);
2803-
security_tun_dev_free_security(tun->security);
2804-
err_free_stat:
2805-
free_percpu(dev->tstats);
2806-
err_free_dev:
2807-
free_netdev(dev);
2808-
return err;
28092812
}
28102813

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

0 commit comments

Comments
 (0)