--- /dev/null
+From 1ade48d0c27d5da1ccf4b583d8c5fc8b534a3ac8 Mon Sep 17 00:00:00 2001
+From: Lin Ma <linma@zju.edu.cn>
+Date: Fri, 17 Dec 2021 10:29:41 +0800
+Subject: ax25: NPD bug when detaching AX25 device
+
+From: Lin Ma <linma@zju.edu.cn>
+
+commit 1ade48d0c27d5da1ccf4b583d8c5fc8b534a3ac8 upstream.
+
+The existing cleanup routine implementation is not well synchronized
+with the syscall routine. When a device is detaching, below race could
+occur.
+
+static int ax25_sendmsg(...) {
+ ...
+ lock_sock()
+ ax25 = sk_to_ax25(sk);
+ if (ax25->ax25_dev == NULL) // CHECK
+ ...
+ ax25_queue_xmit(skb, ax25->ax25_dev->dev); // USE
+ ...
+}
+
+static void ax25_kill_by_device(...) {
+ ...
+ if (s->ax25_dev == ax25_dev) {
+ s->ax25_dev = NULL;
+ ...
+}
+
+Other syscall functions like ax25_getsockopt, ax25_getname,
+ax25_info_show also suffer from similar races. To fix them, this patch
+introduce lock_sock() into ax25_kill_by_device in order to guarantee
+that the nullify action in cleanup routine cannot proceed when another
+socket request is pending.
+
+Signed-off-by: Hanjie Wu <nagi@zju.edu.cn>
+Signed-off-by: Lin Ma <linma@zju.edu.cn>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/ax25/af_ax25.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/net/ax25/af_ax25.c
++++ b/net/ax25/af_ax25.c
+@@ -85,8 +85,10 @@ static void ax25_kill_by_device(struct n
+ again:
+ ax25_for_each(s, &ax25_list) {
+ if (s->ax25_dev == ax25_dev) {
+- s->ax25_dev = NULL;
+ spin_unlock_bh(&ax25_list_lock);
++ lock_sock(s->sk);
++ s->ax25_dev = NULL;
++ release_sock(s->sk);
+ ax25_disconnect(s, ENETUNREACH);
+ spin_lock_bh(&ax25_list_lock);
+
--- /dev/null
+From 3e0588c291d6ce225f2b891753ca41d45ba42469 Mon Sep 17 00:00:00 2001
+From: Lin Ma <linma@zju.edu.cn>
+Date: Mon, 8 Nov 2021 18:37:21 +0800
+Subject: hamradio: defer ax25 kfree after unregister_netdev
+
+From: Lin Ma <linma@zju.edu.cn>
+
+commit 3e0588c291d6ce225f2b891753ca41d45ba42469 upstream.
+
+There is a possible race condition (use-after-free) like below
+
+ (USE) | (FREE)
+ax25_sendmsg |
+ ax25_queue_xmit |
+ dev_queue_xmit |
+ __dev_queue_xmit |
+ __dev_xmit_skb |
+ sch_direct_xmit | ...
+ xmit_one |
+ netdev_start_xmit | tty_ldisc_kill
+ __netdev_start_xmit | mkiss_close
+ ax_xmit | kfree
+ ax_encaps |
+ |
+
+Even though there are two synchronization primitives before the kfree:
+1. wait_for_completion(&ax->dead). This can prevent the race with
+routines from mkiss_ioctl. However, it cannot stop the routine coming
+from upper layer, i.e., the ax25_sendmsg.
+
+2. netif_stop_queue(ax->dev). It seems that this line of code aims to
+halt the transmit queue but it fails to stop the routine that already
+being xmit.
+
+This patch reorder the kfree after the unregister_netdev to avoid the
+possible UAF as the unregister_netdev() is well synchronized and won't
+return if there is a running routine.
+
+Signed-off-by: Lin Ma <linma@zju.edu.cn>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/hamradio/mkiss.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/hamradio/mkiss.c
++++ b/drivers/net/hamradio/mkiss.c
+@@ -792,13 +792,14 @@ static void mkiss_close(struct tty_struc
+ */
+ netif_stop_queue(ax->dev);
+
+- /* Free all AX25 frame buffers. */
+- kfree(ax->rbuff);
+- kfree(ax->xbuff);
+-
+ ax->tty = NULL;
+
+ unregister_netdev(ax->dev);
++
++ /* Free all AX25 frame buffers after unreg. */
++ kfree(ax->rbuff);
++ kfree(ax->xbuff);
++
+ free_netdev(ax->dev);
+ }
+
--- /dev/null
+From b2f37aead1b82a770c48b5d583f35ec22aabb61e Mon Sep 17 00:00:00 2001
+From: Lin Ma <linma@zju.edu.cn>
+Date: Fri, 17 Dec 2021 10:13:56 +0800
+Subject: hamradio: improve the incomplete fix to avoid NPD
+
+From: Lin Ma <linma@zju.edu.cn>
+
+commit b2f37aead1b82a770c48b5d583f35ec22aabb61e upstream.
+
+The previous commit 3e0588c291d6 ("hamradio: defer ax25 kfree after
+unregister_netdev") reorder the kfree operations and unregister_netdev
+operation to prevent UAF.
+
+This commit improves the previous one by also deferring the nullify of
+the ax->tty pointer. Otherwise, a NULL pointer dereference bug occurs.
+Partial of the stack trace is shown below.
+
+BUG: kernel NULL pointer dereference, address: 0000000000000538
+RIP: 0010:ax_xmit+0x1f9/0x400
+...
+Call Trace:
+ dev_hard_start_xmit+0xec/0x320
+ sch_direct_xmit+0xea/0x240
+ __qdisc_run+0x166/0x5c0
+ __dev_queue_xmit+0x2c7/0xaf0
+ ax25_std_establish_data_link+0x59/0x60
+ ax25_connect+0x3a0/0x500
+ ? security_socket_connect+0x2b/0x40
+ __sys_connect+0x96/0xc0
+ ? __hrtimer_init+0xc0/0xc0
+ ? common_nsleep+0x2e/0x50
+ ? switch_fpu_return+0x139/0x1a0
+ __x64_sys_connect+0x11/0x20
+ do_syscall_64+0x33/0x40
+ entry_SYSCALL_64_after_hwframe+0x44/0xa9
+
+The crash point is shown as below
+
+static void ax_encaps(...) {
+ ...
+ set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags); // ax->tty = NULL!
+ ...
+}
+
+By placing the nullify action after the unregister_netdev, the ax->tty
+pointer won't be assigned as NULL net_device framework layer is well
+synchronized.
+
+Signed-off-by: Lin Ma <linma@zju.edu.cn>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/hamradio/mkiss.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/hamradio/mkiss.c
++++ b/drivers/net/hamradio/mkiss.c
+@@ -792,14 +792,14 @@ static void mkiss_close(struct tty_struc
+ */
+ netif_stop_queue(ax->dev);
+
+- ax->tty = NULL;
+-
+ unregister_netdev(ax->dev);
+
+ /* Free all AX25 frame buffers after unreg. */
+ kfree(ax->rbuff);
+ kfree(ax->xbuff);
+
++ ax->tty = NULL;
++
+ free_netdev(ax->dev);
+ }
+
--- /dev/null
+From da7dc0568491104c7acb632e9d41ddce9aaabbb1 Mon Sep 17 00:00:00 2001
+From: Guenter Roeck <linux@roeck-us.net>
+Date: Fri, 26 Nov 2021 22:43:39 -0800
+Subject: hwmom: (lm90) Fix citical alarm status for MAX6680/MAX6681
+
+From: Guenter Roeck <linux@roeck-us.net>
+
+commit da7dc0568491104c7acb632e9d41ddce9aaabbb1 upstream.
+
+Tests with a real chip and a closer look into the datasheet reveals
+that the local and remote critical alarm status bits are swapped for
+MAX6680/MAX6681.
+
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/hwmon/lm90.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+--- a/drivers/hwmon/lm90.c
++++ b/drivers/hwmon/lm90.c
+@@ -190,6 +190,7 @@ enum chips { lm90, adm1032, lm99, lm86,
+ #define LM90_HAVE_EXTENDED_TEMP (1 << 8) /* extended temperature support*/
+ #define LM90_PAUSE_FOR_CONFIG (1 << 9) /* Pause conversion for config */
+ #define LM90_HAVE_CRIT (1 << 10)/* Chip supports CRIT/OVERT register */
++#define LM90_HAVE_CRIT_ALRM_SWP (1 << 11)/* critical alarm bits swapped */
+
+ /* LM90 status */
+ #define LM90_STATUS_LTHRM (1 << 0) /* local THERM limit tripped */
+@@ -415,7 +416,8 @@ static const struct lm90_params lm90_par
+ .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
+ },
+ [max6680] = {
+- .flags = LM90_HAVE_OFFSET | LM90_HAVE_CRIT,
++ .flags = LM90_HAVE_OFFSET | LM90_HAVE_CRIT
++ | LM90_HAVE_CRIT_ALRM_SWP,
+ .alert_alarms = 0x7c,
+ .max_convrate = 7,
+ },
+@@ -1201,6 +1203,7 @@ static const u8 lm90_temp_emerg_index[3]
+ static const u8 lm90_min_alarm_bits[3] = { 5, 3, 11 };
+ static const u8 lm90_max_alarm_bits[3] = { 6, 4, 12 };
+ static const u8 lm90_crit_alarm_bits[3] = { 0, 1, 9 };
++static const u8 lm90_crit_alarm_bits_swapped[3] = { 1, 0, 9 };
+ static const u8 lm90_emergency_alarm_bits[3] = { 15, 13, 14 };
+ static const u8 lm90_fault_bits[3] = { 0, 2, 10 };
+
+@@ -1226,7 +1229,10 @@ static int lm90_temp_read(struct device
+ *val = (data->alarms >> lm90_max_alarm_bits[channel]) & 1;
+ break;
+ case hwmon_temp_crit_alarm:
+- *val = (data->alarms >> lm90_crit_alarm_bits[channel]) & 1;
++ if (data->flags & LM90_HAVE_CRIT_ALRM_SWP)
++ *val = (data->alarms >> lm90_crit_alarm_bits_swapped[channel]) & 1;
++ else
++ *val = (data->alarms >> lm90_crit_alarm_bits[channel]) & 1;
+ break;
+ case hwmon_temp_emergency_alarm:
+ *val = (data->alarms >> lm90_emergency_alarm_bits[channel]) & 1;
--- /dev/null
+From cdc5287acad9ede121924a9c9313544b80d15842 Mon Sep 17 00:00:00 2001
+From: Guenter Roeck <linux@roeck-us.net>
+Date: Fri, 3 Dec 2021 13:42:22 -0800
+Subject: hwmon: (lm90) Do not report 'busy' status bit as alarm
+
+From: Guenter Roeck <linux@roeck-us.net>
+
+commit cdc5287acad9ede121924a9c9313544b80d15842 upstream.
+
+Bit 7 of the status register indicates that the chip is busy
+doing a conversion. It does not indicate an alarm status.
+Stop reporting it as alarm status bit.
+
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/hwmon/lm90.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/hwmon/lm90.c
++++ b/drivers/hwmon/lm90.c
+@@ -200,6 +200,7 @@ enum chips { lm90, adm1032, lm99, lm86,
+ #define LM90_STATUS_RHIGH (1 << 4) /* remote high temp limit tripped */
+ #define LM90_STATUS_LLOW (1 << 5) /* local low temp limit tripped */
+ #define LM90_STATUS_LHIGH (1 << 6) /* local high temp limit tripped */
++#define LM90_STATUS_BUSY (1 << 7) /* conversion is ongoing */
+
+ #define MAX6696_STATUS2_R2THRM (1 << 1) /* remote2 THERM limit tripped */
+ #define MAX6696_STATUS2_R2OPEN (1 << 2) /* remote2 is an open circuit */
+@@ -820,7 +821,7 @@ static int lm90_update_device(struct dev
+ val = lm90_read_reg(client, LM90_REG_R_STATUS);
+ if (val < 0)
+ return val;
+- data->alarms = val; /* lower 8 bit of alarms */
++ data->alarms = val & ~LM90_STATUS_BUSY;
+
+ if (data->kind == max6696) {
+ val = lm90_select_remote_channel(data, 1);
--- /dev/null
+From 75a2f31520095600f650597c0ac41f48b5ba0068 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= <remi@remlab.net>
+Date: Sun, 19 Dec 2021 19:03:39 +0200
+Subject: phonet/pep: refuse to enable an unbound pipe
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Rémi Denis-Courmont <remi@remlab.net>
+
+commit 75a2f31520095600f650597c0ac41f48b5ba0068 upstream.
+
+This ioctl() implicitly assumed that the socket was already bound to
+a valid local socket name, i.e. Phonet object. If the socket was not
+bound, two separate problems would occur:
+
+1) We'd send an pipe enablement request with an invalid source object.
+2) Later socket calls could BUG on the socket unexpectedly being
+ connected yet not bound to a valid object.
+
+Reported-by: syzbot+2dc91e7fc3dea88b1e8a@syzkaller.appspotmail.com
+Signed-off-by: Rémi Denis-Courmont <remi@remlab.net>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/phonet/pep.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/net/phonet/pep.c
++++ b/net/phonet/pep.c
+@@ -946,6 +946,8 @@ static int pep_ioctl(struct sock *sk, in
+ ret = -EBUSY;
+ else if (sk->sk_state == TCP_ESTABLISHED)
+ ret = -EISCONN;
++ else if (!pn->pn_sk.sobject)
++ ret = -EADDRNOTAVAIL;
+ else
+ ret = pep_sock_enable(sk, NULL, 0);
+ release_sock(sk);
--- /dev/null
+From 2d5446da5acecf9c67db1c9d55ae2c3e5de01f8d Mon Sep 17 00:00:00 2001
+From: Guodong Liu <guodong.liu@mediatek.corp-partner.google.com>
+Date: Wed, 10 Nov 2021 15:19:00 +0800
+Subject: pinctrl: mediatek: fix global-out-of-bounds issue
+
+From: Guodong Liu <guodong.liu@mediatek.corp-partner.google.com>
+
+commit 2d5446da5acecf9c67db1c9d55ae2c3e5de01f8d upstream.
+
+When eint virtual eint number is greater than gpio number,
+it maybe produce 'desc[eint_n]' size globle-out-of-bounds issue.
+
+Signed-off-by: Guodong Liu <guodong.liu@mediatek.corp-partner.google.com>
+Signed-off-by: Zhiyong Tao <zhiyong.tao@mediatek.com>
+Reviewed-by: Chen-Yu Tsai <wenst@chromium.org>
+Link: https://lore.kernel.org/r/20211110071900.4490-2-zhiyong.tao@mediatek.com
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
++++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
+@@ -285,8 +285,12 @@ static int mtk_xt_get_gpio_n(void *data,
+ desc = (const struct mtk_pin_desc *)hw->soc->pins;
+ *gpio_chip = &hw->chip;
+
+- /* Be greedy to guess first gpio_n is equal to eint_n */
+- if (desc[eint_n].eint.eint_n == eint_n)
++ /*
++ * Be greedy to guess first gpio_n is equal to eint_n.
++ * Only eint virtual eint number is greater than gpio number.
++ */
++ if (hw->soc->npins > eint_n &&
++ desc[eint_n].eint.eint_n == eint_n)
+ *gpio_n = eint_n;
+ else
+ *gpio_n = mtk_xt_find_eint_num(hw, eint_n);
--- /dev/null
+From b24edca309535c2d9af86aab95d64065f6ef1d26 Mon Sep 17 00:00:00 2001
+From: Hayes Wang <hayeswang@realtek.com>
+Date: Thu, 23 Dec 2021 17:27:02 +0800
+Subject: r8152: sync ocp base
+
+From: Hayes Wang <hayeswang@realtek.com>
+
+commit b24edca309535c2d9af86aab95d64065f6ef1d26 upstream.
+
+There are some chances that the actual base of hardware is different
+from the value recorded by driver, so we have to reset the variable
+of ocp_base to sync it.
+
+Set ocp_base to -1. Then, it would be updated and the new base would be
+set to the hardware next time.
+
+Signed-off-by: Hayes Wang <hayeswang@realtek.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/usb/r8152.c | 26 ++++++++++++++++++++++----
+ 1 file changed, 22 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/usb/r8152.c
++++ b/drivers/net/usb/r8152.c
+@@ -32,7 +32,7 @@
+ #define NETNEXT_VERSION "12"
+
+ /* Information for net */
+-#define NET_VERSION "11"
++#define NET_VERSION "12"
+
+ #define DRIVER_VERSION "v1." NETNEXT_VERSION "." NET_VERSION
+ #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
+@@ -4016,6 +4016,11 @@ static void rtl_clear_bp(struct r8152 *t
+ ocp_write_word(tp, type, PLA_BP_BA, 0);
+ }
+
++static inline void rtl_reset_ocp_base(struct r8152 *tp)
++{
++ tp->ocp_base = -1;
++}
++
+ static int rtl_phy_patch_request(struct r8152 *tp, bool request, bool wait)
+ {
+ u16 data, check;
+@@ -4087,8 +4092,6 @@ static int rtl_post_ram_code(struct r815
+
+ rtl_phy_patch_request(tp, false, wait);
+
+- ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, tp->ocp_base);
+-
+ return 0;
+ }
+
+@@ -4800,6 +4803,8 @@ static void rtl_ram_code_speed_up(struct
+ u32 len;
+ u8 *data;
+
++ rtl_reset_ocp_base(tp);
++
+ if (sram_read(tp, SRAM_GPHY_FW_VER) >= __le16_to_cpu(phy->version)) {
+ dev_dbg(&tp->intf->dev, "PHY firmware has been the newest\n");
+ return;
+@@ -4845,7 +4850,8 @@ static void rtl_ram_code_speed_up(struct
+ }
+ }
+
+- ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, tp->ocp_base);
++ rtl_reset_ocp_base(tp);
++
+ rtl_phy_patch_request(tp, false, wait);
+
+ if (sram_read(tp, SRAM_GPHY_FW_VER) == __le16_to_cpu(phy->version))
+@@ -4861,6 +4867,8 @@ static int rtl8152_fw_phy_ver(struct r81
+ ver_addr = __le16_to_cpu(phy_ver->ver.addr);
+ ver = __le16_to_cpu(phy_ver->ver.data);
+
++ rtl_reset_ocp_base(tp);
++
+ if (sram_read(tp, ver_addr) >= ver) {
+ dev_dbg(&tp->intf->dev, "PHY firmware has been the newest\n");
+ return 0;
+@@ -4877,6 +4885,8 @@ static void rtl8152_fw_phy_fixup(struct
+ {
+ u16 addr, data;
+
++ rtl_reset_ocp_base(tp);
++
+ addr = __le16_to_cpu(fix->setting.addr);
+ data = ocp_reg_read(tp, addr);
+
+@@ -4908,6 +4918,8 @@ static void rtl8152_fw_phy_union_apply(s
+ u32 length;
+ int i, num;
+
++ rtl_reset_ocp_base(tp);
++
+ num = phy->pre_num;
+ for (i = 0; i < num; i++)
+ sram_write(tp, __le16_to_cpu(phy->pre_set[i].addr),
+@@ -4938,6 +4950,8 @@ static void rtl8152_fw_phy_nc_apply(stru
+ u32 length, i, num;
+ __le16 *data;
+
++ rtl_reset_ocp_base(tp);
++
+ mode_reg = __le16_to_cpu(phy->mode_reg);
+ sram_write(tp, mode_reg, __le16_to_cpu(phy->mode_pre));
+ sram_write(tp, __le16_to_cpu(phy->ba_reg),
+@@ -5107,6 +5121,7 @@ post_fw:
+ if (rtl_fw->post_fw)
+ rtl_fw->post_fw(tp);
+
++ rtl_reset_ocp_base(tp);
+ strscpy(rtl_fw->version, fw_hdr->version, RTL_VER_SIZE);
+ dev_info(&tp->intf->dev, "load %s successfully\n", rtl_fw->version);
+ }
+@@ -8484,6 +8499,8 @@ static int rtl8152_resume(struct usb_int
+
+ mutex_lock(&tp->control);
+
++ rtl_reset_ocp_base(tp);
++
+ if (test_bit(SELECTIVE_SUSPEND, &tp->flags))
+ ret = rtl8152_runtime_resume(tp);
+ else
+@@ -8499,6 +8516,7 @@ static int rtl8152_reset_resume(struct u
+ struct r8152 *tp = usb_get_intfdata(intf);
+
+ clear_bit(SELECTIVE_SUSPEND, &tp->flags);
++ rtl_reset_ocp_base(tp);
+ tp->rtl_ops.init(tp);
+ queue_delayed_work(system_long_wq, &tp->hw_phy_work, 0);
+ set_ethernet_addr(tp, true);
asoc-sof-intel-pci-tgl-add-new-adl-p-variant.patch
asoc-sof-intel-pci-tgl-add-adl-n-support.patch
asoc-rt5682-fix-the-wrong-jack-type-detected.patch
+pinctrl-mediatek-fix-global-out-of-bounds-issue.patch
+hwmom-lm90-fix-citical-alarm-status-for-max6680-max6681.patch
+hwmon-lm90-do-not-report-busy-status-bit-as-alarm.patch
+r8152-sync-ocp-base.patch
+ax25-npd-bug-when-detaching-ax25-device.patch
+hamradio-defer-ax25-kfree-after-unregister_netdev.patch
+hamradio-improve-the-incomplete-fix-to-avoid-npd.patch
+tun-avoid-double-free-in-tun_free_netdev.patch
+phonet-pep-refuse-to-enable-an-unbound-pipe.patch
--- /dev/null
+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>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/tun.c | 115 +++++++++++++++++++++++++++---------------------------
+ 1 file changed, 59 insertions(+), 56 deletions(-)
+
+--- a/drivers/net/tun.c
++++ b/drivers/net/tun.c
+@@ -209,6 +209,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 {
+@@ -216,6 +219,9 @@ struct veth {
+ __be16 h_vlan_TCI;
+ };
+
++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);
+@@ -953,6 +959,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;
++
++ dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
++ if (!dev->tstats)
++ return -ENOMEM;
++
++ spin_lock_init(&tun->lock);
++
++ err = security_tun_dev_alloc_security(&tun->security);
++ if (err < 0) {
++ free_percpu(dev->tstats);
++ 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(dev->tstats);
++ return err;
++ }
++ return 0;
++}
++
+ /* Net device detach from fd. */
+ static void tun_net_uninit(struct net_device *dev)
+ {
+@@ -1169,6 +1218,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,
+@@ -1252,6 +1302,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,
+@@ -1292,7 +1343,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);
+
+@@ -2206,11 +2257,6 @@ static void tun_free_netdev(struct net_d
+ BUG_ON(!(list_empty(&tun->disabled)));
+
+ free_percpu(dev->tstats);
+- /* We clear tstats so that tun_set_iff() can tell if
+- * tun_free_netdev() has been called from register_netdevice().
+- */
+- dev->tstats = NULL;
+-
+ tun_flow_uninit(tun);
+ security_tun_dev_free_security(tun->security);
+ __tun_set_ebpf(tun, &tun->steering_prog, NULL);
+@@ -2716,41 +2762,16 @@ static int tun_set_iff(struct net *net,
+ tun->rx_batched = 0;
+ RCU_INIT_POINTER(tun->steering_prog, NULL);
+
+- dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
+- if (!dev->tstats) {
+- 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);
+-
+- 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);
++ tun->ifr = ifr;
++ tun->file = file;
+
+- 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 avoid race
+ * with dev_put() we need publish tun after registration.
+ */
+@@ -2767,24 +2788,6 @@ static int tun_set_iff(struct net *net,
+
+ strcpy(ifr->ifr_name, tun->dev->name);
+ return 0;
+-
+-err_detach:
+- tun_detach_all(dev);
+- /* We are here because register_netdevice() has failed.
+- * If register_netdevice() already called tun_free_netdev()
+- * while dealing with the error, dev->stats has been cleared.
+- */
+- if (!dev->tstats)
+- goto err_free_dev;
+-
+-err_free_flow:
+- tun_flow_uninit(tun);
+- security_tun_dev_free_security(tun->security);
+-err_free_stat:
+- free_percpu(dev->tstats);
+-err_free_dev:
+- free_netdev(dev);
+- return err;
+ }
+
+ static void tun_get_iff(struct tun_struct *tun, struct ifreq *ifr)