]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.18-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 5 Aug 2026 09:39:40 +0000 (11:39 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 5 Aug 2026 09:39:40 +0000 (11:39 +0200)
added patches:
audit-fix-potential-integer-overflow-in-audit_log_n_string.patch
audit-fix-potential-use-after-free-in-audit_del_rule.patch
bluetooth-btmtk-fix-short-read-errors-in-btmtk_usb_uhw_reg_read.patch
bluetooth-btusb-fix-short-read-errors-in-btusb_qca_send_vendor_req.patch
bluetooth-hci_sync-fix-advertising-data-uafs.patch
bluetooth-hidp-reject-frames-without-a-transaction-header.patch
bluetooth-hidp-validate-numbered-report-payloads.patch
bluetooth-mgmt-fix-pending-command-uaf-in-eir-updates.patch
bluetooth-mgmt-fix-uaf-in-pair-command-cancellation.patch
bluetooth-sco-give-the-socket-its-own-sco_conn-reference.patch
dibs-fix-use-after-free-of-dmb_node-in-loopback-attach-detach-unregister.patch
fortify-disable-wstringop-overread-in-tests.patch
fs-proc-task_mmu-fix-pagemap_scan-written-state-for-pmd-holes.patch
kvm-s390-pci-fix-memory-accounting-for-pinned-unpinned-pages.patch
kvm-s390-pci-fix-missing-error-codes-and-memory-unaccounting.patch
kvm-s390-pci-fix-null-dereference-on-aibv-allocation-failure.patch
kvm-s390-pci-reject-adapter-interrupt-forwarding-if-already-enabled.patch
kvm-s390-pci-validate-aibv-and-aisb-before-pinning-guest-pages.patch
kvm-svm-update-x2apic-msr-intercepts-if-avic-is-inhibited-while-l2-is-active.patch
kvm-vmx-add-memory-clobber-to-asm-for-vmx-instructions.patch
mm-hugetlb-fix-list-corruption-in-allocate_file_region_entries.patch
mm-migrate_device-fix-pte_pfn-pte_dirty-called-on-non-present-pte.patch
mm-percpu-km-fix-bitmap-overflow-and-accounting-in-pcpu_create_chunk.patch
mm-util-don-t-read-__page_2-for-order-1-folios-in-snapshot_page.patch
mm-vmstat-fold-stranded-per-cpu-node-stats-when-a-node-comes-online.patch
sctp-validate-adaptation-indication-parameter-length.patch
selftest-fix-headers-in-fclog.c.patch
tracing-fprobe-roll-back-on-enable_trace_fprobe-failure.patch
tracing-probes-reject-arg0-in-meta-argument-expansion.patch

30 files changed:
queue-6.18/audit-fix-potential-integer-overflow-in-audit_log_n_string.patch [new file with mode: 0644]
queue-6.18/audit-fix-potential-use-after-free-in-audit_del_rule.patch [new file with mode: 0644]
queue-6.18/bluetooth-btmtk-fix-short-read-errors-in-btmtk_usb_uhw_reg_read.patch [new file with mode: 0644]
queue-6.18/bluetooth-btusb-fix-short-read-errors-in-btusb_qca_send_vendor_req.patch [new file with mode: 0644]
queue-6.18/bluetooth-hci_sync-fix-advertising-data-uafs.patch [new file with mode: 0644]
queue-6.18/bluetooth-hidp-reject-frames-without-a-transaction-header.patch [new file with mode: 0644]
queue-6.18/bluetooth-hidp-validate-numbered-report-payloads.patch [new file with mode: 0644]
queue-6.18/bluetooth-mgmt-fix-pending-command-uaf-in-eir-updates.patch [new file with mode: 0644]
queue-6.18/bluetooth-mgmt-fix-uaf-in-pair-command-cancellation.patch [new file with mode: 0644]
queue-6.18/bluetooth-sco-give-the-socket-its-own-sco_conn-reference.patch [new file with mode: 0644]
queue-6.18/dibs-fix-use-after-free-of-dmb_node-in-loopback-attach-detach-unregister.patch [new file with mode: 0644]
queue-6.18/fortify-disable-wstringop-overread-in-tests.patch [new file with mode: 0644]
queue-6.18/fs-proc-task_mmu-fix-pagemap_scan-written-state-for-pmd-holes.patch [new file with mode: 0644]
queue-6.18/kvm-s390-pci-fix-memory-accounting-for-pinned-unpinned-pages.patch [new file with mode: 0644]
queue-6.18/kvm-s390-pci-fix-missing-error-codes-and-memory-unaccounting.patch [new file with mode: 0644]
queue-6.18/kvm-s390-pci-fix-null-dereference-on-aibv-allocation-failure.patch [new file with mode: 0644]
queue-6.18/kvm-s390-pci-reject-adapter-interrupt-forwarding-if-already-enabled.patch [new file with mode: 0644]
queue-6.18/kvm-s390-pci-validate-aibv-and-aisb-before-pinning-guest-pages.patch [new file with mode: 0644]
queue-6.18/kvm-svm-update-x2apic-msr-intercepts-if-avic-is-inhibited-while-l2-is-active.patch [new file with mode: 0644]
queue-6.18/kvm-vmx-add-memory-clobber-to-asm-for-vmx-instructions.patch [new file with mode: 0644]
queue-6.18/mm-hugetlb-fix-list-corruption-in-allocate_file_region_entries.patch [new file with mode: 0644]
queue-6.18/mm-migrate_device-fix-pte_pfn-pte_dirty-called-on-non-present-pte.patch [new file with mode: 0644]
queue-6.18/mm-percpu-km-fix-bitmap-overflow-and-accounting-in-pcpu_create_chunk.patch [new file with mode: 0644]
queue-6.18/mm-util-don-t-read-__page_2-for-order-1-folios-in-snapshot_page.patch [new file with mode: 0644]
queue-6.18/mm-vmstat-fold-stranded-per-cpu-node-stats-when-a-node-comes-online.patch [new file with mode: 0644]
queue-6.18/sctp-validate-adaptation-indication-parameter-length.patch [new file with mode: 0644]
queue-6.18/selftest-fix-headers-in-fclog.c.patch [new file with mode: 0644]
queue-6.18/series
queue-6.18/tracing-fprobe-roll-back-on-enable_trace_fprobe-failure.patch [new file with mode: 0644]
queue-6.18/tracing-probes-reject-arg0-in-meta-argument-expansion.patch [new file with mode: 0644]

diff --git a/queue-6.18/audit-fix-potential-integer-overflow-in-audit_log_n_string.patch b/queue-6.18/audit-fix-potential-integer-overflow-in-audit_log_n_string.patch
new file mode 100644 (file)
index 0000000..3eb5a1e
--- /dev/null
@@ -0,0 +1,61 @@
+From f865c143629d4094866a811dba5f329250bad486 Mon Sep 17 00:00:00 2001
+From: Zhan Xusheng <zhanxusheng1024@gmail.com>
+Date: Sat, 18 Jul 2026 13:09:22 +0800
+Subject: audit: fix potential integer overflow in audit_log_n_string()
+
+From: Zhan Xusheng <zhanxusheng1024@gmail.com>
+
+commit f865c143629d4094866a811dba5f329250bad486 upstream.
+
+audit_log_n_string() computes new_len as "slen + 3" (enclosing quotes
+plus the NUL terminator) and stores it into an int, while slen is a
+size_t.  For a sufficiently large slen the addition can overflow and/or
+the result be truncated when assigned to the int new_len, so the
+"new_len > avail" check can be bypassed and the subsequent
+memcpy(ptr, string, slen) can write past the skb tail.
+
+This is the same class of bug that was fixed for the hex sibling in
+commit 65dfde57d1e2 ("audit: fix potential integer overflow in
+audit_log_n_hex()"); both helpers are reached through
+audit_log_n_untrustedstring() with the same length source.
+
+Make new_len a size_t and use check_add_overflow() to catch the
+overflow, mirroring the audit_log_n_hex() fix.  No functional change for
+the in-tree callers, which all pass bounded lengths.
+
+Cc: stable@vger.kernel.org
+Fixes: 168b7173959f ("AUDIT: Clean up logging of untrusted strings")
+Signed-off-by: Zhan Xusheng <zhanxusheng@xiaomi.com>
+Signed-off-by: Paul Moore <paul@paul-moore.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/audit.c |   11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+--- a/kernel/audit.c
++++ b/kernel/audit.c
+@@ -2115,7 +2115,8 @@ void audit_log_n_hex(struct audit_buffer
+ void audit_log_n_string(struct audit_buffer *ab, const char *string,
+                       size_t slen)
+ {
+-      int avail, new_len;
++      int avail;
++      size_t new_len;
+       unsigned char *ptr;
+       struct sk_buff *skb;
+@@ -2125,7 +2126,13 @@ void audit_log_n_string(struct audit_buf
+       BUG_ON(!ab->skb);
+       skb = ab->skb;
+       avail = skb_tailroom(skb);
+-      new_len = slen + 3;     /* enclosing quotes + null terminator */
++
++      /* enclosing quotes + null terminator */
++      if (check_add_overflow(slen, 3, &new_len)) {
++              audit_log_format(ab, "?");
++              return;
++      }
++
+       if (new_len > avail) {
+               avail = audit_expand(ab, new_len);
+               if (!avail)
diff --git a/queue-6.18/audit-fix-potential-use-after-free-in-audit_del_rule.patch b/queue-6.18/audit-fix-potential-use-after-free-in-audit_del_rule.patch
new file mode 100644 (file)
index 0000000..14e10cf
--- /dev/null
@@ -0,0 +1,55 @@
+From 246df90b5f1a8a6e6abbd2f058b029558720adec Mon Sep 17 00:00:00 2001
+From: Luxiao Xu <rakukuip@gmail.com>
+Date: Tue, 21 Jul 2026 23:37:41 +0800
+Subject: audit: fix potential use-after-free in audit_del_rule()
+
+From: Luxiao Xu <rakukuip@gmail.com>
+
+commit 246df90b5f1a8a6e6abbd2f058b029558720adec upstream.
+
+`audit_del_rule()` destroys `e->rule.exe` via `audit_remove_mark_rule()`
+before unlinking the rule from RCU-visible filter lists and waiting for a
+grace period. Concurrent readers in `audit_filter()` and
+`audit_filter_rules()` still dereference `e->rule.exe`, while the fsnotify
+mark can be freed on an independent lifetime path. This creates a
+use-after-free window during rule deletion.
+
+Fix this by unlinking the rule from the RCU-visible lists and invoking
+`synchronize_rcu()` before calling `audit_remove_mark_rule()` (and other
+rule removal helpers). This ensures that all existing RCU readers have
+exited the critical section before any underlying resources are destroyed.
+
+Cc: stable@vger.kernel.org
+Fixes: 34d99af52ad4 ("audit: implement audit by executable")
+Reported-by: Vega <vega@nebusec.ai>
+Assisted-by: Codex:gpt-5.4
+Signed-off-by: Luxiao Xu <rakukuip@gmail.com>
+Signed-off-by: Ren Wei <enjou1224z@gmail.com>
+Signed-off-by: Paul Moore <paul@paul-moore.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/auditfilter.c |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/kernel/auditfilter.c
++++ b/kernel/auditfilter.c
+@@ -1047,6 +1047,10 @@ int audit_del_rule(struct audit_entry *e
+               goto out;
+       }
++      list_del_rcu(&e->list);
++      list_del(&e->rule.list);
++      synchronize_rcu();
++
+       if (e->rule.watch)
+               audit_remove_watch_rule(&e->rule);
+@@ -1064,8 +1068,6 @@ int audit_del_rule(struct audit_entry *e
+               audit_signals--;
+ #endif
+-      list_del_rcu(&e->list);
+-      list_del(&e->rule.list);
+       call_rcu(&e->rcu, audit_free_rule_rcu);
+ out:
diff --git a/queue-6.18/bluetooth-btmtk-fix-short-read-errors-in-btmtk_usb_uhw_reg_read.patch b/queue-6.18/bluetooth-btmtk-fix-short-read-errors-in-btmtk_usb_uhw_reg_read.patch
new file mode 100644 (file)
index 0000000..a4606c4
--- /dev/null
@@ -0,0 +1,167 @@
+From b186c18c4843dd58adc29443369bddc71cb626a3 Mon Sep 17 00:00:00 2001
+From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Date: Mon, 27 Jul 2026 17:57:32 +0200
+Subject: Bluetooth: btmtk: Fix short read errors in btmtk_usb_uhw_reg_read()
+
+From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+commit b186c18c4843dd58adc29443369bddc71cb626a3 upstream.
+
+If btmtk_usb_uhw_reg_read() gets a "short" read from a device, it will
+accidentally treat that as a "real" read and populate the returned value
+with some unknown and probably totally invalid data.
+
+Fix this logic error up by calling usb_control_msg_recv() which
+guarantees a "full" read happens, and then simplify the error checking
+for when btmtk_usb_uhw_reg_read() is called.
+
+Note, one caller of btmtk_usb_uhw_reg_read() does not check the return
+value, but as we pre-initialize the return value as 0, an incorrect read
+will not do anything wrong.
+
+Cc: stable <stable@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/bluetooth/btmtk.c |   50 ++++++++++++++++++++--------------------------
+ 1 file changed, 22 insertions(+), 28 deletions(-)
+
+--- a/drivers/bluetooth/btmtk.c
++++ b/drivers/bluetooth/btmtk.c
+@@ -763,30 +763,24 @@ static int btmtk_usb_uhw_reg_write(struc
+ static int btmtk_usb_uhw_reg_read(struct hci_dev *hdev, u32 reg, u32 *val)
+ {
+       struct btmtk_data *data = hci_get_priv(hdev);
+-      int pipe, err;
+-      void *buf;
+-
+-      buf = kzalloc(4, GFP_KERNEL);
+-      if (!buf)
+-              return -ENOMEM;
++      u8 buf[sizeof(u32)];
++      int err;
+-      pipe = usb_rcvctrlpipe(data->udev, 0);
+-      err = usb_control_msg(data->udev, pipe, 0x01,
+-                            0xDE,
+-                            reg >> 16, reg & 0xffff,
+-                            buf, 4, USB_CTRL_GET_TIMEOUT);
+-      if (err < 0) {
++      *val = 0;
++      err = usb_control_msg_recv(data->udev, 0, 0x01,
++                                 0xDE,
++                                 reg >> 16, reg & 0xffff,
++                                 buf, sizeof(buf), USB_CTRL_GET_TIMEOUT,
++                                 GFP_KERNEL);
++      if (err) {
+               bt_dev_err(hdev, "Failed to read uhw reg(%d)", err);
+-              goto err_free_buf;
++              return err;
+       }
+       *val = get_unaligned_le32(buf);
+       bt_dev_dbg(hdev, "reg=%x, value=0x%08x", reg, *val);
+-err_free_buf:
+-      kfree(buf);
+-
+-      return err;
++      return 0;
+ }
+ static int btmtk_usb_reg_read(struct hci_dev *hdev, u32 reg, u32 *val)
+@@ -836,7 +830,7 @@ int btmtk_usb_subsys_reset(struct hci_de
+       if (dev_id == 0x7922) {
+               err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_SUBSYS_RST, &val);
+-              if (err < 0)
++              if (err)
+                       return err;
+               val |= 0x00002020;
+               err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_SUBSYS_RST, val);
+@@ -846,7 +840,7 @@ int btmtk_usb_subsys_reset(struct hci_de
+               if (err < 0)
+                       return err;
+               err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_SUBSYS_RST, &val);
+-              if (err < 0)
++              if (err)
+                       return err;
+               val |= BIT(0);
+               err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_SUBSYS_RST, val);
+@@ -855,14 +849,14 @@ int btmtk_usb_subsys_reset(struct hci_de
+               msleep(100);
+       } else if (dev_id == 0x7925) {
+               err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_RESET_REG_CONNV3, &val);
+-              if (err < 0)
++              if (err)
+                       return err;
+               val |= (1 << 5);
+               err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_RESET_REG_CONNV3, val);
+               if (err < 0)
+                       return err;
+               err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_RESET_REG_CONNV3, &val);
+-              if (err < 0)
++              if (err)
+                       return err;
+               val &= 0xFFFF00FF;
+               val |= (1 << 13);
+@@ -873,7 +867,7 @@ int btmtk_usb_subsys_reset(struct hci_de
+               if (err < 0)
+                       return err;
+               err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_RESET_REG_CONNV3, &val);
+-              if (err < 0)
++              if (err)
+                       return err;
+               val |= (1 << 0);
+               err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_RESET_REG_CONNV3, val);
+@@ -883,13 +877,13 @@ int btmtk_usb_subsys_reset(struct hci_de
+               if (err < 0)
+                       return err;
+               err = btmtk_usb_uhw_reg_read(hdev, MTK_UDMA_INT_STA_BT, &val);
+-              if (err < 0)
++              if (err)
+                       return err;
+               err = btmtk_usb_uhw_reg_write(hdev, MTK_UDMA_INT_STA_BT1, 0x000000FF);
+               if (err < 0)
+                       return err;
+               err = btmtk_usb_uhw_reg_read(hdev, MTK_UDMA_INT_STA_BT1, &val);
+-              if (err < 0)
++              if (err)
+                       return err;
+               msleep(100);
+       } else {
+@@ -899,7 +893,7 @@ int btmtk_usb_subsys_reset(struct hci_de
+               if (err < 0)
+                       return err;
+               err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_WDT_STATUS, &val);
+-              if (err < 0)
++              if (err)
+                       return err;
+               /* Reset the bluetooth chip via USB interface. */
+               err = btmtk_usb_uhw_reg_write(hdev, MTK_BT_SUBSYS_RST, 1);
+@@ -909,13 +903,13 @@ int btmtk_usb_subsys_reset(struct hci_de
+               if (err < 0)
+                       return err;
+               err = btmtk_usb_uhw_reg_read(hdev, MTK_UDMA_INT_STA_BT, &val);
+-              if (err < 0)
++              if (err)
+                       return err;
+               err = btmtk_usb_uhw_reg_write(hdev, MTK_UDMA_INT_STA_BT1, 0x000000FF);
+               if (err < 0)
+                       return err;
+               err = btmtk_usb_uhw_reg_read(hdev, MTK_UDMA_INT_STA_BT1, &val);
+-              if (err < 0)
++              if (err)
+                       return err;
+               /* MT7921 need to delay 20ms between toggle reset bit */
+               msleep(20);
+@@ -923,7 +917,7 @@ int btmtk_usb_subsys_reset(struct hci_de
+               if (err < 0)
+                       return err;
+               err = btmtk_usb_uhw_reg_read(hdev, MTK_BT_SUBSYS_RST, &val);
+-              if (err < 0)
++              if (err)
+                       return err;
+       }
diff --git a/queue-6.18/bluetooth-btusb-fix-short-read-errors-in-btusb_qca_send_vendor_req.patch b/queue-6.18/bluetooth-btusb-fix-short-read-errors-in-btusb_qca_send_vendor_req.patch
new file mode 100644 (file)
index 0000000..940ace8
--- /dev/null
@@ -0,0 +1,97 @@
+From cac43d360c928bc0cbbd18809632388265649761 Mon Sep 17 00:00:00 2001
+From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Date: Mon, 27 Jul 2026 17:57:34 +0200
+Subject: Bluetooth: btusb: Fix short read errors in btusb_qca_send_vendor_req()
+
+From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+commit cac43d360c928bc0cbbd18809632388265649761 upstream.
+
+If btusb_qca_send_vendor_req() gets a "short" read from a device, it
+will accidentally treat that as a "real" read and populate the returned
+value with some unknown and probably totally invalid data.
+
+Fix this logic error up by calling usb_control_msg_recv() which
+guarantees a "full" read happens, and then simplify the error checking
+for when btusb_qca_send_vendor_req() is called.
+
+Cc: stable <stable@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/bluetooth/btusb.c |   30 +++++++++---------------------
+ 1 file changed, 9 insertions(+), 21 deletions(-)
+
+--- a/drivers/bluetooth/btusb.c
++++ b/drivers/bluetooth/btusb.c
+@@ -3345,28 +3345,16 @@ static const char *qca_get_fw_subdirecto
+ static int btusb_qca_send_vendor_req(struct usb_device *udev, u8 request,
+                                    void *data, u16 size)
+ {
+-      int pipe, err;
+-      u8 *buf;
+-
+-      buf = kmalloc(size, GFP_KERNEL);
+-      if (!buf)
+-              return -ENOMEM;
++      int err;
+       /* Found some of USB hosts have IOT issues with ours so that we should
+        * not wait until HCI layer is ready.
+        */
+-      pipe = usb_rcvctrlpipe(udev, 0);
+-      err = usb_control_msg(udev, pipe, request, USB_TYPE_VENDOR | USB_DIR_IN,
+-                            0, 0, buf, size, USB_CTRL_GET_TIMEOUT);
+-      if (err < 0) {
++      err = usb_control_msg_recv(udev, 0, request, USB_TYPE_VENDOR | USB_DIR_IN,
++                                 0, 0, data, size, USB_CTRL_GET_TIMEOUT,
++                                 GFP_KERNEL);
++      if (err)
+               dev_err(&udev->dev, "Failed to access otp area (%d)", err);
+-              goto done;
+-      }
+-
+-      memcpy(data, buf, size);
+-
+-done:
+-      kfree(buf);
+       return err;
+ }
+@@ -3573,7 +3561,7 @@ static bool btusb_qca_need_patch(struct
+       struct qca_version ver;
+       if (btusb_qca_send_vendor_req(udev, QCA_GET_TARGET_VERSION, &ver,
+-                                    sizeof(ver)) < 0)
++                                    sizeof(ver)))
+               return false;
+       /* only low ROM versions need patches */
+       return !(le32_to_cpu(ver.rom_version) & ~0xffffU);
+@@ -3591,7 +3579,7 @@ static int btusb_setup_qca(struct hci_de
+       err = btusb_qca_send_vendor_req(udev, QCA_GET_TARGET_VERSION, &ver,
+                                       sizeof(ver));
+-      if (err < 0)
++      if (err)
+               return err;
+       ver_rom = le32_to_cpu(ver.rom_version);
+@@ -3614,7 +3602,7 @@ static int btusb_setup_qca(struct hci_de
+       err = btusb_qca_send_vendor_req(udev, QCA_CHECK_STATUS, &status,
+                                       sizeof(status));
+-      if (err < 0)
++      if (err)
+               return err;
+       if (!(status & QCA_PATCH_UPDATED)) {
+@@ -3625,7 +3613,7 @@ static int btusb_setup_qca(struct hci_de
+       err = btusb_qca_send_vendor_req(udev, QCA_GET_TARGET_VERSION, &ver,
+                                       sizeof(ver));
+-      if (err < 0)
++      if (err)
+               return err;
+       btdata->qca_dump.fw_version = le32_to_cpu(ver.patch_version);
diff --git a/queue-6.18/bluetooth-hci_sync-fix-advertising-data-uafs.patch b/queue-6.18/bluetooth-hci_sync-fix-advertising-data-uafs.patch
new file mode 100644 (file)
index 0000000..697de17
--- /dev/null
@@ -0,0 +1,341 @@
+From cdc36db204ffd97b947d64374cf23a210dc74777 Mon Sep 17 00:00:00 2001
+From: Chengfeng Ye <nicoyip.dev@gmail.com>
+Date: Thu, 23 Jul 2026 23:34:40 +0800
+Subject: Bluetooth: hci_sync: Fix advertising data UAFs
+
+From: Chengfeng Ye <nicoyip.dev@gmail.com>
+
+commit cdc36db204ffd97b947d64374cf23a210dc74777 upstream.
+
+hci_find_adv_instance() returns an adv_info pointer that is valid only
+while hdev->lock is held.  The advertising command-sync paths perform
+instance lookups without that lock and, in some cases, retain the pointer
+while waiting for a controller response.
+
+An advertising termination event can therefore interleave as follows:
+
+  hci_cmd_sync_work                 hci_rx_work
+  hci_find_adv_instance()
+  __hci_cmd_sync_status()
+    wait for controller reply       hci_dev_lock()
+                                    hci_remove_adv_instance()
+                                      kfree(adv)
+  adv->scan_rsp_changed = false
+
+KASAN reported:
+
+  BUG: KASAN: slab-use-after-free in hci_set_ext_scan_rsp_data_sync+0x2e1/0x300
+  Write of size 1 at addr ffff88810a45d21d by task kworker/u17:0/88
+  Workqueue: hci0 hci_cmd_sync_work
+  Call Trace:
+   hci_set_ext_scan_rsp_data_sync+0x2e1/0x300
+   hci_schedule_adv_instance_sync+0x390/0x4c0
+   hci_cmd_sync_work+0x173/0x300
+  Allocated by task 87:
+   hci_add_adv_instance+0x538/0xac0
+   add_advertising+0x885/0x1160
+  Freed by task 89:
+   kfree+0x131/0x3c0
+   hci_remove_adv_instance+0x1d8/0x3b0
+   hci_le_ext_adv_term_evt+0x17b/0x730
+
+Protect the instance lookup and payload construction in the extended
+advertising, scan response, and periodic advertising data paths.  Snapshot
+the advertising parameters under hdev->lock, but release the lock before
+waiting for the controller.
+
+Clear advertising-data dirty bits before issuing their commands and
+restore them after a failure using a fresh lookup.  Likewise, update the
+reported transmit power through a fresh lookup after the parameter command
+completes.  No adv_info pointer then survives an HCI command wait.
+
+Fixes: cba6b758711c ("Bluetooth: hci_sync: Make use of hci_cmd_sync_queue set 2")
+Cc: stable@vger.kernel.org
+Suggested-by: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
+Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/bluetooth/hci_sync.c |  131 ++++++++++++++++++++++++++++++++++-------------
+ 1 file changed, 97 insertions(+), 34 deletions(-)
+
+--- a/net/bluetooth/hci_sync.c
++++ b/net/bluetooth/hci_sync.c
+@@ -1233,10 +1233,11 @@ static int hci_set_adv_set_random_addr_s
+ }
+ static int
+-hci_set_ext_adv_params_sync(struct hci_dev *hdev, struct adv_info *adv,
++hci_set_ext_adv_params_sync(struct hci_dev *hdev, u8 instance,
+                           const struct hci_cp_le_set_ext_adv_params *cp,
+                           struct hci_rp_le_set_ext_adv_params *rp)
+ {
++      struct adv_info *adv;
+       struct sk_buff *skb;
+       skb = __hci_cmd_sync(hdev, HCI_OP_LE_SET_EXT_ADV_PARAMS, sizeof(*cp),
+@@ -1264,11 +1265,15 @@ hci_set_ext_adv_params_sync(struct hci_d
+       if (!rp->status) {
+               hdev->adv_addr_type = cp->own_addr_type;
+-              if (!cp->handle) {
++              if (!instance) {
+                       /* Store in hdev for instance 0 */
+                       hdev->adv_tx_power = rp->tx_power;
+-              } else if (adv) {
+-                      adv->tx_power = rp->tx_power;
++              } else {
++                      hci_dev_lock(hdev);
++                      adv = hci_find_adv_instance(hdev, instance);
++                      if (adv)
++                              adv->tx_power = rp->tx_power;
++                      hci_dev_unlock(hdev);
+               }
+       }
+@@ -1284,9 +1289,13 @@ static int hci_set_ext_adv_data_sync(str
+       int err;
+       if (instance) {
++              hci_dev_lock(hdev);
++
+               adv = hci_find_adv_instance(hdev, instance);
+-              if (!adv || !adv->adv_data_changed)
++              if (!adv || !adv->adv_data_changed) {
++                      hci_dev_unlock(hdev);
+                       return 0;
++              }
+       }
+       len = eir_create_adv_data(hdev, instance, pdu->data,
+@@ -1297,16 +1306,27 @@ static int hci_set_ext_adv_data_sync(str
+       pdu->operation = LE_SET_ADV_DATA_OP_COMPLETE;
+       pdu->frag_pref = LE_SET_ADV_DATA_NO_FRAG;
++      if (adv) {
++              adv->adv_data_changed = false;
++              hci_dev_unlock(hdev);
++      }
++
+       err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_DATA,
+                                   struct_size(pdu, data, len), pdu,
+                                   HCI_CMD_TIMEOUT);
+-      if (err)
++      if (err) {
++              if (instance) {
++                      hci_dev_lock(hdev);
++                      adv = hci_find_adv_instance(hdev, instance);
++                      if (adv)
++                              adv->adv_data_changed = true;
++                      hci_dev_unlock(hdev);
++              }
++
+               return err;
++      }
+-      /* Update data if the command succeed */
+-      if (adv) {
+-              adv->adv_data_changed = false;
+-      } else {
++      if (!instance) {
+               memcpy(hdev->adv_data, pdu->data, len);
+               hdev->adv_data_len = len;
+       }
+@@ -1360,22 +1380,22 @@ int hci_setup_ext_adv_instance_sync(stru
+       struct adv_info *adv;
+       bool secondary_adv;
+-      if (instance > 0) {
+-              adv = hci_find_adv_instance(hdev, instance);
+-              if (!adv)
+-                      return -EINVAL;
+-      } else {
+-              adv = NULL;
+-      }
+-
+       /* Updating parameters of an active instance will return a
+-       * Command Disallowed error, so we must first disable the
+-       * instance if it is active.
++       * Command Disallowed error, so disable it before taking a snapshot.
+        */
+-      if (adv) {
++      if (instance > 0) {
+               err = hci_disable_ext_adv_instance_sync(hdev, instance);
+               if (err)
+                       return err;
++
++              hci_dev_lock(hdev);
++              adv = hci_find_adv_instance(hdev, instance);
++              if (!adv) {
++                      hci_dev_unlock(hdev);
++                      return -EINVAL;
++              }
++      } else {
++              adv = NULL;
+       }
+       flags = hci_adv_instance_flags(hdev, instance);
+@@ -1386,8 +1406,11 @@ int hci_setup_ext_adv_instance_sync(stru
+       connectable = (flags & MGMT_ADV_FLAG_CONNECTABLE) ||
+                     mgmt_get_connectable(hdev);
+-      if (!is_advertising_allowed(hdev, connectable))
++      if (!is_advertising_allowed(hdev, connectable)) {
++              if (instance)
++                      hci_dev_unlock(hdev);
+               return -EPERM;
++      }
+       /* Set require_privacy to true only when non-connectable
+        * advertising is used and it is not periodic.
+@@ -1398,8 +1421,11 @@ int hci_setup_ext_adv_instance_sync(stru
+       err = hci_get_random_address(hdev, require_privacy,
+                                    adv_use_rpa(hdev, flags), adv,
+                                    &own_addr_type, &random_addr);
+-      if (err < 0)
++      if (err < 0) {
++              if (instance)
++                      hci_dev_unlock(hdev);
+               return err;
++      }
+       memset(&cp, 0, sizeof(cp));
+@@ -1450,6 +1476,9 @@ int hci_setup_ext_adv_instance_sync(stru
+       cp.channel_map = hdev->le_adv_channel_map;
+       cp.handle = adv ? adv->handle : instance;
++      if (instance)
++              hci_dev_unlock(hdev);
++
+       if (flags & MGMT_ADV_FLAG_SEC_2M) {
+               cp.primary_phy = HCI_ADV_PHY_1M;
+               cp.secondary_phy = HCI_ADV_PHY_2M;
+@@ -1462,12 +1491,12 @@ int hci_setup_ext_adv_instance_sync(stru
+               cp.secondary_phy = HCI_ADV_PHY_1M;
+       }
+-      err = hci_set_ext_adv_params_sync(hdev, adv, &cp, &rp);
++      err = hci_set_ext_adv_params_sync(hdev, instance, &cp, &rp);
+       if (err)
+               return err;
+       /* Update adv data as tx power is known now */
+-      err = hci_set_ext_adv_data_sync(hdev, cp.handle);
++      err = hci_set_ext_adv_data_sync(hdev, instance);
+       if (err)
+               return err;
+@@ -1475,9 +1504,14 @@ int hci_setup_ext_adv_instance_sync(stru
+            own_addr_type == ADDR_LE_DEV_RANDOM_RESOLVED) &&
+           bacmp(&random_addr, BDADDR_ANY)) {
+               /* Check if random address need to be updated */
+-              if (adv) {
+-                      if (!bacmp(&random_addr, &adv->random_addr))
++              if (instance) {
++                      hci_dev_lock(hdev);
++                      adv = hci_find_adv_instance(hdev, instance);
++                      if (!adv || !bacmp(&random_addr, &adv->random_addr)) {
++                              hci_dev_unlock(hdev);
+                               return 0;
++                      }
++                      hci_dev_unlock(hdev);
+               } else {
+                       if (!bacmp(&random_addr, &hdev->random_addr))
+                               return 0;
+@@ -1499,9 +1533,13 @@ static int hci_set_ext_scan_rsp_data_syn
+       int err;
+       if (instance) {
++              hci_dev_lock(hdev);
++
+               adv = hci_find_adv_instance(hdev, instance);
+-              if (!adv || !adv->scan_rsp_changed)
++              if (!adv || !adv->scan_rsp_changed) {
++                      hci_dev_unlock(hdev);
+                       return 0;
++              }
+       }
+       len = eir_create_scan_rsp(hdev, instance, pdu->data);
+@@ -1511,15 +1549,27 @@ static int hci_set_ext_scan_rsp_data_syn
+       pdu->operation = LE_SET_ADV_DATA_OP_COMPLETE;
+       pdu->frag_pref = LE_SET_ADV_DATA_NO_FRAG;
++      if (adv) {
++              adv->scan_rsp_changed = false;
++              hci_dev_unlock(hdev);
++      }
++
+       err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_SCAN_RSP_DATA,
+                                   struct_size(pdu, data, len), pdu,
+                                   HCI_CMD_TIMEOUT);
+-      if (err)
++      if (err) {
++              if (instance) {
++                      hci_dev_lock(hdev);
++                      adv = hci_find_adv_instance(hdev, instance);
++                      if (adv)
++                              adv->scan_rsp_changed = true;
++                      hci_dev_unlock(hdev);
++              }
++
+               return err;
++      }
+-      if (adv) {
+-              adv->scan_rsp_changed = false;
+-      } else {
++      if (!instance) {
+               memcpy(hdev->scan_rsp_data, pdu->data, len);
+               hdev->scan_rsp_data_len = len;
+       }
+@@ -1534,8 +1584,14 @@ static int __hci_set_scan_rsp_data_sync(
+       memset(&cp, 0, sizeof(cp));
++      if (instance)
++              hci_dev_lock(hdev);
++
+       len = eir_create_scan_rsp(hdev, instance, cp.data);
++      if (instance)
++              hci_dev_unlock(hdev);
++
+       if (hdev->scan_rsp_data_len == len &&
+           !memcmp(cp.data, hdev->scan_rsp_data, len))
+               return 0;
+@@ -1670,9 +1726,13 @@ static int hci_set_per_adv_data_sync(str
+       struct adv_info *adv = NULL;
+       if (instance) {
++              hci_dev_lock(hdev);
++
+               adv = hci_find_adv_instance(hdev, instance);
+-              if (!adv || !adv->periodic)
++              if (!adv || !adv->periodic) {
++                      hci_dev_unlock(hdev);
+                       return 0;
++              }
+       }
+       len = eir_create_per_adv_data(hdev, instance, pdu->data);
+@@ -1681,6 +1741,9 @@ static int hci_set_per_adv_data_sync(str
+       pdu->handle = adv ? adv->handle : instance;
+       pdu->operation = LE_SET_ADV_DATA_OP_COMPLETE;
++      if (adv)
++              hci_dev_unlock(hdev);
++
+       return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_PER_ADV_DATA,
+                                    struct_size(pdu, data, len), pdu,
+                                    HCI_CMD_TIMEOUT);
+@@ -6449,7 +6512,7 @@ static int hci_le_ext_directed_advertisi
+       if (err)
+               return err;
+-      err = hci_set_ext_adv_params_sync(hdev, NULL, &cp, &rp);
++      err = hci_set_ext_adv_params_sync(hdev, 0, &cp, &rp);
+       if (err)
+               return err;
diff --git a/queue-6.18/bluetooth-hidp-reject-frames-without-a-transaction-header.patch b/queue-6.18/bluetooth-hidp-reject-frames-without-a-transaction-header.patch
new file mode 100644 (file)
index 0000000..bca8802
--- /dev/null
@@ -0,0 +1,105 @@
+From 47778d2c2087b5d192398f6fddf692d16a5431cf Mon Sep 17 00:00:00 2001
+From: Sangho Lee <kudo3228@gmail.com>
+Date: Thu, 23 Jul 2026 12:28:06 +0900
+Subject: Bluetooth: HIDP: reject frames without a transaction header
+
+From: Sangho Lee <kudo3228@gmail.com>
+
+commit 47778d2c2087b5d192398f6fddf692d16a5431cf upstream.
+
+hidp_recv_ctrl_frame() and hidp_recv_intr_frame() read skb->data[0]
+before checking that the L2CAP SDU contains a transaction header. A
+connected HIDP peer can send an empty basic-mode SDU and make both paths
+use an uninitialized byte from skb tailroom.
+
+KMSAN reports the use in hidp_session_run(), with the uninitialized value
+originating in __alloc_skb() through vhci_write(). The control path
+produces two reports and the interrupt path produces one.
+
+The byte can also be controlled by a malformed lower-layer packet. If an
+HCI ACL packet contains an L2CAP PDU with a declared zero-length payload
+followed by an extra 0x15 byte, l2cap_recv_acldata() reduces skb->len to
+the declared PDU length before dispatch. The current HIDP path nevertheless
+consumes the extra byte as HIDP_TRANS_HID_CONTROL |
+HIDP_CTRL_VIRTUAL_CABLE_UNPLUG and terminates the HIDP session. With this
+change, the same packet is discarded and a subsequent feature report
+request succeeds.
+
+Pull the transaction header with skb_pull_data() and discard frames that
+do not contain it.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Cc: stable@vger.kernel.org
+Signed-off-by: Sangho Lee <kudo3228@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/bluetooth/hidp/core.c |   25 +++++++++++++++----------
+ 1 file changed, 15 insertions(+), 10 deletions(-)
+
+--- a/net/bluetooth/hidp/core.c
++++ b/net/bluetooth/hidp/core.c
+@@ -563,16 +563,18 @@ static int hidp_process_data(struct hidp
+ static void hidp_recv_ctrl_frame(struct hidp_session *session,
+                                       struct sk_buff *skb)
+ {
+-      unsigned char hdr, type, param;
++      unsigned char type, param;
++      u8 *hdr;
+       int free_skb = 1;
+       BT_DBG("session %p skb %p len %u", session, skb, skb->len);
+-      hdr = skb->data[0];
+-      skb_pull(skb, 1);
++      hdr = skb_pull_data(skb, 1);
++      if (!hdr)
++              goto free;
+-      type = hdr & HIDP_HEADER_TRANS_MASK;
+-      param = hdr & HIDP_HEADER_PARAM_MASK;
++      type = *hdr & HIDP_HEADER_TRANS_MASK;
++      param = *hdr & HIDP_HEADER_PARAM_MASK;
+       switch (type) {
+       case HIDP_TRANS_HANDSHAKE:
+@@ -593,6 +595,7 @@ static void hidp_recv_ctrl_frame(struct
+               break;
+       }
++free:
+       if (free_skb)
+               kfree_skb(skb);
+ }
+@@ -600,14 +603,15 @@ static void hidp_recv_ctrl_frame(struct
+ static void hidp_recv_intr_frame(struct hidp_session *session,
+                               struct sk_buff *skb)
+ {
+-      unsigned char hdr;
++      u8 *hdr;
+       BT_DBG("session %p skb %p len %u", session, skb, skb->len);
+-      hdr = skb->data[0];
+-      skb_pull(skb, 1);
++      hdr = skb_pull_data(skb, 1);
++      if (!hdr)
++              goto free;
+-      if (hdr == (HIDP_TRANS_DATA | HIDP_DATA_RTYPE_INPUT)) {
++      if (*hdr == (HIDP_TRANS_DATA | HIDP_DATA_RTYPE_INPUT)) {
+               hidp_set_timer(session);
+               if (session->input)
+@@ -619,9 +623,10 @@ static void hidp_recv_intr_frame(struct
+                       BT_DBG("report len %d", skb->len);
+               }
+       } else {
+-              BT_DBG("Unsupported protocol header 0x%02x", hdr);
++              BT_DBG("Unsupported protocol header 0x%02x", *hdr);
+       }
++free:
+       kfree_skb(skb);
+ }
diff --git a/queue-6.18/bluetooth-hidp-validate-numbered-report-payloads.patch b/queue-6.18/bluetooth-hidp-validate-numbered-report-payloads.patch
new file mode 100644 (file)
index 0000000..afb4c57
--- /dev/null
@@ -0,0 +1,53 @@
+From 34f53d27b81a16a02828c8fdfa4e02badc326f17 Mon Sep 17 00:00:00 2001
+From: Sangho Lee <kudo3228@gmail.com>
+Date: Thu, 23 Jul 2026 12:28:07 +0900
+Subject: Bluetooth: HIDP: validate numbered report payloads
+
+From: Sangho Lee <kudo3228@gmail.com>
+
+commit 34f53d27b81a16a02828c8fdfa4e02badc326f17 upstream.
+
+When hidp_get_raw_report() waits for a numbered report,
+hidp_process_data() compares the expected report number with skb->data[0].
+A connected HIDP peer can reply with only a DATA transaction header,
+leaving the skb empty after the header is removed.
+
+KMSAN reports an uninitialized-value use in hidp_session_run(), with the
+value originating in __alloc_skb() through vhci_write(). The transaction
+header checks remove the empty-frame reports, but this report remains until
+the payload check is added.
+
+The comparison can also consume a peer-controlled byte beyond the declared
+L2CAP PDU. A DATA | FEATURE response followed by an extra 0x01 byte made
+the current code accept that byte as report ID 1 and complete
+HIDIOCGFEATURE with a zero-byte result. With this change the malformed
+response is rejected with -EIO, while a subsequent valid response still
+succeeds.
+
+Require a payload byte before comparing a numbered report ID. Unnumbered
+reports continue to accept an empty payload.
+
+Fixes: 0ff1731a1ae5 ("HID: bt: Add support for hidraw HIDIOCGFEATURE and HIDIOCSFEATURE")
+Cc: stable@vger.kernel.org
+Signed-off-by: Sangho Lee <kudo3228@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/bluetooth/hidp/core.c |    5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/net/bluetooth/hidp/core.c
++++ b/net/bluetooth/hidp/core.c
+@@ -546,9 +546,10 @@ static int hidp_process_data(struct hidp
+       }
+       if (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags) &&
+-                              param == session->waiting_report_type) {
++          param == session->waiting_report_type) {
+               if (session->waiting_report_number < 0 ||
+-                  session->waiting_report_number == skb->data[0]) {
++                  (skb->len &&
++                   session->waiting_report_number == skb->data[0])) {
+                       /* hidp_get_raw_report() is waiting on this report. */
+                       session->report_return = skb;
+                       done_with_skb = 0;
diff --git a/queue-6.18/bluetooth-mgmt-fix-pending-command-uaf-in-eir-updates.patch b/queue-6.18/bluetooth-mgmt-fix-pending-command-uaf-in-eir-updates.patch
new file mode 100644 (file)
index 0000000..f5d8bb0
--- /dev/null
@@ -0,0 +1,91 @@
+From 8f2f62855a41d1730fb9e8122912bd2c8d6bed5d Mon Sep 17 00:00:00 2001
+From: Zihan Xi <zihanx@nebusec.ai>
+Date: Fri, 24 Jul 2026 00:43:46 +0800
+Subject: Bluetooth: mgmt: fix pending command UAF in EIR updates
+
+From: Zihan Xi <zihanx@nebusec.ai>
+
+commit 8f2f62855a41d1730fb9e8122912bd2c8d6bed5d upstream.
+
+MGMT_OP_SET_LOCAL_NAME is handled asynchronously on powered controllers
+and can run set_name_sync().  When the controller is BR/EDR capable,
+set_name_sync() updates the local name and then rebuilds EIR data through
+eir_create().  The EIR builder walks hdev->uuids, but the UUID list can
+be changed and entries can be freed by MGMT_OP_ADD_UUID and
+MGMT_OP_REMOVE_UUID.
+
+pending_eir_or_class() is meant to serialize management commands that
+can change EIR or the class of device, but it did not include
+MGMT_OP_SET_LOCAL_NAME.  In addition, it walked hdev->mgmt_pending
+without hdev->mgmt_pending_lock even though pending commands are added
+and removed under that mutex.  A racing command completion can therefore
+remove and free a pending command while pending_eir_or_class() is still
+inspecting it, leading to a use-after-free in the pending-command list or
+allowing a local name update to rebuild EIR while UUID entries are being
+removed.
+
+Take hdev->mgmt_pending_lock while scanning hdev->mgmt_pending and treat
+MGMT_OP_SET_LOCAL_NAME as an EIR/class-affecting pending command on the
+powered asynchronous path.  Check for a conflicting pending command before
+copying the new short name so a rejected SET_LOCAL_NAME request does not
+modify hdev->short_name.
+
+Fixes: 6fe26f694c82 ("Bluetooth: MGMT: Protect mgmt_pending list with its own lock")
+Cc: stable@vger.kernel.org
+Reported-by: Vega <vega@nebusec.ai>
+Assisted-by: Codex:gpt-5.4
+Signed-off-by: Zihan Xi <zihanx@nebusec.ai>
+Signed-off-by: Ren Wei <enjou1224z@gmail.com>
+Reported-by: Vega <vega@nebusec.ai>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/bluetooth/mgmt.c |   20 ++++++++++++++++++--
+ 1 file changed, 18 insertions(+), 2 deletions(-)
+
+--- a/net/bluetooth/mgmt.c
++++ b/net/bluetooth/mgmt.c
+@@ -2699,18 +2699,28 @@ static int mgmt_hci_cmd_sync(struct sock
+ static bool pending_eir_or_class(struct hci_dev *hdev)
+ {
+       struct mgmt_pending_cmd *cmd;
++      bool pending = false;
++
++      mutex_lock(&hdev->mgmt_pending_lock);
+       list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
+               switch (cmd->opcode) {
+               case MGMT_OP_ADD_UUID:
+               case MGMT_OP_REMOVE_UUID:
+               case MGMT_OP_SET_DEV_CLASS:
++              case MGMT_OP_SET_LOCAL_NAME:
+               case MGMT_OP_SET_POWERED:
+-                      return true;
++                      pending = true;
++                      break;
+               }
++
++              if (pending)
++                      break;
+       }
+-      return false;
++      mutex_unlock(&hdev->mgmt_pending_lock);
++
++      return pending;
+ }
+ static const u8 bluetooth_base_uuid[] = {
+@@ -4046,6 +4056,12 @@ static int set_local_name(struct sock *s
+               goto failed;
+       }
++      if (hdev_is_powered(hdev) && pending_eir_or_class(hdev)) {
++              err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
++                                    MGMT_STATUS_BUSY);
++              goto failed;
++      }
++
+       memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
+       if (!hdev_is_powered(hdev)) {
diff --git a/queue-6.18/bluetooth-mgmt-fix-uaf-in-pair-command-cancellation.patch b/queue-6.18/bluetooth-mgmt-fix-uaf-in-pair-command-cancellation.patch
new file mode 100644 (file)
index 0000000..60c2b01
--- /dev/null
@@ -0,0 +1,198 @@
+From d0a7b48ad0921bd88effaee10bf970ab1d5d0ddd Mon Sep 17 00:00:00 2001
+From: Zihan Xi <xizh2024@lzu.edu.cn>
+Date: Tue, 21 Jul 2026 22:36:07 +0800
+Subject: Bluetooth: mgmt: fix UAF in pair command cancellation
+
+From: Zihan Xi <xizh2024@lzu.edu.cn>
+
+commit d0a7b48ad0921bd88effaee10bf970ab1d5d0ddd upstream.
+
+The pairing completion and authentication failure callbacks look up the
+pending MGMT_OP_PAIR_DEVICE command by walking hdev->mgmt_pending. The
+lookup returned a command that was still linked on the shared pending list,
+without keeping mgmt_pending_lock held for the later dereference and
+removal.
+
+A concurrent MGMT_OP_CANCEL_PAIR_DEVICE request can remove and free the
+same pending command before the callback uses it. The reverse race is also
+possible when cancel_pair_device() gets a command from pending_find() and a
+callback removes it before the cancel path dereferences it. This can lead
+to a use-after-free and a second list_del().
+
+Make the pairing lookup helpers transfer ownership of the pending command
+by removing it from hdev->mgmt_pending while holding mgmt_pending_lock.
+The callbacks and cancel path then complete the command and free it
+directly, so racing paths cannot find or free the same command again. Take
+a temporary hci_conn reference in cancel_pair_device() because the command
+completion drops the reference stored in the pending command.
+
+Fixes: e9a416b5ce0c ("Bluetooth: Add mgmt_pair_device command")
+Cc: stable@vger.kernel.org
+Reported-by: Vega <vega@nebusec.ai>
+Assisted-by: Codex:gpt-5.4
+Signed-off-by: Zihan Xi <xizh2024@lzu.edu.cn>
+Reviewed-by: Ren Wei <enjou1224z@gmail.com>
+Reported-by: Vega <vega@nebusec.ai>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/bluetooth/mgmt.c |   64 ++++++++++++++++++++++++++++++++++++---------------
+ 1 file changed, 46 insertions(+), 18 deletions(-)
+
+--- a/net/bluetooth/mgmt.c
++++ b/net/bluetooth/mgmt.c
+@@ -3527,11 +3527,13 @@ static int set_io_capability(struct sock
+                                NULL, 0);
+ }
+-static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
++static struct mgmt_pending_cmd *remove_pairing(struct hci_conn *conn)
+ {
+       struct hci_dev *hdev = conn->hdev;
+       struct mgmt_pending_cmd *cmd;
++      mutex_lock(&hdev->mgmt_pending_lock);
++
+       list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
+               if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
+                       continue;
+@@ -3539,9 +3541,39 @@ static struct mgmt_pending_cmd *find_pai
+               if (cmd->user_data != conn)
+                       continue;
++              list_del(&cmd->list);
++              mutex_unlock(&hdev->mgmt_pending_lock);
+               return cmd;
+       }
++      mutex_unlock(&hdev->mgmt_pending_lock);
++
++      return NULL;
++}
++
++static struct mgmt_pending_cmd *remove_pairing_by_addr(struct hci_dev *hdev,
++                                                     bdaddr_t *bdaddr)
++{
++      struct mgmt_pending_cmd *cmd;
++      struct hci_conn *conn;
++
++      mutex_lock(&hdev->mgmt_pending_lock);
++
++      list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
++              if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
++                      continue;
++
++              conn = cmd->user_data;
++              if (bacmp(bdaddr, &conn->dst) != 0)
++                      continue;
++
++              list_del(&cmd->list);
++              mutex_unlock(&hdev->mgmt_pending_lock);
++              return cmd;
++      }
++
++      mutex_unlock(&hdev->mgmt_pending_lock);
++
+       return NULL;
+ }
+@@ -3579,10 +3611,10 @@ void mgmt_smp_complete(struct hci_conn *
+       u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
+       struct mgmt_pending_cmd *cmd;
+-      cmd = find_pairing(conn);
++      cmd = remove_pairing(conn);
+       if (cmd) {
+               cmd->cmd_complete(cmd, status);
+-              mgmt_pending_remove(cmd);
++              mgmt_pending_free(cmd);
+       }
+ }
+@@ -3592,14 +3624,14 @@ static void pairing_complete_cb(struct h
+       BT_DBG("status %u", status);
+-      cmd = find_pairing(conn);
++      cmd = remove_pairing(conn);
+       if (!cmd) {
+               BT_DBG("Unable to find a pending command");
+               return;
+       }
+       cmd->cmd_complete(cmd, mgmt_status(status));
+-      mgmt_pending_remove(cmd);
++      mgmt_pending_free(cmd);
+ }
+ static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
+@@ -3611,14 +3643,14 @@ static void le_pairing_complete_cb(struc
+       if (!status)
+               return;
+-      cmd = find_pairing(conn);
++      cmd = remove_pairing(conn);
+       if (!cmd) {
+               BT_DBG("Unable to find a pending command");
+               return;
+       }
+       cmd->cmd_complete(cmd, mgmt_status(status));
+-      mgmt_pending_remove(cmd);
++      mgmt_pending_free(cmd);
+ }
+ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
+@@ -3775,23 +3807,17 @@ static int cancel_pair_device(struct soc
+               goto unlock;
+       }
+-      cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
++      cmd = remove_pairing_by_addr(hdev, &addr->bdaddr);
+       if (!cmd) {
+               err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
+                                     MGMT_STATUS_INVALID_PARAMS);
+               goto unlock;
+       }
+-      conn = cmd->user_data;
+-
+-      if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
+-              err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
+-                                    MGMT_STATUS_INVALID_PARAMS);
+-              goto unlock;
+-      }
++      conn = hci_conn_get(cmd->user_data);
+       cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
+-      mgmt_pending_remove(cmd);
++      mgmt_pending_free(cmd);
+       err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
+                               addr, sizeof(*addr));
+@@ -3809,6 +3835,8 @@ static int cancel_pair_device(struct soc
+       if (conn->conn_reason == CONN_REASON_PAIR_DEVICE)
+               hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
++      hci_conn_put(conn);
++
+ unlock:
+       hci_dev_unlock(hdev);
+       return err;
+@@ -10135,14 +10163,14 @@ void mgmt_auth_failed(struct hci_conn *c
+       ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
+       ev.status = status;
+-      cmd = find_pairing(conn);
++      cmd = remove_pairing(conn);
+       mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
+                   cmd ? cmd->sk : NULL);
+       if (cmd) {
+               cmd->cmd_complete(cmd, status);
+-              mgmt_pending_remove(cmd);
++              mgmt_pending_free(cmd);
+       }
+ }
diff --git a/queue-6.18/bluetooth-sco-give-the-socket-its-own-sco_conn-reference.patch b/queue-6.18/bluetooth-sco-give-the-socket-its-own-sco_conn-reference.patch
new file mode 100644 (file)
index 0000000..d2689fa
--- /dev/null
@@ -0,0 +1,164 @@
+From abd93c85c8667add738ee82aeab95dd9fc8265a2 Mon Sep 17 00:00:00 2001
+From: Aldo Ariel Panzardo <qwe.aldo@gmail.com>
+Date: Sat, 25 Jul 2026 16:52:30 -0300
+Subject: Bluetooth: SCO: give the socket its own sco_conn reference
+
+From: Aldo Ariel Panzardo <qwe.aldo@gmail.com>
+
+commit abd93c85c8667add738ee82aeab95dd9fc8265a2 upstream.
+
+sco_conn_del() drops a reference it does not own. It takes one transient
+reference via sco_conn_hold_unless_zero() and releases it with the
+sco_conn_put() that follows sco_sock_hold(); the additional put in the
+!sk branch releases a second one:
+
+    conn = sco_conn_hold_unless_zero(conn);
+    ...
+    sk = sco_sock_hold(conn);
+    sco_conn_unlock(conn);
+    sco_conn_put(conn);
+
+    if (!sk) {
+            sco_conn_put(conn);
+            return;
+    }
+
+When close() races the controller's Disconnection Complete, sco_chan_del()
+clears conn->sk and drops the socket's reference while sco_conn_del() is
+running. sco_conn_del() then sees sk == NULL, its own put drops the count
+to zero and frees the conn, and the second put writes to the freed kref:
+
+    BUG: KASAN: slab-use-after-free in sco_conn_put.part.0+0x1a/0x190
+    Write of size 4 at addr ffff8881099dec74 by task kworker/u17:3/413
+    Workqueue: hci1 hci_rx_work
+    Call Trace:
+     sco_conn_put.part.0+0x1a/0x190
+     hci_disconn_complete_evt+0x1ee/0x3e0
+     hci_event_packet+0x54a/0x650
+     hci_rx_work+0x321/0x3d0
+    Allocated by task 413:
+     sco_conn_add+0x72/0x1a0
+     sco_connect_cfm+0x88/0x670
+    Freed by task 413:
+     sco_conn_del.isra.0+0x3f/0xf0
+     hci_disconn_complete_evt+0x1ee/0x3e0
+    refcount_t: underflow; use-after-free.
+
+The root cause is that the socket stores the connection without holding a
+reference of its own. __sco_chan_add() does:
+
+    sco_pi(sk)->conn = conn;
+
+so the socket borrows whatever reference its caller happened to hold, and
+the callers paper over that with ad-hoc holds and puts. Give the socket a
+counted reference instead: __sco_chan_add() takes one and it is released
+together with the channel (sco_chan_del()) and in sco_sock_destruct().
+With the socket holding its own reference, sco_conn_del() no longer needs
+the extra put and the redundant hold in sco_conn_ready() goes away.
+
+Making the socket own its reference means the connection is now actually
+freed on the error paths of sco_connect() where it used to leak, which in
+turn runs sco_conn_free() and its hci_conn_drop(conn->hcon). To keep the
+hci_conn accounting balanced, make that ownership explicit as well:
+sco_conn_add() consumes one hci_conn reference and the sco_conn owns it for
+its lifetime. sco_connect() hands over the reference returned by
+hci_connect_sco() and no longer drops it on the error paths;
+sco_connect_cfm(), which is not given a reference, takes one with
+hci_conn_hold() before handing it to sco_conn_add() (and drops it again if
+the allocation fails); and the explicit hci_conn_hold() in sco_conn_ready()
+is removed. Every reference then has a single, clear owner.
+
+Fixes: e6720779ae61 ("Bluetooth: SCO: Use kref to track lifetime of sco_conn")
+Cc: stable@vger.kernel.org
+Suggested-by: Pauli Virtanen <pav@iki.fi>
+Signed-off-by: Aldo Ariel Panzardo <qwe.aldo@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/bluetooth/sco.c |   22 +++++++++++++---------
+ 1 file changed, 13 insertions(+), 9 deletions(-)
+
+--- a/net/bluetooth/sco.c
++++ b/net/bluetooth/sco.c
+@@ -190,6 +190,9 @@ static void sco_sock_clear_timer(struct
+ }
+ /* ---- SCO connections ---- */
++/* Consumes a reference on @hcon, which the returned sco_conn owns until it is
++ * freed. On failure (NULL return) the reference is left for the caller to drop.
++ */
+ static struct sco_conn *sco_conn_add(struct hci_conn *hcon)
+ {
+       struct sco_conn *conn = hcon->sco_data;
+@@ -200,6 +203,9 @@ static struct sco_conn *sco_conn_add(str
+                       sco_conn_lock(conn);
+                       conn->hcon = hcon;
+                       sco_conn_unlock(conn);
++              } else {
++                      /* conn already owns a reference on hcon */
++                      hci_conn_drop(hcon);
+               }
+               return conn;
+       }
+@@ -267,10 +273,8 @@ static void sco_conn_del(struct hci_conn
+       sco_conn_unlock(conn);
+       sco_conn_put(conn);
+-      if (!sk) {
+-              sco_conn_put(conn);
++      if (!sk)
+               return;
+-      }
+       /* Kill socket */
+       lock_sock(sk);
+@@ -285,7 +289,7 @@ static void __sco_chan_add(struct sco_co
+ {
+       BT_DBG("conn %p", conn);
+-      sco_pi(sk)->conn = conn;
++      sco_pi(sk)->conn = sco_conn_hold(conn);
+       conn->sk = sk;
+       if (parent)
+@@ -368,15 +372,15 @@ static int sco_connect(struct sock *sk)
+        */
+       if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
+               release_sock(sk);
+-              hci_conn_drop(hcon);
++              sco_conn_put(conn);
+               err = -EBADFD;
+               goto unlock;
+       }
+       err = sco_chan_add(conn, sk, NULL);
++      sco_conn_put(conn);
+       if (err) {
+               release_sock(sk);
+-              hci_conn_drop(hcon);
+               goto unlock;
+       }
+@@ -1452,8 +1456,6 @@ static void sco_conn_ready(struct sco_co
+               bacpy(&sco_pi(sk)->src, &conn->hcon->src);
+               bacpy(&sco_pi(sk)->dst, &conn->hcon->dst);
+-              sco_conn_hold(conn);
+-              hci_conn_hold(conn->hcon);
+               __sco_chan_add(conn, sk, parent);
+               if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags))
+@@ -1509,10 +1511,12 @@ static void sco_connect_cfm(struct hci_c
+       if (!status) {
+               struct sco_conn *conn;
+-              conn = sco_conn_add(hcon);
++              conn = sco_conn_add(hci_conn_hold(hcon));
+               if (conn) {
+                       sco_conn_ready(conn);
+                       sco_conn_put(conn);
++              } else {
++                      hci_conn_drop(hcon);
+               }
+       } else
+               sco_conn_del(hcon, bt_to_errno(status));
diff --git a/queue-6.18/dibs-fix-use-after-free-of-dmb_node-in-loopback-attach-detach-unregister.patch b/queue-6.18/dibs-fix-use-after-free-of-dmb_node-in-loopback-attach-detach-unregister.patch
new file mode 100644 (file)
index 0000000..e83ed1d
--- /dev/null
@@ -0,0 +1,180 @@
+From a10ea943356b9d70c5616a0a06f6fa97cfdaccb1 Mon Sep 17 00:00:00 2001
+From: Hidayath Khan <hidayath@linux.ibm.com>
+Date: Mon, 27 Jul 2026 11:35:30 +0200
+Subject: dibs: fix use-after-free of dmb_node in loopback attach/detach/unregister
+
+From: Hidayath Khan <hidayath@linux.ibm.com>
+
+commit a10ea943356b9d70c5616a0a06f6fa97cfdaccb1 upstream.
+
+dibs_lo_attach_dmb(), dibs_lo_detach_dmb() and dibs_lo_unregister_dmb()
+look up the dmb_node under dmb_ht_lock, drop the lock and only then
+operate on the node's refcount. Nothing keeps the node alive across
+that window: __dibs_lo_unregister_dmb() removes the node from the hash
+table under the write lock and immediately frees it.
+
+A concurrent final put can therefore free the node between the lookup
+and the refcount operation:
+
+CPU0 (attach)                     CPU1 (owner unregisters)
+
+read_lock_bh(&dmb_ht_lock)
+find dmb_node (refcnt == 1)
+read_unlock_bh(&dmb_ht_lock)
+                                  refcount_dec_and_test() 1 -> 0
+                                  write_lock_bh(&dmb_ht_lock)
+                                  hash_del(&dmb_node->list)
+                                  write_unlock_bh(&dmb_ht_lock)
+                                  kfree(dmb_node)
+refcount_inc_not_zero(&dmb_node->refcnt)  <-- use-after-free
+
+The same window exists for the refcount_dec_and_test() calls in the
+detach and unregister paths.
+
+Close the race structurally by making hash table membership and the
+refcount transitions atomic with respect to each other:
+
+- Perform the final refcount_dec_and_test() and hash_del() in a single
+  dmb_ht_lock write-side critical section, in both the unregister and
+  the detach path. Freeing the node still happens after the lock is
+  dropped, which is safe because a node whose refcount reached zero has
+  left the hash table and can no longer be found.
+
+- This establishes the invariant that any node found in the hash table
+  holds at least one reference, and that the final reference can only
+  be dropped under the write lock. dibs_lo_attach_dmb() can thus take
+  its reference with a plain refcount_inc() while still holding the
+  read lock; refcount_inc_not_zero() is no longer needed.
+
+__dibs_lo_unregister_dmb() no longer touches the hash table and is
+renamed to dibs_lo_free_dmb() accordingly.
+
+Note: commit cc21191b584c ("dibs: Move data path to dibs layer") moved
+the code to its current location; the race was introduced earlier by
+commit c3a910f2380f ("net/smc: implement DMB-merged operations of
+loopback-ism").
+
+Tested SMC-D via ISM and dibs loopback.
+
+Cc: stable@vger.kernel.org
+Fixes: c3a910f2380f ("net/smc: implement DMB-merged operations of loopback-ism")
+Reported-by: Rahul Chandelkar <rc@rexion.ai>
+Signed-off-by: Hidayath Khan <hidayath@linux.ibm.com>
+Reviewed-by: Alexandra Winter <wintera@linux.ibm.com>
+Link: https://patch.msgid.link/20260727093530.968834-1-hidayath@linux.ibm.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/dibs/dibs_loopback.c |   47 +++++++++++++++++++++----------------------
+ 1 file changed, 24 insertions(+), 23 deletions(-)
+
+--- a/drivers/dibs/dibs_loopback.c
++++ b/drivers/dibs/dibs_loopback.c
+@@ -118,14 +118,9 @@ err_bit:
+       return rc;
+ }
+-static void __dibs_lo_unregister_dmb(struct dibs_lo_dev *ldev,
+-                                   struct dibs_lo_dmb_node *dmb_node)
++static void dibs_lo_free_dmb(struct dibs_lo_dev *ldev,
++                           struct dibs_lo_dmb_node *dmb_node)
+ {
+-      /* remove dmb from hash table */
+-      write_lock_bh(&ldev->dmb_ht_lock);
+-      hash_del(&dmb_node->list);
+-      write_unlock_bh(&ldev->dmb_ht_lock);
+-
+       clear_bit(dmb_node->sba_idx, ldev->sba_idx_mask);
+       folio_put(virt_to_folio(dmb_node->cpu_addr));
+       kfree(dmb_node);
+@@ -139,27 +134,33 @@ static int dibs_lo_unregister_dmb(struct
+       struct dibs_lo_dmb_node *dmb_node = NULL, *tmp_node;
+       struct dibs_lo_dev *ldev;
+       unsigned long flags;
++      bool last;
+       ldev = dibs->drv_priv;
+       /* find dmb from hash table */
+-      read_lock_bh(&ldev->dmb_ht_lock);
++      write_lock_bh(&ldev->dmb_ht_lock);
+       hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb->dmb_tok) {
+               if (tmp_node->token == dmb->dmb_tok) {
+                       dmb_node = tmp_node;
+                       break;
+               }
+       }
+-      read_unlock_bh(&ldev->dmb_ht_lock);
+-      if (!dmb_node)
++      if (!dmb_node) {
++              write_unlock_bh(&ldev->dmb_ht_lock);
+               return -EINVAL;
++      }
++      last = refcount_dec_and_test(&dmb_node->refcnt);
++      if (last)
++              hash_del(&dmb_node->list);
++      write_unlock_bh(&ldev->dmb_ht_lock);
+-      if (refcount_dec_and_test(&dmb_node->refcnt)) {
++      if (last) {
+               spin_lock_irqsave(&dibs->lock, flags);
+               dibs->dmb_clientid_arr[dmb_node->sba_idx] = NO_DIBS_CLIENT;
+               spin_unlock_irqrestore(&dibs->lock, flags);
+-              __dibs_lo_unregister_dmb(ldev, dmb_node);
++              dibs_lo_free_dmb(ldev, dmb_node);
+       }
+       return 0;
+ }
+@@ -188,14 +189,9 @@ static int dibs_lo_attach_dmb(struct dib
+               read_unlock_bh(&ldev->dmb_ht_lock);
+               return -EINVAL;
+       }
++      refcount_inc(&dmb_node->refcnt);
+       read_unlock_bh(&ldev->dmb_ht_lock);
+-      if (!refcount_inc_not_zero(&dmb_node->refcnt))
+-              /* the dmb is being unregistered, but has
+-               * not been removed from the hash table.
+-               */
+-              return -EINVAL;
+-
+       /* provide dmb information */
+       dmb->idx = dmb_node->sba_idx;
+       dmb->dmb_tok = dmb_node->token;
+@@ -209,11 +205,12 @@ static int dibs_lo_detach_dmb(struct dib
+ {
+       struct dibs_lo_dmb_node *dmb_node = NULL, *tmp_node;
+       struct dibs_lo_dev *ldev;
++      bool last;
+       ldev = dibs->drv_priv;
+       /* find dmb_node according to dmb->dmb_tok */
+-      read_lock_bh(&ldev->dmb_ht_lock);
++      write_lock_bh(&ldev->dmb_ht_lock);
+       hash_for_each_possible(ldev->dmb_ht, tmp_node, list, token) {
+               if (tmp_node->token == token) {
+                       dmb_node = tmp_node;
+@@ -221,13 +218,17 @@ static int dibs_lo_detach_dmb(struct dib
+               }
+       }
+       if (!dmb_node) {
+-              read_unlock_bh(&ldev->dmb_ht_lock);
++              write_unlock_bh(&ldev->dmb_ht_lock);
+               return -EINVAL;
+       }
+-      read_unlock_bh(&ldev->dmb_ht_lock);
++      last = refcount_dec_and_test(&dmb_node->refcnt);
++      if (last)
++              hash_del(&dmb_node->list);
++      write_unlock_bh(&ldev->dmb_ht_lock);
++
++      if (last)
++              dibs_lo_free_dmb(ldev, dmb_node);
+-      if (refcount_dec_and_test(&dmb_node->refcnt))
+-              __dibs_lo_unregister_dmb(ldev, dmb_node);
+       return 0;
+ }
diff --git a/queue-6.18/fortify-disable-wstringop-overread-in-tests.patch b/queue-6.18/fortify-disable-wstringop-overread-in-tests.patch
new file mode 100644 (file)
index 0000000..1eb405d
--- /dev/null
@@ -0,0 +1,55 @@
+From c1f3e770eec26d6f96dd6d2ea30555ba7c09a244 Mon Sep 17 00:00:00 2001
+From: Nathan Chancellor <nathan@kernel.org>
+Date: Tue, 23 Jun 2026 13:23:46 -0700
+Subject: fortify: Disable -Wstringop-overread in tests
+
+From: Nathan Chancellor <nathan@kernel.org>
+
+commit c1f3e770eec26d6f96dd6d2ea30555ba7c09a244 upstream.
+
+clang recently added support for -Wstringop-overread [1], which is on by
+default like -Wfortify-source. This breaks the usage of -Werror in the
+fortify tests, resulting in the following false positive warnings in the
+kernel build:
+
+  warning: unsafe memcmp() usage lacked '__read_overflow2' warning in lib/test_fortify/read_overflow2-memcmp.c
+  warning: unsafe memcmp() usage lacked '__read_overflow' warning in lib/test_fortify/read_overflow-memcmp.c
+  warning: unsafe memchr() usage lacked '__read_overflow' warning in lib/test_fortify/read_overflow-memchr.c
+
+Examining the fortify test logs shows a warning like the following in
+each of the failed logs:
+
+  In file included from lib/test_fortify/read_overflow2-memcmp.c:5:
+  lib/test_fortify/test_fortify.h:34:2: error: 'memcmp' reading 17 bytes from a region of size 16 [-Werror,-Wstringop-overread]
+     34 |         TEST;
+        |         ^
+  lib/test_fortify/read_overflow2-memcmp.c:3:2: note: expanded from macro 'TEST'
+      3 |         memcmp(large, small, sizeof(small) + 1)
+        |         ^
+  1 error generated.
+
+Disable -Wstringop-overread for the fortify tests, as it defeats the
+purpose of testing the Linux specific implementation of fortify, like
+-Wfortify-source.
+
+Cc: stable@vger.kernel.org
+Closes: https://github.com/ClangBuiltLinux/linux/issues/2168
+Link: https://github.com/llvm/llvm-project/commit/86f2e71cb8d165b59ad31a442b2391e23826133e [1]
+Signed-off-by: Nathan Chancellor <nathan@kernel.org>
+Link: https://patch.msgid.link/20260623-fix-test_fortify-for-clang-stringop-overread-v1-1-15ee8342a953@kernel.org
+Signed-off-by: Kees Cook <kees@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ lib/test_fortify/Makefile |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/lib/test_fortify/Makefile
++++ b/lib/test_fortify/Makefile
+@@ -1,6 +1,7 @@
+ # SPDX-License-Identifier: GPL-2.0
+ ccflags-y := $(call cc-disable-warning,fortify-source)
++ccflags-y += $(call cc-disable-warning,stringop-overread)
+ quiet_cmd_test_fortify = TEST    $@
+       cmd_test_fortify = $(CONFIG_SHELL) $(src)/test_fortify.sh \
diff --git a/queue-6.18/fs-proc-task_mmu-fix-pagemap_scan-written-state-for-pmd-holes.patch b/queue-6.18/fs-proc-task_mmu-fix-pagemap_scan-written-state-for-pmd-holes.patch
new file mode 100644 (file)
index 0000000..a46bfc1
--- /dev/null
@@ -0,0 +1,99 @@
+From 40de8160ca7f67d14619ee0351ce5d68fc4a237a Mon Sep 17 00:00:00 2001
+From: "Kiryl Shutsemau (Meta)" <kas@kernel.org>
+Date: Wed, 15 Jul 2026 15:42:33 +0100
+Subject: fs/proc/task_mmu: fix PAGEMAP_SCAN written state for PMD holes
+
+From: Kiryl Shutsemau (Meta) <kas@kernel.org>
+
+commit 40de8160ca7f67d14619ee0351ce5d68fc4a237a upstream.
+
+PAGEMAP_SCAN reports an unpopulated PTE in a uffd-wp VMA as written, but a
+range with no page table at all -- a PMD hole -- is skipped:
+pagemap_scan_pte_hole() tests p->cur_vma_category, which never carries
+PAGE_IS_WRITTEN, so the hole is neither reported nor (under
+PM_SCAN_WP_MATCHING) armed.
+
+In a uffd-wp VMA, WP_UNPOPULATED installs uffd-wp markers when protecting
+a range, allocating page tables as needed, so an unpopulated slot is
+treated as written -- see the pte_none() handling in
+pagemap_page_category().  A missing marker therefore means the range was
+zapped, e.g.  via MADV_DONTNEED.  This applies to anon and shmem VMAs.
+
+An anonymous THP is write-protected in place as a huge PMD, so a full-PMD
+MADV_DONTNEED clears it to pmd_none -- a hole with no page table -- and
+pagemap_scan_pte_hole() misses it.  For a MAP_PRIVATE|MAP_ANON mapping
+MADV_DONTNEED has fill-with-zeros semantics, so a write-tracking
+checkpoint/migration tool (e.g.  CRIU) treats the range as unchanged and
+keeps its previous contents; after restore or live migration the process
+reads stale data instead of zeroes -- data corruption.
+
+Report a hole in a non-hugetlb uffd-wp VMA as written, matching the
+pte_none handling in pagemap_page_category(); the existing
+PM_SCAN_WP_MATCHING path then arms it via uffd_wp_range().
+
+hugetlb is excluded: pagemap_hugetlb_category() reports an empty hugetlb
+entry (huge_pte_none) as not-written, unlike pagemap_page_category(),
+which reports pte_none as written.  pagemap_scan_pte_hole() fires for a
+hugetlb slot only when it has no page table; keeping that not-written
+matches how an allocated-but-empty hugetlb entry reads, so the hole and
+the empty-entry cases agree within the VMA.
+
+Link: https://lore.kernel.org/20260715144234.442721-2-kirill@shutemov.name
+Fixes: 2bad466cc9d9 ("mm/uffd: UFFD_FEATURE_WP_UNPOPULATED")
+Signed-off-by: Kiryl Shutsemau <kas@kernel.org>
+Reported-by: Sashiko AI review <sashiko-bot@kernel.org>
+Closes: https://sashiko.dev/#/patchset/20260707151349.92143-1-kirill@shutemov.name
+Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
+Acked-by: David Hildenbrand (Arm) <david@kernel.org>
+Cc: Peter Xu <peterx@redhat.com>
+Cc: Jann Horn <jannh@google.com>
+Cc: Liam R. Howlett <liam@infradead.org>
+Cc: Lorenzo Stoakes <ljs@kernel.org>
+Cc: Michal Hocko <mhocko@suse.com>
+Cc: Mike Rapoport <rppt@kernel.org>
+Cc: Pedro Falcato <pfalcato@suse.de>
+Cc: Shuah Khan <shuah@kernel.org>
+Cc: Suren Baghdasaryan <surenb@google.com>
+Cc: Vlastimil Babka <vbabka@kernel.org>
+Cc: Zenghui Yu <zenghui.yu@linux.dev>
+Assisted-by: Claude:claude-fable-5
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/proc/task_mmu.c |   20 ++++++++++++++++++--
+ 1 file changed, 18 insertions(+), 2 deletions(-)
+
+--- a/fs/proc/task_mmu.c
++++ b/fs/proc/task_mmu.c
+@@ -2918,12 +2918,28 @@ static int pagemap_scan_pte_hole(unsigne
+ {
+       struct pagemap_scan_private *p = walk->private;
+       struct vm_area_struct *vma = walk->vma;
++      unsigned long categories;
+       int ret, err;
+-      if (!vma || !pagemap_scan_is_interesting_page(p->cur_vma_category, p))
++      if (!vma)
+               return 0;
+-      ret = pagemap_scan_output(p->cur_vma_category, p, addr, &end);
++      /*
++       * In a uffd-wp VMA an unpopulated range is treated as written:
++       * uffd-wp registration populates page tables and installs markers
++       * with WP_UNPOPULATED, so a missing marker means the range was
++       * zapped. See the pte_none() handling in pagemap_page_category().
++       *
++       * hugetlb differs, see pagemap_hugetlb_category().
++       */
++      categories = p->cur_vma_category;
++      if (userfaultfd_wp(vma) && !is_vm_hugetlb_page(vma))
++              categories |= PAGE_IS_WRITTEN;
++
++      if (!pagemap_scan_is_interesting_page(categories, p))
++              return 0;
++
++      ret = pagemap_scan_output(categories, p, addr, &end);
+       if (addr == end)
+               return ret;
diff --git a/queue-6.18/kvm-s390-pci-fix-memory-accounting-for-pinned-unpinned-pages.patch b/queue-6.18/kvm-s390-pci-fix-memory-accounting-for-pinned-unpinned-pages.patch
new file mode 100644 (file)
index 0000000..78817a9
--- /dev/null
@@ -0,0 +1,129 @@
+From 36f6999ecde3976731a8bfc0b8e667da6f593069 Mon Sep 17 00:00:00 2001
+From: Farhan Ali <alifm@linux.ibm.com>
+Date: Thu, 23 Jul 2026 15:14:05 -0700
+Subject: KVM: s390: pci: Fix memory accounting for pinned/unpinned pages
+
+From: Farhan Ali <alifm@linux.ibm.com>
+
+commit 36f6999ecde3976731a8bfc0b8e667da6f593069 upstream.
+
+The account_mem() and unaccount_mem() functions call get_uid() which
+increments the reference count of struct user_struct on every invocation.
+But we don't decrement the count by calling free_uid(). It also
+accounted/unaccounted the pages against the current->mm. But its possible
+the unaccount_mem() can be called from a different process context than the
+one that originally pinned the pages.
+
+Let's fix this by storing the pinning process user_struct and mm_struct
+when accounting for pinned pages, and subsequently free these resources
+when the pages are unpinned.
+
+Fixes: 3c5a1b6f0a18 ("KVM: s390: pci: provide routines for enabling/disabling interrupt forwarding")
+Cc: stable@vger.kernel.org
+Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com>
+Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
+Signed-off-by: Farhan Ali <alifm@linux.ibm.com>
+Tested-by: Matthew Rosato <mjrosato@linux.ibm.com>
+[borntraeger@linux.ibm.com: Fixed whitespace]
+Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/s390/kvm/pci.c |   43 ++++++++++++++++++++++++++++++++-----------
+ arch/s390/kvm/pci.h |    2 ++
+ 2 files changed, 34 insertions(+), 11 deletions(-)
+
+--- a/arch/s390/kvm/pci.c
++++ b/arch/s390/kvm/pci.c
+@@ -191,33 +191,54 @@ static int kvm_zpci_clear_airq(struct zp
+       return cc ? -EIO : 0;
+ }
+-static inline void unaccount_mem(unsigned long nr_pages)
++static inline void unaccount_mem(struct kvm_zdev *kzdev, unsigned long nr_pages)
+ {
+-      struct user_struct *user = get_uid(current_user());
++      struct user_struct *user = kzdev->user_account;
++      struct mm_struct *mm_account = kzdev->mm_account;
+-      if (user)
++      if (user) {
+               atomic_long_sub(nr_pages, &user->locked_vm);
+-      if (current->mm)
+-              atomic64_sub(nr_pages, &current->mm->pinned_vm);
++              free_uid(user);
++              kzdev->user_account = NULL;
++      }
++
++      if (mm_account) {
++              atomic64_sub(nr_pages, &mm_account->pinned_vm);
++              mmdrop(mm_account);
++              kzdev->mm_account = NULL;
++      }
+ }
+-static inline int account_mem(unsigned long nr_pages)
++static inline int account_mem(struct kvm_zdev *kzdev, unsigned long nr_pages)
+ {
+       struct user_struct *user = get_uid(current_user());
+       unsigned long page_limit, cur_pages, new_pages;
++      int rc = 0;
+       page_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+       cur_pages = atomic_long_read(&user->locked_vm);
+       do {
+               new_pages = cur_pages + nr_pages;
+-              if (new_pages > page_limit)
+-                      return -ENOMEM;
++              if (new_pages > page_limit) {
++                      rc = -ENOMEM;
++                      goto out;
++              }
+       } while (!atomic_long_try_cmpxchg(&user->locked_vm, &cur_pages, new_pages));
+-      atomic64_add(nr_pages, &current->mm->pinned_vm);
++      if (current->mm) {
++              mmgrab(current->mm);
++              atomic64_add(nr_pages, &current->mm->pinned_vm);
++      }
++
++      kzdev->user_account = user;
++      kzdev->mm_account = current->mm;
+       return 0;
++
++out:
++      free_uid(user);
++      return rc;
+ }
+ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
+@@ -280,7 +301,7 @@ static int kvm_s390_pci_aif_enable(struc
+       }
+       /* Account for pinned pages, roll back on failure */
+-      if (account_mem(pcount))
++      if (account_mem(zdev->kzdev, pcount))
+               goto unpin2;
+       /* AISB must be allocated before we can fill in GAITE */
+@@ -401,7 +422,7 @@ static int kvm_s390_pci_aif_disable(stru
+               pcount++;
+       }
+       if (pcount > 0)
+-              unaccount_mem(pcount);
++              unaccount_mem(kzdev, pcount);
+ out:
+       mutex_unlock(&aift->aift_lock);
+--- a/arch/s390/kvm/pci.h
++++ b/arch/s390/kvm/pci.h
+@@ -22,6 +22,8 @@ struct kvm_zdev {
+       struct kvm *kvm;
+       struct zpci_fib fib;
+       struct list_head entry;
++      struct user_struct *user_account;
++      struct mm_struct *mm_account;
+ };
+ struct zpci_gaite {
diff --git a/queue-6.18/kvm-s390-pci-fix-missing-error-codes-and-memory-unaccounting.patch b/queue-6.18/kvm-s390-pci-fix-missing-error-codes-and-memory-unaccounting.patch
new file mode 100644 (file)
index 0000000..e31bbe3
--- /dev/null
@@ -0,0 +1,57 @@
+From f86842e4d6c482300f4567f492d512c9ccf5bc4f Mon Sep 17 00:00:00 2001
+From: Farhan Ali <alifm@linux.ibm.com>
+Date: Thu, 23 Jul 2026 15:14:06 -0700
+Subject: KVM: s390: pci: Fix missing error codes and memory unaccounting
+
+From: Farhan Ali <alifm@linux.ibm.com>
+
+commit f86842e4d6c482300f4567f492d512c9ccf5bc4f upstream.
+
+In kvm_s390_pci_aif_enable() two error paths failed to set an error code,
+causing the function to return 0 on failure. It also failed to rollback
+memory accounting on failure. Fix both by propagating an error code on
+failure and calling unaccount_mem() in the cleanup path.
+
+Fixes: 3c5a1b6f0a18 ("KVM: s390: pci: provide routines for enabling/disabling interrupt forwarding")
+Cc: stable@vger.kernel.org
+Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com>
+Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
+Signed-off-by: Farhan Ali <alifm@linux.ibm.com>
+Tested-by: Matthew Rosato <mjrosato@linux.ibm.com>
+Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/s390/kvm/pci.c |    9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+--- a/arch/s390/kvm/pci.c
++++ b/arch/s390/kvm/pci.c
+@@ -301,14 +301,17 @@ static int kvm_s390_pci_aif_enable(struc
+       }
+       /* Account for pinned pages, roll back on failure */
+-      if (account_mem(zdev->kzdev, pcount))
++      rc = account_mem(zdev->kzdev, pcount);
++      if (rc)
+               goto unpin2;
+       /* AISB must be allocated before we can fill in GAITE */
+       mutex_lock(&aift->aift_lock);
+       bit = airq_iv_alloc_bit(aift->sbv);
+-      if (bit == -1UL)
++      if (bit == -1UL) {
++              rc = -ENOMEM;
+               goto unlock;
++      }
+       zdev->aisb = bit; /* store the summary bit number */
+       zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA |
+                                   AIRQ_IV_BITLOCK |
+@@ -352,6 +355,8 @@ static int kvm_s390_pci_aif_enable(struc
+       return rc;
+ unlock:
++      if (pcount > 0)
++              unaccount_mem(zdev->kzdev, pcount);
+       mutex_unlock(&aift->aift_lock);
+ unpin2:
+       if (fib->fmt0.sum == 1)
diff --git a/queue-6.18/kvm-s390-pci-fix-null-dereference-on-aibv-allocation-failure.patch b/queue-6.18/kvm-s390-pci-fix-null-dereference-on-aibv-allocation-failure.patch
new file mode 100644 (file)
index 0000000..556bd78
--- /dev/null
@@ -0,0 +1,50 @@
+From 8bf09b9b7d3232806df95f409581f8a9fd99a3fa Mon Sep 17 00:00:00 2001
+From: Farhan Ali <alifm@linux.ibm.com>
+Date: Thu, 23 Jul 2026 15:14:07 -0700
+Subject: KVM: s390: pci: Fix NULL dereference on AIBV allocation failure
+
+From: Farhan Ali <alifm@linux.ibm.com>
+
+commit 8bf09b9b7d3232806df95f409581f8a9fd99a3fa upstream.
+
+The airq_iv_create() can return NULL on failure, but the return value was
+never checked. If it fails, zdev->aibv will be NULL and fail when
+dereferenced in kvm_zpci_set_airq(). Add a NULL check and free the
+previously allocated AISB bit and zdev->aisb on failure.
+
+Fixes: 3c5a1b6f0a18 ("KVM: s390: pci: provide routines for enabling/disabling interrupt forwarding")
+Cc: stable@vger.kernel.org
+Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com>
+Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
+Signed-off-by: Farhan Ali <alifm@linux.ibm.com>
+Tested-by: Matthew Rosato <mjrosato@linux.ibm.com>
+Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/s390/kvm/pci.c |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/arch/s390/kvm/pci.c
++++ b/arch/s390/kvm/pci.c
+@@ -318,6 +318,11 @@ static int kvm_s390_pci_aif_enable(struc
+                                   AIRQ_IV_GUESTVEC,
+                                   phys_to_virt(fib->fmt0.aibv));
++      if (!zdev->aibv) {
++              rc = -ENOMEM;
++              goto free_aisb;
++      }
++
+       spin_lock_irq(&aift->gait_lock);
+       gaite = aift->gait + zdev->aisb;
+@@ -354,6 +359,9 @@ static int kvm_s390_pci_aif_enable(struc
+       rc = kvm_zpci_set_airq(zdev);
+       return rc;
++free_aisb:
++      airq_iv_free_bit(aift->sbv, zdev->aisb);
++      zdev->aisb = 0;
+ unlock:
+       if (pcount > 0)
+               unaccount_mem(zdev->kzdev, pcount);
diff --git a/queue-6.18/kvm-s390-pci-reject-adapter-interrupt-forwarding-if-already-enabled.patch b/queue-6.18/kvm-s390-pci-reject-adapter-interrupt-forwarding-if-already-enabled.patch
new file mode 100644 (file)
index 0000000..64426aa
--- /dev/null
@@ -0,0 +1,40 @@
+From 8fa01be5a6149404adb82c0979a78f6347edd3ef Mon Sep 17 00:00:00 2001
+From: Farhan Ali <alifm@linux.ibm.com>
+Date: Thu, 23 Jul 2026 15:14:04 -0700
+Subject: KVM: s390: pci: Reject adapter interrupt forwarding if already enabled
+
+From: Farhan Ali <alifm@linux.ibm.com>
+
+commit 8fa01be5a6149404adb82c0979a78f6347edd3ef upstream.
+
+The MPCIFC instruction doesn't allow registering adapter interrupts without
+first unregistering. So reject any request to enable interrupt forwarding
+if its already enabled for the zPCI device. This also fixes overwriting and
+thus leaking resources when the ioctl is called multiple times for the same
+device.
+
+Fixes: 3c5a1b6f0a18 ("KVM: s390: pci: provide routines for enabling/disabling interrupt forwarding")
+Cc: stable@vger.kernel.org
+Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com>
+Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
+Signed-off-by: Farhan Ali <alifm@linux.ibm.com>
+Tested-by: Matthew Rosato <mjrosato@linux.ibm.com>
+Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/s390/kvm/pci.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/arch/s390/kvm/pci.c
++++ b/arch/s390/kvm/pci.c
+@@ -238,6 +238,10 @@ static int kvm_s390_pci_aif_enable(struc
+       if (zdev->gisa == 0)
+               return -EINVAL;
++      /* AIF already enabled for the device */
++      if (zdev->kzdev->fib.fmt0.aibv != 0)
++              return -EINVAL;
++
+       kvm = zdev->kzdev->kvm;
+       msi_vecs = min_t(unsigned int, fib->fmt0.noi, zdev->max_msi);
diff --git a/queue-6.18/kvm-s390-pci-validate-aibv-and-aisb-before-pinning-guest-pages.patch b/queue-6.18/kvm-s390-pci-validate-aibv-and-aisb-before-pinning-guest-pages.patch
new file mode 100644 (file)
index 0000000..4aa9a12
--- /dev/null
@@ -0,0 +1,71 @@
+From 868d32ac72cba21c5c6d8a66a814b7c25a3a5c01 Mon Sep 17 00:00:00 2001
+From: Farhan Ali <alifm@linux.ibm.com>
+Date: Thu, 23 Jul 2026 15:14:09 -0700
+Subject: KVM: s390: pci: Validate AIBV and AISB before pinning guest pages
+
+From: Farhan Ali <alifm@linux.ibm.com>
+
+commit 868d32ac72cba21c5c6d8a66a814b7c25a3a5c01 upstream.
+
+The AIBV holds one bit per MSI-X vector for a given function. The size of
+the bit vector is derived from the NOI and the AIBVO. If the size of the
+AIBV exceeds a single page boundary, then reject the request as we cannot
+safely pin the guest AIBV.
+
+Similarly reject the request if the AISB address is not 8-byte aligned as
+the architecture requires doubleword alignment for the summary bit address.
+Since the AISBO can address up to 64 bits, the size of the AISB can only be
+8 bytes for the function. This also ensures the AISB doesn't exceed a
+single page boundary.
+
+Fixes: 3c5a1b6f0a18 ("KVM: s390: pci: provide routines for enabling/disabling interrupt forwarding")
+Cc: stable@vger.kernel.org
+Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com>
+Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
+Signed-off-by: Farhan Ali <alifm@linux.ibm.com>
+Tested-by: Matthew Rosato <mjrosato@linux.ibm.com>
+Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/s390/kvm/pci.c |   16 +++++++++++++++-
+ 1 file changed, 15 insertions(+), 1 deletion(-)
+
+--- a/arch/s390/kvm/pci.c
++++ b/arch/s390/kvm/pci.c
+@@ -245,7 +245,7 @@ static int kvm_s390_pci_aif_enable(struc
+                                  bool assist)
+ {
+       struct page *pages[1], *aibv_page, *aisb_page = NULL;
+-      unsigned int msi_vecs, idx;
++      unsigned int msi_vecs, idx, size;
+       struct zpci_gaite *gaite;
+       unsigned long hva, bit;
+       struct kvm *kvm;
+@@ -272,6 +272,14 @@ static int kvm_s390_pci_aif_enable(struc
+               return gisc;
+       /* Replace AIBV address */
++      size = BITS_TO_LONGS(msi_vecs + fib->fmt0.aibvo) * sizeof(unsigned long);
++      npages = DIV_ROUND_UP((fib->fmt0.aibv & ~PAGE_MASK) + size, PAGE_SIZE);
++      /* AIBV cannot span more than 1 page */
++      if (npages > 1) {
++              rc = -EINVAL;
++              goto out;
++      }
++
+       idx = srcu_read_lock(&kvm->srcu);
+       hva = gfn_to_hva(kvm, gpa_to_gfn((gpa_t)fib->fmt0.aibv));
+       npages = pin_user_pages_fast(hva, 1, FOLL_WRITE | FOLL_LONGTERM, pages);
+@@ -287,6 +295,12 @@ static int kvm_s390_pci_aif_enable(struc
+       /* Pin the guest AISB if one was specified */
+       if (fib->fmt0.sum == 1) {
++              /* AISB must be dword aligned */
++              if (fib->fmt0.aisb & 0x7) {
++                      rc = -EINVAL;
++                      goto unpin1;
++              }
++
+               idx = srcu_read_lock(&kvm->srcu);
+               hva = gfn_to_hva(kvm, gpa_to_gfn((gpa_t)fib->fmt0.aisb));
+               npages = pin_user_pages_fast(hva, 1, FOLL_WRITE | FOLL_LONGTERM,
diff --git a/queue-6.18/kvm-svm-update-x2apic-msr-intercepts-if-avic-is-inhibited-while-l2-is-active.patch b/queue-6.18/kvm-svm-update-x2apic-msr-intercepts-if-avic-is-inhibited-while-l2-is-active.patch
new file mode 100644 (file)
index 0000000..8de7df9
--- /dev/null
@@ -0,0 +1,75 @@
+From 7d3aae206663c4e006b25a1c7a20a4029e67da76 Mon Sep 17 00:00:00 2001
+From: Sean Christopherson <seanjc@google.com>
+Date: Fri, 10 Jul 2026 09:20:51 -0700
+Subject: KVM: SVM: Update x2APIC MSR intercepts if AVIC is inhibited while L2 is active
+
+From: Sean Christopherson <seanjc@google.com>
+
+commit 7d3aae206663c4e006b25a1c7a20a4029e67da76 upstream.
+
+Always update x2APIC MSR intercepts for L1 when AVIC is deactivated, even
+if L2 is active and KVM is using a separate MSR bitmap to run L2.  If AVIC
+is fully enabled prior to running L2, and is then inhibited while L2 is
+active (for a VM-scoped inhibit), then KVM will run L1 with AVIC disabled,
+but with x2APIC MSR intercepts disabled, i.e. will allow L1 to read most of
+the host's APIC state, send arbitrary interrupts, change task priority, and
+ultimately trivially DoS the host.
+
+E.g. sending a self-IPI in L1 on HYPERV_REENLIGHTENMENT_VECTOR, 0xee, with
+CONFIG_HYPERV=n in the host kernel as a "safe" PoC, yields:
+
+  Spurious interrupt (vector 0xee) on CPU#425. Acked
+
+And hacking KVM to abuse kvm_set_posted_intr_wakeup_handler() to register a
+handler and WARN on POSTED_INTR_WAKEUP_VECTOR yields:
+
+  ------------[ cut here ]------------
+  WARNING: arch/x86/kvm/svm/svm.c:5594 at pi_wakeup_handler+0x9/0x10 [kvm_amd], CPU#156: nested_x2apic_t/316940
+  CPU: 156 UID: 0 PID: 316940 Comm: nested_x2apic_t Tainted: G S   U
+  Tainted: [S]=CPU_OUT_OF_SPEC, [U]=USER
+  Hardware name: Google Astoria-Turin/astoria, BIOS 0.20260209.0-0 02/09/2026
+  RIP: 0010:pi_wakeup_handler+0x9/0x10 [kvm_amd]
+  Call Trace:
+   <IRQ>
+   sysvec_kvm_posted_intr_wakeup_ipi+0x64/0x80
+   </IRQ>
+   <TASK>
+   asm_sysvec_kvm_posted_intr_wakeup_ipi+0x1a/0x20
+  RIP: 0010:vcpu_run+0x1430/0x1e40 [kvm]
+   kvm_arch_vcpu_ioctl_run+0x2c1/0x600 [kvm]
+   kvm_vcpu_ioctl+0x580/0x6b0 [kvm]
+   __se_sys_ioctl+0x6d/0xb0
+   do_syscall_64+0x10a/0x480
+   entry_SYSCALL_64_after_hwframe+0x4b/0x53
+  RIP: 0033:0x46ff4b
+   </TASK>
+  ---[ end trace 0000000000000000 ]---
+
+Fixes: 091abbf578f9 ("KVM: x86: nSVM: optimize svm_set_x2apic_msr_interception")
+Cc: stable@vger.kernel.org
+Cc: Yosry Ahmed <yosry@kernel.org>
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+Link: https://patch.msgid.link/20260729213558.639074-1-pbonzini@redhat.com/
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/svm/avic.c |    8 --------
+ 1 file changed, 8 deletions(-)
+
+--- a/arch/x86/kvm/svm/avic.c
++++ b/arch/x86/kvm/svm/avic.c
+@@ -220,14 +220,6 @@ static void avic_deactivate_vmcb(struct
+       if (!sev_es_guest(svm->vcpu.kvm))
+               svm_set_intercept(svm, INTERCEPT_CR8_WRITE);
+-      /*
+-       * If running nested and the guest uses its own MSR bitmap, there
+-       * is no need to update L0's msr bitmap
+-       */
+-      if (is_guest_mode(&svm->vcpu) &&
+-          vmcb12_is_intercept(&svm->nested.ctl, INTERCEPT_MSR_PROT))
+-              return;
+-
+       /* Enabling MSR intercept for x2APIC registers */
+       avic_set_x2apic_msr_interception(svm, true);
+ }
diff --git a/queue-6.18/kvm-vmx-add-memory-clobber-to-asm-for-vmx-instructions.patch b/queue-6.18/kvm-vmx-add-memory-clobber-to-asm-for-vmx-instructions.patch
new file mode 100644 (file)
index 0000000..a5497c4
--- /dev/null
@@ -0,0 +1,70 @@
+From 0e65cd9e5d41c34f86b7c347967bedac54926041 Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini@redhat.com>
+Date: Tue, 21 Jul 2026 18:31:49 +0200
+Subject: KVM: VMX: add memory clobber to asm for VMX instructions
+
+From: Paolo Bonzini <pbonzini@redhat.com>
+
+commit 0e65cd9e5d41c34f86b7c347967bedac54926041 upstream.
+
+VMCLEAR/VMREAD/VMWRITE/VMPTRLD access the internal VMCS cache, which
+is not visible to the compiler; without a memory clobber, the compiler
+can reorder them in troublesome ways because "asm volatile" and "asm goto"
+only protect against removal of the asm.  For example, placing a VMWRITE
+before the corresponding VMCS pointer is loaded can lead to corruption.
+While none of this has been observed, it is better to prevent than cure.
+
+Likewise, INVEPT and INVVPID access the TLB and, even though in their
+case the effect is only visible to the next VMLAUNCH/VMRESUME, it is
+technically correct to add the clobber there too.  So avoid any urge to
+special case them, and simply hardcode "memory" into the clobber list
+of vmx_asm1() and vmx_asm2().  __vmcs_readl() open-codes its own asm,
+so add the clobber there as well.
+
+Link: https://lore.kernel.org/kvm/CABgObfbL3t21yVeSwiLSjjOUER+rTYDPHYAH9YU4TWGRjx6XHg@mail.gmail.com/
+Cc: Sean Christopherson <seanjc@google.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/vmx/vmx_ops.h |    8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/arch/x86/kvm/vmx/vmx_ops.h
++++ b/arch/x86/kvm/vmx/vmx_ops.h
+@@ -101,7 +101,7 @@ static __always_inline unsigned long __v
+                         : [output] "=r" (value)
+                         : [field] "r" (field)
+-                        : "cc"
++                        : "cc", "memory"
+                         : do_fail, do_exception);
+       return value;
+@@ -146,7 +146,7 @@ do_exception:
+                    : ASM_CALL_CONSTRAINT, [output] "=&r" (value)
+                    : [field] "r" (field)
+-                   : "cc");
++                   : "cc", "memory");
+       return value;
+ #endif /* CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
+@@ -194,7 +194,7 @@ do {                                                                       \
+                         ".byte 0x2e\n\t" /* branch not taken hint */  \
+                         "jna %l[error]\n\t"                           \
+                         _ASM_EXTABLE(1b, %l[fault])                   \
+-                        : : op1 : "cc" : error, fault);               \
++                        : : op1 : "cc", "memory" : error, fault);     \
+       return;                                                         \
+ error:                                                                        \
+       instrumentation_begin();                                        \
+@@ -211,7 +211,7 @@ do {                                                                       \
+                         ".byte 0x2e\n\t" /* branch not taken hint */  \
+                         "jna %l[error]\n\t"                           \
+                         _ASM_EXTABLE(1b, %l[fault])                   \
+-                        : : op1, op2 : "cc" : error, fault);          \
++                        : : op1, op2 : "cc", "memory" : error, fault);\
+       return;                                                         \
+ error:                                                                        \
+       instrumentation_begin();                                        \
diff --git a/queue-6.18/mm-hugetlb-fix-list-corruption-in-allocate_file_region_entries.patch b/queue-6.18/mm-hugetlb-fix-list-corruption-in-allocate_file_region_entries.patch
new file mode 100644 (file)
index 0000000..5b13da7
--- /dev/null
@@ -0,0 +1,77 @@
+From dd9623f58ec702a07b2d67179d6fcea79c52231a Mon Sep 17 00:00:00 2001
+From: Xiangfeng Cai <caixiangfeng@bytedance.com>
+Date: Tue, 14 Jul 2026 01:14:55 +0800
+Subject: mm/hugetlb: fix list corruption in allocate_file_region_entries()
+
+From: Xiangfeng Cai <caixiangfeng@bytedance.com>
+
+commit dd9623f58ec702a07b2d67179d6fcea79c52231a upstream.
+
+allocate_file_region_entries() tops up resv->region_cache with freshly
+allocated file_region descriptors.  The allocation uses GFP_KERNEL, so
+resv->lock is dropped around it: the new entries are gathered on a
+stack-local list head, allocated_regions, and spliced into
+resv->region_cache once the lock is re-acquired.
+
+The splice used list_splice(), which moves the entries but does not
+re-initialize the source head, so allocated_regions is left pointing at an
+entry that now lives on resv->region_cache.  The top-up runs in a while
+loop that re-checks the cache deficit after re-acquiring the lock.  For a
+shared mapping the resv_map is shared by every mapper of the hugetlbfs
+inode, so a concurrent region_chg()/region_add()/region_del() on the same
+resv_map can consume cache entries during the unlocked window and force a
+second iteration.  That iteration calls list_add() on the stale head and
+corrupts the list; with CONFIG_DEBUG_LIST the __list_add_valid() check
+trips:
+
+  list_add corruption. next->prev should be prev (ffffc900011ff7f8),
+  but was ffff88814c281460. (next=ffff88814c545640).
+  kernel BUG at lib/list_debug.c:31!
+   allocate_file_region_entries+0x191/0x420
+   region_chg+0x267/0x300
+   hugetlb_reserve_pages+0x387/0xc80
+   hugetlbfs_file_mmap+0x2ce/0x3f0
+   mmap_region+0x1348/0x1a80
+   do_mmap+0x85e/0xb90
+   vm_mmap_pgoff+0x18c/0x330
+   ksys_mmap_pgoff+0x2a1/0x3e0
+   do_syscall_64+0xd7/0x420
+
+Without CONFIG_DEBUG_LIST the bad list_add() silently links a kernel-stack
+address into resv->region_cache, leading to later use-after-free.
+
+This was observed as a real host panic on a dense KVM host where a QEMU
+guest-RAM hugetlbfs file was mapped MAP_SHARED by both QEMU and a separate
+SPDK/DPDK vhost-user target, generating concurrent region_* traffic on one
+shared resv_map.
+
+Use list_splice_init() so the source head is re-initialized empty after
+each splice, making the retry loop safe.
+
+Link: https://lore.kernel.org/20260713171456.300518-2-caixiangfeng@bytedance.com
+Fixes: d3ec7b6e09e5 ("mm/hugetlb: use list_splice to merge two list at once")
+Signed-off-by: Xiangfeng Cai <caixiangfeng@bytedance.com>
+Reviewed-by: Muchun Song <muchun.song@linux.dev>
+Cc: Baoquan He <baoquan.he@linux.dev>
+Cc: David Hildenbrand <david@kernel.org>
+Cc: Oscar Salvador <osalvador@suse.de>
+Cc: Shuah Khan <shuah@kernel.org>
+Cc: Wei Yang <richard.weiyang@linux.alibaba.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/hugetlb.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/mm/hugetlb.c
++++ b/mm/hugetlb.c
+@@ -705,7 +705,7 @@ static int allocate_file_region_entries(
+               spin_lock(&resv->lock);
+-              list_splice(&allocated_regions, &resv->region_cache);
++              list_splice_init(&allocated_regions, &resv->region_cache);
+               resv->region_cache_count += to_allocate;
+       }
diff --git a/queue-6.18/mm-migrate_device-fix-pte_pfn-pte_dirty-called-on-non-present-pte.patch b/queue-6.18/mm-migrate_device-fix-pte_pfn-pte_dirty-called-on-non-present-pte.patch
new file mode 100644 (file)
index 0000000..5970970
--- /dev/null
@@ -0,0 +1,59 @@
+From 63867c82d0c0c2d182016a32b1cc0103116b0ea5 Mon Sep 17 00:00:00 2001
+From: Kefeng Wang <wangkefeng.wang@huawei.com>
+Date: Mon, 6 Jul 2026 19:19:58 +0800
+Subject: mm: migrate_device: fix pte_pfn/pte_dirty called on non-present PTE
+
+From: Kefeng Wang <wangkefeng.wang@huawei.com>
+
+commit 63867c82d0c0c2d182016a32b1cc0103116b0ea5 upstream.
+
+pte_pfn() and pte_dirty() have undefined behaviour when called on a
+non-present PTE. In migrate_vma_collect_pmd(), these functions may be
+invoked on non-present entries (e.g., device-private entries), leading
+to potential crashes from pte_pfn() or incorrect dirty folio accounting
+from pte_dirty(). Fix both by guarding with pte_present() checks.
+
+Link: https://lore.kernel.org/20260708003955.4024340-1-wangkefeng.wang@huawei.com
+Link: https://lore.kernel.org/20260706111958.3649651-1-wangkefeng.wang@huawei.com
+Fixes: fd35ca3d12cc ("mm/migrate_device.c: copy pte dirty bit to page")
+Fixes: 6c287605fd56 ("mm: remember exclusively mapped anonymous pages with PG_anon_exclusive")
+Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
+Reviewed-by: Balbir Singh <balbirs@nvidia.com>
+Acked-by: Zi Yan <ziy@nvidia.com>
+Cc: Alistair Popple <apopple@nvidia.com>
+Cc: Byungchul Park <byungchul@sk.com>
+Cc: David Hildenbrand <david@kernel.org>
+Cc: Gregory Price <gourry@gourry.net>
+Cc: "Huang, Ying" <ying.huang@linux.alibaba.com>
+Cc: Joshua Hahn <joshua.hahnjy@gmail.com>
+Cc: Matthew Brost <matthew.brost@intel.com>
+Cc: Rakie Kim <rakie.kim@sk.com>
+Cc: Ying Huang <ying.huang@linux.alibaba.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/migrate_device.c |    5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/mm/migrate_device.c
++++ b/mm/migrate_device.c
+@@ -209,7 +209,8 @@ again:
+                       bool anon_exclusive;
+                       pte_t swp_pte;
+-                      flush_cache_page(vma, addr, pte_pfn(pte));
++                      if (pte_present(pte))
++                              flush_cache_page(vma, addr, pte_pfn(pte));
+                       anon_exclusive = folio_test_anon(folio) &&
+                                         PageAnonExclusive(page);
+                       if (anon_exclusive) {
+@@ -230,7 +231,7 @@ again:
+                       migrate->cpages++;
+                       /* Set the dirty flag on the folio now the pte is gone. */
+-                      if (pte_dirty(pte))
++                      if (pte_present(pte) && pte_dirty(pte))
+                               folio_mark_dirty(folio);
+                       /* Setup special migration page table entry */
diff --git a/queue-6.18/mm-percpu-km-fix-bitmap-overflow-and-accounting-in-pcpu_create_chunk.patch b/queue-6.18/mm-percpu-km-fix-bitmap-overflow-and-accounting-in-pcpu_create_chunk.patch
new file mode 100644 (file)
index 0000000..74a170a
--- /dev/null
@@ -0,0 +1,53 @@
+From 89b1b79c308818a715e75f28744b70d8940a07c9 Mon Sep 17 00:00:00 2001
+From: Zi Yan <ziy@nvidia.com>
+Date: Thu, 9 Jul 2026 15:12:01 -0400
+Subject: mm/percpu-km: fix bitmap overflow and accounting in pcpu_create_chunk()
+
+From: Zi Yan <ziy@nvidia.com>
+
+commit 89b1b79c308818a715e75f28744b70d8940a07c9 upstream.
+
+In pcpu_create_chunk(), nr_pages is the total contiguous backing
+allocation, i.e., nr_units * pcpu_unit_pages, but pcpu_chunk_populated()
+uses it to set chunk->populated, whose size is pcpu_unit_pages, bitmap.
+Since bit N in chunk->populated means page offset N inside every unit is
+backed.  When nr_units > 1, the function writes beyond chunk->populated.
+Fix it by using chunk->nr_pages.
+
+It also fixes the global pcpu_nr_empty_pop_pages accounting, since
+pcpu_balance_free() only iterates up to chunk->nr_pages.
+
+Commit a63d4ac4ab609 ("percpu: make percpu-km set chunk->populated bitmap
+properly") introduced the bitmap overflow issue.  Later, commit
+b539b87fed37f ("percpu: implmeent pcpu_nr_empty_pop_pages and
+chunk->nr_populated") added pcpu_nr_empty_pop_pages and caused the
+accounting issue.
+
+Link: https://lore.kernel.org/20260709-fix-pcpu_create_chunk-in-percpu-km-v1-1-1f64745a84cc@nvidia.com
+Fixes: a63d4ac4ab609 ("percpu: make percpu-km set chunk->populated bitmap properly")
+Reported-by: Sashiko <sashiko-bot@kernel.org>
+Closes: https://sashiko.dev/#/patchset/20260703-keep-subpage-private-zero-at-free-v2-0-2970fe777dd6%40nvidia.com?part=1
+Assisted-by: Codex:GPT-5
+Signed-off-by: Zi Yan <ziy@nvidia.com>
+Acked-by: Dennis Zhou <dennis@kernel.org>
+Cc: Christoph Lameter <cl@linux.com>
+Cc: Tejun Heo <tj@kernel.org>
+Cc: Zi Yan <ziy@nvidia.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/percpu-km.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/mm/percpu-km.c
++++ b/mm/percpu-km.c
+@@ -75,7 +75,7 @@ static struct pcpu_chunk *pcpu_create_ch
+       chunk->base_addr = page_address(pages);
+       spin_lock_irqsave(&pcpu_lock, flags);
+-      pcpu_chunk_populated(chunk, 0, nr_pages);
++      pcpu_chunk_populated(chunk, 0, chunk->nr_pages);
+       spin_unlock_irqrestore(&pcpu_lock, flags);
+       pcpu_stats_chunk_alloc();
diff --git a/queue-6.18/mm-util-don-t-read-__page_2-for-order-1-folios-in-snapshot_page.patch b/queue-6.18/mm-util-don-t-read-__page_2-for-order-1-folios-in-snapshot_page.patch
new file mode 100644 (file)
index 0000000..8c4d529
--- /dev/null
@@ -0,0 +1,54 @@
+From 7441d6348c70738e9ed307510db171c7a9b3f4bf Mon Sep 17 00:00:00 2001
+From: Aboorva Devarajan <aboorvad@linux.ibm.com>
+Date: Thu, 9 Jul 2026 01:49:54 +0530
+Subject: mm/util: don't read __page_2 for order-1 folios in snapshot_page()
+
+From: Aboorva Devarajan <aboorvad@linux.ibm.com>
+
+commit 7441d6348c70738e9ed307510db171c7a9b3f4bf upstream.
+
+snapshot_page() currently reads __page_2 after checking nr_pages > 1, but
+it should only do so when nr_pages > 2.
+
+If an order-1 folio is allocated at the end of a vmemmap section,
+__page_2 will not exist and reading it will cause a fault.
+
+During DLPAR memory remove on a 22 TB ppc64le LPAR, snapshot_page() oopsed
+on the page isolation path while reading an order-1 folio's __page_2 from
+an adjacent absent section (unmapped vmemmap).
+
+Fix this to avoid reading memmap that doesn't exist (e.g., a vmemmap
+hole).
+
+Link: https://lore.kernel.org/20260708201954.686111-1-aboorvad@linux.ibm.com
+Fixes: 31a31da8a618 ("mm: move _pincount in folio to page[2] on 32bit")
+Signed-off-by: Aboorva Devarajan <aboorvad@linux.ibm.com>
+Reported-by: Sourabh Jain <sourabhjain@linux.ibm.com>
+Acked-by: David Hildenbrand (Arm) <david@kernel.org>
+Reviewed-by: Lorenzo Stoakes <ljs@kernel.org>
+Reviewed-by: Matthew Wilcox (Oracle) <willy@infradead.org>
+Reviewed-by: Luiz Capitulino <luizcap@redhat.com>
+Cc: Liam R. Howlett <liam@infradead.org>
+Cc: Michal Hocko <mhocko@suse.com>
+Cc: Mike Rapoport <rppt@kernel.org>
+Cc: "Ritesh Harjani (IBM)" <ritesh.list@gmail.com>
+Cc: Suren Baghdasaryan <surenb@google.com>
+Cc: Vlastimil Babka <vbabka@kernel.org>
+Cc: <stable@vger.kernel.org> # v6.15+
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/util.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/mm/util.c
++++ b/mm/util.c
+@@ -1263,7 +1263,7 @@ again:
+       if (ps->idx < MAX_FOLIO_NR_PAGES) {
+               memcpy(&ps->folio_snapshot, foliop, 2 * sizeof(struct page));
+               nr_pages = folio_nr_pages(&ps->folio_snapshot);
+-              if (nr_pages > 1)
++              if (nr_pages > 2)
+                       memcpy(&ps->folio_snapshot.__page_2, &foliop->__page_2,
+                              sizeof(struct page));
+               set_ps_flags(ps, foliop, page);
diff --git a/queue-6.18/mm-vmstat-fold-stranded-per-cpu-node-stats-when-a-node-comes-online.patch b/queue-6.18/mm-vmstat-fold-stranded-per-cpu-node-stats-when-a-node-comes-online.patch
new file mode 100644 (file)
index 0000000..b1c7323
--- /dev/null
@@ -0,0 +1,74 @@
+From ea3034b2b00fa50c8d2518d0804c9d427bbafa86 Mon Sep 17 00:00:00 2001
+From: Gregory Price <gourry@gourry.net>
+Date: Sat, 27 Jun 2026 16:22:43 -0400
+Subject: mm/vmstat: fold stranded per-cpu node stats when a node comes online
+
+From: Gregory Price <gourry@gourry.net>
+
+commit ea3034b2b00fa50c8d2518d0804c9d427bbafa86 upstream.
+
+A per-node vmstat counter is pgdat->vm_stat[] plus per-cpu deltas.  A
+balanced counter can sit split as global=+N / per-cpu=-N.
+
+The folds reconciling the split only walk online nodes, so when
+try_offline_node() marks a node offline the per-cpu deltas are stranded.
+
+A subsequent online resets the per-cpu area but not pgdat->vm_stat[],
+orphaning the +N permanently.  All NR_VM_NODE_STAT_ITEMS are affected.
+
+The existing code zeroes the per-cpu counters and causes a permanent skew.
+Fold the stranded deltas instead, before the node rejoins the online set.
+The node is not online yet and the hotplug lock is held, so the remote
+access to per-cpu values is safe.
+
+Discovered when node compaction hung for a nearly empty node, as the math
+to determine throttling broke.  Reproduced by repeated memory
+hotplug/unplug cycles on a node under pressure: NR_ISOLATED_ANON ratchets
+up and never returns to zero.
+
+Link: https://lore.kernel.org/20260627202243.758289-1-gourry@gourry.net
+Fixes: 75ef71840539 ("mm, vmstat: add infrastructure for per-node vmstats")
+Signed-off-by: Gregory Price <gourry@gourry.net>
+Cc: Johannes Weiner <hannes@cmpxchg.org>
+Cc: Mel Gorman <mgorman@techsingularity.net>
+Cc: Mike Rapoport <rppt@kernel.org>
+Cc: Vlastimil Babka <vbabka@kernel.org>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/mm_init.c |   15 +++++++++++----
+ 1 file changed, 11 insertions(+), 4 deletions(-)
+
+--- a/mm/mm_init.c
++++ b/mm/mm_init.c
+@@ -1565,7 +1565,7 @@ void __ref free_area_init_core_hotplug(s
+ {
+       int nid = pgdat->node_id;
+       enum zone_type z;
+-      int cpu;
++      int cpu, i;
+       pgdat_init_internals(pgdat);
+@@ -1583,10 +1583,17 @@ void __ref free_area_init_core_hotplug(s
+       pgdat->node_start_pfn = 0;
+       pgdat->node_present_pages = 0;
+-      for_each_online_cpu(cpu) {
+-              struct per_cpu_nodestat *p;
++      /*
++       * Hot-unplug can leave per-cpu vmstat deltas unfolded (folders skip
++       * offline nodes) - reconcile this at online. Foreign access to counters
++       * is safe: the node is not online yet and we hold the hotplug lock.
++       */
++      for_each_possible_cpu(cpu) {
++              struct per_cpu_nodestat *p = per_cpu_ptr(pgdat->per_cpu_nodestats, cpu);
+-              p = per_cpu_ptr(pgdat->per_cpu_nodestats, cpu);
++              for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++)
++                      if (p->vm_node_stat_diff[i])
++                              node_page_state_add(p->vm_node_stat_diff[i], pgdat, i);
+               memset(p, 0, sizeof(*p));
+       }
diff --git a/queue-6.18/sctp-validate-adaptation-indication-parameter-length.patch b/queue-6.18/sctp-validate-adaptation-indication-parameter-length.patch
new file mode 100644 (file)
index 0000000..c480624
--- /dev/null
@@ -0,0 +1,51 @@
+From 74b21f52c5c5a71a05c0ff70e513f4f04ff28b17 Mon Sep 17 00:00:00 2001
+From: Charles Vosburgh <trilobyte777@gmail.com>
+Date: Mon, 27 Jul 2026 19:17:30 -0400
+Subject: sctp: validate Adaptation Indication parameter length
+
+From: Charles Vosburgh <trilobyte777@gmail.com>
+
+commit 74b21f52c5c5a71a05c0ff70e513f4f04ff28b17 upstream.
+
+The Adaptation Layer Indication parameter contains a fixed 32-bit
+Adaptation Code Point after its parameter header. However,
+sctp_verify_param() accepts a header-only parameter because the generic
+parameter walker only requires the header to be present.
+
+sctp_process_param() then reads adaptation_ind beyond the declared
+parameter. When the malformed parameter is last in an INIT, the read
+starts at the receive skb tail, and the value is copied into the state
+cookie returned in the INIT ACK. This may disclose four receive-buffer
+tail bytes.
+
+Require the declared parameter length to match the fixed structure size
+and abort the association through the existing invalid parameter length
+path otherwise.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Cc: stable@vger.kernel.org
+Signed-off-by: Charles Vosburgh <trilobyte777@gmail.com>
+Acked-by: Xin Long <lucien.xin@gmail.com>
+Link: https://patch.msgid.link/20260727-sctp-adaptation-length-v1-1-0ab58b2810a5@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/sctp/sm_make_chunk.c |    6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/net/sctp/sm_make_chunk.c
++++ b/net/sctp/sm_make_chunk.c
+@@ -2168,7 +2168,13 @@ static enum sctp_ierror sctp_verify_para
+       case SCTP_PARAM_HEARTBEAT_INFO:
+       case SCTP_PARAM_UNRECOGNIZED_PARAMETERS:
+       case SCTP_PARAM_ECN_CAPABLE:
++              break;
+       case SCTP_PARAM_ADAPTATION_LAYER_IND:
++              if (ntohs(param.p->length) != sizeof(*param.aind)) {
++                      sctp_process_inv_paramlength(asoc, param.p,
++                                                   chunk, err_chunk);
++                      retval = SCTP_IERROR_ABORT;
++              }
+               break;
+       case SCTP_PARAM_SUPPORTED_EXT:
diff --git a/queue-6.18/selftest-fix-headers-in-fclog.c.patch b/queue-6.18/selftest-fix-headers-in-fclog.c.patch
new file mode 100644 (file)
index 0000000..d97bba3
--- /dev/null
@@ -0,0 +1,42 @@
+From e3a0127eee04db8769e53c8102c4e76aa49be8c3 Mon Sep 17 00:00:00 2001
+From: Jori Koolstra <jkoolstra@xs4all.nl>
+Date: Fri, 10 Jul 2026 19:17:35 +0200
+Subject: selftest: fix headers in fclog.c
+
+From: Jori Koolstra <jkoolstra@xs4all.nl>
+
+commit e3a0127eee04db8769e53c8102c4e76aa49be8c3 upstream.
+
+fclog.c does not compile because it is missing fcntl.h, needed for
+O_RDONLY etc.
+
+There are also some redundant includes that are also in
+kselftest_harness.h.
+
+Link: https://lore.kernel.org/20260710171741.837308-1-jkoolstra@xs4all.nl
+Signed-off-by: Jori Koolstra <jkoolstra@xs4all.nl>
+Cc: Aleksa Sarai <cyphar@cyphar.com>
+Cc: Shuah Khan <shuah@kernel.org>
+Cc: Wei Yang <richard.weiyang@gmail.com>
+Cc: Christian Brauner <brauner@kernel.org>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ tools/testing/selftests/filesystems/fclog.c |    4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/tools/testing/selftests/filesystems/fclog.c
++++ b/tools/testing/selftests/filesystems/fclog.c
+@@ -6,10 +6,8 @@
+ #include <assert.h>
+ #include <errno.h>
++#include <fcntl.h>
+ #include <sched.h>
+-#include <stdio.h>
+-#include <stdlib.h>
+-#include <string.h>
+ #include <unistd.h>
+ #include <sys/mount.h>
index 6a17374f8b7da1b77bb355a0581ef6ff98a147af..06fb1ff305895c99efc50fa3cba7a562ea785aaa 100644 (file)
@@ -165,3 +165,32 @@ pinctrl-microchip-sgpio-add-missing-select-regmap_mmio.patch
 pinctrl-devicetree-don-t-free-uninitialized-dev_name-on-error-path.patch
 erofs-cap-lzma-stream-pool-size.patch
 pinctrl-bm1880-add-missing-select-generic_pinconf.patch
+fortify-disable-wstringop-overread-in-tests.patch
+mm-migrate_device-fix-pte_pfn-pte_dirty-called-on-non-present-pte.patch
+mm-util-don-t-read-__page_2-for-order-1-folios-in-snapshot_page.patch
+selftest-fix-headers-in-fclog.c.patch
+fs-proc-task_mmu-fix-pagemap_scan-written-state-for-pmd-holes.patch
+mm-percpu-km-fix-bitmap-overflow-and-accounting-in-pcpu_create_chunk.patch
+mm-hugetlb-fix-list-corruption-in-allocate_file_region_entries.patch
+mm-vmstat-fold-stranded-per-cpu-node-stats-when-a-node-comes-online.patch
+tracing-probes-reject-arg0-in-meta-argument-expansion.patch
+tracing-fprobe-roll-back-on-enable_trace_fprobe-failure.patch
+kvm-vmx-add-memory-clobber-to-asm-for-vmx-instructions.patch
+kvm-svm-update-x2apic-msr-intercepts-if-avic-is-inhibited-while-l2-is-active.patch
+kvm-s390-pci-reject-adapter-interrupt-forwarding-if-already-enabled.patch
+kvm-s390-pci-fix-memory-accounting-for-pinned-unpinned-pages.patch
+kvm-s390-pci-fix-missing-error-codes-and-memory-unaccounting.patch
+kvm-s390-pci-fix-null-dereference-on-aibv-allocation-failure.patch
+kvm-s390-pci-validate-aibv-and-aisb-before-pinning-guest-pages.patch
+dibs-fix-use-after-free-of-dmb_node-in-loopback-attach-detach-unregister.patch
+sctp-validate-adaptation-indication-parameter-length.patch
+audit-fix-potential-integer-overflow-in-audit_log_n_string.patch
+audit-fix-potential-use-after-free-in-audit_del_rule.patch
+bluetooth-btusb-fix-short-read-errors-in-btusb_qca_send_vendor_req.patch
+bluetooth-btmtk-fix-short-read-errors-in-btmtk_usb_uhw_reg_read.patch
+bluetooth-mgmt-fix-pending-command-uaf-in-eir-updates.patch
+bluetooth-sco-give-the-socket-its-own-sco_conn-reference.patch
+bluetooth-mgmt-fix-uaf-in-pair-command-cancellation.patch
+bluetooth-hci_sync-fix-advertising-data-uafs.patch
+bluetooth-hidp-reject-frames-without-a-transaction-header.patch
+bluetooth-hidp-validate-numbered-report-payloads.patch
diff --git a/queue-6.18/tracing-fprobe-roll-back-on-enable_trace_fprobe-failure.patch b/queue-6.18/tracing-fprobe-roll-back-on-enable_trace_fprobe-failure.patch
new file mode 100644 (file)
index 0000000..439645e
--- /dev/null
@@ -0,0 +1,56 @@
+From aca0cd1bf16574327ef64f3178e5f5e37a61ef0b Mon Sep 17 00:00:00 2001
+From: Raushan Patel <raushan.jhon@gmail.com>
+Date: Fri, 24 Jul 2026 12:12:08 +0530
+Subject: tracing/fprobe: Roll back on enable_trace_fprobe() failure
+
+From: Raushan Patel <raushan.jhon@gmail.com>
+
+commit aca0cd1bf16574327ef64f3178e5f5e37a61ef0b upstream.
+
+enable_trace_fprobe() sets the file link or the TP_FLAG_PROFILE flag and
+then registers each trace_fprobe in the probe list. If
+__register_trace_fprobe() fails partway through, the function returns
+immediately without unregistering the trace_fprobes it already registered
+or undoing the file link / flag it set, leaving the event half-enabled and
+leaking the registered fprobe(s).
+
+enable_trace_kprobe() already handles this with a rollback path. Do the
+same for fprobe: on failure, unregister all probes and clear the file link
+or profile flag.
+
+Link: https://lore.kernel.org/all/20260724064208.480030-1-raushan.jhon@gmail.com/
+
+Fixes: 334e5519c375 ("tracing/probes: Add fprobe events for tracing function entry and exit.")
+Cc: stable@vger.kernel.org
+Signed-off-by: Raushan Patel <raushan.jhon@gmail.com>
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/trace/trace_fprobe.c |   12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+--- a/kernel/trace/trace_fprobe.c
++++ b/kernel/trace/trace_fprobe.c
+@@ -1481,11 +1481,21 @@ static int enable_trace_fprobe(struct tr
+               list_for_each_entry(tf, trace_probe_probe_list(tp), tp.list) {
+                       ret = __register_trace_fprobe(tf);
+                       if (ret < 0)
+-                              return ret;
++                              goto err;
+               }
+       }
+       return 0;
++
++err:
++      /* Failed to enable one of them. Roll back all */
++      list_for_each_entry(tf, trace_probe_probe_list(tp), tp.list)
++              __unregister_trace_fprobe(tf);
++      if (file)
++              trace_probe_remove_file(tp, file);
++      else
++              trace_probe_clear_flag(tp, TP_FLAG_PROFILE);
++      return ret;
+ }
+ /*
diff --git a/queue-6.18/tracing-probes-reject-arg0-in-meta-argument-expansion.patch b/queue-6.18/tracing-probes-reject-arg0-in-meta-argument-expansion.patch
new file mode 100644 (file)
index 0000000..5d9630e
--- /dev/null
@@ -0,0 +1,48 @@
+From 00a8ce2a2a9fa17674e1feec4d9105c1a5d6a419 Mon Sep 17 00:00:00 2001
+From: Raushan Patel <raushan.jhon@gmail.com>
+Date: Fri, 24 Jul 2026 11:14:35 +0530
+Subject: tracing/probes: Reject $arg0 in meta argument expansion
+
+From: Raushan Patel <raushan.jhon@gmail.com>
+
+commit 00a8ce2a2a9fa17674e1feec4d9105c1a5d6a419 upstream.
+
+traceprobe_expand_meta_args() parses $argN with simple_strtoul() and
+calls sprint_nth_btf_arg(n - 1, ...). For $arg0, n is 0 so the index is
+-1. Because ctx->nr_params is signed, the "idx >= nr_params" guard in
+sprint_nth_btf_arg() does not catch the negative index, and
+ctx->params[-1].name_off is read out of bounds.
+
+The normal per-argument path (parse_probe_vars()) already rejects
+$arg0 via its argument-number check, but meta-argument expansion runs
+before per-argument parsing and substitutes the value first, bypassing
+that check.
+
+Reject $arg0 explicitly during expansion.
+
+Link: https://lore.kernel.org/all/20260724054435.146279-1-raushan.jhon@gmail.com/
+
+Fixes: 18b1e870a496 ("tracing/probes: Add $arg* meta argument for all function args")
+Cc: stable@vger.kernel.org
+Signed-off-by: Raushan Patel <raushan.jhon@gmail.com>
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/trace/trace_probe.c |    6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/kernel/trace/trace_probe.c
++++ b/kernel/trace/trace_probe.c
+@@ -1906,7 +1906,11 @@ const char **traceprobe_expand_meta_args
+                               trace_probe_log_err(0, BAD_VAR);
+                               return ERR_PTR(-ENOENT);
+                       }
+-                      /* Note: $argN starts from $arg1 */
++                      /* Note: $argN starts from $arg1, so $arg0 is invalid. */
++                      if (n == 0) {
++                              trace_probe_log_err(0, BAD_ARG_NUM);
++                              return ERR_PTR(-EINVAL);
++                      }
+                       ret = sprint_nth_btf_arg(n - 1, type, buf + used,
+                                                bufsize - used, ctx);
+                       if (ret < 0)