]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.1-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 13 Oct 2025 08:42:07 +0000 (10:42 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 13 Oct 2025 08:42:07 +0000 (10:42 +0200)
added patches:
fs-udf-fix-oob-read-in-lengthallocdescs-handling.patch
mfd-vexpress-sysreg-check-the-return-value-of-devm_gpiochip_add_data.patch
net-nfc-nci-add-parameter-validation-for-packet-data.patch
uio_hv_generic-let-userspace-take-care-of-interrupt-mask.patch

queue-6.1/fs-udf-fix-oob-read-in-lengthallocdescs-handling.patch [new file with mode: 0644]
queue-6.1/mfd-vexpress-sysreg-check-the-return-value-of-devm_gpiochip_add_data.patch [new file with mode: 0644]
queue-6.1/net-nfc-nci-add-parameter-validation-for-packet-data.patch [new file with mode: 0644]
queue-6.1/series
queue-6.1/uio_hv_generic-let-userspace-take-care-of-interrupt-mask.patch [new file with mode: 0644]

diff --git a/queue-6.1/fs-udf-fix-oob-read-in-lengthallocdescs-handling.patch b/queue-6.1/fs-udf-fix-oob-read-in-lengthallocdescs-handling.patch
new file mode 100644 (file)
index 0000000..54ab0ef
--- /dev/null
@@ -0,0 +1,76 @@
+From 3bd5e45c2ce30e239d596becd5db720f7eb83c99 Mon Sep 17 00:00:00 2001
+From: Larshin Sergey <Sergey.Larshin@kaspersky.com>
+Date: Mon, 22 Sep 2025 16:13:58 +0300
+Subject: fs: udf: fix OOB read in lengthAllocDescs handling
+
+From: Larshin Sergey <Sergey.Larshin@kaspersky.com>
+
+commit 3bd5e45c2ce30e239d596becd5db720f7eb83c99 upstream.
+
+When parsing Allocation Extent Descriptor, lengthAllocDescs comes from
+on-disk data and must be validated against the block size. Crafted or
+corrupted images may set lengthAllocDescs so that the total descriptor
+length (sizeof(allocExtDesc) + lengthAllocDescs) exceeds the buffer,
+leading udf_update_tag() to call crc_itu_t() on out-of-bounds memory and
+trigger a KASAN use-after-free read.
+
+BUG: KASAN: use-after-free in crc_itu_t+0x1d5/0x2b0 lib/crc-itu-t.c:60
+Read of size 1 at addr ffff888041e7d000 by task syz-executor317/5309
+
+CPU: 0 UID: 0 PID: 5309 Comm: syz-executor317 Not tainted 6.12.0-rc4-syzkaller-00261-g850925a8133c #0
+Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
+Call Trace:
+ <TASK>
+ __dump_stack lib/dump_stack.c:94 [inline]
+ dump_stack_lvl+0x241/0x360 lib/dump_stack.c:120
+ print_address_description mm/kasan/report.c:377 [inline]
+ print_report+0x169/0x550 mm/kasan/report.c:488
+ kasan_report+0x143/0x180 mm/kasan/report.c:601
+ crc_itu_t+0x1d5/0x2b0 lib/crc-itu-t.c:60
+ udf_update_tag+0x70/0x6a0 fs/udf/misc.c:261
+ udf_write_aext+0x4d8/0x7b0 fs/udf/inode.c:2179
+ extent_trunc+0x2f7/0x4a0 fs/udf/truncate.c:46
+ udf_truncate_tail_extent+0x527/0x7e0 fs/udf/truncate.c:106
+ udf_release_file+0xc1/0x120 fs/udf/file.c:185
+ __fput+0x23f/0x880 fs/file_table.c:431
+ task_work_run+0x24f/0x310 kernel/task_work.c:239
+ exit_task_work include/linux/task_work.h:43 [inline]
+ do_exit+0xa2f/0x28e0 kernel/exit.c:939
+ do_group_exit+0x207/0x2c0 kernel/exit.c:1088
+ __do_sys_exit_group kernel/exit.c:1099 [inline]
+ __se_sys_exit_group kernel/exit.c:1097 [inline]
+ __x64_sys_exit_group+0x3f/0x40 kernel/exit.c:1097
+ x64_sys_call+0x2634/0x2640 arch/x86/include/generated/asm/syscalls_64.h:232
+ do_syscall_x64 arch/x86/entry/common.c:52 [inline]
+ do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+ </TASK>
+
+Validate the computed total length against epos->bh->b_size.
+
+Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
+
+Reported-by: syzbot+8743fca924afed42f93e@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=8743fca924afed42f93e
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Cc: stable@vger.kernel.org
+Signed-off-by: Larshin Sergey <Sergey.Larshin@kaspersky.com>
+Link: https://patch.msgid.link/20250922131358.745579-1-Sergey.Larshin@kaspersky.com
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/udf/inode.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/fs/udf/inode.c
++++ b/fs/udf/inode.c
+@@ -2112,6 +2112,9 @@ int udf_current_aext(struct inode *inode
+               if (check_add_overflow(sizeof(struct allocExtDesc),
+                               le32_to_cpu(header->lengthAllocDescs), &alen))
+                       return -1;
++
++              if (alen > epos->bh->b_size)
++                      return -1;
+       }
+       switch (iinfo->i_alloc_type) {
diff --git a/queue-6.1/mfd-vexpress-sysreg-check-the-return-value-of-devm_gpiochip_add_data.patch b/queue-6.1/mfd-vexpress-sysreg-check-the-return-value-of-devm_gpiochip_add_data.patch
new file mode 100644 (file)
index 0000000..853fc87
--- /dev/null
@@ -0,0 +1,48 @@
+From 1efbee6852f1ff698a9981bd731308dd027189fb Mon Sep 17 00:00:00 2001
+From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Date: Mon, 11 Aug 2025 15:36:16 +0200
+Subject: mfd: vexpress-sysreg: Check the return value of devm_gpiochip_add_data()
+
+From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+commit 1efbee6852f1ff698a9981bd731308dd027189fb upstream.
+
+Commit 974cc7b93441 ("mfd: vexpress: Define the device as MFD cells")
+removed the return value check from the call to gpiochip_add_data() (or
+rather gpiochip_add() back then and later converted to devres) with no
+explanation. This function however can still fail, so check the return
+value and bail-out if it does.
+
+Cc: stable@vger.kernel.org
+Fixes: 974cc7b93441 ("mfd: vexpress: Define the device as MFD cells")
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
+Link: https://lore.kernel.org/r/20250811-gpio-mmio-mfd-conv-v1-1-68c5c958cf80@linaro.org
+Signed-off-by: Lee Jones <lee@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/mfd/vexpress-sysreg.c |    6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/drivers/mfd/vexpress-sysreg.c
++++ b/drivers/mfd/vexpress-sysreg.c
+@@ -98,6 +98,7 @@ static int vexpress_sysreg_probe(struct
+       struct resource *mem;
+       void __iomem *base;
+       struct gpio_chip *mmc_gpio_chip;
++      int ret;
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem)
+@@ -118,7 +119,10 @@ static int vexpress_sysreg_probe(struct
+       bgpio_init(mmc_gpio_chip, &pdev->dev, 0x4, base + SYS_MCI,
+                       NULL, NULL, NULL, NULL, 0);
+       mmc_gpio_chip->ngpio = 2;
+-      devm_gpiochip_add_data(&pdev->dev, mmc_gpio_chip, NULL);
++
++      ret = devm_gpiochip_add_data(&pdev->dev, mmc_gpio_chip, NULL);
++      if (ret)
++              return ret;
+       return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO,
+                       vexpress_sysreg_cells,
diff --git a/queue-6.1/net-nfc-nci-add-parameter-validation-for-packet-data.patch b/queue-6.1/net-nfc-nci-add-parameter-validation-for-packet-data.patch
new file mode 100644 (file)
index 0000000..d79e70d
--- /dev/null
@@ -0,0 +1,342 @@
+From 9c328f54741bd5465ca1dc717c84c04242fac2e1 Mon Sep 17 00:00:00 2001
+From: Deepak Sharma <deepak.sharma.472935@gmail.com>
+Date: Thu, 25 Sep 2025 18:58:46 +0530
+Subject: net: nfc: nci: Add parameter validation for packet data
+
+From: Deepak Sharma <deepak.sharma.472935@gmail.com>
+
+commit 9c328f54741bd5465ca1dc717c84c04242fac2e1 upstream.
+
+Syzbot reported an uninitialized value bug in nci_init_req, which was
+introduced by commit 5aca7966d2a7 ("Merge tag
+'perf-tools-fixes-for-v6.17-2025-09-16' of
+git://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools").
+
+This bug arises due to very limited and poor input validation
+that was done at nic_valid_size(). This validation only
+validates the skb->len (directly reflects size provided at the
+userspace interface) with the length provided in the buffer
+itself (interpreted as NCI_HEADER). This leads to the processing
+of memory content at the address assuming the correct layout
+per what opcode requires there. This leads to the accesses to
+buffer of `skb_buff->data` which is not assigned anything yet.
+
+Following the same silent drop of packets of invalid sizes at
+`nic_valid_size()`, add validation of the data in the respective
+handlers and return error values in case of failure. Release
+the skb if error values are returned from handlers in
+`nci_nft_packet` and effectively do a silent drop
+
+Possible TODO: because we silently drop the packets, the
+call to `nci_request` will be waiting for completion of request
+and will face timeouts. These timeouts can get excessively logged
+in the dmesg. A proper handling of them may require to export
+`nci_request_cancel` (or propagate error handling from the
+nft packets handlers).
+
+Reported-by: syzbot+740e04c2a93467a0f8c8@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=740e04c2a93467a0f8c8
+Fixes: 6a2968aaf50c ("NFC: basic NCI protocol implementation")
+Tested-by: syzbot+740e04c2a93467a0f8c8@syzkaller.appspotmail.com
+Cc: stable@vger.kernel.org
+Signed-off-by: Deepak Sharma <deepak.sharma.472935@gmail.com>
+Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
+Link: https://patch.msgid.link/20250925132846.213425-1-deepak.sharma.472935@gmail.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/nfc/nci/ntf.c |  135 +++++++++++++++++++++++++++++++++++++++---------------
+ 1 file changed, 99 insertions(+), 36 deletions(-)
+
+--- a/net/nfc/nci/ntf.c
++++ b/net/nfc/nci/ntf.c
+@@ -27,11 +27,16 @@
+ /* Handle NCI Notification packets */
+-static void nci_core_reset_ntf_packet(struct nci_dev *ndev,
+-                                    const struct sk_buff *skb)
++static int nci_core_reset_ntf_packet(struct nci_dev *ndev,
++                                   const struct sk_buff *skb)
+ {
+       /* Handle NCI 2.x core reset notification */
+-      const struct nci_core_reset_ntf *ntf = (void *)skb->data;
++      const struct nci_core_reset_ntf *ntf;
++
++      if (skb->len < sizeof(struct nci_core_reset_ntf))
++              return -EINVAL;
++
++      ntf = (struct nci_core_reset_ntf *)skb->data;
+       ndev->nci_ver = ntf->nci_ver;
+       pr_debug("nci_ver 0x%x, config_status 0x%x\n",
+@@ -42,15 +47,22 @@ static void nci_core_reset_ntf_packet(st
+               __le32_to_cpu(ntf->manufact_specific_info);
+       nci_req_complete(ndev, NCI_STATUS_OK);
++
++      return 0;
+ }
+-static void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
+-                                           struct sk_buff *skb)
++static int nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
++                                          struct sk_buff *skb)
+ {
+-      struct nci_core_conn_credit_ntf *ntf = (void *) skb->data;
++      struct nci_core_conn_credit_ntf *ntf;
+       struct nci_conn_info *conn_info;
+       int i;
++      if (skb->len < sizeof(struct nci_core_conn_credit_ntf))
++              return -EINVAL;
++
++      ntf = (struct nci_core_conn_credit_ntf *)skb->data;
++
+       pr_debug("num_entries %d\n", ntf->num_entries);
+       if (ntf->num_entries > NCI_MAX_NUM_CONN)
+@@ -68,7 +80,7 @@ static void nci_core_conn_credits_ntf_pa
+               conn_info = nci_get_conn_info_by_conn_id(ndev,
+                                                        ntf->conn_entries[i].conn_id);
+               if (!conn_info)
+-                      return;
++                      return 0;
+               atomic_add(ntf->conn_entries[i].credits,
+                          &conn_info->credits_cnt);
+@@ -77,12 +89,19 @@ static void nci_core_conn_credits_ntf_pa
+       /* trigger the next tx */
+       if (!skb_queue_empty(&ndev->tx_q))
+               queue_work(ndev->tx_wq, &ndev->tx_work);
++
++      return 0;
+ }
+-static void nci_core_generic_error_ntf_packet(struct nci_dev *ndev,
+-                                            const struct sk_buff *skb)
++static int nci_core_generic_error_ntf_packet(struct nci_dev *ndev,
++                                           const struct sk_buff *skb)
+ {
+-      __u8 status = skb->data[0];
++      __u8 status;
++
++      if (skb->len < 1)
++              return -EINVAL;
++
++      status = skb->data[0];
+       pr_debug("status 0x%x\n", status);
+@@ -91,12 +110,19 @@ static void nci_core_generic_error_ntf_p
+                  (the state remains the same) */
+               nci_req_complete(ndev, status);
+       }
++
++      return 0;
+ }
+-static void nci_core_conn_intf_error_ntf_packet(struct nci_dev *ndev,
+-                                              struct sk_buff *skb)
++static int nci_core_conn_intf_error_ntf_packet(struct nci_dev *ndev,
++                                             struct sk_buff *skb)
+ {
+-      struct nci_core_intf_error_ntf *ntf = (void *) skb->data;
++      struct nci_core_intf_error_ntf *ntf;
++
++      if (skb->len < sizeof(struct nci_core_intf_error_ntf))
++              return -EINVAL;
++
++      ntf = (struct nci_core_intf_error_ntf *)skb->data;
+       ntf->conn_id = nci_conn_id(&ntf->conn_id);
+@@ -105,6 +131,8 @@ static void nci_core_conn_intf_error_ntf
+       /* complete the data exchange transaction, if exists */
+       if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags))
+               nci_data_exchange_complete(ndev, NULL, ntf->conn_id, -EIO);
++
++      return 0;
+ }
+ static const __u8 *
+@@ -329,13 +357,18 @@ void nci_clear_target_list(struct nci_de
+       ndev->n_targets = 0;
+ }
+-static void nci_rf_discover_ntf_packet(struct nci_dev *ndev,
+-                                     const struct sk_buff *skb)
++static int nci_rf_discover_ntf_packet(struct nci_dev *ndev,
++                                    const struct sk_buff *skb)
+ {
+       struct nci_rf_discover_ntf ntf;
+-      const __u8 *data = skb->data;
++      const __u8 *data;
+       bool add_target = true;
++      if (skb->len < sizeof(struct nci_rf_discover_ntf))
++              return -EINVAL;
++
++      data = skb->data;
++
+       ntf.rf_discovery_id = *data++;
+       ntf.rf_protocol = *data++;
+       ntf.rf_tech_and_mode = *data++;
+@@ -390,6 +423,8 @@ static void nci_rf_discover_ntf_packet(s
+               nfc_targets_found(ndev->nfc_dev, ndev->targets,
+                                 ndev->n_targets);
+       }
++
++      return 0;
+ }
+ static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev,
+@@ -531,14 +566,19 @@ static int nci_store_general_bytes_nfc_d
+       return NCI_STATUS_OK;
+ }
+-static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
+-                                           const struct sk_buff *skb)
++static int nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
++                                          const struct sk_buff *skb)
+ {
+       struct nci_conn_info *conn_info;
+       struct nci_rf_intf_activated_ntf ntf;
+-      const __u8 *data = skb->data;
++      const __u8 *data;
+       int err = NCI_STATUS_OK;
++      if (skb->len < sizeof(struct nci_rf_intf_activated_ntf))
++              return -EINVAL;
++
++      data = skb->data;
++
+       ntf.rf_discovery_id = *data++;
+       ntf.rf_interface = *data++;
+       ntf.rf_protocol = *data++;
+@@ -645,7 +685,7 @@ exit:
+       if (err == NCI_STATUS_OK) {
+               conn_info = ndev->rf_conn_info;
+               if (!conn_info)
+-                      return;
++                      return 0;
+               conn_info->max_pkt_payload_len = ntf.max_data_pkt_payload_size;
+               conn_info->initial_num_credits = ntf.initial_num_credits;
+@@ -691,19 +731,26 @@ listen:
+                               pr_err("error when signaling tm activation\n");
+               }
+       }
++
++      return 0;
+ }
+-static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev,
+-                                       const struct sk_buff *skb)
++static int nci_rf_deactivate_ntf_packet(struct nci_dev *ndev,
++                                      const struct sk_buff *skb)
+ {
+       const struct nci_conn_info *conn_info;
+-      const struct nci_rf_deactivate_ntf *ntf = (void *)skb->data;
++      const struct nci_rf_deactivate_ntf *ntf;
++
++      if (skb->len < sizeof(struct nci_rf_deactivate_ntf))
++              return -EINVAL;
++
++      ntf = (struct nci_rf_deactivate_ntf *)skb->data;
+       pr_debug("entry, type 0x%x, reason 0x%x\n", ntf->type, ntf->reason);
+       conn_info = ndev->rf_conn_info;
+       if (!conn_info)
+-              return;
++              return 0;
+       /* drop tx data queue */
+       skb_queue_purge(&ndev->tx_q);
+@@ -735,14 +782,20 @@ static void nci_rf_deactivate_ntf_packet
+       }
+       nci_req_complete(ndev, NCI_STATUS_OK);
++
++      return 0;
+ }
+-static void nci_nfcee_discover_ntf_packet(struct nci_dev *ndev,
+-                                        const struct sk_buff *skb)
++static int nci_nfcee_discover_ntf_packet(struct nci_dev *ndev,
++                                       const struct sk_buff *skb)
+ {
+       u8 status = NCI_STATUS_OK;
+-      const struct nci_nfcee_discover_ntf *nfcee_ntf =
+-                              (struct nci_nfcee_discover_ntf *)skb->data;
++      const struct nci_nfcee_discover_ntf *nfcee_ntf;
++
++      if (skb->len < sizeof(struct nci_nfcee_discover_ntf))
++              return -EINVAL;
++
++      nfcee_ntf = (struct nci_nfcee_discover_ntf *)skb->data;
+       /* NFCForum NCI 9.2.1 HCI Network Specific Handling
+        * If the NFCC supports the HCI Network, it SHALL return one,
+@@ -753,6 +806,8 @@ static void nci_nfcee_discover_ntf_packe
+       ndev->cur_params.id = nfcee_ntf->nfcee_id;
+       nci_req_complete(ndev, status);
++
++      return 0;
+ }
+ void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb)
+@@ -779,35 +834,43 @@ void nci_ntf_packet(struct nci_dev *ndev
+       switch (ntf_opcode) {
+       case NCI_OP_CORE_RESET_NTF:
+-              nci_core_reset_ntf_packet(ndev, skb);
++              if (nci_core_reset_ntf_packet(ndev, skb))
++                      goto end;
+               break;
+       case NCI_OP_CORE_CONN_CREDITS_NTF:
+-              nci_core_conn_credits_ntf_packet(ndev, skb);
++              if (nci_core_conn_credits_ntf_packet(ndev, skb))
++                      goto end;
+               break;
+       case NCI_OP_CORE_GENERIC_ERROR_NTF:
+-              nci_core_generic_error_ntf_packet(ndev, skb);
++              if (nci_core_generic_error_ntf_packet(ndev, skb))
++                      goto end;
+               break;
+       case NCI_OP_CORE_INTF_ERROR_NTF:
+-              nci_core_conn_intf_error_ntf_packet(ndev, skb);
++              if (nci_core_conn_intf_error_ntf_packet(ndev, skb))
++                      goto end;
+               break;
+       case NCI_OP_RF_DISCOVER_NTF:
+-              nci_rf_discover_ntf_packet(ndev, skb);
++              if (nci_rf_discover_ntf_packet(ndev, skb))
++                      goto end;
+               break;
+       case NCI_OP_RF_INTF_ACTIVATED_NTF:
+-              nci_rf_intf_activated_ntf_packet(ndev, skb);
++              if (nci_rf_intf_activated_ntf_packet(ndev, skb))
++                      goto end;
+               break;
+       case NCI_OP_RF_DEACTIVATE_NTF:
+-              nci_rf_deactivate_ntf_packet(ndev, skb);
++              if (nci_rf_deactivate_ntf_packet(ndev, skb))
++                      goto end;
+               break;
+       case NCI_OP_NFCEE_DISCOVER_NTF:
+-              nci_nfcee_discover_ntf_packet(ndev, skb);
++              if (nci_nfcee_discover_ntf_packet(ndev, skb))
++                      goto end;
+               break;
+       case NCI_OP_RF_NFCEE_ACTION_NTF:
index b9451be32cb4ccde3241caa09e2bd859ddd86b5b..e7716df8611b825998773c954ab0e1017dcc32f1 100644 (file)
@@ -172,3 +172,7 @@ net-mlx5-fw-reset-add-reset-timeout-work.patch
 revert-net-mlx5e-update-and-set-xon-xoff-upon-mtu-se.patch
 vhost-vringh-modify-the-return-value-check.patch
 squashfs-fix-uninit-value-in-squashfs_get_parent.patch
+uio_hv_generic-let-userspace-take-care-of-interrupt-mask.patch
+fs-udf-fix-oob-read-in-lengthallocdescs-handling.patch
+net-nfc-nci-add-parameter-validation-for-packet-data.patch
+mfd-vexpress-sysreg-check-the-return-value-of-devm_gpiochip_add_data.patch
diff --git a/queue-6.1/uio_hv_generic-let-userspace-take-care-of-interrupt-mask.patch b/queue-6.1/uio_hv_generic-let-userspace-take-care-of-interrupt-mask.patch
new file mode 100644 (file)
index 0000000..2ffd512
--- /dev/null
@@ -0,0 +1,97 @@
+From b15b7d2a1b09ef5428a8db260251897405a19496 Mon Sep 17 00:00:00 2001
+From: Naman Jain <namjain@linux.microsoft.com>
+Date: Thu, 28 Aug 2025 10:12:00 +0530
+Subject: uio_hv_generic: Let userspace take care of interrupt mask
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Naman Jain <namjain@linux.microsoft.com>
+
+commit b15b7d2a1b09ef5428a8db260251897405a19496 upstream.
+
+Remove the logic to set interrupt mask by default in uio_hv_generic
+driver as the interrupt mask value is supposed to be controlled
+completely by the user space. If the mask bit gets changed
+by the driver, concurrently with user mode operating on the ring,
+the mask bit may be set when it is supposed to be clear, and the
+user-mode driver will miss an interrupt which will cause a hang.
+
+For eg- when the driver sets inbound ring buffer interrupt mask to 1,
+the host does not interrupt the guest on the UIO VMBus channel.
+However, setting the mask does not prevent the host from putting a
+message in the inbound ring buffer. So let’s assume that happens,
+the host puts a message into the ring buffer but does not interrupt.
+
+Subsequently, the user space code in the guest sets the inbound ring
+buffer interrupt mask to 0, saying “Hey, I’m ready for interrupts”.
+User space code then calls pread() to wait for an interrupt.
+Then one of two things happens:
+
+* The host never sends another message. So the pread() waits forever.
+* The host does send another message. But because there’s already a
+  message in the ring buffer, it doesn’t generate an interrupt.
+  This is the correct behavior, because the host should only send an
+  interrupt when the inbound ring buffer transitions from empty to
+  not-empty. Adding an additional message to a ring buffer that is not
+  empty is not supposed to generate an interrupt on the guest.
+  Since the guest is waiting in pread() and not removing messages from
+  the ring buffer, the pread() waits forever.
+
+This could be easily reproduced in hv_fcopy_uio_daemon if we delay
+setting interrupt mask to 0.
+
+Similarly if hv_uio_channel_cb() sets the interrupt_mask to 1,
+there’s a race condition. Once user space empties the inbound ring
+buffer, but before user space sets interrupt_mask to 0, the host could
+put another message in the ring buffer but it wouldn’t interrupt.
+Then the next pread() would hang.
+
+Fix these by removing all instances where interrupt_mask is changed,
+while keeping the one in set_event() unchanged to enable userspace
+control the interrupt mask by writing 0/1 to /dev/uioX.
+
+Fixes: 95096f2fbd10 ("uio-hv-generic: new userspace i/o driver for VMBus")
+Suggested-by: John Starks <jostarks@microsoft.com>
+Signed-off-by: Naman Jain <namjain@linux.microsoft.com>
+Cc: stable@vger.kernel.org
+Reviewed-by: Michael Kelley <mhklinux@outlook.com>
+Reviewed-by: Long Li <longli@microsoft.com>
+Reviewed-by: Tianyu Lan <tiala@microsoft.com>
+Tested-by: Tianyu Lan <tiala@microsoft.com>
+Link: https://lore.kernel.org/r/20250828044200.492030-1-namjain@linux.microsoft.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/uio/uio_hv_generic.c |    7 +------
+ 1 file changed, 1 insertion(+), 6 deletions(-)
+
+--- a/drivers/uio/uio_hv_generic.c
++++ b/drivers/uio/uio_hv_generic.c
+@@ -96,7 +96,6 @@ static void hv_uio_channel_cb(void *cont
+       struct hv_device *hv_dev = chan->device_obj;
+       struct hv_uio_private_data *pdata = hv_get_drvdata(hv_dev);
+-      chan->inbound.ring_buffer->interrupt_mask = 1;
+       virt_mb();
+       uio_event_notify(&pdata->info);
+@@ -173,8 +172,6 @@ hv_uio_new_channel(struct vmbus_channel
+               return;
+       }
+-      /* Disable interrupts on sub channel */
+-      new_sc->inbound.ring_buffer->interrupt_mask = 1;
+       set_channel_read_mode(new_sc, HV_CALL_ISR);
+       ret = sysfs_create_bin_file(&new_sc->kobj, &ring_buffer_bin_attr);
+@@ -218,9 +215,7 @@ hv_uio_open(struct uio_info *info, struc
+       ret = vmbus_connect_ring(dev->channel,
+                                hv_uio_channel_cb, dev->channel);
+-      if (ret == 0)
+-              dev->channel->inbound.ring_buffer->interrupt_mask = 1;
+-      else
++      if (ret)
+               atomic_dec(&pdata->refcnt);
+       return ret;