]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 28 Mar 2023 13:32:25 +0000 (15:32 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 28 Mar 2023 13:32:25 +0000 (15:32 +0200)
added patches:
tun-avoid-double-free-in-tun_free_netdev.patch

queue-5.4/series
queue-5.4/tun-avoid-double-free-in-tun_free_netdev.patch [new file with mode: 0644]

index fbceff95beaf8b615e3ec5db579e689628bf579d..090973fa25ab5ee451fd34c33b6d2837253d3950 100644 (file)
@@ -56,3 +56,4 @@ dm-stats-check-for-and-propagate-alloc_percpu-failure.patch
 dm-crypt-add-cond_resched-to-dmcrypt_write.patch
 sched-fair-sanitize-vruntime-of-entity-being-placed.patch
 sched-fair-sanitize-vruntime-of-entity-being-migrated.patch
+tun-avoid-double-free-in-tun_free_netdev.patch
diff --git a/queue-5.4/tun-avoid-double-free-in-tun_free_netdev.patch b/queue-5.4/tun-avoid-double-free-in-tun_free_netdev.patch
new file mode 100644 (file)
index 0000000..ecf5a17
--- /dev/null
@@ -0,0 +1,237 @@
+From 158b515f703e75e7d68289bf4d98c664e1d632df Mon Sep 17 00:00:00 2001
+From: George Kennedy <george.kennedy@oracle.com>
+Date: Thu, 16 Dec 2021 13:25:32 -0500
+Subject: tun: avoid double free in tun_free_netdev
+
+From: George Kennedy <george.kennedy@oracle.com>
+
+commit 158b515f703e75e7d68289bf4d98c664e1d632df upstream.
+
+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>
+[DP: adjusted context for 5.4 stable]
+Signed-off-by: Dragos-Marian Panait <dragos.panait@windriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/tun.c |  109 +++++++++++++++++++++++++++++-------------------------
+ 1 file changed, 59 insertions(+), 50 deletions(-)
+
+--- a/drivers/net/tun.c
++++ b/drivers/net/tun.c
+@@ -250,6 +250,9 @@ struct tun_struct {
+       struct tun_prog __rcu *steering_prog;
+       struct tun_prog __rcu *filter_prog;
+       struct ethtool_link_ksettings link_ksettings;
++      /* init args */
++      struct file *file;
++      struct ifreq *ifr;
+ };
+ struct veth {
+@@ -275,6 +278,9 @@ void *tun_ptr_to_xdp(void *ptr)
+ }
+ EXPORT_SYMBOL(tun_ptr_to_xdp);
++static void tun_flow_init(struct tun_struct *tun);
++static void tun_flow_uninit(struct tun_struct *tun);
++
+ static int tun_napi_receive(struct napi_struct *napi, int budget)
+ {
+       struct tun_file *tfile = container_of(napi, struct tun_file, napi);
+@@ -1027,6 +1033,49 @@ static int check_filter(struct tap_filte
+ static const struct ethtool_ops tun_ethtool_ops;
++static int tun_net_init(struct net_device *dev)
++{
++      struct tun_struct *tun = netdev_priv(dev);
++      struct ifreq *ifr = tun->ifr;
++      int err;
++
++      tun->pcpu_stats = netdev_alloc_pcpu_stats(struct tun_pcpu_stats);
++      if (!tun->pcpu_stats)
++              return -ENOMEM;
++
++      spin_lock_init(&tun->lock);
++
++      err = security_tun_dev_alloc_security(&tun->security);
++      if (err < 0) {
++              free_percpu(tun->pcpu_stats);
++              return err;
++      }
++
++      tun_flow_init(tun);
++
++      dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST |
++                         TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |
++                         NETIF_F_HW_VLAN_STAG_TX;
++      dev->features = dev->hw_features | NETIF_F_LLTX;
++      dev->vlan_features = dev->features &
++                           ~(NETIF_F_HW_VLAN_CTAG_TX |
++                             NETIF_F_HW_VLAN_STAG_TX);
++
++      tun->flags = (tun->flags & ~TUN_FEATURES) |
++                    (ifr->ifr_flags & TUN_FEATURES);
++
++      INIT_LIST_HEAD(&tun->disabled);
++      err = tun_attach(tun, tun->file, false, ifr->ifr_flags & IFF_NAPI,
++                       ifr->ifr_flags & IFF_NAPI_FRAGS, false);
++      if (err < 0) {
++              tun_flow_uninit(tun);
++              security_tun_dev_free_security(tun->security);
++              free_percpu(tun->pcpu_stats);
++              return err;
++      }
++      return 0;
++}
++
+ /* Net device detach from fd. */
+ static void tun_net_uninit(struct net_device *dev)
+ {
+@@ -1285,6 +1334,7 @@ static int tun_net_change_carrier(struct
+ }
+ static const struct net_device_ops tun_netdev_ops = {
++      .ndo_init               = tun_net_init,
+       .ndo_uninit             = tun_net_uninit,
+       .ndo_open               = tun_net_open,
+       .ndo_stop               = tun_net_close,
+@@ -1365,6 +1415,7 @@ static int tun_xdp_tx(struct net_device
+ }
+ static const struct net_device_ops tap_netdev_ops = {
++      .ndo_init               = tun_net_init,
+       .ndo_uninit             = tun_net_uninit,
+       .ndo_open               = tun_net_open,
+       .ndo_stop               = tun_net_close,
+@@ -1405,7 +1456,7 @@ static void tun_flow_uninit(struct tun_s
+ #define MAX_MTU 65535
+ /* Initialize net device. */
+-static void tun_net_init(struct net_device *dev)
++static void tun_net_initialize(struct net_device *dev)
+ {
+       struct tun_struct *tun = netdev_priv(dev);
+@@ -2839,9 +2890,6 @@ static int tun_set_iff(struct net *net,
+               if (!dev)
+                       return -ENOMEM;
+-              err = dev_get_valid_name(net, dev, name);
+-              if (err < 0)
+-                      goto err_free_dev;
+               dev_net_set(dev, net);
+               dev->rtnl_link_ops = &tun_link_ops;
+@@ -2860,41 +2908,16 @@ static int tun_set_iff(struct net *net,
+               tun->rx_batched = 0;
+               RCU_INIT_POINTER(tun->steering_prog, NULL);
+-              tun->pcpu_stats = netdev_alloc_pcpu_stats(struct tun_pcpu_stats);
+-              if (!tun->pcpu_stats) {
+-                      err = -ENOMEM;
+-                      goto err_free_dev;
+-              }
+-
+-              spin_lock_init(&tun->lock);
+-
+-              err = security_tun_dev_alloc_security(&tun->security);
+-              if (err < 0)
+-                      goto err_free_stat;
+-
+-              tun_net_init(dev);
+-              tun_flow_init(tun);
++              tun->ifr = ifr;
++              tun->file = file;
+-              dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST |
+-                                 TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |
+-                                 NETIF_F_HW_VLAN_STAG_TX;
+-              dev->features = dev->hw_features | NETIF_F_LLTX;
+-              dev->vlan_features = dev->features &
+-                                   ~(NETIF_F_HW_VLAN_CTAG_TX |
+-                                     NETIF_F_HW_VLAN_STAG_TX);
+-
+-              tun->flags = (tun->flags & ~TUN_FEATURES) |
+-                            (ifr->ifr_flags & TUN_FEATURES);
+-
+-              INIT_LIST_HEAD(&tun->disabled);
+-              err = tun_attach(tun, file, false, ifr->ifr_flags & IFF_NAPI,
+-                               ifr->ifr_flags & IFF_NAPI_FRAGS, false);
+-              if (err < 0)
+-                      goto err_free_flow;
++              tun_net_initialize(dev);
+               err = register_netdevice(tun->dev);
+-              if (err < 0)
+-                      goto err_detach;
++              if (err < 0) {
++                      free_netdev(dev);
++                      return err;
++              }
+               /* free_netdev() won't check refcnt, to aovid race
+                * with dev_put() we need publish tun after registration.
+                */
+@@ -2913,20 +2936,6 @@ static int tun_set_iff(struct net *net,
+       strcpy(ifr->ifr_name, tun->dev->name);
+       return 0;
+-
+-err_detach:
+-      tun_detach_all(dev);
+-      /* register_netdevice() already called tun_free_netdev() */
+-      goto err_free_dev;
+-
+-err_free_flow:
+-      tun_flow_uninit(tun);
+-      security_tun_dev_free_security(tun->security);
+-err_free_stat:
+-      free_percpu(tun->pcpu_stats);
+-err_free_dev:
+-      free_netdev(dev);
+-      return err;
+ }
+ static void tun_get_iff(struct tun_struct *tun, struct ifreq *ifr)