From: Greg Kroah-Hartman Date: Thu, 28 May 2026 09:00:43 +0000 (+0200) Subject: 7.0-stable patches X-Git-Tag: v5.10.258~41 X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=80a621163e01c2bfcb3f354e0a373c44792ac1d3;p=thirdparty%2Fkernel%2Fstable-queue.git 7.0-stable patches added patches: acpi-battery-fix-system-wakeup-on-critical-battery-status.patch alsa-asihpi-fix-potential-oob-array-access-at-reading-cache.patch alsa-pcm-don-t-setup-bogus-iov_iter-for-silencing.patch alsa-scarlett2-allow-flash-writes-ending-at-segment-boundary.patch alsa-ua101-reject-too-short-usb-descriptors.patch bluetooth-bnep-fix-uaf-read-of-dev-name.patch bluetooth-fix-uaf-in-l2cap_sock_cleanup_listen-vs-l2cap_conn_del.patch bluetooth-hci_qca-convert-timeout-from-jiffies-to-ms.patch bluetooth-hci_uart-fix-uafs-and-race-conditions-in-close-and-init-paths.patch bluetooth-iso-drop-iso_end-frames-received-without-prior-iso_start.patch bluetooth-l2cap-ecred_reconfigure-send-packed-pdu-not-stack-pointer.patch bluetooth-mgmt-validate-add-extended-advertising-data-length.patch bluetooth-serialize-accept_q-access.patch drivers-base-memory-fix-memory-block-reference-leak-in-poison-accounting.patch efi-allocate-runtime-workqueue-before-acpi-init.patch hwmon-pmbus-adm1266-widen-blackbox-info-buffer-to-i2c_smbus_block_max.patch io_uring-waitid-clear-waitid-info-before-copying-it-to-userspace.patch ipv6-ioam-refresh-hdr-pointer-before-ioam6_event.patch ksmbd-fix-null-pointer-dereference-in-compare_guid_key.patch ksmbd-fix-null-pointer-dereference-in-proc_show_files.patch ksmbd-fix-sid-memory-leak-in-set_posix_acl_entries_dacl-on-overflow.patch ksmbd-validate-sid-in-parent-security-descriptor-during-acl-inheritance.patch mm-damon-fix-damos_stat-tracepoint-format-for-sz_applied.patch mm-damon-sysfs-schemes-call-missing-mem_cgroup_iter_break.patch mm-fix-__vm_normal_page-to-handle-missing-support-for-pmd_special-pud_special.patch mm-memory-fix-spurious-warning-when-unmapping-device-private-exclusive-pages.patch mm-memory_hotplug-fix-memory-block-reference-leak-on-remove.patch mm-migrate_device-fix-spinlock-leak-in-migrate_vma_insert_huge_pmd_page.patch mm-page_alloc-fix-initialization-of-tags-of-the-huge-zero-folio-with-init_on_free.patch net-bcmgenet-keep-rbuf-eee-pm-disabled.patch net-devmem-reject-dma-buf-bind-with-non-page-aligned-size-or-sg-length.patch net-hsr-defer-node-table-free-until-after-rcu-readers.patch net-ifb-report-ethtool-stats-over-num_tx_queues.patch net-mlx5e-fix-use-after-free-in-mlx5e_tx_reporter_timeout_recover.patch net-phy-skip-eee-advertisement-write-when-autoneg-is-disabled.patch net-pse-pd-fix-sign-on-enoent-check-in-of_load_pse_pis.patch net-wwan-iosm-fix-potential-memory-leaks-in-ipc_imem_init.patch netfilter-ip6t_hbh-reject-oversized-option-lists.patch netfilter-ipset-stop-hash-range-iteration-at-end.patch netfilter-nf_queue-hold-bridge-skb-dev-while-queued.patch netfilter-nft_inner-fix-ipv6-inner_thoff-desync.patch phonet-pep-disable-bh-around-forwarded-sk_receive_skb.patch regulator-tps65219-fix-irq_data.rdev-not-being-assigned.patch scripts-gdb-mm-cast-untyped-symbols-in-x86_page_ops.patch selftests-mm-run_vmtests.sh-fix-destructive-tests-invocation.patch smb-client-protect-tc_count-increment-in-smb2_find_smb_sess_tcon_unlocked.patch smb-client-require-net-admin-for-cifs-swn-netlink.patch smb-client-use-data_len-for-smb2-read-encrypted-folioq-copy.patch smb-server-promote-s_del_on_cls-to-s_del_pending-when-close.patch spi-amd-set-correct-bus-number-in-acpi-probe-path.patch sysfs-don-t-remove-existing-directory-on-update-failure.patch x86-mm-disable-broadcast-tlb-flush-when-pcid-is-disabled.patch --- diff --git a/queue-7.0/acpi-battery-fix-system-wakeup-on-critical-battery-status.patch b/queue-7.0/acpi-battery-fix-system-wakeup-on-critical-battery-status.patch new file mode 100644 index 0000000000..099a6a096e --- /dev/null +++ b/queue-7.0/acpi-battery-fix-system-wakeup-on-critical-battery-status.patch @@ -0,0 +1,53 @@ +From c35cb4fc7231702d1e9952aec1a442f3e27df6f5 Mon Sep 17 00:00:00 2001 +From: "Rafael J. Wysocki" +Date: Fri, 15 May 2026 19:03:59 +0200 +Subject: ACPI: battery: Fix system wakeup on critical battery status + +From: Rafael J. Wysocki + +commit c35cb4fc7231702d1e9952aec1a442f3e27df6f5 upstream. + +Commit 0a869409a981 ("ACPI: battery: Convert the driver to a platform +one") changed the parent of the battery wakeup source to the platform +device used for driver binding, but it forgot to update the +acpi_pm_wakeup_event() call in acpi_battery_update() accordingly. + +Do it now to unbreak waking up the system on critical battery status +during suspend-to-idle and during transitions to ACPI S3/S4. + +Fixes: 0a869409a981 ("ACPI: battery: Convert the driver to a platform one") +Signed-off-by: Rafael J. Wysocki +Cc: 7.0+ # 7.0+ +Link: https://patch.msgid.link/12898712.O9o76ZdvQC@rafael.j.wysocki +Signed-off-by: Greg Kroah-Hartman +--- + drivers/acpi/battery.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/acpi/battery.c ++++ b/drivers/acpi/battery.c +@@ -96,6 +96,7 @@ struct acpi_battery { + struct power_supply *bat; + struct power_supply_desc bat_desc; + struct acpi_device *device; ++ struct device *phys_dev; + struct notifier_block pm_nb; + struct list_head list; + unsigned long update_time; +@@ -1035,7 +1036,7 @@ static int acpi_battery_update(struct ac + if ((battery->state & ACPI_BATTERY_STATE_CRITICAL) || + (test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags) && + (battery->capacity_now <= battery->alarm))) +- acpi_pm_wakeup_event(&battery->device->dev); ++ acpi_pm_wakeup_event(battery->phys_dev); + + return result; + } +@@ -1228,6 +1229,7 @@ static int acpi_battery_probe(struct pla + + platform_set_drvdata(pdev, battery); + ++ battery->phys_dev = &pdev->dev; + battery->device = device; + strscpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME); + strscpy(acpi_device_class(device), ACPI_BATTERY_CLASS); diff --git a/queue-7.0/alsa-asihpi-fix-potential-oob-array-access-at-reading-cache.patch b/queue-7.0/alsa-asihpi-fix-potential-oob-array-access-at-reading-cache.patch new file mode 100644 index 0000000000..c6877a4a2b --- /dev/null +++ b/queue-7.0/alsa-asihpi-fix-potential-oob-array-access-at-reading-cache.patch @@ -0,0 +1,37 @@ +From 7b7d6572145c1dab2dd9bfb550b188e5f0ff3c3f Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Fri, 15 May 2026 10:55:58 +0200 +Subject: ALSA: asihpi: Fix potential OOB array access at reading cache + +From: Takashi Iwai + +commit 7b7d6572145c1dab2dd9bfb550b188e5f0ff3c3f upstream. + +find_control() to retrieve a cached info accesses the array with the +given index blindly, which may lead to an OOB array access. +Add a sanity check for avoiding it. + +Link: https://sashiko.dev/#/patchset/20260511230121.28606-1-rosenp%40gmail.com +Cc: +Link: https://patch.msgid.link/20260515085606.242284-1-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/pci/asihpi/hpicmn.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/sound/pci/asihpi/hpicmn.c ++++ b/sound/pci/asihpi/hpicmn.c +@@ -276,6 +276,12 @@ static short find_control(u16 control_in + return 0; + } + ++ if (control_index >= p_cache->control_count) { ++ HPI_DEBUG_LOG(VERBOSE, "control_index out of bounce %d\n", ++ control_index); ++ return 0; ++ } ++ + *pI = p_cache->p_info[control_index]; + if (!*pI) { + HPI_DEBUG_LOG(VERBOSE, "Uncached Control %d\n", diff --git a/queue-7.0/alsa-pcm-don-t-setup-bogus-iov_iter-for-silencing.patch b/queue-7.0/alsa-pcm-don-t-setup-bogus-iov_iter-for-silencing.patch new file mode 100644 index 0000000000..770c54136d --- /dev/null +++ b/queue-7.0/alsa-pcm-don-t-setup-bogus-iov_iter-for-silencing.patch @@ -0,0 +1,42 @@ +From e4d3386b74fba8e01280484b67ee481ece00201e Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Sun, 17 May 2026 18:51:20 +0200 +Subject: ALSA: pcm: Don't setup bogus iov_iter for silencing + +From: Takashi Iwai + +commit e4d3386b74fba8e01280484b67ee481ece00201e upstream. + +At transition to the iov_iter for PCM data transfer, we blindly +applied the iov_iter setup also for silencing (i.e. data = NULL), and +it leads to a calculation of bogus iov_iter. Fortunately this didn't +cause troubles on most of architectures but it goes wrong on RISC-V +now, causing a NULL dereference. + +Handle the NULL data case to treat the silencing in interleaved_copy() +for addressing the bug above. noninterleaved_copy() has already the +NULL data handling, so it doesn't need changes. + +Reported-by: Jiakai Xu +Closes: https://lore.kernel.org/20260515051516.3103036-1-xujiakai24@mails.ucas.ac.cn +Fixes: cf393babb37a ("ALSA: pcm: Add copy ops with iov_iter") +Cc: +Link: https://patch.msgid.link/20260517165121.31399-1-tiwai@suse.de +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/core/pcm_lib.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/sound/core/pcm_lib.c ++++ b/sound/core/pcm_lib.c +@@ -2138,6 +2138,9 @@ static int interleaved_copy(struct snd_p + off = frames_to_bytes(runtime, off); + frames = frames_to_bytes(runtime, frames); + ++ if (!data) ++ return fill_silence(substream, 0, hwoff, NULL, frames); ++ + return do_transfer(substream, 0, hwoff, data + off, frames, transfer, + in_kernel); + } diff --git a/queue-7.0/alsa-scarlett2-allow-flash-writes-ending-at-segment-boundary.patch b/queue-7.0/alsa-scarlett2-allow-flash-writes-ending-at-segment-boundary.patch new file mode 100644 index 0000000000..535db579c7 --- /dev/null +++ b/queue-7.0/alsa-scarlett2-allow-flash-writes-ending-at-segment-boundary.patch @@ -0,0 +1,52 @@ +From a69b677e47a80319ce148d61cc29a2b57006e78d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?C=C3=A1ssio=20Gabriel?= +Date: Tue, 19 May 2026 11:46:19 -0300 +Subject: ALSA: scarlett2: Allow flash writes ending at segment boundary +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +commit a69b677e47a80319ce148d61cc29a2b57006e78d upstream. + +scarlett2_hwdep_write() rejects writes when offset + count is greater than +or equal to the selected flash segment size. That incorrectly treats a +write ending exactly at the end of the segment as out of space, although +the last byte written is still within the segment. + +Split invalid argument checks from the segment-space check, keep +zero-length writes as no-ops, and compare count against the remaining +segment size. This permits exact-end writes and avoids relying on +offset + count before deciding whether the request is in bounds. + +Fixes: 1abfbd3c9527 ("ALSA: scarlett2: Add support for uploading new firmware") +Cc: stable@vger.kernel.org +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260519-alsa-scarlett2-flash-write-boundary-v1-1-b550480e92da@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/usb/mixer_scarlett2.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/sound/usb/mixer_scarlett2.c ++++ b/sound/usb/mixer_scarlett2.c +@@ -9185,12 +9185,15 @@ static long scarlett2_hwdep_write(struct + flash_size = private->flash_segment_blocks[segment_id] * + SCARLETT2_FLASH_BLOCK_SIZE; + +- if (count < 0 || *offset < 0 || *offset + count >= flash_size) +- return -ENOSPC; ++ if (count < 0 || *offset < 0) ++ return -EINVAL; + + if (!count) + return 0; + ++ if (*offset >= flash_size || count > flash_size - *offset) ++ return -ENOSPC; ++ + /* Limit the *req size to SCARLETT2_FLASH_RW_MAX */ + if (count > max_data_size) + count = max_data_size; diff --git a/queue-7.0/alsa-ua101-reject-too-short-usb-descriptors.patch b/queue-7.0/alsa-ua101-reject-too-short-usb-descriptors.patch new file mode 100644 index 0000000000..014ea0ed15 --- /dev/null +++ b/queue-7.0/alsa-ua101-reject-too-short-usb-descriptors.patch @@ -0,0 +1,45 @@ +From b59d5c51bb328a60749b4dd5fe7e649bfb4089b4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?C=C3=A1ssio=20Gabriel?= +Date: Tue, 19 May 2026 00:32:15 -0300 +Subject: ALSA: ua101: Reject too-short USB descriptors +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Cássio Gabriel + +commit b59d5c51bb328a60749b4dd5fe7e649bfb4089b4 upstream. + +find_format_descriptor() walks the class-specific interface extras by +advancing with bLength. It rejects descriptors that extend past the +remaining buffer, but it does not reject descriptor lengths smaller than +a USB descriptor header. + +Reject too-short descriptors before using bLength to advance the local +scan. This keeps the UA-101 parser robust against malformed descriptor +data and matches the usual USB descriptor walking rules. + +Fixes: 63978ab3e3e9 ("sound: add Edirol UA-101 support") +Cc: stable@vger.kernel.org +Signed-off-by: Cássio Gabriel +Link: https://patch.msgid.link/20260519-alsa-ua101-desc-len-v1-1-4307d1a5e054@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman +--- + sound/usb/misc/ua101.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/sound/usb/misc/ua101.c ++++ b/sound/usb/misc/ua101.c +@@ -894,8 +894,9 @@ find_format_descriptor(struct usb_interf + struct uac_format_type_i_discrete_descriptor *desc; + + desc = (struct uac_format_type_i_discrete_descriptor *)extra; +- if (desc->bLength > extralen) { +- dev_err(&interface->dev, "descriptor overflow\n"); ++ if (desc->bLength < sizeof(struct usb_descriptor_header) || ++ desc->bLength > extralen) { ++ dev_err(&interface->dev, "invalid descriptor length\n"); + return NULL; + } + if (desc->bLength == UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1) && diff --git a/queue-7.0/bluetooth-bnep-fix-uaf-read-of-dev-name.patch b/queue-7.0/bluetooth-bnep-fix-uaf-read-of-dev-name.patch new file mode 100644 index 0000000000..6a21f2441e --- /dev/null +++ b/queue-7.0/bluetooth-bnep-fix-uaf-read-of-dev-name.patch @@ -0,0 +1,40 @@ +From 59e932ded949fa6f0340bf7c6d7818f962fa4fd2 Mon Sep 17 00:00:00 2001 +From: Jann Horn +Date: Tue, 12 May 2026 22:15:39 +0200 +Subject: Bluetooth: bnep: Fix UAF read of dev->name + +From: Jann Horn + +commit 59e932ded949fa6f0340bf7c6d7818f962fa4fd2 upstream. + +bnep_add_connection() needs to keep holding the bnep_session_sem while +reading dev->name (just like bnep_get_connlist() does); otherwise the +bnep_session() thread can concurrently free the net_device, which can for +example be triggered by a concurrent bnep_del_connection(). + +(This UAF is fairly uninteresting from a security perspective; +calling bnep_add_connection() requires passing a capable(CAP_NET_ADMIN) +check. It also requires completely tearing down a netdev during a fairly +tight race window.) + +Cc: stable@vger.kernel.org +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Jann Horn +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Greg Kroah-Hartman +--- + net/bluetooth/bnep/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/bluetooth/bnep/core.c ++++ b/net/bluetooth/bnep/core.c +@@ -638,8 +638,8 @@ int bnep_add_connection(struct bnep_conn + goto failed; + } + +- up_write(&bnep_session_sem); + strcpy(req->device, dev->name); ++ up_write(&bnep_session_sem); + return 0; + + failed: diff --git a/queue-7.0/bluetooth-fix-uaf-in-l2cap_sock_cleanup_listen-vs-l2cap_conn_del.patch b/queue-7.0/bluetooth-fix-uaf-in-l2cap_sock_cleanup_listen-vs-l2cap_conn_del.patch new file mode 100644 index 0000000000..51b9f549c3 --- /dev/null +++ b/queue-7.0/bluetooth-fix-uaf-in-l2cap_sock_cleanup_listen-vs-l2cap_conn_del.patch @@ -0,0 +1,236 @@ +From ab1513597c6cf17cd1ad2a21e3b045421b48e022 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Safa=20Karaku=C5=9F?= +Date: Sat, 16 May 2026 21:15:04 +0300 +Subject: Bluetooth: fix UAF in l2cap_sock_cleanup_listen() vs l2cap_conn_del() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Safa Karakuş + +commit ab1513597c6cf17cd1ad2a21e3b045421b48e022 upstream. + +bt_accept_dequeue() unlinks a not-yet-accepted child from the parent +accept queue and release_sock()s it before returning, so the returned +sk has no caller reference and is unlocked. + +l2cap_sock_cleanup_listen() walks these children on listening-socket +close. A concurrent HCI disconnect drives hci_rx_work -> +l2cap_conn_del() which runs l2cap_chan_del() + l2cap_sock_kill() and +frees the child sk and its l2cap_chan; cleanup_listen() then uses both: + + BUG: KASAN: slab-use-after-free in l2cap_sock_kill + l2cap_sock_kill / l2cap_sock_cleanup_listen / __x64_sys_close + Freed by: l2cap_conn_del -> l2cap_sock_close_cb -> l2cap_sock_kill + +This is distinct from the two fixes already in this area: commit +e83f5e24da741 ("Bluetooth: serialize accept_q access") serialises the +accept_q list/poll and takes temporary refs inside bt_accept_dequeue(), +and CVE-2025-39860 serialises the userspace close()/accept() race by +calling cleanup_listen() under lock_sock() in l2cap_sock_release(). +Neither covers l2cap_conn_del() running from hci_rx_work, so this UAF +still reproduces on current bluetooth/master. + +Take the reference at the source: bt_accept_dequeue() does sock_hold() +while sk is still locked, before release_sock(); callers sock_put(). +cleanup_listen() pins the chan with l2cap_chan_hold_unless_zero() under +a brief child sk lock (serialising vs l2cap_sock_teardown_cb()), drops +it before l2cap_chan_lock(), and skips a duplicate l2cap_sock_kill() on +SOCK_DEAD. conn->lock is not taken here: cleanup_listen() runs under +the parent sk lock and that would invert +conn->lock -> chan->lock -> sk_lock (lockdep). + +KASAN/SMP: an unprivileged listen/close vs HCI-disconnect race produced +12 use-after-free reports per run before this change; 0, and no lockdep +report, over 1600+ raced iterations after it on bluetooth/master. + +Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode") +Cc: stable@vger.kernel.org +Reported-by: Siwei Zhang +Reviewed-by: Siwei Zhang +Signed-off-by: Safa Karakuş +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Greg Kroah-Hartman +--- + net/bluetooth/af_bluetooth.c | 10 ++++++++ + net/bluetooth/iso.c | 9 ++++++- + net/bluetooth/l2cap_sock.c | 51 +++++++++++++++++++++++++++++++++++++------ + net/bluetooth/rfcomm/sock.c | 9 ++++++- + net/bluetooth/sco.c | 9 ++++++- + 5 files changed, 78 insertions(+), 10 deletions(-) + +--- a/net/bluetooth/af_bluetooth.c ++++ b/net/bluetooth/af_bluetooth.c +@@ -309,6 +309,16 @@ restart: + if (newsock) + sock_graft(sk, newsock); + ++ /* Hand the caller a reference taken while sk is ++ * still locked. bt_accept_unlink() just dropped ++ * the accept-queue reference; without this hold a ++ * concurrent teardown (e.g. l2cap_conn_del() -> ++ * l2cap_sock_kill()) could free sk between ++ * release_sock() and the caller using it. Every ++ * caller drops this with sock_put() when done. ++ */ ++ sock_hold(sk); ++ + release_sock(sk); + return sk; + } +--- a/net/bluetooth/iso.c ++++ b/net/bluetooth/iso.c +@@ -759,6 +759,8 @@ static void iso_sock_cleanup_listen(stru + while ((sk = bt_accept_dequeue(parent, NULL))) { + iso_sock_close(sk); + iso_sock_kill(sk); ++ /* Drop the reference handed back by bt_accept_dequeue(). */ ++ sock_put(sk); + } + + /* If listening socket has a hcon, properly disconnect it */ +@@ -1364,8 +1366,13 @@ static int iso_sock_accept(struct socket + } + + ch = bt_accept_dequeue(sk, newsock); +- if (ch) ++ if (ch) { ++ /* Drop the bridging ref from bt_accept_dequeue(); ++ * the grafted socket keeps ch alive from here. ++ */ ++ sock_put(ch); + break; ++ } + + if (!timeo) { + err = -EAGAIN; +--- a/net/bluetooth/l2cap_sock.c ++++ b/net/bluetooth/l2cap_sock.c +@@ -349,8 +349,13 @@ static int l2cap_sock_accept(struct sock + } + + nsk = bt_accept_dequeue(sk, newsock); +- if (nsk) ++ if (nsk) { ++ /* Drop the bridging ref from bt_accept_dequeue(); ++ * the grafted socket keeps nsk alive from here. ++ */ ++ sock_put(nsk); + break; ++ } + + if (!timeo) { + err = -EAGAIN; +@@ -1475,22 +1480,54 @@ static void l2cap_sock_cleanup_listen(st + BT_DBG("parent %p state %s", parent, + state_to_string(parent->sk_state)); + +- /* Close not yet accepted channels */ ++ /* Close not yet accepted channels. ++ * ++ * bt_accept_dequeue() now returns sk with an extra reference held ++ * (taken while sk was still locked) so a concurrent l2cap_conn_del() ++ * -> l2cap_sock_kill() cannot free sk under us. ++ * ++ * cleanup_listen() runs under the parent sk lock, so unlike ++ * l2cap_sock_shutdown() we must NOT take conn->lock here: that would ++ * establish sk_lock -> conn->lock and invert the established ++ * conn->lock -> chan->lock -> sk_lock order (lockdep deadlock). ++ * ++ * Instead, briefly take the child sk lock to fetch and pin its chan. ++ * l2cap_conn_del() reaches the chan free only via ++ * l2cap_chan_del() -> l2cap_sock_teardown_cb(), which itself takes ++ * the child sk lock; holding it across l2cap_chan_hold_unless_zero() ++ * therefore guarantees the chan cannot be freed while we read and ++ * pin it (hold_unless_zero() additionally skips a chan already past ++ * its last reference). We then drop the sk lock before taking ++ * chan->lock, so sk and chan locks are never held together. ++ */ + while ((sk = bt_accept_dequeue(parent, NULL))) { +- struct l2cap_chan *chan = l2cap_pi(sk)->chan; ++ struct l2cap_chan *chan; ++ ++ lock_sock_nested(sk, L2CAP_NESTING_NORMAL); ++ chan = l2cap_chan_hold_unless_zero(l2cap_pi(sk)->chan); ++ release_sock(sk); ++ if (!chan) { ++ /* l2cap_conn_del() already tearing this child down */ ++ sock_put(sk); ++ continue; ++ } + + BT_DBG("child chan %p state %s", chan, + state_to_string(chan->state)); + +- l2cap_chan_hold(chan); + l2cap_chan_lock(chan); +- + __clear_chan_timer(chan); + l2cap_chan_close(chan, ECONNRESET); +- l2cap_sock_kill(sk); +- ++ /* l2cap_conn_del() may already have killed this socket ++ * (it sets SOCK_DEAD); skip the duplicate to avoid a ++ * double sock_put()/l2cap_chan_put(). ++ */ ++ if (!sock_flag(sk, SOCK_DEAD)) ++ l2cap_sock_kill(sk); + l2cap_chan_unlock(chan); ++ + l2cap_chan_put(chan); ++ sock_put(sk); + } + } + +--- a/net/bluetooth/rfcomm/sock.c ++++ b/net/bluetooth/rfcomm/sock.c +@@ -180,6 +180,8 @@ static void rfcomm_sock_cleanup_listen(s + while ((sk = bt_accept_dequeue(parent, NULL))) { + rfcomm_sock_close(sk); + rfcomm_sock_kill(sk); ++ /* Drop the reference handed back by bt_accept_dequeue(). */ ++ sock_put(sk); + } + + parent->sk_state = BT_CLOSED; +@@ -497,8 +499,13 @@ static int rfcomm_sock_accept(struct soc + } + + nsk = bt_accept_dequeue(sk, newsock); +- if (nsk) ++ if (nsk) { ++ /* Drop the bridging ref from bt_accept_dequeue(); ++ * the grafted socket keeps nsk alive from here. ++ */ ++ sock_put(nsk); + break; ++ } + + if (!timeo) { + err = -EAGAIN; +--- a/net/bluetooth/sco.c ++++ b/net/bluetooth/sco.c +@@ -498,6 +498,8 @@ static void sco_sock_cleanup_listen(stru + while ((sk = bt_accept_dequeue(parent, NULL))) { + sco_sock_close(sk); + sco_sock_kill(sk); ++ /* Drop the reference handed back by bt_accept_dequeue(). */ ++ sock_put(sk); + } + + parent->sk_state = BT_CLOSED; +@@ -759,8 +761,13 @@ static int sco_sock_accept(struct socket + } + + ch = bt_accept_dequeue(sk, newsock); +- if (ch) ++ if (ch) { ++ /* Drop the bridging ref from bt_accept_dequeue(); ++ * the grafted socket keeps ch alive from here. ++ */ ++ sock_put(ch); + break; ++ } + + if (!timeo) { + err = -EAGAIN; diff --git a/queue-7.0/bluetooth-hci_qca-convert-timeout-from-jiffies-to-ms.patch b/queue-7.0/bluetooth-hci_qca-convert-timeout-from-jiffies-to-ms.patch new file mode 100644 index 0000000000..928976399c --- /dev/null +++ b/queue-7.0/bluetooth-hci_qca-convert-timeout-from-jiffies-to-ms.patch @@ -0,0 +1,150 @@ +From 375ba7484132662a4a8c7547d088fb6275c00282 Mon Sep 17 00:00:00 2001 +From: Shuai Zhang +Date: Mon, 11 May 2026 21:58:37 +0800 +Subject: Bluetooth: hci_qca: Convert timeout from jiffies to ms + +From: Shuai Zhang + +commit 375ba7484132662a4a8c7547d088fb6275c00282 upstream. + +Since the timer uses jiffies as its unit rather than ms, the timeout value +must be converted from ms to jiffies when configuring the timer. Otherwise, +the intended 8s timeout is incorrectly set to approximately 33s. + +To improve readability, embed msecs_to_jiffies() directly in the macro +definitions and drop the _MS suffix from macros that now yield jiffies +values: MEMDUMP_TIMEOUT, FW_DOWNLOAD_TIMEOUT, IBS_DISABLE_SSR_TIMEOUT, +CMD_TRANS_TIMEOUT, and IBS_BTSOC_TX_IDLE_TIMEOUT. + +IBS_WAKE_RETRANS_TIMEOUT_MS and IBS_HOST_TX_IDLE_TIMEOUT_MS are +intentionally left unchanged. Their values are stored in the struct fields +wake_retrans and tx_idle_delay, which hold ms values at runtime and can be +modified via debugfs. The msecs_to_jiffies() conversion happens at each +call site against the field value, so it cannot be embedded in the macro. + +Wake timer depends on commit c347ca17d62a + +Cc: stable@vger.kernel.org +Fixes: d841502c79e3 ("Bluetooth: hci_qca: Collect controller memory dump during SSR") +Reviewed-by: Paul Menzel +Acked-by: Bartosz Golaszewski +Signed-off-by: Shuai Zhang +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Greg Kroah-Hartman +--- + drivers/bluetooth/hci_qca.c | 33 ++++++++++++++++----------------- + 1 file changed, 16 insertions(+), 17 deletions(-) + +--- a/drivers/bluetooth/hci_qca.c ++++ b/drivers/bluetooth/hci_qca.c +@@ -48,13 +48,12 @@ + #define HCI_MAX_IBS_SIZE 10 + + #define IBS_WAKE_RETRANS_TIMEOUT_MS 100 +-#define IBS_BTSOC_TX_IDLE_TIMEOUT_MS 200 ++#define IBS_BTSOC_TX_IDLE_TIMEOUT msecs_to_jiffies(200) + #define IBS_HOST_TX_IDLE_TIMEOUT_MS 2000 +-#define CMD_TRANS_TIMEOUT_MS 100 +-#define MEMDUMP_TIMEOUT_MS 8000 +-#define IBS_DISABLE_SSR_TIMEOUT_MS \ +- (MEMDUMP_TIMEOUT_MS + FW_DOWNLOAD_TIMEOUT_MS) +-#define FW_DOWNLOAD_TIMEOUT_MS 3000 ++#define CMD_TRANS_TIMEOUT msecs_to_jiffies(100) ++#define MEMDUMP_TIMEOUT msecs_to_jiffies(8000) ++#define FW_DOWNLOAD_TIMEOUT msecs_to_jiffies(3000) ++#define IBS_DISABLE_SSR_TIMEOUT (MEMDUMP_TIMEOUT + FW_DOWNLOAD_TIMEOUT) + + /* susclk rate */ + #define SUSCLK_RATE_32KHZ 32768 +@@ -1093,7 +1092,7 @@ static void qca_controller_memdump(struc + + queue_delayed_work(qca->workqueue, + &qca->ctrl_memdump_timeout, +- msecs_to_jiffies(MEMDUMP_TIMEOUT_MS)); ++ MEMDUMP_TIMEOUT); + skb_pull(skb, sizeof(qca_memdump->ram_dump_size)); + qca_memdump->current_seq_no = 0; + qca_memdump->received_dump = 0; +@@ -1366,7 +1365,7 @@ static int qca_set_baudrate(struct hci_d + + if (hu->serdev) + serdev_device_wait_until_sent(hu->serdev, +- msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS)); ++ CMD_TRANS_TIMEOUT); + + /* Give the controller time to process the request */ + switch (qca_soc_type(hu)) { +@@ -1398,8 +1397,8 @@ static inline void host_set_baudrate(str + + static int qca_send_power_pulse(struct hci_uart *hu, bool on) + { ++ int timeout = CMD_TRANS_TIMEOUT; + int ret; +- int timeout = msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS); + u8 cmd = on ? QCA_WCN3990_POWERON_PULSE : QCA_WCN3990_POWEROFF_PULSE; + + /* These power pulses are single byte command which are sent +@@ -1604,7 +1603,7 @@ static void qca_wait_for_dump_collection + struct qca_data *qca = hu->priv; + + wait_on_bit_timeout(&qca->flags, QCA_MEMDUMP_COLLECTION, +- TASK_UNINTERRUPTIBLE, MEMDUMP_TIMEOUT_MS); ++ TASK_UNINTERRUPTIBLE, MEMDUMP_TIMEOUT); + + clear_bit(QCA_MEMDUMP_COLLECTION, &qca->flags); + } +@@ -2577,7 +2576,7 @@ static void qca_serdev_remove(struct ser + static void qca_serdev_shutdown(struct serdev_device *serdev) + { + int ret; +- int timeout = msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS); ++ int timeout = CMD_TRANS_TIMEOUT; + struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev); + struct hci_uart *hu = &qcadev->serdev_hu; + struct hci_dev *hdev = hu->hdev; +@@ -2634,7 +2633,7 @@ static int __maybe_unused qca_suspend(st + bool tx_pending = false; + int ret = 0; + u8 cmd; +- u32 wait_timeout = 0; ++ unsigned long wait_timeout = 0; + + set_bit(QCA_SUSPENDING, &qca->flags); + +@@ -2655,15 +2654,15 @@ static int __maybe_unused qca_suspend(st + if (test_bit(QCA_IBS_DISABLED, &qca->flags) || + test_bit(QCA_SSR_TRIGGERED, &qca->flags)) { + wait_timeout = test_bit(QCA_SSR_TRIGGERED, &qca->flags) ? +- IBS_DISABLE_SSR_TIMEOUT_MS : +- FW_DOWNLOAD_TIMEOUT_MS; ++ IBS_DISABLE_SSR_TIMEOUT : ++ FW_DOWNLOAD_TIMEOUT; + + /* QCA_IBS_DISABLED flag is set to true, During FW download + * and during memory dump collection. It is reset to false, + * After FW download complete. + */ + wait_on_bit_timeout(&qca->flags, QCA_IBS_DISABLED, +- TASK_UNINTERRUPTIBLE, msecs_to_jiffies(wait_timeout)); ++ TASK_UNINTERRUPTIBLE, wait_timeout); + + if (test_bit(QCA_IBS_DISABLED, &qca->flags)) { + bt_dev_err(hu->hdev, "SSR or FW download time out"); +@@ -2715,7 +2714,7 @@ static int __maybe_unused qca_suspend(st + + if (tx_pending) { + serdev_device_wait_until_sent(hu->serdev, +- msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS)); ++ CMD_TRANS_TIMEOUT); + serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_OFF, hu); + } + +@@ -2724,7 +2723,7 @@ static int __maybe_unused qca_suspend(st + */ + ret = wait_event_interruptible_timeout(qca->suspend_wait_q, + qca->rx_ibs_state == HCI_IBS_RX_ASLEEP, +- msecs_to_jiffies(IBS_BTSOC_TX_IDLE_TIMEOUT_MS)); ++ IBS_BTSOC_TX_IDLE_TIMEOUT); + if (ret == 0) { + ret = -ETIMEDOUT; + goto error; diff --git a/queue-7.0/bluetooth-hci_uart-fix-uafs-and-race-conditions-in-close-and-init-paths.patch b/queue-7.0/bluetooth-hci_uart-fix-uafs-and-race-conditions-in-close-and-init-paths.patch new file mode 100644 index 0000000000..929d324104 --- /dev/null +++ b/queue-7.0/bluetooth-hci_uart-fix-uafs-and-race-conditions-in-close-and-init-paths.patch @@ -0,0 +1,173 @@ +From c1bb9336ae6b54a5f6a353c4bd4ed9a4307e429b Mon Sep 17 00:00:00 2001 +From: Mingyu Wang <25181214217@stu.xidian.edu.cn> +Date: Mon, 18 May 2026 10:49:49 +0800 +Subject: Bluetooth: hci_uart: fix UAFs and race conditions in close and init paths + +From: Mingyu Wang <25181214217@stu.xidian.edu.cn> + +commit c1bb9336ae6b54a5f6a353c4bd4ed9a4307e429b upstream. + +Vulnerabilities leading to Use-After-Free (UAF) and Null Pointer +Dereference (NPD) conditions were observed in the lifecycle management +of hci_uart. + +The primary issue arises because the workqueues (init_ready and +write_work) are only flushed/cancelled if the HCI_UART_PROTO_READY +flag is set during TTY close. If a hangup occurs before setup completes, +hci_uart_tty_close() skips the teardown of these workqueues and +proceeds to free the `hu` struct. When the scheduled work executes +later, it blindly dereferences the freed `hu` struct. + +Furthermore, several data races and UAFs were identified in the teardown +sequence: +1. Calling hci_uart_flush() from hci_uart_close() without effectively + disabling write_work causes a race condition where both can concurrently + double-free hu->tx_skb. This happens because protocol timers can + concurrently invoke hci_uart_tx_wakeup() and requeue write_work. +2. Calling hci_free_dev(hdev) before hu->proto->close(hu) causes a UAF + when vendor specific protocol close callbacks dereference hu->hdev. +3. In the initialization error paths, failing to take the proto_lock + write lock before clearing PROTO_READY leads to races with active + readers. Additionally, hci_uart_tty_receive() accesses hu->hdev + outside the read lock, leading to UAFs if the initialization error + path frees hdev concurrently. + +Fix these synchronization and lifecycle issues by: +1. Re-ordering hci_uart_tty_close() to clear HCI_UART_PROTO_READY first, + followed immediately by a cancel_work_sync(&hu->write_work). Clearing + the flag locks out concurrent protocol timers from successfully invoking + hci_uart_tx_wakeup(), effectively rendering the cancellation permanent + and preventing the tx_skb double-free. +2. Note: Clearing PROTO_READY early causes hci_uart_close() to skip + hu->proto->flush(). This is perfectly safe in the tty_close path + because hu->proto->close() executes shortly after, which intrinsically + purges all protocol SKB queues and tears down the state. +3. Relocating hu->proto->close(hu) strictly prior to hci_free_dev(hdev) + across all close and error paths to prevent vendor-level UAFs. +4. Moving the hdev->stat.byte_rx increment in hci_uart_tty_receive() + inside the proto_lock read-side critical section to safely synchronize + with device unregistration. +5. Adding cancel_work_sync(&hu->write_work) to hci_uart_close() to safely + flush the workqueue before hci_uart_flush() is invoked via the HCI core. +6. Utilizing cancel_work_sync() instead of disable_work_sync() across + all paths to prevent permanently breaking user-space retry capabilities. + +Fixes: 3b799254cf6f ("Bluetooth: hci_uart: Cancel init work before unregistering") +Cc: stable@vger.kernel.org +Signed-off-by: Mingyu Wang <25181214217@stu.xidian.edu.cn> +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Greg Kroah-Hartman +--- + drivers/bluetooth/hci_ldisc.c | 48 +++++++++++++++++++++++++++++++++++------- + 1 file changed, 40 insertions(+), 8 deletions(-) + +--- a/drivers/bluetooth/hci_ldisc.c ++++ b/drivers/bluetooth/hci_ldisc.c +@@ -194,7 +194,15 @@ void hci_uart_init_work(struct work_stru + err = hci_register_dev(hu->hdev); + if (err < 0) { + BT_ERR("Can't register HCI device"); ++ ++ percpu_down_write(&hu->proto_lock); + clear_bit(HCI_UART_PROTO_READY, &hu->flags); ++ percpu_up_write(&hu->proto_lock); ++ ++ /* Safely cancel work after clearing flags */ ++ cancel_work_sync(&hu->write_work); ++ ++ /* Close protocol before freeing hdev */ + hu->proto->close(hu); + hdev = hu->hdev; + hu->hdev = NULL; +@@ -263,8 +271,12 @@ static int hci_uart_open(struct hci_dev + /* Close device */ + static int hci_uart_close(struct hci_dev *hdev) + { ++ struct hci_uart *hu = hci_get_drvdata(hdev); ++ + BT_DBG("hdev %p", hdev); + ++ cancel_work_sync(&hu->write_work); ++ + hci_uart_flush(hdev); + hdev->flush = NULL; + return 0; +@@ -531,6 +543,7 @@ static void hci_uart_tty_close(struct tt + { + struct hci_uart *hu = tty->disc_data; + struct hci_dev *hdev; ++ bool proto_ready; + + BT_DBG("tty %p", tty); + +@@ -540,24 +553,38 @@ static void hci_uart_tty_close(struct tt + if (!hu) + return; + +- hdev = hu->hdev; +- if (hdev) +- hci_uart_close(hdev); ++ /* Wait for init_ready to finish to prevent registration races */ ++ cancel_work_sync(&hu->init_ready); + +- if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) { ++ proto_ready = test_bit(HCI_UART_PROTO_READY, &hu->flags); ++ if (proto_ready) { + percpu_down_write(&hu->proto_lock); + clear_bit(HCI_UART_PROTO_READY, &hu->flags); + percpu_up_write(&hu->proto_lock); ++ } + +- cancel_work_sync(&hu->init_ready); +- cancel_work_sync(&hu->write_work); ++ /* ++ * Unconditionally cancel write_work AFTER clearing PROTO_READY. ++ * This ensures that concurrent protocol timers cannot requeue ++ * write_work via hci_uart_tx_wakeup(), permanently preventing ++ * double-free races and UAFs. ++ */ ++ cancel_work_sync(&hu->write_work); ++ ++ hdev = hu->hdev; ++ if (hdev) ++ hci_uart_close(hdev); /* proto->flush is safely skipped */ + ++ if (proto_ready) { + if (hdev) { + if (test_bit(HCI_UART_REGISTERED, &hu->flags)) + hci_unregister_dev(hdev); +- hci_free_dev(hdev); + } ++ /* Close protocol before freeing hdev (intrinsically purges queues) */ + hu->proto->close(hu); ++ ++ if (hdev) ++ hci_free_dev(hdev); + } + clear_bit(HCI_UART_PROTO_SET, &hu->flags); + +@@ -625,11 +652,12 @@ static void hci_uart_tty_receive(struct + * tty caller + */ + hu->proto->recv(hu, data, count); +- percpu_up_read(&hu->proto_lock); + + if (hu->hdev) + hu->hdev->stat.byte_rx += count; + ++ percpu_up_read(&hu->proto_lock); ++ + tty_unthrottle(tty); + } + +@@ -695,6 +723,10 @@ static int hci_uart_register_dev(struct + percpu_down_write(&hu->proto_lock); + clear_bit(HCI_UART_PROTO_INIT, &hu->flags); + percpu_up_write(&hu->proto_lock); ++ /* Cancel work after clearing flags */ ++ cancel_work_sync(&hu->write_work); ++ ++ /* Close protocol before freeing hdev */ + hu->proto->close(hu); + hu->hdev = NULL; + hci_free_dev(hdev); diff --git a/queue-7.0/bluetooth-iso-drop-iso_end-frames-received-without-prior-iso_start.patch b/queue-7.0/bluetooth-iso-drop-iso_end-frames-received-without-prior-iso_start.patch new file mode 100644 index 0000000000..9daabf4775 --- /dev/null +++ b/queue-7.0/bluetooth-iso-drop-iso_end-frames-received-without-prior-iso_start.patch @@ -0,0 +1,47 @@ +From 84c24fb151fc1179355296d7ff29129ac7c42129 Mon Sep 17 00:00:00 2001 +From: David Carlier +Date: Fri, 15 May 2026 07:25:25 +0100 +Subject: Bluetooth: ISO: drop ISO_END frames received without prior ISO_START + +From: David Carlier + +commit 84c24fb151fc1179355296d7ff29129ac7c42129 upstream. + +ISO data PDUs carry a packet-boundary flag indicating START, CONT, END +or SINGLE. The ISO_CONT branch of iso_recv() guards against a missing +ISO_START by checking conn->rx_len before touching conn->rx_skb, but +ISO_END does not. + +If a peer sends an ISO_END as the first packet on a fresh ISO +connection, conn->rx_skb is still NULL and conn->rx_len is zero, so +skb_put(conn->rx_skb, ...) dereferences NULL and oopses. For BIS, +where receivers sync to a broadcaster without pairing, any broadcaster +on the air can trigger this. + +Mirror the ISO_CONT check at the top of ISO_END so a stray end fragment +is logged and dropped instead of crashing the host. + +Fixes: ccf74f2390d6 ("Bluetooth: Add BTPROTO_ISO socket type") +Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-opus-4-7 +Signed-off-by: David Carlier +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Greg Kroah-Hartman +--- + net/bluetooth/iso.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/net/bluetooth/iso.c ++++ b/net/bluetooth/iso.c +@@ -2594,6 +2594,11 @@ int iso_recv(struct hci_dev *hdev, u16 h + break; + + case ISO_END: ++ if (!conn->rx_len) { ++ BT_ERR("Unexpected end frame (len %d)", skb->len); ++ goto drop; ++ } ++ + skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len), + skb->len); + conn->rx_len -= skb->len; diff --git a/queue-7.0/bluetooth-l2cap-ecred_reconfigure-send-packed-pdu-not-stack-pointer.patch b/queue-7.0/bluetooth-l2cap-ecred_reconfigure-send-packed-pdu-not-stack-pointer.patch new file mode 100644 index 0000000000..98a28b24f1 --- /dev/null +++ b/queue-7.0/bluetooth-l2cap-ecred_reconfigure-send-packed-pdu-not-stack-pointer.patch @@ -0,0 +1,84 @@ +From 3374ef8cf99368a40f7efd51a2a375a4c5dc6f0d Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Mon, 11 May 2026 08:26:41 -0400 +Subject: Bluetooth: L2CAP: ecred_reconfigure: send packed pdu, not stack pointer + +From: Michael Bommarito + +commit 3374ef8cf99368a40f7efd51a2a375a4c5dc6f0d upstream. + +Commit 1c08108f3014 ("Bluetooth: L2CAP: Avoid -Wflex-array-member-not-at-end +warnings") converted the on-stack request PDU in l2cap_ecred_reconfigure() +from an explicit packed struct to DEFINE_RAW_FLEX(), but did not adjust the +size and source-pointer arguments to l2cap_send_cmd(): + + - struct { + - struct l2cap_ecred_reconf_req req; + - __le16 scid; + - } pdu; + + DEFINE_RAW_FLEX(struct l2cap_ecred_reconf_req, pdu, scid, 1); + ... + l2cap_send_cmd(conn, chan->ident, L2CAP_ECRED_RECONF_REQ, + sizeof(pdu), &pdu); + +After the conversion, DEFINE_RAW_FLEX() expands to declare an anonymous +union pdu_u plus a local pointer "pdu" pointing at it. Therefore: + + - sizeof(pdu) is now sizeof(struct l2cap_ecred_reconf_req *) = 8 on + 64-bit (4 on 32-bit), not the 6 bytes of (mtu, mps, scid[1]). + - &pdu is the address of the local pointer's stack storage, not the + address of the request payload. + +l2cap_send_cmd() forwards (data, count) to l2cap_build_cmd(), which calls +skb_put_data(skb, data, count). The L2CAP_ECRED_RECONFIGURE_REQ packet +body therefore contains 8 bytes copied from the kernel stack starting at +&pdu -- the 8 bytes overlap the pdu pointer's value, leaking a kernel +stack address to the paired Bluetooth peer. The intended (mtu, mps, scid) +fields are not transmitted at all, so the peer rejects the request as +malformed and the L2CAP_ECRED_RECONFIGURE feature itself has been broken +for the local-side initiator since the introducing commit landed. + +The sibling site l2cap_ecred_conn_req() in the same commit was converted +correctly (sizeof(*pdu) + len, pdu); only this site was missed. + +Restore the original semantics: pass the full flex-struct size via +struct_size(pdu, scid, 1) and the pdu pointer (the struct address) as +the source. + +Validated on a stock 7.0-based host kernel via the real call path: +setsockopt(SOL_BLUETOOTH, BT_RCVMTU, ...) on a BT_CONNECTED +L2CAP_MODE_EXT_FLOWCTL socket emits an L2CAP_ECRED_RECONFIGURE_REQ +whose body is 8 bytes (the on-stack pdu local's value) rather than +the expected 6. Three captures from fresh socket / fresh hciemu peer +on the same host -- low bytes vary per call, high 0xffff confirms a +kernel virtual address (KASLR-randomised stack slot, not a fixed +string): + + RECONF_REQ body (ident=0x02 len=8): 42 fb 54 af 0e ca ff ff + RECONF_REQ body (ident=0x02 len=8): 52 3d 2e af 0e ca ff ff + RECONF_REQ body (ident=0x02 len=8): b2 fc 5b af 0e ca ff ff + +After this patch the body is 6 bytes carrying the expected +little-endian (mtu, mps, scid). + +Cc: stable@vger.kernel.org +Fixes: 1c08108f3014 ("Bluetooth: L2CAP: Avoid -Wflex-array-member-not-at-end warnings") +Assisted-by: Claude:claude-opus-4-7 +Signed-off-by: Michael Bommarito +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Greg Kroah-Hartman +--- + net/bluetooth/l2cap_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -7275,7 +7275,7 @@ static void l2cap_ecred_reconfigure(stru + chan->ident = l2cap_get_ident(conn); + + l2cap_send_cmd(conn, chan->ident, L2CAP_ECRED_RECONF_REQ, +- sizeof(pdu), &pdu); ++ struct_size(pdu, scid, 1), pdu); + } + + int l2cap_chan_reconfigure(struct l2cap_chan *chan, __u16 mtu) diff --git a/queue-7.0/bluetooth-mgmt-validate-add-extended-advertising-data-length.patch b/queue-7.0/bluetooth-mgmt-validate-add-extended-advertising-data-length.patch new file mode 100644 index 0000000000..4af0d9c598 --- /dev/null +++ b/queue-7.0/bluetooth-mgmt-validate-add-extended-advertising-data-length.patch @@ -0,0 +1,54 @@ +From d3f7d17960ed50df3a6709c5158caff989c8c905 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Fri, 15 May 2026 10:38:19 -0400 +Subject: Bluetooth: MGMT: validate Add Extended Advertising Data length + +From: Michael Bommarito + +commit d3f7d17960ed50df3a6709c5158caff989c8c905 upstream. + +MGMT_OP_ADD_EXT_ADV_DATA is registered as a variable-length command, +with MGMT_ADD_EXT_ADV_DATA_SIZE as the fixed header size. The handler +then uses cp->adv_data_len and cp->scan_rsp_len to validate and copy +cp->data, but it never checks that those bytes are part of the mgmt +command payload. + +A short command can therefore make add_ext_adv_data() pass an +out-of-bounds pointer into tlv_data_is_valid(). If the bytes beyond +the command buffer are addressable, they can also be copied into the +advertising instance as scan response data, where the caller can read +them back via MGMT_OP_GET_ADV_INSTANCE. The trigger requires +CAP_NET_ADMIN in the initial user namespace; KASAN reports an 8-byte +slab-out-of-bounds read. + +Reject commands whose length does not match the fixed header plus both +advertising data lengths before parsing cp->data. + +Fixes: 12410572833a ("Bluetooth: Break add adv into two mgmt commands") +Cc: stable@vger.kernel.org +Assisted-by: Claude:claude-opus-4-7 +Signed-off-by: Michael Bommarito +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Greg Kroah-Hartman +--- + net/bluetooth/mgmt.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/net/bluetooth/mgmt.c ++++ b/net/bluetooth/mgmt.c +@@ -9110,9 +9110,15 @@ static int add_ext_adv_data(struct sock + struct adv_info *adv_instance; + int err = 0; + struct mgmt_pending_cmd *cmd; ++ u16 expected_len; + + BT_DBG("%s", hdev->name); + ++ expected_len = struct_size(cp, data, cp->adv_data_len + cp->scan_rsp_len); ++ if (expected_len != data_len) ++ return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_EXT_ADV_DATA, ++ MGMT_STATUS_INVALID_PARAMS); ++ + hci_dev_lock(hdev); + + adv_instance = hci_find_adv_instance(hdev, cp->instance); diff --git a/queue-7.0/bluetooth-serialize-accept_q-access.patch b/queue-7.0/bluetooth-serialize-accept_q-access.patch new file mode 100644 index 0000000000..3ab99aa5aa --- /dev/null +++ b/queue-7.0/bluetooth-serialize-accept_q-access.patch @@ -0,0 +1,218 @@ +From e83f5e24da741fa9405aeeff00b08c5ee7c37b88 Mon Sep 17 00:00:00 2001 +From: Jiexun Wang +Date: Wed, 6 May 2026 19:43:30 +0800 +Subject: Bluetooth: serialize accept_q access + +From: Jiexun Wang + +commit e83f5e24da741fa9405aeeff00b08c5ee7c37b88 upstream. + +bt_sock_poll() walks the accept queue without synchronization, while +child teardown can unlink the same socket and drop its last reference. +The unsynchronized accept queue walk has existed since the initial +Bluetooth import. + +Protect accept_q with a dedicated lock for queue updates and polling. +Also rework bt_accept_dequeue() to take temporary child references under +the queue lock before dropping it and locking the child socket. + +Fixes: 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 ("Linux-2.6.12-rc2") +Cc: stable@vger.kernel.org +Reported-by: Jann Horn +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Signed-off-by: Jiexun Wang +Signed-off-by: Ren Wei +Signed-off-by: Jiexun Wang +Reviewed-by: Jann Horn +Signed-off-by: Luiz Augusto von Dentz +Signed-off-by: Greg Kroah-Hartman +--- + include/net/bluetooth/bluetooth.h | 1 + net/bluetooth/af_bluetooth.c | 87 ++++++++++++++++++++++++++++---------- + 2 files changed, 66 insertions(+), 22 deletions(-) + +--- a/include/net/bluetooth/bluetooth.h ++++ b/include/net/bluetooth/bluetooth.h +@@ -398,6 +398,7 @@ void baswap(bdaddr_t *dst, const bdaddr_ + struct bt_sock { + struct sock sk; + struct list_head accept_q; ++ spinlock_t accept_q_lock; /* protects accept_q */ + struct sock *parent; + unsigned long flags; + void (*skb_msg_name)(struct sk_buff *, void *, int *); +--- a/net/bluetooth/af_bluetooth.c ++++ b/net/bluetooth/af_bluetooth.c +@@ -154,6 +154,7 @@ struct sock *bt_sock_alloc(struct net *n + + sock_init_data(sock, sk); + INIT_LIST_HEAD(&bt_sk(sk)->accept_q); ++ spin_lock_init(&bt_sk(sk)->accept_q_lock); + + sock_reset_flag(sk, SOCK_ZAPPED); + +@@ -214,6 +215,7 @@ void bt_accept_enqueue(struct sock *pare + { + const struct cred *old_cred; + struct pid *old_pid; ++ struct bt_sock *par = bt_sk(parent); + + BT_DBG("parent %p, sk %p", parent, sk); + +@@ -224,9 +226,13 @@ void bt_accept_enqueue(struct sock *pare + else + lock_sock_nested(sk, SINGLE_DEPTH_NESTING); + +- list_add_tail(&bt_sk(sk)->accept_q, &bt_sk(parent)->accept_q); + bt_sk(sk)->parent = parent; + ++ spin_lock_bh(&par->accept_q_lock); ++ list_add_tail(&bt_sk(sk)->accept_q, &par->accept_q); ++ sk_acceptq_added(parent); ++ spin_unlock_bh(&par->accept_q_lock); ++ + /* Copy credentials from parent since for incoming connections the + * socket is allocated by the kernel. + */ +@@ -244,8 +250,6 @@ void bt_accept_enqueue(struct sock *pare + bh_unlock_sock(sk); + else + release_sock(sk); +- +- sk_acceptq_added(parent); + } + EXPORT_SYMBOL(bt_accept_enqueue); + +@@ -254,45 +258,72 @@ EXPORT_SYMBOL(bt_accept_enqueue); + */ + void bt_accept_unlink(struct sock *sk) + { ++ struct sock *parent = bt_sk(sk)->parent; ++ + BT_DBG("sk %p state %d", sk, sk->sk_state); + ++ spin_lock_bh(&bt_sk(parent)->accept_q_lock); + list_del_init(&bt_sk(sk)->accept_q); +- sk_acceptq_removed(bt_sk(sk)->parent); ++ sk_acceptq_removed(parent); ++ spin_unlock_bh(&bt_sk(parent)->accept_q_lock); + bt_sk(sk)->parent = NULL; + sock_put(sk); + } + EXPORT_SYMBOL(bt_accept_unlink); + ++static struct sock *bt_accept_get(struct sock *parent, struct sock *sk) ++{ ++ struct bt_sock *bt = bt_sk(parent); ++ struct sock *next = NULL; ++ ++ /* accept_q is modified from child teardown paths too, so take a ++ * temporary reference before dropping the queue lock. ++ */ ++ spin_lock_bh(&bt->accept_q_lock); ++ ++ if (sk) { ++ if (bt_sk(sk)->parent != parent) ++ goto out; ++ ++ if (!list_is_last(&bt_sk(sk)->accept_q, &bt->accept_q)) { ++ next = &list_next_entry(bt_sk(sk), accept_q)->sk; ++ sock_hold(next); ++ } ++ } else if (!list_empty(&bt->accept_q)) { ++ next = &list_first_entry(&bt->accept_q, ++ struct bt_sock, accept_q)->sk; ++ sock_hold(next); ++ } ++ ++out: ++ spin_unlock_bh(&bt->accept_q_lock); ++ return next; ++} ++ + struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock) + { +- struct bt_sock *s, *n; +- struct sock *sk; ++ struct sock *sk, *next; + + BT_DBG("parent %p", parent); + + restart: +- list_for_each_entry_safe(s, n, &bt_sk(parent)->accept_q, accept_q) { +- sk = (struct sock *)s; +- ++ for (sk = bt_accept_get(parent, NULL); sk; sk = next) { + /* Prevent early freeing of sk due to unlink and sock_kill */ +- sock_hold(sk); + lock_sock(sk); + + /* Check sk has not already been unlinked via + * bt_accept_unlink() due to serialisation caused by sk locking + */ +- if (!bt_sk(sk)->parent) { ++ if (bt_sk(sk)->parent != parent) { + BT_DBG("sk %p, already unlinked", sk); + release_sock(sk); + sock_put(sk); + +- /* Restart the loop as sk is no longer in the list +- * and also avoid a potential infinite loop because +- * list_for_each_entry_safe() is not thread safe. +- */ + goto restart; + } + ++ next = bt_accept_get(parent, sk); ++ + /* sk is safely in the parent list so reduce reference count */ + sock_put(sk); + +@@ -320,6 +351,8 @@ restart: + sock_hold(sk); + + release_sock(sk); ++ if (next) ++ sock_put(next); + return sk; + } + +@@ -528,18 +561,28 @@ EXPORT_SYMBOL(bt_sock_stream_recvmsg); + + static inline __poll_t bt_accept_poll(struct sock *parent) + { +- struct bt_sock *s, *n; ++ struct bt_sock *bt = bt_sk(parent); ++ struct bt_sock *s; + struct sock *sk; ++ __poll_t mask = 0; ++ ++ spin_lock_bh(&bt->accept_q_lock); ++ list_for_each_entry(s, &bt->accept_q, accept_q) { ++ int state; + +- list_for_each_entry_safe(s, n, &bt_sk(parent)->accept_q, accept_q) { + sk = (struct sock *)s; +- if (sk->sk_state == BT_CONNECTED || +- (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags) && +- sk->sk_state == BT_CONNECT2)) +- return EPOLLIN | EPOLLRDNORM; ++ state = READ_ONCE(sk->sk_state); ++ ++ if (state == BT_CONNECTED || ++ (test_bit(BT_SK_DEFER_SETUP, &bt->flags) && ++ state == BT_CONNECT2)) { ++ mask = EPOLLIN | EPOLLRDNORM; ++ break; ++ } + } ++ spin_unlock_bh(&bt->accept_q_lock); + +- return 0; ++ return mask; + } + + __poll_t bt_sock_poll(struct file *file, struct socket *sock, diff --git a/queue-7.0/drivers-base-memory-fix-memory-block-reference-leak-in-poison-accounting.patch b/queue-7.0/drivers-base-memory-fix-memory-block-reference-leak-in-poison-accounting.patch new file mode 100644 index 0000000000..2f8d375bb4 --- /dev/null +++ b/queue-7.0/drivers-base-memory-fix-memory-block-reference-leak-in-poison-accounting.patch @@ -0,0 +1,62 @@ +From 03a2cc1756a0570f887d624cd6c535ea0cbd4951 Mon Sep 17 00:00:00 2001 +From: Muchun Song +Date: Tue, 28 Apr 2026 16:52:18 +0800 +Subject: drivers/base/memory: fix memory block reference leak in poison accounting + +From: Muchun Song + +commit 03a2cc1756a0570f887d624cd6c535ea0cbd4951 upstream. + +memblk_nr_poison_inc() and memblk_nr_poison_sub() look up a memory block +via find_memory_block_by_id(), which acquires a reference to the memory +block device. + +Both helpers use the returned memory block without dropping that +reference, leaking the device reference on each successful lookup. Drop +the reference after updating nr_hwpoison. + +Link: https://lore.kernel.org/20260428085219.1316047-3-songmuchun@bytedance.com +Fixes: 5033091de814 ("mm/hwpoison: introduce per-memory_block hwpoison counter") +Signed-off-by: Muchun Song +Reviewed-by: Miaohe Lin +Acked-by: Oscar Salvador +Acked-by: David Hildenbrand (Arm) +Cc: Danilo Krummrich +Cc: Greg Kroah-Hartman +Cc: "Huang, Ying" +Cc: Naoya Horiguchi +Cc: "Rafael J. Wysocki" +Cc: Vishal Verma +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + drivers/base/memory.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/drivers/base/memory.c ++++ b/drivers/base/memory.c +@@ -1230,8 +1230,10 @@ void memblk_nr_poison_inc(unsigned long + const unsigned long block_id = pfn_to_block_id(pfn); + struct memory_block *mem = find_memory_block_by_id(block_id); + +- if (mem) ++ if (mem) { + atomic_long_inc(&mem->nr_hwpoison); ++ put_device(&mem->dev); ++ } + } + + void memblk_nr_poison_sub(unsigned long pfn, long i) +@@ -1239,8 +1241,10 @@ void memblk_nr_poison_sub(unsigned long + const unsigned long block_id = pfn_to_block_id(pfn); + struct memory_block *mem = find_memory_block_by_id(block_id); + +- if (mem) ++ if (mem) { + atomic_long_sub(i, &mem->nr_hwpoison); ++ put_device(&mem->dev); ++ } + } + + static unsigned long memblk_nr_poison(struct memory_block *mem) diff --git a/queue-7.0/efi-allocate-runtime-workqueue-before-acpi-init.patch b/queue-7.0/efi-allocate-runtime-workqueue-before-acpi-init.patch new file mode 100644 index 0000000000..13303ea2df --- /dev/null +++ b/queue-7.0/efi-allocate-runtime-workqueue-before-acpi-init.patch @@ -0,0 +1,88 @@ +From 13c6da02e767152c9ac4330962247a5e47011035 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Tue, 19 May 2026 10:03:00 +0200 +Subject: efi: Allocate runtime workqueue before ACPI init + +From: Ard Biesheuvel + +commit 13c6da02e767152c9ac4330962247a5e47011035 upstream. + +Since commit + + 5894cf571e14 ("acpi/prmt: Use EFI runtime sandbox to invoke PRM handlers") + +ACPI PRM calls are delegated to a workqueue which runs in a kernel +thread, making it easier to detect and mitigate faulting memory accesses +performed by the firmware. + +Rafael reports that such PRM accesses may occur before efisubsys_init() +executes, which is where the workqueue is allocated, leading to NULL +pointer dereferences. Since acpi_init() [which triggers the early PRM +accesses] executes as a subsys_initcall() as well, and has its own +dependencies that may be sensitive to initcall ordering, deferring +acpi_init() is not an option. + +So instead, split off the workqueue allocation into its own postcore +initcall, as this is the only missing piece to allow EFI runtime calls +to be made. This ensures that EFI runtime call (including PRM calls) are +accessible to all code running at subsys_initcall() level. + +Cc: +Fixes: 5894cf571e14 ("acpi/prmt: Use EFI runtime sandbox to invoke PRM handlers") +Reviewed-by: Rafael J. Wysocki (Intel) +Signed-off-by: Ard Biesheuvel +Signed-off-by: Greg Kroah-Hartman +--- + drivers/firmware/efi/efi.c | 28 ++++++++++++++++------------ + 1 file changed, 16 insertions(+), 12 deletions(-) + +--- a/drivers/firmware/efi/efi.c ++++ b/drivers/firmware/efi/efi.c +@@ -402,21 +402,11 @@ static void __init efi_debugfs_init(void + static inline void efi_debugfs_init(void) {} + #endif + +-/* +- * We register the efi subsystem with the firmware subsystem and the +- * efivars subsystem with the efi subsystem, if the system was booted with +- * EFI. +- */ +-static int __init efisubsys_init(void) ++static int __init efipostcore_init(void) + { +- int error; +- + if (!efi_enabled(EFI_RUNTIME_SERVICES)) + efi.runtime_supported_mask = 0; + +- if (!efi_enabled(EFI_BOOT)) +- return 0; +- + if (efi.runtime_supported_mask) { + /* + * Since we process only one efi_runtime_service() at a time, an +@@ -428,9 +418,23 @@ static int __init efisubsys_init(void) + pr_err("Creating efi_rts_wq failed, EFI runtime services disabled.\n"); + clear_bit(EFI_RUNTIME_SERVICES, &efi.flags); + efi.runtime_supported_mask = 0; +- return 0; + } + } ++ return 0; ++} ++postcore_initcall(efipostcore_init); ++ ++/* ++ * We register the efi subsystem with the firmware subsystem and the ++ * efivars subsystem with the efi subsystem, if the system was booted with ++ * EFI. ++ */ ++static int __init efisubsys_init(void) ++{ ++ int error; ++ ++ if (!efi_enabled(EFI_BOOT)) ++ return 0; + + if (efi_rt_services_supported(EFI_RT_SUPPORTED_TIME_SERVICES)) + platform_device_register_simple("rtc-efi", 0, NULL, 0); diff --git a/queue-7.0/hwmon-pmbus-adm1266-widen-blackbox-info-buffer-to-i2c_smbus_block_max.patch b/queue-7.0/hwmon-pmbus-adm1266-widen-blackbox-info-buffer-to-i2c_smbus_block_max.patch new file mode 100644 index 0000000000..a5192d35be --- /dev/null +++ b/queue-7.0/hwmon-pmbus-adm1266-widen-blackbox-info-buffer-to-i2c_smbus_block_max.patch @@ -0,0 +1,51 @@ +From eee213daa1e1b402eb631bcd1b8c5aa340a6b081 Mon Sep 17 00:00:00 2001 +From: Abdurrahman Hussain +Date: Fri, 15 May 2026 15:11:48 -0700 +Subject: hwmon: (pmbus/adm1266) widen blackbox-info buffer to I2C_SMBUS_BLOCK_MAX + +From: Abdurrahman Hussain + +commit eee213daa1e1b402eb631bcd1b8c5aa340a6b081 upstream. + +adm1266_nvmem_read_blackbox() declares a 5-byte stack buffer and +passes it to i2c_smbus_read_block_data() to retrieve the 4-byte +BLACKBOX_INFO response. i2c_smbus_read_block_data() does not honour +caller buffer sizes -- it memcpy()s data.block[0] bytes from the +SMBus transaction (where data.block[0] is the length byte returned by +the slave device, up to I2C_SMBUS_BLOCK_MAX = 32): + + memcpy(values, &data.block[1], data.block[0]); + +If the device returns any block length above 5, the call overflows +the caller's 5-byte stack buffer before the post-call + + if (ret != 4) + return -EIO; + +check has a chance to reject the response. + +Widen the local buffer to I2C_SMBUS_BLOCK_MAX so the helper has room +for any well-formed SMBus block response, matching the convention used +by the other i2c_smbus_read_block_data() callers in this driver. + +Fixes: 15609d189302 ("hwmon: (pmbus/adm1266) read blackbox") +Cc: stable@vger.kernel.org +Signed-off-by: Abdurrahman Hussain +Link: https://lore.kernel.org/r/20260515-adm1266-fixes-v1-2-1c1ea1349cfe@nexthop.ai +Signed-off-by: Guenter Roeck +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hwmon/pmbus/adm1266.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/hwmon/pmbus/adm1266.c ++++ b/drivers/hwmon/pmbus/adm1266.c +@@ -349,7 +349,7 @@ static int adm1266_nvmem_read_blackbox(s + { + int record_count; + char index; +- u8 buf[5]; ++ u8 buf[I2C_SMBUS_BLOCK_MAX]; + int ret; + + ret = i2c_smbus_read_block_data(data->client, ADM1266_BLACKBOX_INFO, buf); diff --git a/queue-7.0/io_uring-waitid-clear-waitid-info-before-copying-it-to-userspace.patch b/queue-7.0/io_uring-waitid-clear-waitid-info-before-copying-it-to-userspace.patch new file mode 100644 index 0000000000..5c476c580f --- /dev/null +++ b/queue-7.0/io_uring-waitid-clear-waitid-info-before-copying-it-to-userspace.patch @@ -0,0 +1,41 @@ +From 93d93f5f8da791e98159795c6ef683f45bd95d13 Mon Sep 17 00:00:00 2001 +From: Heechan Kang +Date: Sun, 17 May 2026 03:47:09 +0900 +Subject: io_uring/waitid: clear waitid info before copying it to userspace + +From: Heechan Kang + +commit 93d93f5f8da791e98159795c6ef683f45bd95d13 upstream. + +IORING_OP_WAITID stores its result fields in struct io_waitid::info and +later copies them to userspace siginfo. The prep path initializes the +request arguments, but it does not initialize info itself. + +If the wait operation completes without reporting a child event, the common +wait code can return without writing wo_info. In that case io_waitid_finish() +still copies iw->info to userspace, exposing stale bytes from the reused +io_kiocb command storage. + +Clear the result storage during prep so the io_uring path matches the +regular waitid syscall, which uses a zero-initialized struct waitid_info. + +Fixes: f31ecf671ddc ("io_uring: add IORING_OP_WAITID support") +Cc: stable@vger.kernel.org # 6.7+ +Signed-off-by: Heechan Kang +Link: https://patch.msgid.link/20260516184709.852814-1-gganji11@naver.com +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman +--- + io_uring/waitid.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/io_uring/waitid.c ++++ b/io_uring/waitid.c +@@ -275,6 +275,7 @@ int io_waitid_prep(struct io_kiocb *req, + iw->options = READ_ONCE(sqe->file_index); + iw->head = NULL; + iw->infop = u64_to_user_ptr(READ_ONCE(sqe->addr2)); ++ memset(&iw->info, 0, sizeof(iw->info)); + return 0; + } + diff --git a/queue-7.0/ipv6-ioam-refresh-hdr-pointer-before-ioam6_event.patch b/queue-7.0/ipv6-ioam-refresh-hdr-pointer-before-ioam6_event.patch new file mode 100644 index 0000000000..89be3d829c --- /dev/null +++ b/queue-7.0/ipv6-ioam-refresh-hdr-pointer-before-ioam6_event.patch @@ -0,0 +1,62 @@ +From e46e6bc97fb1f339730ff1ba74267fbf48e7a422 Mon Sep 17 00:00:00 2001 +From: Justin Iurman +Date: Wed, 20 May 2026 14:42:42 +0200 +Subject: ipv6: ioam: refresh hdr pointer before ioam6_event() + +From: Justin Iurman + +commit e46e6bc97fb1f339730ff1ba74267fbf48e7a422 upstream. + +Reported by Sashiko: + +In ipv6_hop_ioam(), the hdr pointer is initialized to point into the +skb's linear data buffer. Later, the code calls skb_ensure_writable(), +which might reallocate the buffer: + + if (skb_ensure_writable(skb, optoff + 2 + hdr->opt_len)) + goto drop; + + /* Trace pointer may have changed */ + trace = (struct ioam6_trace_hdr *)(skb_network_header(skb) + + optoff + sizeof(*hdr)); + + ioam6_fill_trace_data(skb, ns, trace, true); + + ioam6_event(IOAM6_EVENT_TRACE, dev_net(skb->dev), + GFP_ATOMIC, (void *)trace, hdr->opt_len - 2); + +If the skb is cloned or lacks sufficient linear headroom, +skb_ensure_writable() will invoke pskb_expand_head(), which reallocates +the skb's data buffer and frees the old one, invalidating pointers to +it. While the code recalculates the trace pointer immediately after the +call to skb_ensure_writable(), it fails to recalculate the hdr pointer. + +This patch fixes the above by recalculating the hdr pointer before +passing hdr->opt_len to ioam6_event(), so that we avoid any UaF. + +Fixes: f655c78d6225 ("net: exthdrs: ioam6: send trace event") +Cc: stable@vger.kernel.org +Signed-off-by: Justin Iurman +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260520124242.32320-1-justin.iurman@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/exthdrs.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/net/ipv6/exthdrs.c ++++ b/net/ipv6/exthdrs.c +@@ -955,9 +955,9 @@ static bool ipv6_hop_ioam(struct sk_buff + if (skb_ensure_writable(skb, optoff + 2 + hdr->opt_len)) + goto drop; + +- /* Trace pointer may have changed */ +- trace = (struct ioam6_trace_hdr *)(skb_network_header(skb) +- + optoff + sizeof(*hdr)); ++ /* Trace and hdr pointers may have changed */ ++ hdr = (struct ioam6_hdr *)(skb_network_header(skb) + optoff); ++ trace = (struct ioam6_trace_hdr *)((u8 *)hdr + sizeof(*hdr)); + + ioam6_fill_trace_data(skb, ns, trace, true); + diff --git a/queue-7.0/ksmbd-fix-null-pointer-dereference-in-compare_guid_key.patch b/queue-7.0/ksmbd-fix-null-pointer-dereference-in-compare_guid_key.patch new file mode 100644 index 0000000000..a542a53127 --- /dev/null +++ b/queue-7.0/ksmbd-fix-null-pointer-dereference-in-compare_guid_key.patch @@ -0,0 +1,73 @@ +From 4b83cbc4c15f09b000cc06f033f64b0824b6dc87 Mon Sep 17 00:00:00 2001 +From: Jeremy Laratro +Date: Wed, 13 May 2026 08:26:16 +0900 +Subject: ksmbd: fix null pointer dereference in compare_guid_key() + +From: Jeremy Laratro + +commit 4b83cbc4c15f09b000cc06f033f64b0824b6dc87 upstream. + +session_fd_check() walks the per-inode m_op_list during durable-handle +session teardown and sets op->conn = NULL for every opinfo whose conn +matched the closing session's connection. The matching opinfo, however, +stays linked in its per-ClientGuid lease_table_list entry's lb->lease_list +because destroy_lease_table() only runs on full TCP-connection teardown, +not on SESSION_LOGOFF. + +If the same TCP connection then negotiates a fresh session with the +same ClientGuid (ClientGuid is bound to NEGOTIATE, not the session, and +is unchanged across LOGOFF + SETUP) and issues a SMB2 CREATE with a +lease context on a different inode, find_same_lease_key() walks +lb->lease_list, reaches the stale opinfo, and calls compare_guid_key(), +which unconditionally dereferences opinfo->conn->ClientGUID. The conn +pointer is NULL and the kernel panics. + +Reproducer requires only a successful SMB2 SESSION_SETUP and a share +configured with 'durable handles = yes'. KASAN report on mainline +70390501d194: + + general protection fault, probably for non-canonical address + 0xdffffc0000000069: 0000 [#1] SMP KASAN PTI + KASAN: null-ptr-deref in range [0x0000000000000348-0x000000000000034f] + Workqueue: ksmbd-io handle_ksmbd_work + RIP: 0010:bcmp+0x5b/0x230 + Call Trace: + compare_guid_key+0x4b/0xd0 + find_same_lease_key+0x324/0x690 + smb2_open+0x6aea/0x8e60 + handle_ksmbd_work+0x796/0xee0 + ... + +Faulting address 0x348 is the offset of ClientGUID within struct +ksmbd_conn, confirming opinfo->conn was NULL. + +Read opinfo->conn once and bail out if it has been cleared by a +concurrent session_fd_check(). A half-detached opinfo cannot be the +owner of an active lease, so returning 0 is the correct match result. + +Fixes: c8efcc786146 ("ksmbd: add support for durable handles v1/v2") +Cc: stable@vger.kernel.org +Signed-off-by: Jeremy Laratro +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/server/oplock.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/fs/smb/server/oplock.c ++++ b/fs/smb/server/oplock.c +@@ -484,8 +484,12 @@ static inline int compare_guid_key(struc + const char *guid1, const char *key1) + { + const char *guid2, *key2; ++ struct ksmbd_conn *conn; + +- guid2 = opinfo->conn->ClientGUID; ++ conn = READ_ONCE(opinfo->conn); ++ if (!conn) ++ return 0; ++ guid2 = conn->ClientGUID; + key2 = opinfo->o_lease->lease_key; + if (!memcmp(guid1, guid2, SMB2_CLIENT_GUID_SIZE) && + !memcmp(key1, key2, SMB2_LEASE_KEY_SIZE)) diff --git a/queue-7.0/ksmbd-fix-null-pointer-dereference-in-proc_show_files.patch b/queue-7.0/ksmbd-fix-null-pointer-dereference-in-proc_show_files.patch new file mode 100644 index 0000000000..4c255a6234 --- /dev/null +++ b/queue-7.0/ksmbd-fix-null-pointer-dereference-in-proc_show_files.patch @@ -0,0 +1,62 @@ +From 904901561e61a2b559070b20c74a8c95491f30aa Mon Sep 17 00:00:00 2001 +From: Jeremy Laratro +Date: Wed, 13 May 2026 08:23:26 +0900 +Subject: ksmbd: fix null pointer dereference in proc_show_files() + +From: Jeremy Laratro + +commit 904901561e61a2b559070b20c74a8c95491f30aa upstream. + +When a SMB2 client opens a file with a durable v2 handle and then issues +SMB2 SESSION_LOGOFF, session_fd_check() clears fp->tcon = NULL on the +reconnectable file pointer but leaves the fp registered in global_ft.idr +until the durable scavenger fires (up to fp->durable_timeout seconds +later). + +During that window any read of /proc/fs/ksmbd/files (mode 0400) panics +the kernel because proc_show_files() walks global_ft.idr and +unconditionally dereferences fp->tcon->id with no NULL guard. + +Reproducer requires only a successful SMB2 SESSION_SETUP and a share +configured with 'durable handles = yes'. KASAN report on mainline +70390501d194: + + general protection fault, probably for non-canonical address + 0xdffffc0000000000: 0000 [#1] SMP KASAN PTI + KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] + RIP: 0010:proc_show_files+0x118/0x740 + Call Trace: + proc_show_files+0x118/0x740 + seq_read_iter+0x4ef/0xe10 + proc_reg_read_iter+0x1b7/0x280 + ... + +Guard the dereference. A durable-disconnected fp legitimately has no +tcon; report its tree id as 0 rather than oopsing. + +Fixes: b38f99c1217a ("ksmbd: add procfs interface for runtime monitoring and statistics") +Cc: stable@vger.kernel.org +Signed-off-by: Jeremy Laratro +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/server/vfs_cache.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c +index 354c4d8a1cfb..913164c958b1 100644 +--- a/fs/smb/server/vfs_cache.c ++++ b/fs/smb/server/vfs_cache.c +@@ -81,7 +81,7 @@ static int proc_show_files(struct seq_file *m, void *v) + read_lock(&global_ft.lock); + idr_for_each_entry(global_ft.idr, fp, id) { + seq_printf(m, "%#-10x %#-10llx %#-10llx %#-10x", +- fp->tcon->id, ++ fp->tcon ? fp->tcon->id : 0, + fp->persistent_id, + fp->volatile_id, + atomic_read(&fp->refcount)); +-- +2.54.0 + diff --git a/queue-7.0/ksmbd-fix-sid-memory-leak-in-set_posix_acl_entries_dacl-on-overflow.patch b/queue-7.0/ksmbd-fix-sid-memory-leak-in-set_posix_acl_entries_dacl-on-overflow.patch new file mode 100644 index 0000000000..367b3664bd --- /dev/null +++ b/queue-7.0/ksmbd-fix-sid-memory-leak-in-set_posix_acl_entries_dacl-on-overflow.patch @@ -0,0 +1,76 @@ +From af92ee994cc7f7e83a41c2025f32257a2f82a7ef Mon Sep 17 00:00:00 2001 +From: Ferry Meng +Date: Mon, 11 May 2026 21:18:16 +0800 +Subject: ksmbd: fix SID memory leak in set_posix_acl_entries_dacl() on overflow + +From: Ferry Meng + +commit af92ee994cc7f7e83a41c2025f32257a2f82a7ef upstream. + +Commit 299f962c0b02 ("ksmbd: use check_add_overflow() to prevent u16 +DACL size overflow") added check_add_overflow() guards that break out +of the ACE-building loops in set_posix_acl_entries_dacl() when the +accumulated DACL size would wrap past 65535. + +However, each iteration allocates a struct smb_sid via kmalloc_obj() +at the top of the loop and relies on the kfree(sid) call at the end +of the loop body (the 'pass_same_sid' label in the first loop, and +the explicit kfree at the tail of the second loop) to release it. +The newly introduced 'break' statements bypass those kfree() calls, +leaking the sid buffer every time an overflow is detected. + +A malicious or malformed file with enough POSIX ACL entries to trip +the overflow check will leak one or more struct smb_sid allocations +on every request that touches the file's DACL, providing a trivial +kernel memory exhaustion vector. + +Free sid before breaking out of the loops to plug the leak. + +Fixes: 299f962c0b02 ("ksmbd: use check_add_overflow() to prevent u16 DACL size overflow") +Cc: stable@vger.kernel.org +Signed-off-by: Ferry Meng +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/server/smbacl.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +--- a/fs/smb/server/smbacl.c ++++ b/fs/smb/server/smbacl.c +@@ -643,8 +643,10 @@ static void set_posix_acl_entries_dacl(s + ntace = (struct smb_ace *)((char *)pndace + *size); + ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, flags, + pace->e_perm, 0777); +- if (check_add_overflow(*size, ace_sz, size)) ++ if (check_add_overflow(*size, ace_sz, size)) { ++ kfree(sid); + break; ++ } + (*num_aces)++; + if (pace->e_tag == ACL_USER) + ntace->access_req |= +@@ -655,8 +657,10 @@ static void set_posix_acl_entries_dacl(s + ntace = (struct smb_ace *)((char *)pndace + *size); + ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, + 0x03, pace->e_perm, 0777); +- if (check_add_overflow(*size, ace_sz, size)) ++ if (check_add_overflow(*size, ace_sz, size)) { ++ kfree(sid); + break; ++ } + (*num_aces)++; + if (pace->e_tag == ACL_USER) + ntace->access_req |= +@@ -698,8 +702,10 @@ posix_default_acl: + ntace = (struct smb_ace *)((char *)pndace + *size); + ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, 0x0b, + pace->e_perm, 0777); +- if (check_add_overflow(*size, ace_sz, size)) ++ if (check_add_overflow(*size, ace_sz, size)) { ++ kfree(sid); + break; ++ } + (*num_aces)++; + if (pace->e_tag == ACL_USER) + ntace->access_req |= diff --git a/queue-7.0/ksmbd-validate-sid-in-parent-security-descriptor-during-acl-inheritance.patch b/queue-7.0/ksmbd-validate-sid-in-parent-security-descriptor-during-acl-inheritance.patch new file mode 100644 index 0000000000..23fa8490e2 --- /dev/null +++ b/queue-7.0/ksmbd-validate-sid-in-parent-security-descriptor-during-acl-inheritance.patch @@ -0,0 +1,130 @@ +From 69f030cf95488ae1186c72ac8c66fd279664ea7f Mon Sep 17 00:00:00 2001 +From: Junyi Liu +Date: Tue, 19 May 2026 16:12:04 +0900 +Subject: ksmbd: validate SID in parent security descriptor during ACL inheritance + +From: Junyi Liu + +commit 69f030cf95488ae1186c72ac8c66fd279664ea7f upstream. + +Introduce smb_validate_ntsd_sid() helper to safely validate Owner SID +and Group SID inside the NT Security Descriptor (smb_ntsd) retrieved +from the parent directory. + +Cc: stable@vger.kernel.org +Signed-off-by: Junyi Liu +Signed-off-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/server/smbacl.c | 66 +++++++++++++++++++++++++++++++++++++------------ + 1 file changed, 50 insertions(+), 16 deletions(-) + +--- a/fs/smb/server/smbacl.c ++++ b/fs/smb/server/smbacl.c +@@ -1096,6 +1096,40 @@ static int smb_append_inherited_ace(stru + return 0; + } + ++static int smb_validate_ntsd_sid(struct smb_ntsd *pntsd, size_t pntsd_size, ++ unsigned int sid_offset, struct smb_sid **sid, ++ size_t *sid_size) ++{ ++ size_t sid_end; ++ ++ *sid = NULL; ++ *sid_size = 0; ++ ++ if (!sid_offset) ++ return 0; ++ ++ if (sid_offset < sizeof(struct smb_ntsd) || ++ check_add_overflow(sid_offset, (size_t)CIFS_SID_BASE_SIZE, ++ &sid_end) || ++ sid_end > pntsd_size) ++ return -EINVAL; ++ ++ *sid = (struct smb_sid *)((char *)pntsd + sid_offset); ++ if ((*sid)->num_subauth > SID_MAX_SUB_AUTHORITIES) ++ return -EINVAL; ++ ++ if (check_add_overflow((size_t)CIFS_SID_BASE_SIZE, ++ sizeof(__le32) * (size_t)(*sid)->num_subauth, ++ &sid_end)) ++ return -EINVAL; ++ ++ if (sid_offset > pntsd_size || sid_end > pntsd_size - sid_offset) ++ return -EINVAL; ++ ++ *sid_size = sid_end; ++ return 0; ++} ++ + int smb_inherit_dacl(struct ksmbd_conn *conn, + const struct path *path, + unsigned int uid, unsigned int gid) +@@ -1108,28 +1142,28 @@ int smb_inherit_dacl(struct ksmbd_conn * + struct dentry *parent = path->dentry->d_parent; + struct mnt_idmap *idmap = mnt_idmap(path->mnt); + int inherited_flags = 0, flags = 0, i, nt_size = 0, pdacl_size; +- int rc = 0, pntsd_type, pntsd_size, acl_len, aces_size; ++ int rc = 0, pntsd_type, ppntsd_size, acl_len, aces_size; + unsigned int dacloffset; + size_t dacl_struct_end; + u16 num_aces, ace_cnt = 0; + char *aces_base; + bool is_dir = S_ISDIR(d_inode(path->dentry)->i_mode); + +- pntsd_size = ksmbd_vfs_get_sd_xattr(conn, idmap, ++ ppntsd_size = ksmbd_vfs_get_sd_xattr(conn, idmap, + parent, &parent_pntsd); +- if (pntsd_size <= 0) ++ if (ppntsd_size <= 0) + return -ENOENT; + + dacloffset = le32_to_cpu(parent_pntsd->dacloffset); + if (!dacloffset || + check_add_overflow(dacloffset, sizeof(struct smb_acl), &dacl_struct_end) || +- dacl_struct_end > (size_t)pntsd_size) { ++ dacl_struct_end > (size_t)ppntsd_size) { + rc = -EINVAL; + goto free_parent_pntsd; + } + + parent_pdacl = (struct smb_acl *)((char *)parent_pntsd + dacloffset); +- acl_len = pntsd_size - dacloffset; ++ acl_len = ppntsd_size - dacloffset; + num_aces = le16_to_cpu(parent_pdacl->num_aces); + pntsd_type = le16_to_cpu(parent_pntsd->type); + pdacl_size = le16_to_cpu(parent_pdacl->size); +@@ -1243,19 +1277,19 @@ pass: + struct smb_ntsd *pntsd; + struct smb_acl *pdacl; + struct smb_sid *powner_sid = NULL, *pgroup_sid = NULL; +- int powner_sid_size = 0, pgroup_sid_size = 0, pntsd_size; ++ size_t powner_sid_size = 0, pgroup_sid_size = 0, pntsd_size; + size_t pntsd_alloc_size; + +- if (parent_pntsd->osidoffset) { +- powner_sid = (struct smb_sid *)((char *)parent_pntsd + +- le32_to_cpu(parent_pntsd->osidoffset)); +- powner_sid_size = 1 + 1 + 6 + (powner_sid->num_subauth * 4); +- } +- if (parent_pntsd->gsidoffset) { +- pgroup_sid = (struct smb_sid *)((char *)parent_pntsd + +- le32_to_cpu(parent_pntsd->gsidoffset)); +- pgroup_sid_size = 1 + 1 + 6 + (pgroup_sid->num_subauth * 4); +- } ++ rc = smb_validate_ntsd_sid(parent_pntsd, ppntsd_size, ++ le32_to_cpu(parent_pntsd->osidoffset), ++ &powner_sid, &powner_sid_size); ++ if (rc) ++ goto free_aces_base; ++ rc = smb_validate_ntsd_sid(parent_pntsd, ppntsd_size, ++ le32_to_cpu(parent_pntsd->gsidoffset), ++ &pgroup_sid, &pgroup_sid_size); ++ if (rc) ++ goto free_aces_base; + + if (check_add_overflow(sizeof(struct smb_ntsd), + (size_t)powner_sid_size, diff --git a/queue-7.0/mm-damon-fix-damos_stat-tracepoint-format-for-sz_applied.patch b/queue-7.0/mm-damon-fix-damos_stat-tracepoint-format-for-sz_applied.patch new file mode 100644 index 0000000000..af40b1cb1d --- /dev/null +++ b/queue-7.0/mm-damon-fix-damos_stat-tracepoint-format-for-sz_applied.patch @@ -0,0 +1,35 @@ +From 620072fd783290ad92c2d445a47b0a61b161f352 Mon Sep 17 00:00:00 2001 +From: SeongJae Park +Date: Sun, 26 Apr 2026 12:31:17 -0700 +Subject: mm/damon: fix damos_stat tracepoint format for sz_applied + +From: SeongJae Park + +commit 620072fd783290ad92c2d445a47b0a61b161f352 upstream. + +The print format is wrongly marking sz_applied as sz_tried. Fix it. + +Link: https://lore.kernel.org/20260426193119.88095-1-sj@kernel.org +Fixes: 804c26b961da ("mm/damon/core: add trace point for damos stat per apply interval") +Signed-off-by: SeongJae Park +Cc: "Masami Hiramatsu (Google)" +Cc: Mathieu Desnoyers +Cc: Steven Rostedt +Cc: # 7.0.x +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + include/trace/events/damon.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/include/trace/events/damon.h ++++ b/include/trace/events/damon.h +@@ -41,7 +41,7 @@ TRACE_EVENT(damos_stat_after_apply_inter + ), + + TP_printk("ctx_idx=%u scheme_idx=%u nr_tried=%lu sz_tried=%lu " +- "nr_applied=%lu sz_tried=%lu sz_ops_filter_passed=%lu " ++ "nr_applied=%lu sz_applied=%lu sz_ops_filter_passed=%lu " + "qt_exceeds=%lu nr_snapshots=%lu", + __entry->context_idx, __entry->scheme_idx, + __entry->nr_tried, __entry->sz_tried, diff --git a/queue-7.0/mm-damon-sysfs-schemes-call-missing-mem_cgroup_iter_break.patch b/queue-7.0/mm-damon-sysfs-schemes-call-missing-mem_cgroup_iter_break.patch new file mode 100644 index 0000000000..17351a4520 --- /dev/null +++ b/queue-7.0/mm-damon-sysfs-schemes-call-missing-mem_cgroup_iter_break.patch @@ -0,0 +1,36 @@ +From d4e7b5c4cc353f154d5ab8bb2e1ce7714d77a6e9 Mon Sep 17 00:00:00 2001 +From: SeongJae Park +Date: Sun, 26 Apr 2026 10:36:12 -0700 +Subject: mm/damon/sysfs-schemes: call missing mem_cgroup_iter_break() + +From: SeongJae Park + +commit d4e7b5c4cc353f154d5ab8bb2e1ce7714d77a6e9 upstream. + +damon_sysfs_memcg_path_to_id() breaks mem_cgroup_iter() loop without +calling mem_cgroup_iter_break(). This leaks the cgroup reference. Fix +the issue by calling mem_cgroup_iter_break() before the break. + +The issue was discovered [1] by Sashiko. + +Link: https://lore.kernel.org/20260426173625.86521-1-sj@kernel.org +Link: https://lore.kernel.org/20260423004148.74722-1-sj@kernel.org [1] +Fixes: 29cbb9a13f05 ("mm/damon/sysfs-schemes: implement scheme filters") +Signed-off-by: SeongJae Park +Cc: # 6.3.x +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + mm/damon/sysfs-schemes.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/mm/damon/sysfs-schemes.c ++++ b/mm/damon/sysfs-schemes.c +@@ -2537,6 +2537,7 @@ static int damon_sysfs_memcg_path_to_id( + if (damon_sysfs_memcg_path_eq(memcg, path, memcg_path)) { + *id = mem_cgroup_id(memcg); + found = true; ++ mem_cgroup_iter_break(NULL, memcg); + break; + } + } diff --git a/queue-7.0/mm-fix-__vm_normal_page-to-handle-missing-support-for-pmd_special-pud_special.patch b/queue-7.0/mm-fix-__vm_normal_page-to-handle-missing-support-for-pmd_special-pud_special.patch new file mode 100644 index 0000000000..20818e9714 --- /dev/null +++ b/queue-7.0/mm-fix-__vm_normal_page-to-handle-missing-support-for-pmd_special-pud_special.patch @@ -0,0 +1,105 @@ +From c0c6ccd9828c3a1950623b546fa57292a77b5c73 Mon Sep 17 00:00:00 2001 +From: "David Hildenbrand (Arm)" +Date: Thu, 30 Apr 2026 13:31:22 +0200 +Subject: mm: fix __vm_normal_page() to handle missing support for pmd_special()/pud_special() + +From: David Hildenbrand (Arm) + +commit c0c6ccd9828c3a1950623b546fa57292a77b5c73 upstream. + +On x86 32-bit with THP enabled, zap_huge_pmd() is seen to generate a +"WARNING: mm/memory.c:735 at __vm_normal_page+0x6a/0x7d", from the +VM_WARN_ON_ONCE(is_zero_pfn(pfn) || is_huge_zero_pfn(pfn)); followed by +"BUG: Bad rss-counter state"s, then later "BUG: Bad page state"s when +reclaim gets to call shrink_huge_zero_folio_scan(). + +It's as if the _PAGE_SPECIAL bit never got set in the huge_zero pmd: and +indeed, whereas pte_special() and pte_mkspecial() are subject to a +dedicated CONFIG_ARCH_HAS_PTE_SPECIAL, pmd_special() and pmd_mkspecial() +are subject to CONFIG_ARCH_SUPPORTS_PMD_PFNMAP, which is never enabled on +any 32-bit architecture. + +While the problem was exposed through commit d80a9cb1a64a +("mm/huge_memory: add and use normal_or_softleaf_folio_pmd()"), it was an +oversight in commit af38538801c6 ("mm/memory: factor out common code from +vm_normal_page_*()") and would result in other problems: +* huge zero folio accounted in smaps, pagemap (PAGE_IS_FILE) and + numamaps as file-backed THP +* folio_walk_start() returning the folio even without FW_ZEROPAGE set. + Callers seem to tolerate that, though. + +... and triggering the VM_WARN_ON_ONE(), although never reported so far. + +To fix it, teach vm_normal_page_pmd()/vm_normal_page_pud() to consider +whether pmd_special/pud_special is actually implemented. + +Link: https://lore.kernel.org/20260430-pmd_special-v1-1-dbcbcfd72c20@kernel.org +Fixes: af38538801c6 ("mm/memory: factor out common code from vm_normal_page_*()") +Signed-off-by: David Hildenbrand (Arm) +Reported-by: Hugh Dickins +Closes: https://lore.kernel.org/r/74a75b59-2e13-3985-ee99-d5521f39df2a@google.com +Reported-by: Bibo Mao +Closes: https://lore.kernel.org/r/20260430041121.2839350-1-maobibo@loongson.cn +Debugged-by: Hugh Dickins +Reviewed-by: Lance Yang +Tested-by: Bibo Mao +Reviewed-by: Baolin Wang +Reviewed-by: Oscar Salvador +Reviewed-by: Lorenzo Stoakes +Cc: Liam R. Howlett +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + mm/memory.c | 22 +++++++++++++++++++--- + 1 file changed, 19 insertions(+), 3 deletions(-) + +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -625,6 +625,21 @@ static void print_bad_page_map(struct vm + dump_stack(); + add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE); + } ++ ++static inline bool pgtable_level_has_pxx_special(enum pgtable_level level) ++{ ++ switch (level) { ++ case PGTABLE_LEVEL_PTE: ++ return IS_ENABLED(CONFIG_ARCH_HAS_PTE_SPECIAL); ++ case PGTABLE_LEVEL_PMD: ++ return IS_ENABLED(CONFIG_ARCH_SUPPORTS_PMD_PFNMAP); ++ case PGTABLE_LEVEL_PUD: ++ return IS_ENABLED(CONFIG_ARCH_SUPPORTS_PUD_PFNMAP); ++ default: ++ return false; ++ } ++} ++ + #define print_bad_pte(vma, addr, pte, page) \ + print_bad_page_map(vma, addr, pte_val(pte), page, PGTABLE_LEVEL_PTE) + +@@ -697,7 +712,7 @@ static inline struct page *__vm_normal_p + unsigned long addr, unsigned long pfn, bool special, + unsigned long long entry, enum pgtable_level level) + { +- if (IS_ENABLED(CONFIG_ARCH_HAS_PTE_SPECIAL)) { ++ if (pgtable_level_has_pxx_special(level)) { + if (unlikely(special)) { + #ifdef CONFIG_FIND_NORMAL_PAGE + if (vma->vm_ops && vma->vm_ops->find_normal_page) +@@ -712,8 +727,9 @@ static inline struct page *__vm_normal_p + return NULL; + } + /* +- * With CONFIG_ARCH_HAS_PTE_SPECIAL, any special page table +- * mappings (incl. shared zero folios) are marked accordingly. ++ * With working pte_special()/pmd_special()..., any special page ++ * table mappings (incl. shared zero folios) are marked ++ * accordingly. + */ + } else { + if (unlikely(vma->vm_flags & (VM_PFNMAP | VM_MIXEDMAP))) { diff --git a/queue-7.0/mm-memory-fix-spurious-warning-when-unmapping-device-private-exclusive-pages.patch b/queue-7.0/mm-memory-fix-spurious-warning-when-unmapping-device-private-exclusive-pages.patch new file mode 100644 index 0000000000..abd505bb09 --- /dev/null +++ b/queue-7.0/mm-memory-fix-spurious-warning-when-unmapping-device-private-exclusive-pages.patch @@ -0,0 +1,190 @@ +From be3f38d05cc5a7c3f13e51994c5dd043ab604d28 Mon Sep 17 00:00:00 2001 +From: Alistair Popple +Date: Fri, 1 May 2026 16:51:16 +1000 +Subject: mm/memory: fix spurious warning when unmapping device-private/exclusive pages +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Alistair Popple + +commit be3f38d05cc5a7c3f13e51994c5dd043ab604d28 upstream. + +Device private and exclusive entries are only supported for anonymous +folios. This condition is tested in __migrate_device_pages() and +make_device_exclusive() using folio_test_anon(). However the unmap path +tests this assumption using vma_is_anonymous(). + +This is wrong because whilst anonymous VMAs can only contain folios where +folio_test_anon() is true the opposite relation does not hold. A folio +for which folio_test_anon() is true does not imply vma_is_anonymous() is +true. Such a condition can occur if for example a folio is part of a +private filebacked mapping. + +In this case vma_is_anonymous() is false as the mapping is filebacked, but +folio_test_anon() may be true, thus permitting devices to migrate the +folio to device private memory. This can lead to the following spurious +warnings during process teardown: + +[ 772.737706] ------------[ cut here ]------------ +[ 772.739201] WARNING: mm/memory.c:1754 at unmap_page_range.cold+0x26/0x18a, CPU#17: hmm-tests/2041 +[ 772.742050] Modules linked in: test_hmm nvidia_uvm(O) nvidia(O) +[ 772.743959] CPU: 17 UID: 0 PID: 2041 Comm: hmm-tests Tainted: G W O 7.0.0+ #387 PREEMPT(full) +[ 772.747104] Tainted: [W]=WARN, [O]=OOT_MODULE +[ 772.748509] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.17.0-0-gb52ca86e094d-prebuilt.qemu.org 04/01/2014 +[ 772.752117] RIP: 0010:unmap_page_range.cold+0x26/0x18a +[ 772.753780] Code: 7e fe ff ff 48 89 4c 24 78 4c 89 44 24 38 e8 f2 ff b1 00 48 8b 4c 24 78 4c 8b 44 24 38 48 8b 44 24 18 48 83 78 48 00 74 04 90 <0f> 0b 90 48 89 ca b8 ff ff 37 00 48 c1 ea 03 48 c1 e0 2a 80 3c 02 +[ 772.759602] RSP: 0018:ffff888112607550 EFLAGS: 00010286 +[ 772.761310] RAX: ffff88811bbf4dc0 RBX: dffffc0000000000 RCX: ffffea03e9bfffd8 +[ 772.763583] RDX: 1ffff1102377e9c1 RSI: 0000000000000008 RDI: ffff88811bbf4e08 +[ 772.765914] RBP: 0000000000000006 R08: ffff8881059f7448 R09: ffffed10224c0e68 +[ 772.768184] R10: ffff888112607347 R11: 0000000000000001 R12: 0000000000000001 +[ 772.770461] R13: ffffea03e9bfffc0 R14: ffff888112607908 R15: ffffea03e9bfffc0 +[ 772.772782] FS: 00007f327caa2780(0000) GS:ffff888427b7d000(0000) knlGS:0000000000000000 +[ 772.775328] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 772.777187] CR2: 00007f327ca89000 CR3: 00000001994d5000 CR4: 00000000000006f0 +[ 772.779135] Call Trace: +[ 772.779792] +[ 772.780317] ? dmirror_interval_invalidate+0x1a3/0x290 [test_hmm] +[ 772.781873] ? vm_normal_page_pud+0x2b0/0x2b0 +[ 772.782992] ? __rwlock_init+0x150/0x150 +[ 772.784006] ? lock_release+0x216/0x2b0 +[ 772.785008] ? __mmu_notifier_invalidate_range_start+0x505/0x6e0 +[ 772.786522] ? lock_release+0x216/0x2b0 +[ 772.787498] ? unmap_single_vma+0xb6/0x210 +[ 772.788573] unmap_vmas+0x27d/0x520 +[ 772.789506] ? unmap_single_vma+0x210/0x210 +[ 772.790607] ? mas_update_gap.part.0+0x620/0x620 +[ 772.791834] unmap_region+0x19e/0x350 +[ 772.792769] ? remove_vma+0x130/0x130 +[ 772.793684] ? mas_alloc_nodes+0x1f2/0x300 +[ 772.794730] vms_complete_munmap_vmas+0x8c1/0xe20 +[ 772.795926] ? unmap_region+0x350/0x350 +[ 772.796917] do_vmi_align_munmap+0x36a/0x4e0 +[ 772.798018] ? lock_release+0x216/0x2b0 +[ 772.799024] ? vma_shrink+0x620/0x620 +[ 772.799983] do_vmi_munmap+0x150/0x2c0 +[ 772.800939] __vm_munmap+0x161/0x2c0 +[ 772.801872] ? expand_downwards+0xd60/0xd60 +[ 772.802948] ? clockevents_program_event+0x1ef/0x540 +[ 772.804217] ? lock_release+0x216/0x2b0 +[ 772.805158] __x64_sys_munmap+0x59/0x80 +[ 772.805776] do_syscall_64+0xfc/0x670 +[ 772.806336] ? irqentry_exit+0xda/0x580 +[ 772.806976] entry_SYSCALL_64_after_hwframe+0x4b/0x53 +[ 772.807772] RIP: 0033:0x7f327cbb2717 +[ 772.808323] Code: 73 01 c3 48 8b 0d f9 76 0d 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 b8 0b 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d c9 76 0d 00 f7 d8 64 89 01 48 +[ 772.811337] RSP: 002b:00007ffde7f57d38 EFLAGS: 00000202 ORIG_RAX: 000000000000000b +[ 772.812564] RAX: ffffffffffffffda RBX: 00007f327cc9c000 RCX: 00007f327cbb2717 +[ 772.813733] RDX: 0000000000000000 RSI: 0000000000400000 RDI: 00007f327c289000 +[ 772.814867] RBP: 0000000000421360 R08: 000000000000001a R09: 0000000000000000 +[ 772.815991] R10: 0000000000000003 R11: 0000000000000202 R12: 00007ffde7f57d74 +[ 772.817121] R13: 00007f327c689010 R14: 0000000000100000 R15: 00007f327c289000 +[ 772.818272] +[ 772.818614] irq event stamp: 0 +[ 772.819159] hardirqs last enabled at (0): [<0000000000000000>] 0x0 +[ 772.820174] hardirqs last disabled at (0): [] copy_process+0x19f3/0x6440 +[ 772.821511] softirqs last enabled at (0): [] copy_process+0x1a40/0x6440 +[ 772.822869] softirqs last disabled at (0): [<0000000000000000>] 0x0 +[ 772.823871] ---[ end trace 0000000000000000 ]--- + +Fix this by using the same check for folio_test_anon() in +zap_nonpresent_ptes(). Also add a hmm-test case for this. + +Link: https://lore.kernel.org/20260501065116.2057242-1-apopple@nvidia.com +Fixes: 999dad824c39 ("mm/shmem: persist uffd-wp bit across zapping for file-backed") +Signed-off-by: Alistair Popple +Reported-by: Arsen Arsenović +Reviewed-by: Balbir Singh +Cc: David Hildenbrand +Cc: Jason Gunthorpe +Cc: John Hubbard +Cc: Leon Romanovsky +Cc: Liam R. Howlett +Cc: Lorenzo Stoakes +Cc: Peter Xu +Cc: Matthew Brost +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Shuah Khan +Cc: Suren Baghdasaryan +Cc: Thomas Hellström +Cc: Vlastimil Babka +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + mm/memory.c | 2 - + tools/testing/selftests/mm/hmm-tests.c | 50 +++++++++++++++++++++++++++++++++ + 2 files changed, 51 insertions(+), 1 deletion(-) + +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -1750,7 +1750,7 @@ static inline int zap_nonpresent_ptes(st + * consider uffd-wp bit when zap. For more information, + * see zap_install_uffd_wp_if_needed(). + */ +- WARN_ON_ONCE(!vma_is_anonymous(vma)); ++ WARN_ON_ONCE(!folio_test_anon(folio)); + rss[mm_counter(folio)]--; + folio_remove_rmap_pte(folio, page, vma); + folio_put(folio); +--- a/tools/testing/selftests/mm/hmm-tests.c ++++ b/tools/testing/selftests/mm/hmm-tests.c +@@ -986,6 +986,56 @@ TEST_F(hmm, migrate) + } + + /* ++ * Migrate private file memory to device private memory. ++ */ ++TEST_F(hmm, migrate_file_private) ++{ ++ struct hmm_buffer *buffer; ++ unsigned long npages; ++ unsigned long size; ++ unsigned long i; ++ int *ptr; ++ int ret; ++ int fd; ++ ++ npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift; ++ ASSERT_NE(npages, 0); ++ size = npages << self->page_shift; ++ ++ fd = hmm_create_file(size); ++ ASSERT_GE(fd, 0); ++ ++ buffer = malloc(sizeof(*buffer)); ++ ASSERT_NE(buffer, NULL); ++ ++ buffer->fd = fd; ++ buffer->size = size; ++ buffer->mirror = malloc(size); ++ ASSERT_NE(buffer->mirror, NULL); ++ ++ buffer->ptr = mmap(NULL, size, ++ PROT_READ | PROT_WRITE, ++ MAP_PRIVATE, ++ buffer->fd, 0); ++ ASSERT_NE(buffer->ptr, MAP_FAILED); ++ ++ /* Initialize buffer in system memory. */ ++ for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) ++ ptr[i] = i; ++ ++ /* Migrate memory to device. */ ++ ret = hmm_migrate_sys_to_dev(self->fd, buffer, npages); ++ ASSERT_EQ(ret, 0); ++ ASSERT_EQ(buffer->cpages, npages); ++ ++ /* Check what the device read. */ ++ for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) ++ ASSERT_EQ(ptr[i], i); ++ ++ hmm_buffer_free(buffer); ++} ++ ++/* + * Migrate anonymous memory to device private memory and fault some of it back + * to system memory, then try migrating the resulting mix of system and device + * private memory to the device. diff --git a/queue-7.0/mm-memory_hotplug-fix-memory-block-reference-leak-on-remove.patch b/queue-7.0/mm-memory_hotplug-fix-memory-block-reference-leak-on-remove.patch new file mode 100644 index 0000000000..973adc50ff --- /dev/null +++ b/queue-7.0/mm-memory_hotplug-fix-memory-block-reference-leak-on-remove.patch @@ -0,0 +1,57 @@ +From 93866f55f7e292fe3d47d36c9efe5ee10213a06b Mon Sep 17 00:00:00 2001 +From: Muchun Song +Date: Tue, 28 Apr 2026 16:52:17 +0800 +Subject: mm/memory_hotplug: fix memory block reference leak on remove + +From: Muchun Song + +commit 93866f55f7e292fe3d47d36c9efe5ee10213a06b upstream. + +Patch series "mm: Fix memory block leaks and locking", v2. + +This series fixes two memory block device reference leaks and one locking +issue around the per-memory_block hwpoison counter. + + +This patch (of 2): + +remove_memory_blocks_and_altmaps() looks up each memory block with +find_memory_block(), which acquires a reference to the memory block +device. + +That reference is never dropped on this path, resulting in a leaked device +reference when removing memory blocks and their altmaps. Drop the +reference after retrieving mem->altmap and clearing mem->altmap, before +removing the memory block device. + +Link: https://lore.kernel.org/20260428085219.1316047-1-songmuchun@bytedance.com +Link: https://lore.kernel.org/20260428085219.1316047-2-songmuchun@bytedance.com +Fixes: 6b8f0798b85a ("mm/memory_hotplug: split memmap_on_memory requests across memblocks") +Signed-off-by: Muchun Song +Acked-by: Oscar Salvador +Acked-by: David Hildenbrand (Arm) +Cc: Danilo Krummrich +Cc: Greg Kroah-Hartman +Cc: "Huang, Ying" +Cc: Miaohe Lin +Cc: Naoya Horiguchi +Cc: "Rafael J. Wysocki" +Cc: Vishal Verma +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + mm/memory_hotplug.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/mm/memory_hotplug.c ++++ b/mm/memory_hotplug.c +@@ -1430,6 +1430,8 @@ static void remove_memory_blocks_and_alt + + altmap = mem->altmap; + mem->altmap = NULL; ++ /* drop the ref. we got via find_memory_block() */ ++ put_device(&mem->dev); + + remove_memory_block_devices(cur_start, memblock_size); + diff --git a/queue-7.0/mm-migrate_device-fix-spinlock-leak-in-migrate_vma_insert_huge_pmd_page.patch b/queue-7.0/mm-migrate_device-fix-spinlock-leak-in-migrate_vma_insert_huge_pmd_page.patch new file mode 100644 index 0000000000..e0a6aa86b3 --- /dev/null +++ b/queue-7.0/mm-migrate_device-fix-spinlock-leak-in-migrate_vma_insert_huge_pmd_page.patch @@ -0,0 +1,49 @@ +From 63451de16e0a08be40f9ab5e7c5c8f5c79676fb1 Mon Sep 17 00:00:00 2001 +From: Sunny Patel +Date: Sat, 25 Apr 2026 19:05:27 +0530 +Subject: mm/migrate_device: fix spinlock leak in migrate_vma_insert_huge_pmd_page + +From: Sunny Patel + +commit 63451de16e0a08be40f9ab5e7c5c8f5c79676fb1 upstream. + +When check_stable_address_space() fails after the PMD spinlock has +been acquired via pmd_lock(), the code jumps directly to the abort +label, bypassing the spin_unlock() call in unlock_abort. This causes +the PMD spinlock to be permanently held, leading to a deadlock. + +Change the goto target from abort to unlock_abort to ensure the +spinlock is always released on this error path. + +Link: https://lore.kernel.org/20260425133537.17463-1-nueralspacetech@gmail.com +Fixes: a30b48bf1b24 ("mm/migrate_device: implement THP migration of zone device pages") +Signed-off-by: Sunny Patel +Reviewed-by: Andrew Morton +Acked-by: Zi Yan +Acked-by: Balbir Singh +Acked-by: David Hildenbrand (Arm) +Cc: Alistair Popple +Cc: Byungchul Park +Cc: Gregory Price +Cc: "Huang, Ying" +Cc: Joshua Hahn +Cc: Matthew Brost +Cc: Rakie Kim +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + mm/migrate_device.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/mm/migrate_device.c ++++ b/mm/migrate_device.c +@@ -856,7 +856,7 @@ static int migrate_vma_insert_huge_pmd_p + ptl = pmd_lock(vma->vm_mm, pmdp); + csa_ret = check_stable_address_space(vma->vm_mm); + if (csa_ret) +- goto abort; ++ goto unlock_abort; + + /* + * Check for userfaultfd but do not deliver the fault. Instead, diff --git a/queue-7.0/mm-page_alloc-fix-initialization-of-tags-of-the-huge-zero-folio-with-init_on_free.patch b/queue-7.0/mm-page_alloc-fix-initialization-of-tags-of-the-huge-zero-folio-with-init_on_free.patch new file mode 100644 index 0000000000..3b3969b455 --- /dev/null +++ b/queue-7.0/mm-page_alloc-fix-initialization-of-tags-of-the-huge-zero-folio-with-init_on_free.patch @@ -0,0 +1,189 @@ +From 6a288a4ddb4a994490505ab5f41c445f8e6b6467 Mon Sep 17 00:00:00 2001 +From: "David Hildenbrand (Arm)" +Date: Tue, 21 Apr 2026 17:39:07 +0200 +Subject: mm/page_alloc: fix initialization of tags of the huge zero folio with init_on_free + +From: David Hildenbrand (Arm) + +commit 6a288a4ddb4a994490505ab5f41c445f8e6b6467 upstream. + +__GFP_ZEROTAGS semantics are currently a bit weird, but effectively this +flag is only ever set alongside __GFP_ZERO and __GFP_SKIP_KASAN. + +If we run with init_on_free, we will zero out pages during +__free_pages_prepare(), to skip zeroing on the allocation path. + +However, when allocating with __GFP_ZEROTAG set, post_alloc_hook() will +consequently not only skip clearing page content, but also skip clearing +tag memory. + +Not clearing tags through __GFP_ZEROTAGS is irrelevant for most pages that +will get mapped to user space through set_pte_at() later: set_pte_at() and +friends will detect that the tags have not been initialized yet +(PG_mte_tagged not set), and initialize them. + +However, for the huge zero folio, which will be mapped through a PMD +marked as special, this initialization will not be performed, ending up +exposing whatever tags were still set for the pages. + +The docs (Documentation/arch/arm64/memory-tagging-extension.rst) state +that allocation tags are set to 0 when a page is first mapped to user +space. That no longer holds with the huge zero folio when init_on_free is +enabled. + +Fix it by decoupling __GFP_ZEROTAGS from __GFP_ZERO, passing to +tag_clear_highpages() whether we want to also clear page content. + +Invert the meaning of the tag_clear_highpages() return value to have +clearer semantics. + +Reproduced with the huge zero folio by modifying the check_buffer_fill +arm64/mte selftest to use a 2 MiB area, after making sure that pages have +a non-0 tag set when freeing (note that, during boot, we will not actually +initialize tags, but only set KASAN_TAG_KERNEL in the page flags). + + $ ./check_buffer_fill + 1..20 + ... + not ok 17 Check initial tags with private mapping, sync error mode and mmap memory + not ok 18 Check initial tags with private mapping, sync error mode and mmap/mprotect memory + ... + +This code needs more cleanups; we'll tackle that next, like +decoupling __GFP_ZEROTAGS from __GFP_SKIP_KASAN. + +[akpm@linux-foundation.org: s/__GPF_ZERO/__GFP_ZERO/, per David] +Link: https://lore.kernel.org/20260421-zerotags-v2-1-05cb1035482e@kernel.org +Fixes: adfb6609c680 ("mm/huge_memory: initialise the tags of the huge zero folio") +Signed-off-by: David Hildenbrand (Arm) +Reviewed-by: Catalin Marinas +Tested-by: Lance Yang +Cc: Brendan Jackman +Cc: Dev Jain +Cc: Johannes Weiner +Cc: Liam Howlett +Cc: Lorenzo Stoakes (Oracle) +Cc: Mark Brown +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Ryan Roberts +Cc: Suren Baghdasaryan +Cc: Will Deacon +Cc: Zi Yan +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm64/include/asm/page.h | 2 +- + arch/arm64/mm/fault.c | 11 +++++++---- + include/linux/gfp_types.h | 10 +++++----- + include/linux/highmem.h | 7 ++++--- + mm/page_alloc.c | 8 ++++---- + 5 files changed, 21 insertions(+), 17 deletions(-) + +--- a/arch/arm64/include/asm/page.h ++++ b/arch/arm64/include/asm/page.h +@@ -33,7 +33,7 @@ struct folio *vma_alloc_zeroed_movable_f + unsigned long vaddr); + #define vma_alloc_zeroed_movable_folio vma_alloc_zeroed_movable_folio + +-bool tag_clear_highpages(struct page *to, int numpages); ++bool tag_clear_highpages(struct page *to, int numpages, bool clear_pages); + #define __HAVE_ARCH_TAG_CLEAR_HIGHPAGES + + #define copy_user_page(to, from, vaddr, pg) copy_page(to, from) +--- a/arch/arm64/mm/fault.c ++++ b/arch/arm64/mm/fault.c +@@ -971,7 +971,7 @@ struct folio *vma_alloc_zeroed_movable_f + return vma_alloc_folio(flags, 0, vma, vaddr); + } + +-bool tag_clear_highpages(struct page *page, int numpages) ++bool tag_clear_highpages(struct page *page, int numpages, bool clear_pages) + { + /* + * Check if MTE is supported and fall back to clear_highpage(). +@@ -979,13 +979,16 @@ bool tag_clear_highpages(struct page *pa + * post_alloc_hook() will invoke tag_clear_highpages(). + */ + if (!system_supports_mte()) +- return false; ++ return clear_pages; + + /* Newly allocated pages, shouldn't have been tagged yet */ + for (int i = 0; i < numpages; i++, page++) { + WARN_ON_ONCE(!try_page_mte_tagging(page)); +- mte_zero_clear_page_tags(page_address(page)); ++ if (clear_pages) ++ mte_zero_clear_page_tags(page_address(page)); ++ else ++ mte_clear_page_tags(page_address(page)); + set_page_mte_tagged(page); + } +- return true; ++ return false; + } +--- a/include/linux/gfp_types.h ++++ b/include/linux/gfp_types.h +@@ -273,11 +273,11 @@ enum { + * + * %__GFP_ZERO returns a zeroed page on success. + * +- * %__GFP_ZEROTAGS zeroes memory tags at allocation time if the memory itself +- * is being zeroed (either via __GFP_ZERO or via init_on_alloc, provided that +- * __GFP_SKIP_ZERO is not set). This flag is intended for optimization: setting +- * memory tags at the same time as zeroing memory has minimal additional +- * performance impact. ++ * %__GFP_ZEROTAGS zeroes memory tags at allocation time. Setting memory tags at ++ * the same time as zeroing memory (e.g., with __GFP_ZERO) has minimal ++ * additional performance impact. However, __GFP_ZEROTAGS also zeroes the tags ++ * even if memory is not getting zeroed at allocation time (e.g., ++ * with init_on_free). + * + * %__GFP_SKIP_KASAN makes KASAN skip unpoisoning on page allocation. + * Used for userspace and vmalloc pages; the latter are unpoisoned by +--- a/include/linux/highmem.h ++++ b/include/linux/highmem.h +@@ -347,10 +347,11 @@ static inline void clear_highpage_kasan_ + + #ifndef __HAVE_ARCH_TAG_CLEAR_HIGHPAGES + +-/* Return false to let people know we did not initialize the pages */ +-static inline bool tag_clear_highpages(struct page *page, int numpages) ++/* Returns true if the caller has to initialize the pages */ ++static inline bool tag_clear_highpages(struct page *page, int numpages, ++ bool clear_pages) + { +- return false; ++ return clear_pages; + } + + #endif +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -1847,9 +1847,9 @@ static inline bool should_skip_init(gfp_ + inline void post_alloc_hook(struct page *page, unsigned int order, + gfp_t gfp_flags) + { ++ const bool zero_tags = gfp_flags & __GFP_ZEROTAGS; + bool init = !want_init_on_free() && want_init_on_alloc(gfp_flags) && + !should_skip_init(gfp_flags); +- bool zero_tags = init && (gfp_flags & __GFP_ZEROTAGS); + int i; + + set_page_private(page, 0); +@@ -1871,11 +1871,11 @@ inline void post_alloc_hook(struct page + */ + + /* +- * If memory tags should be zeroed +- * (which happens only when memory should be initialized as well). ++ * Clearing tags can efficiently clear the memory for us as well, if ++ * required. + */ + if (zero_tags) +- init = !tag_clear_highpages(page, 1 << order); ++ init = tag_clear_highpages(page, 1 << order, /* clear_pages= */init); + + if (!should_skip_kasan_unpoison(gfp_flags) && + kasan_unpoison_pages(page, order, init)) { diff --git a/queue-7.0/net-bcmgenet-keep-rbuf-eee-pm-disabled.patch b/queue-7.0/net-bcmgenet-keep-rbuf-eee-pm-disabled.patch new file mode 100644 index 0000000000..2c94a92da5 --- /dev/null +++ b/queue-7.0/net-bcmgenet-keep-rbuf-eee-pm-disabled.patch @@ -0,0 +1,62 @@ +From 9a1730245e416d11ad5c0f2c100061d61cc43f60 Mon Sep 17 00:00:00 2001 +From: Nicolai Buchwitz +Date: Wed, 20 May 2026 20:43:20 +0200 +Subject: net: bcmgenet: keep RBUF EEE/PM disabled + +From: Nicolai Buchwitz + +commit 9a1730245e416d11ad5c0f2c100061d61cc43f60 upstream. + +Setting RBUF_EEE_EN | RBUF_PM_EN in RBUF_ENERGY_CTRL breaks the RX +path on GENET hardware once MAC EEE becomes active. RX traffic stops +flowing while the link stays up and the usual descriptor/RX error +counters remain quiet. In that state the MAC still accepts frames +(rbuf_ovflow_cnt keeps climbing) but RBUF no longer forwards them to +DMA, so rx_packets is no longer incremented at the netdev level. On +some boards the corruption ends up as a paging fault in +skb_release_data via bcmgenet_rx_poll on an LPI exit. + +Reproduced on Pi 4B (BCM2711 + BCM54213PE) and confirmed by Florian +Fainelli on an internal Broadcom 4908-family board with the same crash +signature. RBUF_PM_EN is not publicly documented. + +This shows up more often now that phy_support_eee() enables EEE by +default, but it also affects older kernels as soon as TX LPI is +turned on via ethtool, so it is not specific to recent changes. + +Always clear RBUF_EEE_EN | RBUF_PM_EN in bcmgenet_eee_enable_set so +the bits stay off across resets. UMAC and TBUF setup is left alone so +TX-side EEE keeps working. + +Link: https://github.com/raspberrypi/linux/issues/7304 +Fixes: 6ef398ea60d9 ("net: bcmgenet: add EEE support") +Cc: stable@vger.kernel.org +Signed-off-by: Nicolai Buchwitz +Reviewed-by: Florian Fainelli +Link: https://patch.msgid.link/20260520184320.652053-1-nb@tipi-net.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/broadcom/genet/bcmgenet.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c ++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c +@@ -1368,13 +1368,12 @@ void bcmgenet_eee_enable_set(struct net_ + reg &= ~(TBUF_EEE_EN | TBUF_PM_EN); + bcmgenet_writel(reg, priv->base + off); + +- /* Do the same for thing for RBUF */ ++ /* RBUF EEE/PM can break the RX path on GENET. Keep it disabled. */ + reg = bcmgenet_rbuf_readl(priv, RBUF_ENERGY_CTRL); +- if (enable) +- reg |= RBUF_EEE_EN | RBUF_PM_EN; +- else ++ if (reg & (RBUF_EEE_EN | RBUF_PM_EN)) { + reg &= ~(RBUF_EEE_EN | RBUF_PM_EN); +- bcmgenet_rbuf_writel(priv, reg, RBUF_ENERGY_CTRL); ++ bcmgenet_rbuf_writel(priv, reg, RBUF_ENERGY_CTRL); ++ } + + if (!enable && priv->clk_eee_enabled) { + clk_disable_unprepare(priv->clk_eee); diff --git a/queue-7.0/net-devmem-reject-dma-buf-bind-with-non-page-aligned-size-or-sg-length.patch b/queue-7.0/net-devmem-reject-dma-buf-bind-with-non-page-aligned-size-or-sg-length.patch new file mode 100644 index 0000000000..22e4544bd2 --- /dev/null +++ b/queue-7.0/net-devmem-reject-dma-buf-bind-with-non-page-aligned-size-or-sg-length.patch @@ -0,0 +1,69 @@ +From 4eb82ba543421e9e38cc14e4e82058b78850df50 Mon Sep 17 00:00:00 2001 +From: David Carlier +Date: Tue, 19 May 2026 21:35:30 +0100 +Subject: net: devmem: reject dma-buf bind with non-page-aligned size or SG length + +From: David Carlier + +commit 4eb82ba543421e9e38cc14e4e82058b78850df50 upstream. + +net_devmem_bind_dmabuf() trusts dmabuf->size and sg_dma_len() to be +PAGE_SIZE multiples without checking: + + - tx_vec is sized dmabuf->size / PAGE_SIZE, and + net_devmem_get_niov_at() only bounds-checks virt_addr < dmabuf->size + before indexing tx_vec[virt_addr / PAGE_SIZE]. With size = + N*PAGE_SIZE + r (1 <= r < PAGE_SIZE), sendmsg() at iov_base = + N*PAGE_SIZE passes the bound check and reads tx_vec[N] -- one past. + + - owner->area.num_niovs = len / PAGE_SIZE while gen_pool_add_owner() + covers the full byte len, so a non-page-multiple non-final sg + desyncs num_niovs from the gen_pool region for every later sg, on + both RX and TX. + +dma-buf does not require page-aligned sizes, so the bind path has to +enforce what its own indexing assumes. Reject both with -EINVAL. + +The size check is TX-only (only tx_vec is sized off dmabuf->size); the +SG-length check covers both directions. + +Fixes: bd61848900bf ("net: devmem: Implement TX path") +Cc: stable@vger.kernel.org +Signed-off-by: David Carlier +Reviewed-by: Bobby Eshleman +Acked-by: Stanislav Fomichev +Reviewed-by: Mina Almasry +Link: https://patch.msgid.link/20260519203530.66310-1-devnexen@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/core/devmem.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +--- a/net/core/devmem.c ++++ b/net/core/devmem.c +@@ -241,6 +241,11 @@ net_devmem_bind_dmabuf(struct net_device + } + + if (direction == DMA_TO_DEVICE) { ++ if (!IS_ALIGNED(dmabuf->size, PAGE_SIZE)) { ++ err = -EINVAL; ++ NL_SET_ERR_MSG(extack, "TX dma-buf size must be a multiple of PAGE_SIZE"); ++ goto err_unmap; ++ } + binding->tx_vec = kvmalloc_objs(struct net_iov *, + dmabuf->size / PAGE_SIZE); + if (!binding->tx_vec) { +@@ -267,6 +272,12 @@ net_devmem_bind_dmabuf(struct net_device + size_t len = sg_dma_len(sg); + struct net_iov *niov; + ++ if (!IS_ALIGNED(len, PAGE_SIZE)) { ++ err = -EINVAL; ++ NL_SET_ERR_MSG(extack, "dma-buf SG length must be PAGE_SIZE aligned"); ++ goto err_free_chunks; ++ } ++ + owner = kzalloc_node(sizeof(*owner), GFP_KERNEL, + dev_to_node(&dev->dev)); + if (!owner) { diff --git a/queue-7.0/net-hsr-defer-node-table-free-until-after-rcu-readers.patch b/queue-7.0/net-hsr-defer-node-table-free-until-after-rcu-readers.patch new file mode 100644 index 0000000000..a7f0511f73 --- /dev/null +++ b/queue-7.0/net-hsr-defer-node-table-free-until-after-rcu-readers.patch @@ -0,0 +1,48 @@ +From aaec7096f9961eb223b5b149abe9495525c205d9 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Wed, 13 May 2026 19:38:38 -0400 +Subject: net: hsr: defer node table free until after RCU readers + +From: Michael Bommarito + +commit aaec7096f9961eb223b5b149abe9495525c205d9 upstream. + +HSR node-list and node-status generic-netlink operations run under +rcu_read_lock(). They walk hsr->node_db through hsr_get_next_node() and +hsr_get_node_data(), but RTM_DELLINK teardown removes the same node table +with plain list_del() and frees each node immediately. + +That lets a generic-netlink reader hold a struct hsr_node pointer across +hsr_dellink(). In a KASAN build, widening the reader window after +hsr_get_next_node() obtains the node reproduces a slab-use-after-free +when the reader copies node->macaddress_A; the freeing stack is +hsr_del_nodes() from hsr_dellink(). + +Use list_del_rcu() and defer the free through the existing +hsr_free_node_rcu() callback. This matches the lifetime rule used by the +HSR prune paths, which already delete nodes with list_del_rcu() and +call_rcu(). + +Fixes: b9a1e627405d ("hsr: implement dellink to clean up resources") +Cc: stable@vger.kernel.org # v5.3+ +Signed-off-by: Michael Bommarito +Link: https://patch.msgid.link/20260513233838.3064715-2-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/hsr/hsr_framereg.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/net/hsr/hsr_framereg.c ++++ b/net/hsr/hsr_framereg.c +@@ -163,8 +163,8 @@ void hsr_del_nodes(struct list_head *nod + struct hsr_node *tmp; + + list_for_each_entry_safe(node, tmp, node_db, mac_list) { +- list_del(&node->mac_list); +- hsr_free_node(node); ++ list_del_rcu(&node->mac_list); ++ call_rcu(&node->rcu_head, hsr_free_node_rcu); + } + } + diff --git a/queue-7.0/net-ifb-report-ethtool-stats-over-num_tx_queues.patch b/queue-7.0/net-ifb-report-ethtool-stats-over-num_tx_queues.patch new file mode 100644 index 0000000000..9770fe349b --- /dev/null +++ b/queue-7.0/net-ifb-report-ethtool-stats-over-num_tx_queues.patch @@ -0,0 +1,101 @@ +From 5db89c99566fc4728cc92e941d8e1975711e24b5 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Wed, 13 May 2026 21:37:39 -0400 +Subject: net: ifb: report ethtool stats over num_tx_queues + +From: Michael Bommarito + +commit 5db89c99566fc4728cc92e941d8e1975711e24b5 upstream. + +ifb_dev_init() allocates dp->tx_private to dev->num_tx_queues +entries via kzalloc_objs(*txp, dev->num_tx_queues). Both IFB +per-queue RX and TX stats live in those entries: ifb_xmit() updates +txp->rx_stats using the skb queue mapping, ifb_ri_tasklet() updates +txp->tx_stats, and ifb_stats64() aggregates both over +dev->num_tx_queues. + +The ethtool stats callbacks instead size and walk the per-queue +stats with dev->real_num_rx_queues and dev->real_num_tx_queues. With +an asymmetric device where the RX queue count exceeds the TX queue +count, for example: + + ip link add name ifb10 numtxqueues 1 numrxqueues 8 type ifb + ethtool -S ifb10 + +ifb_get_ethtool_stats() indexes past the tx_private allocation and +copies adjacent slab data through ETHTOOL_GSTATS. + +Use dev->num_tx_queues consistently for the stats strings, the +stats count, and the stats data walks. This reports one RX stats +group and one TX stats group for each backing ifb_q_private entry, +which is the queue set IFB can actually populate. + +Reproduced under UML+KASAN at v7.1-rc2: + + BUG: KASAN: slab-out-of-bounds in ifb_fill_stats_data+0x3c/0xae + Read of size 8 at addr 0000000062dbd228 by task ethtool/36 + ifb_fill_stats_data+0x3c/0xae + ifb_get_ethtool_stats+0xc0/0x129 + __dev_ethtool+0x1ca5/0x363c + dev_ethtool+0x123/0x1b3 + dev_ioctl+0x56c/0x744 + sock_do_ioctl+0x15f/0x1b2 + sock_ioctl+0x4d5/0x50a + sys_ioctl+0xd8b/0xde9 + +With the patch applied, the same UML+KASAN repro is silent and +ethtool -S ifb10 reports only the stats backed by the single +allocated tx_private entry. + +Fixes: a21ee5b2fcb8 ("net: ifb: support ethtools stats") +Cc: stable@vger.kernel.org +Signed-off-by: Michael Bommarito +Link: https://patch.msgid.link/20260514013739.3549624-1-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ifb.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +--- a/drivers/net/ifb.c ++++ b/drivers/net/ifb.c +@@ -211,12 +211,12 @@ static void ifb_get_strings(struct net_d + + switch (stringset) { + case ETH_SS_STATS: +- for (i = 0; i < dev->real_num_rx_queues; i++) ++ for (i = 0; i < dev->num_tx_queues; i++) + for (j = 0; j < IFB_Q_STATS_LEN; j++) + ethtool_sprintf(&p, "rx_queue_%u_%.18s", + i, ifb_q_stats_desc[j].desc); + +- for (i = 0; i < dev->real_num_tx_queues; i++) ++ for (i = 0; i < dev->num_tx_queues; i++) + for (j = 0; j < IFB_Q_STATS_LEN; j++) + ethtool_sprintf(&p, "tx_queue_%u_%.18s", + i, ifb_q_stats_desc[j].desc); +@@ -229,8 +229,7 @@ static int ifb_get_sset_count(struct net + { + switch (sset) { + case ETH_SS_STATS: +- return IFB_Q_STATS_LEN * (dev->real_num_rx_queues + +- dev->real_num_tx_queues); ++ return IFB_Q_STATS_LEN * dev->num_tx_queues * 2; + default: + return -EOPNOTSUPP; + } +@@ -262,12 +261,12 @@ static void ifb_get_ethtool_stats(struct + struct ifb_q_private *txp; + int i; + +- for (i = 0; i < dev->real_num_rx_queues; i++) { ++ for (i = 0; i < dev->num_tx_queues; i++) { + txp = dp->tx_private + i; + ifb_fill_stats_data(&data, &txp->rx_stats); + } + +- for (i = 0; i < dev->real_num_tx_queues; i++) { ++ for (i = 0; i < dev->num_tx_queues; i++) { + txp = dp->tx_private + i; + ifb_fill_stats_data(&data, &txp->tx_stats); + } diff --git a/queue-7.0/net-mlx5e-fix-use-after-free-in-mlx5e_tx_reporter_timeout_recover.patch b/queue-7.0/net-mlx5e-fix-use-after-free-in-mlx5e_tx_reporter_timeout_recover.patch new file mode 100644 index 0000000000..1fb54b51c6 --- /dev/null +++ b/queue-7.0/net-mlx5e-fix-use-after-free-in-mlx5e_tx_reporter_timeout_recover.patch @@ -0,0 +1,73 @@ +From 7d260c5d2d89eb2c8c528d54b576b3aae3e20231 Mon Sep 17 00:00:00 2001 +From: Matt Fleming +Date: Wed, 13 May 2026 12:22:26 +0100 +Subject: net/mlx5e: Fix use-after-free in mlx5e_tx_reporter_timeout_recover + +From: Matt Fleming + +commit 7d260c5d2d89eb2c8c528d54b576b3aae3e20231 upstream. + +mlx5e_tx_reporter_timeout_recover() accesses sq->netdev after +mlx5e_safe_reopen_channels() has torn down and freed the channel (and +its embedded SQs). Replace the three sq->netdev references with +priv->netdev which is safe because priv outlives channel teardown. + +The netdev_err() call already used priv->netdev for this reason; make +the trylock/unlock and health_channel_eq_recover calls consistent. + +This fixes the following KASAN splat: + + BUG: KASAN: use-after-free in mlx5e_tx_reporter_timeout_recover+0x1dd/0x360 [mlx5_core] + Read of size 8 at addr ffff889860ed0b28 by task kworker/u113:2/5277 + + Call Trace: + mlx5e_tx_reporter_timeout_recover+0x1dd/0x360 [mlx5_core] + devlink_health_reporter_recover+0xa2/0x150 + devlink_health_report+0x254/0x7c0 + mlx5e_reporter_tx_timeout+0x297/0x380 [mlx5_core] + mlx5e_tx_timeout_work+0x109/0x170 [mlx5_core] + process_one_work+0x677/0xf20 + worker_thread+0x51f/0xd90 + kthread+0x3a5/0x810 + ret_from_fork+0x208/0x400 + ret_from_fork_asm+0x1a/0x30 + +Fixes: 83ac0304a2d7 ("net/mlx5e: Fix deadlocks between devlink and netdev instance locks") +Cc: stable@vger.kernel.org +Reviewed-by: Cosmin Ratiu +Reviewed-by: Tariq Toukan +Signed-off-by: Matt Fleming +Link: https://patch.msgid.link/20260513112226.140512-1-matt@readmodwrite.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c +@@ -160,13 +160,13 @@ static int mlx5e_tx_reporter_timeout_rec + * channels are being closed for other reason and this work is not + * relevant anymore. + */ +- while (!netdev_trylock(sq->netdev)) { ++ while (!netdev_trylock(priv->netdev)) { + if (!test_bit(MLX5E_STATE_CHANNELS_ACTIVE, &priv->state)) + return 0; + msleep(20); + } + +- err = mlx5e_health_channel_eq_recover(sq->netdev, eq, sq->cq.ch_stats); ++ err = mlx5e_health_channel_eq_recover(priv->netdev, eq, sq->cq.ch_stats); + if (!err) { + to_ctx->status = 0; /* this sq recovered */ + goto out; +@@ -186,7 +186,7 @@ static int mlx5e_tx_reporter_timeout_rec + "mlx5e_safe_reopen_channels failed recovering from a tx_timeout, err(%d).\n", + err); + out: +- netdev_unlock(sq->netdev); ++ netdev_unlock(priv->netdev); + return err; + } + diff --git a/queue-7.0/net-phy-skip-eee-advertisement-write-when-autoneg-is-disabled.patch b/queue-7.0/net-phy-skip-eee-advertisement-write-when-autoneg-is-disabled.patch new file mode 100644 index 0000000000..77bd4b4f0c --- /dev/null +++ b/queue-7.0/net-phy-skip-eee-advertisement-write-when-autoneg-is-disabled.patch @@ -0,0 +1,67 @@ +From 960e77ce14a83ef7f226e8e4b4d75765633ba48b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Nerijus=20Bend=C5=BEi=C5=ABnas?= + +Date: Sat, 16 May 2026 18:02:51 +0300 +Subject: net: phy: skip EEE advertisement write when autoneg is disabled +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Nerijus Bendžiūnas + +commit 960e77ce14a83ef7f226e8e4b4d75765633ba48b upstream. + +genphy_c45_an_config_eee_aneg() writes the EEE advertisement to the +auto-negotiation device's MMD register space (MDIO_MMD_AN, register +MDIO_AN_EEE_ADV). These registers are read by the link partner only +during auto-negotiation, so writing them while autoneg is disabled +cannot influence the link. On some PHYs (e.g. Broadcom BCM54213PE) +the write nevertheless reaches the chip and disturbs the receive +datapath. + +Concretely, running + + ethtool -s eth0 speed 100 duplex full autoneg off + ethtool --set-eee eth0 eee off + +leaves eth0 with TX working and RX completely silent on a +Raspberry Pi 4 / CM4 board (bcmgenet + BCM54213PE in rgmii-rxid). +Switching back to autoneg recovers the link. + +Prior to commit f26a29a038ee ("net: phy: ensure that genphy_c45_an_config_eee_aneg() sees new value of phydev->eee_cfg.eee_enabled"), +the disable path was effectively a no-op because the helper read +the stale eee_cfg.eee_enabled, so the underlying PHY behavior never +surfaced. + +Bisected on rpi-6.12.y between commits 83943264 (good) and +effcbc88 (bad) to f26a29a038ee. + +Fixes: f26a29a038ee ("net: phy: ensure that genphy_c45_an_config_eee_aneg() sees new value of phydev->eee_cfg.eee_enabled") +Cc: stable@vger.kernel.org +Signed-off-by: Nerijus Bendžiūnas +Reviewed-by: Nicolai Buchwitz +Tested-by: Nicolai Buchwitz +Link: https://patch.msgid.link/20260516150251.879680-1-nerijus.bendziunas@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/phy/phy-c45.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/drivers/net/phy/phy-c45.c ++++ b/drivers/net/phy/phy-c45.c +@@ -940,6 +940,14 @@ EXPORT_SYMBOL_GPL(genphy_c45_read_eee_ab + */ + int genphy_c45_an_config_eee_aneg(struct phy_device *phydev) + { ++ /* Writing MMD AN advertisements while autoneg is disabled has no ++ * effect on link-partner negotiation, but on some PHYs (e.g. the ++ * Broadcom BCM54213PE) the write itself disturbs the receive ++ * datapath. Skip it. ++ */ ++ if (phydev->autoneg == AUTONEG_DISABLE) ++ return 0; ++ + if (!phydev->eee_cfg.eee_enabled) { + __ETHTOOL_DECLARE_LINK_MODE_MASK(adv) = {}; + diff --git a/queue-7.0/net-pse-pd-fix-sign-on-enoent-check-in-of_load_pse_pis.patch b/queue-7.0/net-pse-pd-fix-sign-on-enoent-check-in-of_load_pse_pis.patch new file mode 100644 index 0000000000..be77f3a39a --- /dev/null +++ b/queue-7.0/net-pse-pd-fix-sign-on-enoent-check-in-of_load_pse_pis.patch @@ -0,0 +1,41 @@ +From 33d35975cbead3fa6b738ee57e5e45e14fbe0886 Mon Sep 17 00:00:00 2001 +From: Jonas Jelonek +Date: Fri, 15 May 2026 14:31:03 +0000 +Subject: net: pse-pd: fix sign on -ENOENT check in of_load_pse_pis() + +From: Jonas Jelonek + +commit 33d35975cbead3fa6b738ee57e5e45e14fbe0886 upstream. + +of_count_phandle_with_args() returns the count on success and a negative +errno on failure, including -ENOENT when the "pairsets" property is +absent. The existing comparison in of_load_pse_pis() checks against +ENOENT (positive 2) instead of -ENOENT, so the branch is taken for any +error return: legitimate DTs that omit "pairsets" trigger a spurious +"wrong number of pairsets" error and probe fails with -EINVAL. + +Compare against -ENOENT so a missing "pairsets" property is correctly +treated as "this PI has no pairsets, continue". + +Fixes: 9be9567a7c59 ("net: pse-pd: Add support for PSE PIs") +Cc: stable@vger.kernel.org +Signed-off-by: Jonas Jelonek +Acked-by: Oleksij Rempel +Link: https://patch.msgid.link/20260515143103.1721888-1-jelonek.jonas@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/pse-pd/pse_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/pse-pd/pse_core.c ++++ b/drivers/net/pse-pd/pse_core.c +@@ -210,7 +210,7 @@ static int of_load_pse_pis(struct pse_co + ret = of_load_pse_pi_pairsets(node, &pi, ret); + if (ret) + goto out; +- } else if (ret != ENOENT) { ++ } else if (ret != -ENOENT) { + dev_err(pcdev->dev, + "error: wrong number of pairsets. Should be 1 or 2, got %d (%pOF)\n", + ret, node); diff --git a/queue-7.0/net-wwan-iosm-fix-potential-memory-leaks-in-ipc_imem_init.patch b/queue-7.0/net-wwan-iosm-fix-potential-memory-leaks-in-ipc_imem_init.patch new file mode 100644 index 0000000000..c0ec2cb269 --- /dev/null +++ b/queue-7.0/net-wwan-iosm-fix-potential-memory-leaks-in-ipc_imem_init.patch @@ -0,0 +1,34 @@ +From c5d93b2c40355e999715262a824965aac025a427 Mon Sep 17 00:00:00 2001 +From: Abdun Nihaal +Date: Tue, 19 May 2026 11:57:39 +0530 +Subject: net: wwan: iosm: fix potential memory leaks in ipc_imem_init() + +From: Abdun Nihaal + +commit c5d93b2c40355e999715262a824965aac025a427 upstream. + +The memory allocated in ipc_protocol_init() is not freed on the error +paths that follow in ipc_imem_init(). Fix that by calling the +corresponding release function ipc_protocol_deinit() in the error path. + +Fixes: 3670970dd8c6 ("net: iosm: shared memory IPC interface") +Cc: stable@vger.kernel.org +Signed-off-by: Abdun Nihaal +Link: https://patch.msgid.link/20260519062815.55545-1-nihaal@cse.iitm.ac.in +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/wwan/iosm/iosm_ipc_imem.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/net/wwan/iosm/iosm_ipc_imem.c ++++ b/drivers/net/wwan/iosm/iosm_ipc_imem.c +@@ -1425,6 +1425,8 @@ imem_config_fail: + protocol_init_fail: + cancel_work_sync(&ipc_imem->run_state_worker); + ipc_task_deinit(ipc_imem->ipc_task); ++ if (ipc_imem->ipc_protocol) ++ ipc_protocol_deinit(ipc_imem->ipc_protocol); + ipc_task_init_fail: + kfree(ipc_imem->ipc_task); + ipc_task_fail: diff --git a/queue-7.0/netfilter-ip6t_hbh-reject-oversized-option-lists.patch b/queue-7.0/netfilter-ip6t_hbh-reject-oversized-option-lists.patch new file mode 100644 index 0000000000..89f34c5f05 --- /dev/null +++ b/queue-7.0/netfilter-ip6t_hbh-reject-oversized-option-lists.patch @@ -0,0 +1,51 @@ +From 4322dcde6b4173c2d8e8e6118ed290794263bcc8 Mon Sep 17 00:00:00 2001 +From: Zhengchuan Liang +Date: Wed, 13 May 2026 15:57:17 +0800 +Subject: netfilter: ip6t_hbh: reject oversized option lists + +From: Zhengchuan Liang + +commit 4322dcde6b4173c2d8e8e6118ed290794263bcc8 upstream. + +struct ip6t_opts stores at most IP6T_OPTS_OPTSNR option descriptors, +but hbh_mt6_check() does not reject larger optsnr values supplied from +userspace. + +Validate optsnr in the rule setup path so only match data that fits the +fixed-size opts array can be installed. This follows the existing xtables +pattern of rejecting invalid user-provided counts in checkentry() and +keeps the packet matching path unchanged. + +`struct ip6t_opts` has a fixed `opts[IP6T_OPTS_OPTSNR]` array, +where `IP6T_OPTS_OPTSNR` is 16, then off-by-one array access is possible: + +[ 137.924693][ T8692] UBSAN: array-index-out-of-bounds in ../net/ipv6/netfilter/ip6t_hbh.c:110:29 +[ 137.926167][ T8692] index 16 is out of range for type '__u16 [16]' + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Cc: stable@kernel.org +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Signed-off-by: Zhengchuan Liang +Signed-off-by: Ren Wei +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/netfilter/ip6t_hbh.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/net/ipv6/netfilter/ip6t_hbh.c ++++ b/net/ipv6/netfilter/ip6t_hbh.c +@@ -168,6 +168,10 @@ static int hbh_mt6_check(const struct xt + pr_debug("unknown flags %X\n", optsinfo->invflags); + return -EINVAL; + } ++ if (optsinfo->optsnr > IP6T_OPTS_OPTSNR) { ++ pr_debug("too many supported opts specified\n"); ++ return -EINVAL; ++ } + + if (optsinfo->flags & IP6T_OPTS_NSTRICT) { + pr_debug("Not strict - not implemented"); diff --git a/queue-7.0/netfilter-ipset-stop-hash-range-iteration-at-end.patch b/queue-7.0/netfilter-ipset-stop-hash-range-iteration-at-end.patch new file mode 100644 index 0000000000..1e328a5889 --- /dev/null +++ b/queue-7.0/netfilter-ipset-stop-hash-range-iteration-at-end.patch @@ -0,0 +1,130 @@ +From 0d3a282ab5f165fc207ff49ea5b6ad8f54616bd6 Mon Sep 17 00:00:00 2001 +From: Nan Li +Date: Tue, 12 May 2026 16:50:01 +0800 +Subject: netfilter: ipset: stop hash:* range iteration at end + +From: Nan Li + +commit 0d3a282ab5f165fc207ff49ea5b6ad8f54616bd6 upstream. + +The following hash set variants: + +hash:ip,mark +hash:ip,port +hash:ip,port,ip +hash:ip,port,net + +iterate IPv4 ranges with a 32-bit iterator. + +The iterator must stop once the last address in the requested range has +been processed. Advancing it once more can move the traversal state past +the end of the request, so a later retry may continue from an unintended +position. + +Handle the iterator increment explicitly at the end of the loop and stop +once the upper bound has been processed. This keeps the existing retry +behaviour intact for valid ranges while preventing traversal from +continuing past the original boundary. + +Fixes: 48596a8ddc46 ("netfilter: ipset: Fix adding an IPv4 range containing more than 2^31 addresses") +Cc: stable@kernel.org +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Signed-off-by: Nan Li +Signed-off-by: Ren Wei +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman +--- + net/netfilter/ipset/ip_set_hash_ipmark.c | 6 +++++- + net/netfilter/ipset/ip_set_hash_ipport.c | 5 ++++- + net/netfilter/ipset/ip_set_hash_ipportip.c | 5 ++++- + net/netfilter/ipset/ip_set_hash_ipportnet.c | 5 ++++- + 4 files changed, 17 insertions(+), 4 deletions(-) + +--- a/net/netfilter/ipset/ip_set_hash_ipmark.c ++++ b/net/netfilter/ipset/ip_set_hash_ipmark.c +@@ -150,7 +150,7 @@ hash_ipmark4_uadt(struct ip_set *set, st + + if (retried) + ip = ntohl(h->next.ip); +- for (; ip <= ip_to; ip++, i++) { ++ for (; ip <= ip_to; i++) { + e.ip = htonl(ip); + if (i > IPSET_MAX_RANGE) { + hash_ipmark4_data_next(&h->next, &e); +@@ -162,6 +162,10 @@ hash_ipmark4_uadt(struct ip_set *set, st + return ret; + + ret = 0; ++ ++ if (ip == ip_to) ++ break; ++ ip++; + } + return ret; + } +--- a/net/netfilter/ipset/ip_set_hash_ipport.c ++++ b/net/netfilter/ipset/ip_set_hash_ipport.c +@@ -186,7 +186,7 @@ hash_ipport4_uadt(struct ip_set *set, st + + if (retried) + ip = ntohl(h->next.ip); +- for (; ip <= ip_to; ip++) { ++ for (; ip <= ip_to;) { + p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port) + : port; + for (; p <= port_to; p++, i++) { +@@ -203,6 +203,9 @@ hash_ipport4_uadt(struct ip_set *set, st + + ret = 0; + } ++ if (ip == ip_to) ++ break; ++ ip++; + } + return ret; + } +--- a/net/netfilter/ipset/ip_set_hash_ipportip.c ++++ b/net/netfilter/ipset/ip_set_hash_ipportip.c +@@ -182,7 +182,7 @@ hash_ipportip4_uadt(struct ip_set *set, + + if (retried) + ip = ntohl(h->next.ip); +- for (; ip <= ip_to; ip++) { ++ for (; ip <= ip_to;) { + p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port) + : port; + for (; p <= port_to; p++, i++) { +@@ -199,6 +199,9 @@ hash_ipportip4_uadt(struct ip_set *set, + + ret = 0; + } ++ if (ip == ip_to) ++ break; ++ ip++; + } + return ret; + } +--- a/net/netfilter/ipset/ip_set_hash_ipportnet.c ++++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c +@@ -274,7 +274,7 @@ hash_ipportnet4_uadt(struct ip_set *set, + p = port; + ip2 = ip2_from; + } +- for (; ip <= ip_to; ip++) { ++ for (; ip <= ip_to;) { + e.ip = htonl(ip); + for (; p <= port_to; p++) { + e.port = htons(p); +@@ -298,6 +298,9 @@ hash_ipportnet4_uadt(struct ip_set *set, + ip2 = ip2_from; + } + p = port; ++ if (ip == ip_to) ++ break; ++ ip++; + } + return ret; + } diff --git a/queue-7.0/netfilter-nf_queue-hold-bridge-skb-dev-while-queued.patch b/queue-7.0/netfilter-nf_queue-hold-bridge-skb-dev-while-queued.patch new file mode 100644 index 0000000000..9d854c8a83 --- /dev/null +++ b/queue-7.0/netfilter-nf_queue-hold-bridge-skb-dev-while-queued.patch @@ -0,0 +1,90 @@ +From e196115ec330a18de415bdb9f5071aa9f08e53ce Mon Sep 17 00:00:00 2001 +From: Haoze Xie +Date: Fri, 15 May 2026 11:19:02 +0800 +Subject: netfilter: nf_queue: hold bridge skb->dev while queued + +From: Haoze Xie + +commit e196115ec330a18de415bdb9f5071aa9f08e53ce upstream. + +br_pass_frame_up() rewrites skb->dev from the ingress port to the bridge +master before queueing bridge LOCAL_IN packets. NFQUEUE only holds +references on state.in/out and bridge physdevs, so a queued bridge +packet can retain a freed bridge master in skb->dev until reinjection. + +When the verdict is reinjected later, br_netif_receive_skb() re-enters +the receive path with skb->dev still pointing at the freed bridge master, +triggering a use-after-free. + +Store skb->dev in the queue entry, hold a reference on it for the queue +lifetime, and use the saved device when dropping queued packets during +NETDEV_DOWN handling. + +Fixes: ac2863445686 ("netfilter: bridge: add nf_afinfo to enable queuing to userspace") +Cc: stable@kernel.org +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Signed-off-by: Haoze Xie +Signed-off-by: Ren Wei +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman +--- + include/net/netfilter/nf_queue.h | 1 + + net/netfilter/nf_queue.c | 4 +++- + net/netfilter/nfnetlink_queue.c | 2 ++ + 3 files changed, 6 insertions(+), 1 deletion(-) + +--- a/include/net/netfilter/nf_queue.h ++++ b/include/net/netfilter/nf_queue.h +@@ -14,6 +14,7 @@ struct nf_queue_entry { + struct list_head list; + struct rhash_head hash_node; + struct sk_buff *skb; ++ struct net_device *skb_dev; + unsigned int id; + unsigned int hook_index; /* index in hook_entries->hook[] */ + #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) +--- a/net/netfilter/nf_queue.c ++++ b/net/netfilter/nf_queue.c +@@ -60,6 +60,7 @@ static void nf_queue_entry_release_refs( + struct nf_hook_state *state = &entry->state; + + /* Release those devices we held, or Alexey will kill me. */ ++ dev_put(entry->skb_dev); + dev_put(state->in); + dev_put(state->out); + if (state->sk) +@@ -101,6 +102,7 @@ bool nf_queue_entry_get_refs(struct nf_q + if (state->sk && !refcount_inc_not_zero(&state->sk->sk_refcnt)) + return false; + ++ dev_hold(entry->skb_dev); + dev_hold(state->in); + dev_hold(state->out); + +@@ -201,11 +203,11 @@ static int __nf_queue(struct sk_buff *sk + + *entry = (struct nf_queue_entry) { + .skb = skb, ++ .skb_dev = skb->dev, + .state = *state, + .hook_index = index, + .size = sizeof(*entry) + route_key_size, + }; +- + __nf_queue_entry_init_physdevs(entry); + + if (!nf_queue_entry_get_refs(entry)) { +--- a/net/netfilter/nfnetlink_queue.c ++++ b/net/netfilter/nfnetlink_queue.c +@@ -1198,6 +1198,8 @@ dev_cmp(struct nf_queue_entry *entry, un + if (physinif == ifindex || physoutif == ifindex) + return 1; + #endif ++ if (entry->skb_dev && entry->skb_dev->ifindex == ifindex) ++ return 1; + if (entry->state.in) + if (entry->state.in->ifindex == ifindex) + return 1; diff --git a/queue-7.0/netfilter-nft_inner-fix-ipv6-inner_thoff-desync.patch b/queue-7.0/netfilter-nft_inner-fix-ipv6-inner_thoff-desync.patch new file mode 100644 index 0000000000..1003f4bd48 --- /dev/null +++ b/queue-7.0/netfilter-nft_inner-fix-ipv6-inner_thoff-desync.patch @@ -0,0 +1,53 @@ +From b6a91f68ebfed9c38e0e9150f58a9b85da07181c Mon Sep 17 00:00:00 2001 +From: Yizhou Zhao +Date: Tue, 12 May 2026 01:30:41 +0800 +Subject: netfilter: nft_inner: Fix IPv6 inner_thoff desync +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yizhou Zhao + +commit b6a91f68ebfed9c38e0e9150f58a9b85da07181c upstream. + +In nft_inner_parse_l2l3(), when processing inner IPv6 packets, +ipv6_find_hdr() correctly computes the transport header offset +traversing all extension headers, but the result is immediately +overwritten with nhoff + sizeof(_ip6h) (40 bytes), which only +accounts for the IPv6 base header. This creates a desync between +inner_thoff (wrong — points to extension header start) and l4proto +(correct — e.g., IPPROTO_TCP), enabling transport header forgery +and potential firewall bypass. This issue affects stable versions +from Linux 6.2. + +For comparison, the normal (non-inner) IPv6 path correctly +preserves ipv6_find_hdr()'s result. Removing the incorrect overwrite +ensures that ipv6_find_hdr()'s calculated transport header offset is +preserved, thereby fixing the desynchronization. + +Fixes: 3a07327d10a0 ("netfilter: nft_inner: support for inner tunnel header matching") +Cc: stable@vger.kernel.org +Reported-by: Yizhou Zhao +Reported-by: Yuxiang Yang +Reported-by: Xuewei Feng +Reported-by: Qi Li +Reported-by: Ke Xu +Assisted-by: GLM:5.1 Z.ai +Signed-off-by: Yizhou Zhao +Reviewed-by: Fernando Fernandez Mancera +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman +--- + net/netfilter/nft_inner.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/net/netfilter/nft_inner.c ++++ b/net/netfilter/nft_inner.c +@@ -163,7 +163,6 @@ static int nft_inner_parse_l2l3(const st + return -1; + + if (fragoff == 0) { +- thoff = nhoff + sizeof(_ip6h); + ctx->flags |= NFT_PAYLOAD_CTX_INNER_TH; + ctx->inner_thoff = thoff; + ctx->l4proto = l4proto; diff --git a/queue-7.0/phonet-pep-disable-bh-around-forwarded-sk_receive_skb.patch b/queue-7.0/phonet-pep-disable-bh-around-forwarded-sk_receive_skb.patch new file mode 100644 index 0000000000..ebcd6077a1 --- /dev/null +++ b/queue-7.0/phonet-pep-disable-bh-around-forwarded-sk_receive_skb.patch @@ -0,0 +1,105 @@ +From dbc81608e3a653dea6cf403f20cae35468b8ab9c Mon Sep 17 00:00:00 2001 +From: Zijing Yin +Date: Tue, 19 May 2026 10:26:33 -0700 +Subject: phonet/pep: disable BH around forwarded sk_receive_skb() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Zijing Yin + +commit dbc81608e3a653dea6cf403f20cae35468b8ab9c upstream. + +The networking receive path is usually run from softirq context, but +protocols that take the socket lock may have packets stored in the +backlog and processed later from process context. In that case +release_sock() -> __release_sock() drops the slock with spin_unlock_bh() +and then calls sk->sk_backlog_rcv() with bottom halves enabled. + +Typical sk_backlog_rcv handlers process the socket whose backlog is +being drained, so the BH state at entry is irrelevant for the slocks +they touch. pep_do_rcv() is different: when the inbound skb targets an +existing PEP pipe, it forwards the skb to a different *child* socket +via sk_receive_skb(). That helper takes the child slock with +bh_lock_sock_nested(), which is just spin_lock_nested() and assumes BH +is already off. The same child slock therefore ends up acquired with +BH on (process path) and with BH off (softirq path): + + process context softirq context + --------------- --------------- + release_sock(listener) __netif_receive_skb() + __release_sock() phonet_rcv() + spin_unlock_bh() __sk_receive_skb(listener) + [BH now ENABLED] [BH already disabled] + sk_backlog_rcv: sk_backlog_rcv: + pep_do_rcv() pep_do_rcv() + sk_receive_skb(child) sk_receive_skb(child) + bh_lock_sock_nested(child) bh_lock_sock_nested(child) + => SOFTIRQ-ON-W => IN-SOFTIRQ-W + +Lockdep flags this as inconsistent lock state, and it can become a real +self-deadlock if a softirq on the same CPU tries to receive to the same +child socket while its slock is held in the BH-enabled path: + + WARNING: inconsistent lock state + inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage. + (slock-AF_PHONET/1){+.?.}-{3:3}, at: __sk_receive_skb+0x1cf/0x900 + __sk_receive_skb net/core/sock.c:563 + sk_receive_skb include/net/sock.h:2022 [inline] + pep_do_rcv net/phonet/pep.c:675 + sk_backlog_rcv include/net/sock.h:1190 + __release_sock net/core/sock.c:3216 + release_sock net/core/sock.c:3815 + pep_sock_accept net/phonet/pep.c:879 + +Wrap the forwarded sk_receive_skb() in local_bh_disable() / +local_bh_enable() so the child slock is always acquired with BH off. +local_bh_disable() nests safely on the softirq path. + +Discovered via in-house syzkaller fuzzing; the same root cause also +on the linux-6.1.y syzbot dashboard as extid 44f0626dd6284f02663c. +Reproduced under KASAN + LOCKDEP + PROVE_LOCKING, reproducer: +https://pastebin.com/A3t8xzCR + +Fixes: 9641458d3ec4 ("Phonet: Pipe End Point for Phonet Pipes protocol") +Link: https://syzkaller.appspot.com/bug?extid=44f0626dd6284f02663c +Cc: stable@vger.kernel.org +Signed-off-by: Zijing Yin +Acked-by: Rémi Denis-Courmont +Reported-by: syzbot+9f4a135646b66c509935@syzkaller.appspotmail.com +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260519172635.86304-1-yzjaurora@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/phonet/pep.c | 19 +++++++++++++++++-- + 1 file changed, 17 insertions(+), 2 deletions(-) + +--- a/net/phonet/pep.c ++++ b/net/phonet/pep.c +@@ -671,8 +671,23 @@ static int pep_do_rcv(struct sock *sk, s + + /* Look for an existing pipe handle */ + sknode = pep_find_pipe(&pn->hlist, &dst, pipe_handle); +- if (sknode) +- return sk_receive_skb(sknode, skb, 1); ++ if (sknode) { ++ int rc; ++ ++ /* pep_do_rcv() runs from two contexts: from softirq via ++ * phonet_rcv() -> __sk_receive_skb() with BH disabled, ++ * and from process context via ++ * release_sock() -> __release_sock(), which drops ++ * the listener slock with spin_unlock_bh() before draining ++ * the backlog. The child pipe slock is taken below via ++ * bh_lock_sock_nested(), which does not itself disable BH, so ++ * disable BH here to keep both acquire contexts consistent. ++ */ ++ local_bh_disable(); ++ rc = sk_receive_skb(sknode, skb, 1); ++ local_bh_enable(); ++ return rc; ++ } + + switch (hdr->message_id) { + case PNS_PEP_CONNECT_REQ: diff --git a/queue-7.0/regulator-tps65219-fix-irq_data.rdev-not-being-assigned.patch b/queue-7.0/regulator-tps65219-fix-irq_data.rdev-not-being-assigned.patch new file mode 100644 index 0000000000..599639cec2 --- /dev/null +++ b/queue-7.0/regulator-tps65219-fix-irq_data.rdev-not-being-assigned.patch @@ -0,0 +1,231 @@ +From f9b2d3b703d13df50c630997dfdc25648e96db0d Mon Sep 17 00:00:00 2001 +From: Alexander Sverdlin +Date: Mon, 18 May 2026 10:31:11 +0200 +Subject: regulator: tps65219: fix irq_data.rdev not being assigned + +From: Alexander Sverdlin + +commit f9b2d3b703d13df50c630997dfdc25648e96db0d upstream. + +Commit 64a6b577490c ("regulator: tps65219: Remove debugging helper +function") removed the tps65219_get_rdev_by_name() helper along with +the irq_data.rdev assignment that depended on it. This left +irq_data.rdev uninitialized for all IRQs, causing undefined behavior +when regulator_notifier_call_chain() is called from the IRQ handler: + + Internal error: Oops: 0000000096000004 + pc : regulator_notifier_call_chain + lr : tps65219_regulator_irq_handler + Call trace: + regulator_notifier_call_chain + tps65219_regulator_irq_handler + handle_nested_irq + regmap_irq_thread + irq_thread_fn + irq_thread + kthread + ret_from_fork + +Instead of restoring a dedicated lookup array, restructure the probe +function to combine regulator registration with IRQ registration in +the same loop. This way the rdev returned by devm_regulator_register() +is naturally available for assigning to irq_data.rdev without any +auxiliary data structure. + +Non-regulator IRQs (SENSOR, TIMEOUT) that don't correspond to any +registered regulator are registered with rdev=NULL, and the IRQ handler +is protected with a NULL check to avoid crashing. + +Cc: stable@vger.kernel.org +Closes: https://lore.kernel.org/all/aBDSTxALaOc-PD7X@gaggiata.pivistrello.it/ +Reported-by: Francesco Dolcini +Fixes: 64a6b577490c ("regulator: tps65219: Remove debugging helper function") +Signed-off-by: Alexander Sverdlin +Link: https://patch.msgid.link/20260518083113.2063368-1-alexander.sverdlin@siemens.com +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman +--- + drivers/regulator/tps65219-regulator.c | 135 +++++++++++++++++++++++---------- + 1 file changed, 95 insertions(+), 40 deletions(-) + +--- a/drivers/regulator/tps65219-regulator.c ++++ b/drivers/regulator/tps65219-regulator.c +@@ -346,8 +346,9 @@ static irqreturn_t tps65219_regulator_ir + return IRQ_HANDLED; + } + +- regulator_notifier_call_chain(irq_data->rdev, +- irq_data->type->event, NULL); ++ if (irq_data->rdev) ++ regulator_notifier_call_chain(irq_data->rdev, ++ irq_data->type->event, NULL); + + dev_err(irq_data->dev, "Error IRQ trap %s for %s\n", + irq_data->type->event_name, irq_data->type->regulator_name); +@@ -398,14 +399,65 @@ static struct tps65219_chip_data chip_in + }, + }; + +-static int tps65219_regulator_probe(struct platform_device *pdev) ++static bool tps65219_is_regulator_name(const struct tps65219_chip_data *pmic, ++ const char *name) ++{ ++ int i; ++ ++ for (i = 0; i < pmic->common_rdesc_size; i++) ++ if (!strcmp(pmic->common_rdesc[i].name, name)) ++ return true; ++ for (i = 0; i < pmic->rdesc_size; i++) ++ if (!strcmp(pmic->rdesc[i].name, name)) ++ return true; ++ return false; ++} ++ ++static int tps65219_register_irqs(struct platform_device *pdev, ++ struct tps65219 *tps, ++ struct regulator_dev *rdev, ++ struct tps65219_regulator_irq_type *irq_types, ++ int nirqs, ++ const char *regulator_name) + { + struct tps65219_regulator_irq_data *irq_data; ++ int i, irq, error; ++ ++ for (i = 0; i < nirqs; i++) { ++ if (strcmp(irq_types[i].regulator_name, regulator_name)) ++ continue; ++ ++ irq = platform_get_irq_byname(pdev, irq_types[i].irq_name); ++ if (irq < 0) ++ return -EINVAL; ++ ++ irq_data = devm_kmalloc(tps->dev, sizeof(*irq_data), GFP_KERNEL); ++ if (!irq_data) ++ return -ENOMEM; ++ ++ irq_data->dev = tps->dev; ++ irq_data->type = &irq_types[i]; ++ irq_data->rdev = rdev; ++ ++ error = devm_request_threaded_irq(tps->dev, irq, NULL, ++ tps65219_regulator_irq_handler, ++ IRQF_ONESHOT, ++ irq_types[i].irq_name, ++ irq_data); ++ if (error) ++ return dev_err_probe(tps->dev, error, ++ "Failed to request %s IRQ %d\n", ++ irq_types[i].irq_name, irq); ++ } ++ return 0; ++} ++ ++static int tps65219_regulator_probe(struct platform_device *pdev) ++{ + struct tps65219_regulator_irq_type *irq_type; + struct tps65219_chip_data *pmic; + struct regulator_dev *rdev; + int error; +- int irq; + int i; + + struct tps65219 *tps = dev_get_drvdata(pdev->dev.parent); +@@ -425,6 +477,19 @@ static int tps65219_regulator_probe(stru + return dev_err_probe(tps->dev, PTR_ERR(rdev), + "Failed to register %s regulator\n", + pmic->common_rdesc[i].name); ++ ++ error = tps65219_register_irqs(pdev, tps, rdev, ++ pmic->common_irq_types, ++ pmic->common_irq_size, ++ pmic->common_rdesc[i].name); ++ if (error) ++ return error; ++ error = tps65219_register_irqs(pdev, tps, rdev, ++ pmic->irq_types, ++ pmic->dev_irq_size, ++ pmic->common_rdesc[i].name); ++ if (error) ++ return error; + } + + for (i = 0; i < pmic->rdesc_size; i++) { +@@ -434,52 +499,42 @@ static int tps65219_regulator_probe(stru + return dev_err_probe(tps->dev, PTR_ERR(rdev), + "Failed to register %s regulator\n", + pmic->rdesc[i].name); ++ ++ error = tps65219_register_irqs(pdev, tps, rdev, ++ pmic->common_irq_types, ++ pmic->common_irq_size, ++ pmic->rdesc[i].name); ++ if (error) ++ return error; ++ error = tps65219_register_irqs(pdev, tps, rdev, ++ pmic->irq_types, ++ pmic->dev_irq_size, ++ pmic->rdesc[i].name); ++ if (error) ++ return error; + } + ++ /* Register non-regulator IRQs (TIMEOUT, SENSOR) with rdev=NULL */ + for (i = 0; i < pmic->common_irq_size; ++i) { + irq_type = &pmic->common_irq_types[i]; +- irq = platform_get_irq_byname(pdev, irq_type->irq_name); +- if (irq < 0) +- return -EINVAL; +- +- irq_data = devm_kmalloc(tps->dev, sizeof(*irq_data), GFP_KERNEL); +- if (!irq_data) +- return -ENOMEM; +- +- irq_data->dev = tps->dev; +- irq_data->type = irq_type; +- error = devm_request_threaded_irq(tps->dev, irq, NULL, +- tps65219_regulator_irq_handler, +- IRQF_ONESHOT, +- irq_type->irq_name, +- irq_data); ++ if (tps65219_is_regulator_name(pmic, irq_type->regulator_name)) ++ continue; ++ error = tps65219_register_irqs(pdev, tps, NULL, ++ irq_type, 1, ++ irq_type->regulator_name); + if (error) +- return dev_err_probe(tps->dev, error, +- "Failed to request %s IRQ %d\n", +- irq_type->irq_name, irq); ++ return error; + } + + for (i = 0; i < pmic->dev_irq_size; ++i) { + irq_type = &pmic->irq_types[i]; +- irq = platform_get_irq_byname(pdev, irq_type->irq_name); +- if (irq < 0) +- return -EINVAL; +- +- irq_data = devm_kmalloc(tps->dev, sizeof(*irq_data), GFP_KERNEL); +- if (!irq_data) +- return -ENOMEM; +- +- irq_data->dev = tps->dev; +- irq_data->type = irq_type; +- error = devm_request_threaded_irq(tps->dev, irq, NULL, +- tps65219_regulator_irq_handler, +- IRQF_ONESHOT, +- irq_type->irq_name, +- irq_data); ++ if (tps65219_is_regulator_name(pmic, irq_type->regulator_name)) ++ continue; ++ error = tps65219_register_irqs(pdev, tps, NULL, ++ irq_type, 1, ++ irq_type->regulator_name); + if (error) +- return dev_err_probe(tps->dev, error, +- "Failed to request %s IRQ %d\n", +- irq_type->irq_name, irq); ++ return error; + } + + return 0; diff --git a/queue-7.0/scripts-gdb-mm-cast-untyped-symbols-in-x86_page_ops.patch b/queue-7.0/scripts-gdb-mm-cast-untyped-symbols-in-x86_page_ops.patch new file mode 100644 index 0000000000..588e60e67a --- /dev/null +++ b/queue-7.0/scripts-gdb-mm-cast-untyped-symbols-in-x86_page_ops.patch @@ -0,0 +1,53 @@ +From c416aee7e7d04fec2d2d30786b3c8393108b85d2 Mon Sep 17 00:00:00 2001 +From: Illia Ostapyshyn +Date: Mon, 27 Apr 2026 16:24:47 +0200 +Subject: scripts/gdb: mm: cast untyped symbols in x86_page_ops + +From: Illia Ostapyshyn + +commit c416aee7e7d04fec2d2d30786b3c8393108b85d2 upstream. + +The symbols phys_base, _text, and _end, used in x86_page_ops are either +defined in assembly or implicitly by the linker. Thus, they lack type +information and cause a conversion error after gdb.parse_and_eval. +Explicitly cast these expressions to unsigned long. + +Link: https://lore.kernel.org/20260427142448.666117-2-illia@yshyn.com +Fixes: 55f8b4518d14 ("scripts/gdb: implement x86_page_ops in mm.py") +Signed-off-by: Illia Ostapyshyn +Cc: Florian Fainelli +Cc: Jan Kiszka +Cc: Kieran Bingham +Cc: Vlastimil Babka +Cc: Hao Li +Cc: Harry Yoo +Cc: Seongjun Hong +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + scripts/gdb/linux/mm.py | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/scripts/gdb/linux/mm.py b/scripts/gdb/linux/mm.py +index d78908f6664d..dffadccbb01d 100644 +--- a/scripts/gdb/linux/mm.py ++++ b/scripts/gdb/linux/mm.py +@@ -40,11 +40,11 @@ class x86_page_ops(): + + self.PAGE_OFFSET = int(gdb.parse_and_eval("page_offset_base")) + self.VMEMMAP_START = int(gdb.parse_and_eval("vmemmap_base")) +- self.PHYS_BASE = int(gdb.parse_and_eval("phys_base")) ++ self.PHYS_BASE = int(gdb.parse_and_eval("(unsigned long) phys_base")) + self.START_KERNEL_map = 0xffffffff80000000 + +- self.KERNEL_START = gdb.parse_and_eval("_text") +- self.KERNEL_END = gdb.parse_and_eval("_end") ++ self.KERNEL_START = gdb.parse_and_eval("(unsigned long) &_text") ++ self.KERNEL_END = gdb.parse_and_eval("(unsigned long) &_end") + + self.VMALLOC_START = int(gdb.parse_and_eval("vmalloc_base")) + if self.VMALLOC_START == 0xffffc90000000000: +-- +2.54.0 + diff --git a/queue-7.0/selftests-mm-run_vmtests.sh-fix-destructive-tests-invocation.patch b/queue-7.0/selftests-mm-run_vmtests.sh-fix-destructive-tests-invocation.patch new file mode 100644 index 0000000000..ff285a16e0 --- /dev/null +++ b/queue-7.0/selftests-mm-run_vmtests.sh-fix-destructive-tests-invocation.patch @@ -0,0 +1,43 @@ +From 3432cbb291aabf85f8af4b9d1ec37179168ff999 Mon Sep 17 00:00:00 2001 +From: Luiz Capitulino +Date: Mon, 27 Apr 2026 12:03:51 -0400 +Subject: selftests/mm: run_vmtests.sh: fix destructive tests invocation + +From: Luiz Capitulino + +commit 3432cbb291aabf85f8af4b9d1ec37179168ff999 upstream. + +Destructive tests should be invoked with -d command-line option, but this +won't work today since 'd' is missing in getopts command-line. This +commit fixes it. + +Link: https://lore.kernel.org/214fd9e4-5398-4c26-859e-c982c2e277c3@redhat.com +Fixes: f16ff3b692ad ("selftests/mm: run_vmtests.sh: add missing tests") +Signed-off-by: Luiz Capitulino +Reviewed-by: Mike Rapoport (Microsoft) +Reviewed-by: SeongJae Park +Cc: David Hildenbrand +Cc: Liam R. Howlett +Cc: Lorenzo Stoakes +Cc: Michal Hocko +Cc: Shuah Khan +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + tools/testing/selftests/mm/run_vmtests.sh | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/tools/testing/selftests/mm/run_vmtests.sh ++++ b/tools/testing/selftests/mm/run_vmtests.sh +@@ -103,7 +103,7 @@ RUN_ALL=false + RUN_DESTRUCTIVE=false + TAP_PREFIX="# " + +-while getopts "aht:n" OPT; do ++while getopts "aht:nd" OPT; do + case ${OPT} in + "a") RUN_ALL=true ;; + "h") usage ;; diff --git a/queue-7.0/series b/queue-7.0/series index 9fe8187878..d1ac4a4cb4 100644 --- a/queue-7.0/series +++ b/queue-7.0/series @@ -6,3 +6,55 @@ ata-libata-scsi-improve-readability-of-ata_scsi_qc_issue.patch ata-libata-scsi-do-not-use-the-deferred-qc-feature-for-ata_defer_port.patch ata-libata-scsi-do-not-use-the-deferred-qc-feature-on-pmps-with-cbs.patch ata-libata-scsi-do-not-needlessly-defer-commands-when-using-pmp-with-fbs.patch +sysfs-don-t-remove-existing-directory-on-update-failure.patch +mm-damon-sysfs-schemes-call-missing-mem_cgroup_iter_break.patch +ksmbd-fix-null-pointer-dereference-in-compare_guid_key.patch +ksmbd-fix-null-pointer-dereference-in-proc_show_files.patch +ksmbd-fix-sid-memory-leak-in-set_posix_acl_entries_dacl-on-overflow.patch +ksmbd-validate-sid-in-parent-security-descriptor-during-acl-inheritance.patch +regulator-tps65219-fix-irq_data.rdev-not-being-assigned.patch +x86-mm-disable-broadcast-tlb-flush-when-pcid-is-disabled.patch +scripts-gdb-mm-cast-untyped-symbols-in-x86_page_ops.patch +smb-client-require-net-admin-for-cifs-swn-netlink.patch +smb-client-protect-tc_count-increment-in-smb2_find_smb_sess_tcon_unlocked.patch +smb-client-use-data_len-for-smb2-read-encrypted-folioq-copy.patch +smb-server-promote-s_del_on_cls-to-s_del_pending-when-close.patch +hwmon-pmbus-adm1266-widen-blackbox-info-buffer-to-i2c_smbus_block_max.patch +alsa-ua101-reject-too-short-usb-descriptors.patch +alsa-pcm-don-t-setup-bogus-iov_iter-for-silencing.patch +alsa-asihpi-fix-potential-oob-array-access-at-reading-cache.patch +alsa-scarlett2-allow-flash-writes-ending-at-segment-boundary.patch +acpi-battery-fix-system-wakeup-on-critical-battery-status.patch +efi-allocate-runtime-workqueue-before-acpi-init.patch +spi-amd-set-correct-bus-number-in-acpi-probe-path.patch +io_uring-waitid-clear-waitid-info-before-copying-it-to-userspace.patch +drivers-base-memory-fix-memory-block-reference-leak-in-poison-accounting.patch +ipv6-ioam-refresh-hdr-pointer-before-ioam6_event.patch +mm-memory-fix-spurious-warning-when-unmapping-device-private-exclusive-pages.patch +mm-fix-__vm_normal_page-to-handle-missing-support-for-pmd_special-pud_special.patch +mm-memory_hotplug-fix-memory-block-reference-leak-on-remove.patch +mm-page_alloc-fix-initialization-of-tags-of-the-huge-zero-folio-with-init_on_free.patch +mm-migrate_device-fix-spinlock-leak-in-migrate_vma_insert_huge_pmd_page.patch +selftests-mm-run_vmtests.sh-fix-destructive-tests-invocation.patch +mm-damon-fix-damos_stat-tracepoint-format-for-sz_applied.patch +net-wwan-iosm-fix-potential-memory-leaks-in-ipc_imem_init.patch +bluetooth-fix-uaf-in-l2cap_sock_cleanup_listen-vs-l2cap_conn_del.patch +bluetooth-iso-drop-iso_end-frames-received-without-prior-iso_start.patch +bluetooth-bnep-fix-uaf-read-of-dev-name.patch +bluetooth-hci_uart-fix-uafs-and-race-conditions-in-close-and-init-paths.patch +bluetooth-l2cap-ecred_reconfigure-send-packed-pdu-not-stack-pointer.patch +bluetooth-hci_qca-convert-timeout-from-jiffies-to-ms.patch +bluetooth-mgmt-validate-add-extended-advertising-data-length.patch +bluetooth-serialize-accept_q-access.patch +phonet-pep-disable-bh-around-forwarded-sk_receive_skb.patch +net-bcmgenet-keep-rbuf-eee-pm-disabled.patch +net-devmem-reject-dma-buf-bind-with-non-page-aligned-size-or-sg-length.patch +net-phy-skip-eee-advertisement-write-when-autoneg-is-disabled.patch +net-hsr-defer-node-table-free-until-after-rcu-readers.patch +net-mlx5e-fix-use-after-free-in-mlx5e_tx_reporter_timeout_recover.patch +net-ifb-report-ethtool-stats-over-num_tx_queues.patch +net-pse-pd-fix-sign-on-enoent-check-in-of_load_pse_pis.patch +netfilter-ip6t_hbh-reject-oversized-option-lists.patch +netfilter-nf_queue-hold-bridge-skb-dev-while-queued.patch +netfilter-ipset-stop-hash-range-iteration-at-end.patch +netfilter-nft_inner-fix-ipv6-inner_thoff-desync.patch diff --git a/queue-7.0/smb-client-protect-tc_count-increment-in-smb2_find_smb_sess_tcon_unlocked.patch b/queue-7.0/smb-client-protect-tc_count-increment-in-smb2_find_smb_sess_tcon_unlocked.patch new file mode 100644 index 0000000000..00fa6b22f7 --- /dev/null +++ b/queue-7.0/smb-client-protect-tc_count-increment-in-smb2_find_smb_sess_tcon_unlocked.patch @@ -0,0 +1,38 @@ +From 4d8690dace005a38e6dbde9ecce2da3ad85c7c41 Mon Sep 17 00:00:00 2001 +From: Henrique Carvalho +Date: Thu, 14 May 2026 20:18:25 -0300 +Subject: smb: client: protect tc_count increment in smb2_find_smb_sess_tcon_unlocked() + +From: Henrique Carvalho + +commit 4d8690dace005a38e6dbde9ecce2da3ad85c7c41 upstream. + +Commit 96c4af418586 ("cifs: Fix locking usage for tcon fields") +refactored cifs code to change cifs_tcp_ses_lock for tc_lock around +tc_count changes. + +There was missing lock around tc_count increment inside +smb2_find_smb_sess_tcon_unlocked(). + +Cc: stable@vger.kernel.org +Fixes: 96c4af418586 ("cifs: Fix locking usage for tcon fields") +Reviewed-by: Shyam Prasad N +Signed-off-by: Henrique Carvalho +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/client/smb2transport.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/fs/smb/client/smb2transport.c ++++ b/fs/smb/client/smb2transport.c +@@ -176,7 +176,9 @@ smb2_find_smb_sess_tcon_unlocked(struct + list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { + if (tcon->tid != tid) + continue; ++ spin_lock(&tcon->tc_lock); + ++tcon->tc_count; ++ spin_unlock(&tcon->tc_lock); + trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count, + netfs_trace_tcon_ref_get_find_sess_tcon); + return tcon; diff --git a/queue-7.0/smb-client-require-net-admin-for-cifs-swn-netlink.patch b/queue-7.0/smb-client-require-net-admin-for-cifs-swn-netlink.patch new file mode 100644 index 0000000000..109e19fae4 --- /dev/null +++ b/queue-7.0/smb-client-require-net-admin-for-cifs-swn-netlink.patch @@ -0,0 +1,58 @@ +From d1ebfce2c1d161186a82e77590bf7da2ea1bce91 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Sun, 17 May 2026 20:11:50 -0400 +Subject: smb: client: require net admin for CIFS SWN netlink + +From: Michael Bommarito + +commit d1ebfce2c1d161186a82e77590bf7da2ea1bce91 upstream. + +CIFS_GENL_CMD_SWN_NOTIFY is the userspace witness-notify command. The +intended sender is the cifs.witness helper, but the generic-netlink +operation currently has no capability flag, so any local process can send +RESOURCE_CHANGE or CLIENT_MOVE notifications to the in-kernel witness +handler. + +The same family exposes CIFS_GENL_MCGRP_SWN without multicast-group +capability flags. Register messages sent to that group include the witness +registration id and, for NTLM-authenticated mounts, the username, domain, +and password attributes copied from the CIFS session. An unprivileged +local process should not be able to join that group and receive those +messages. + +Require CAP_NET_ADMIN for incoming SWN_NOTIFY commands with +GENL_ADMIN_PERM, and require CAP_NET_ADMIN over the network namespace for +joining the SWN multicast group with GENL_MCAST_CAP_NET_ADMIN. The +cifs.witness service runs with the privileges needed for both operations. + +Fixes: fed979a7e082 ("cifs: Set witness notification handler for messages from userspace daemon") +Cc: stable@vger.kernel.org +Signed-off-by: Michael Bommarito +Assisted-by: Claude:claude-opus-4-7 +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/client/netlink.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/fs/smb/client/netlink.c ++++ b/fs/smb/client/netlink.c +@@ -33,13 +33,17 @@ static const struct nla_policy cifs_genl + static const struct genl_ops cifs_genl_ops[] = { + { + .cmd = CIFS_GENL_CMD_SWN_NOTIFY, ++ .flags = GENL_ADMIN_PERM, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = cifs_swn_notify, + }, + }; + + static const struct genl_multicast_group cifs_genl_mcgrps[] = { +- [CIFS_GENL_MCGRP_SWN] = { .name = CIFS_GENL_MCGRP_SWN_NAME }, ++ [CIFS_GENL_MCGRP_SWN] = { ++ .name = CIFS_GENL_MCGRP_SWN_NAME, ++ .flags = GENL_MCAST_CAP_NET_ADMIN, ++ }, + }; + + struct genl_family cifs_genl_family = { diff --git a/queue-7.0/smb-client-use-data_len-for-smb2-read-encrypted-folioq-copy.patch b/queue-7.0/smb-client-use-data_len-for-smb2-read-encrypted-folioq-copy.patch new file mode 100644 index 0000000000..87cbe69e81 --- /dev/null +++ b/queue-7.0/smb-client-use-data_len-for-smb2-read-encrypted-folioq-copy.patch @@ -0,0 +1,79 @@ +From d4d76c9ee1997cc8c977a63f6c43551c253c1066 Mon Sep 17 00:00:00 2001 +From: Jeremy Erazo +Date: Fri, 15 May 2026 19:31:41 +0000 +Subject: smb: client: use data_len for SMB2 READ encrypted folioq copy + +From: Jeremy Erazo + +commit d4d76c9ee1997cc8c977a63f6c43551c253c1066 upstream. + +In handle_read_data() the encrypted/folioq branch +(buf_len <= data_offset, reached via receive_encrypted_read for +transform PDUs > CIFSMaxBufSize + MAX_HEADER_SIZE) copies the READ +payload using buffer_len rather than data_len: + + rdata->result = cifs_copy_folioq_to_iter(buffer, buffer_len, + cur_off, + &rdata->subreq.io_iter); + ... + rdata->got_bytes = buffer_len; + +buffer_len comes from the SMB3 transform header OriginalMessageSize +field (OriginalMessageSize - read_rsp_size); it represents the size +of the decrypted message after the SMB2 header. data_len comes from +the SMB2 READ response DataLength field; it represents the actual +READ payload size and may be smaller than buffer_len when the +decrypted message contains padding or other trailing bytes after the +READ payload. The existing check `data_len > buffer_len - pad_len` +only enforces an upper bound, so a server that emits +OriginalMessageSize larger than read_rsp_size + pad_len + data_len +passes the check and the kernel copies buffer_len bytes per response, +ignoring the server-asserted DataLength. + +Two observable failures with a crafted server (DataLength=4, +buffer_len=20000): + + - the kernel returns 20000 bytes per sub-request to userspace and + sets got_bytes = buffer_len, even though the response claimed + only 4 bytes of payload; + + - on a partial netfs sub-request whose iterator is sized to + data_len, the over-large copy_folio_to_iter() short-reads, + cifs_copy_folioq_to_iter() returns -EIO via the n != len path, + and the entire netfs read collapses to -EIO even though the + leading sub-requests succeeded. + +Use data_len for the copy length and for got_bytes so the kernel +honours the server-asserted READ payload size. For well-formed +servers (where buffer_len == pad_len + data_len) the change is +behaviour-equivalent. + +Cc: stable@vger.kernel.org +Signed-off-by: Jeremy Erazo +Acked-by: David Howells +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/client/smb2ops.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/fs/smb/client/smb2ops.c ++++ b/fs/smb/client/smb2ops.c +@@ -4825,7 +4825,7 @@ handle_read_data(struct TCP_Server_Info + } + + /* Copy the data to the output I/O iterator. */ +- rdata->result = cifs_copy_folioq_to_iter(buffer, buffer_len, ++ rdata->result = cifs_copy_folioq_to_iter(buffer, data_len, + cur_off, &rdata->subreq.io_iter); + if (rdata->result != 0) { + if (is_offloaded) +@@ -4834,7 +4834,7 @@ handle_read_data(struct TCP_Server_Info + dequeue_mid(server, mid, rdata->result); + return 0; + } +- rdata->got_bytes = buffer_len; ++ rdata->got_bytes = data_len; + + } else if (buf_len >= data_offset + data_len) { + /* read response payload is in buf */ diff --git a/queue-7.0/smb-server-promote-s_del_on_cls-to-s_del_pending-when-close.patch b/queue-7.0/smb-server-promote-s_del_on_cls-to-s_del_pending-when-close.patch new file mode 100644 index 0000000000..47660c516c --- /dev/null +++ b/queue-7.0/smb-server-promote-s_del_on_cls-to-s_del_pending-when-close.patch @@ -0,0 +1,76 @@ +From 4ec9c8e023c79f613fe4d5ad8cc737112efb2e44 Mon Sep 17 00:00:00 2001 +From: ChenXiaoSong +Date: Mon, 18 May 2026 15:23:22 +0000 +Subject: smb/server: promote S_DEL_ON_CLS to S_DEL_PENDING when close + +From: ChenXiaoSong + +commit 4ec9c8e023c79f613fe4d5ad8cc737112efb2e44 upstream. + +Reproducer: + + 1. server: systemctl start ksmbd + 2. client: mount -t cifs //${server_ip}/export /mnt + 3. client: C program: openat(AT_FDCWD, "/mnt", O_RDWR | O_TMPFILE, 0600) + +Do not treat `FILE_DELETE_ON_CLOSE_LE` as delete pending while files +remain open. + +This patch fixes xfstests generic/004. + +Cc: stable@vger.kernel.org +Link: https://chenxiaosong.com/en/smb-xfstests-generic-004.html +Co-developed-by: Huiwen He +Signed-off-by: Huiwen He +Signed-off-by: ChenXiaoSong +Tested-by: Steve French +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/server/vfs_cache.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +--- a/fs/smb/server/vfs_cache.c ++++ b/fs/smb/server/vfs_cache.c +@@ -211,7 +211,7 @@ int ksmbd_query_inode_status(struct dent + return ret; + + down_read(&ci->m_lock); +- if (ci->m_flags & (S_DEL_PENDING | S_DEL_ON_CLS)) ++ if (ci->m_flags & S_DEL_PENDING) + ret = KSMBD_INODE_STATUS_PENDING_DELETE; + else + ret = KSMBD_INODE_STATUS_OK; +@@ -227,7 +227,7 @@ bool ksmbd_inode_pending_delete(struct k + int ret; + + down_read(&ci->m_lock); +- ret = (ci->m_flags & (S_DEL_PENDING | S_DEL_ON_CLS)); ++ ret = (ci->m_flags & S_DEL_PENDING); + up_read(&ci->m_lock); + + return ret; +@@ -395,12 +395,20 @@ static void __ksmbd_inode_close(struct k + } + } + ++ down_write(&ci->m_lock); ++ /* Promote S_DEL_ON_CLS to S_DEL_PENDING when close */ ++ if (ci->m_flags & S_DEL_ON_CLS) { ++ ci->m_flags &= ~S_DEL_ON_CLS; ++ ci->m_flags |= S_DEL_PENDING; ++ } ++ up_write(&ci->m_lock); ++ + if (atomic_dec_and_test(&ci->m_count)) { + bool do_unlink = false; + + down_write(&ci->m_lock); +- if (ci->m_flags & (S_DEL_ON_CLS | S_DEL_PENDING)) { +- ci->m_flags &= ~(S_DEL_ON_CLS | S_DEL_PENDING); ++ if (ci->m_flags & S_DEL_PENDING) { ++ ci->m_flags &= ~S_DEL_PENDING; + do_unlink = true; + } + up_write(&ci->m_lock); diff --git a/queue-7.0/spi-amd-set-correct-bus-number-in-acpi-probe-path.patch b/queue-7.0/spi-amd-set-correct-bus-number-in-acpi-probe-path.patch new file mode 100644 index 0000000000..b1c24ff8d0 --- /dev/null +++ b/queue-7.0/spi-amd-set-correct-bus-number-in-acpi-probe-path.patch @@ -0,0 +1,38 @@ +From 422bd00b71ab42163aa3b8f8370276fe4c1581e7 Mon Sep 17 00:00:00 2001 +From: Krishnamoorthi M +Date: Thu, 7 May 2026 23:30:51 +0530 +Subject: spi: amd: Set correct bus number in ACPI probe path + +From: Krishnamoorthi M + +commit 422bd00b71ab42163aa3b8f8370276fe4c1581e7 upstream. + +On platforms where the HID2 SPI controller (AMDI0063) is enumerated via +ACPI instead of PCI, amd_spi_probe() unconditionally sets bus_num to 0, +while the PCI probe path assigns bus_num 2 for HID2 controller. + +Align the ACPI probe path to use the same bus number so that userspace +and SPI client drivers see a consistent bus assignment regardless of the +enumeration method. + +Fixes: b644c2776652 ("spi: spi_amd: Add PCI-based driver for AMD HID2 SPI controller") +Cc: stable@vger.kernel.org # v6.16+ +Signed-off-by: Krishnamoorthi M +Link: https://patch.msgid.link/20260507180051.4158674-1-krishnamoorthi.m@amd.com +Signed-off-by: Mark Brown +Signed-off-by: Greg Kroah-Hartman +--- + drivers/spi/spi-amd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/spi/spi-amd.c ++++ b/drivers/spi/spi-amd.c +@@ -868,7 +868,7 @@ static int amd_spi_probe(struct platform + dev_dbg(dev, "io_remap_address: %p\n", amd_spi->io_remap_addr); + + amd_spi->version = (uintptr_t)device_get_match_data(dev); +- host->bus_num = 0; ++ host->bus_num = (amd_spi->version == AMD_HID2_SPI) ? 2 : 0; + + return amd_spi_probe_common(dev, host); + } diff --git a/queue-7.0/sysfs-don-t-remove-existing-directory-on-update-failure.patch b/queue-7.0/sysfs-don-t-remove-existing-directory-on-update-failure.patch new file mode 100644 index 0000000000..c1609637c8 --- /dev/null +++ b/queue-7.0/sysfs-don-t-remove-existing-directory-on-update-failure.patch @@ -0,0 +1,43 @@ +From 237557b8a81ab948e8332f7c0058e758f081c0a3 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman +Date: Wed, 20 May 2026 15:05:04 +0200 +Subject: sysfs: don't remove existing directory on update failure + +From: Greg Kroah-Hartman + +commit 237557b8a81ab948e8332f7c0058e758f081c0a3 upstream. + +When sysfs_update_group() is called for a named group and create_files() +fails (e.g. -ENOMEM), internal_create_group() calls kernfs_remove(kn) on +the group directory. In the update path, kn was obtained via +kernfs_find_and_get() and refers to a directory that already existed +before this call. Removing it silently destroys a sysfs group that the +caller did not create. + +Only remove the directory if we created it ourselves. On update failure +the directory remains as it is left empty by remove_files() inside +create_files(), but can be repopulated by a retry. + +Cc: Rajat Jain +Fixes: c855cf2759d2 ("sysfs: Fix internal_create_group() for named group updates") +Cc: stable +Assisted-by: gkh_clanker_t1000 +Reviewed-by: Rafael J. Wysocki (Intel) +Reviewed-by: Danilo Krummrich +Link: https://patch.msgid.link/2026052003-uniquely-hastily-c093@gregkh +Signed-off-by: Greg Kroah-Hartman +--- + fs/sysfs/group.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/sysfs/group.c ++++ b/fs/sysfs/group.c +@@ -188,7 +188,7 @@ static int internal_create_group(struct + kernfs_get(kn); + error = create_files(kn, kobj, uid, gid, grp, update); + if (error) { +- if (grp->name) ++ if (grp->name && !update) + kernfs_remove(kn); + } + kernfs_put(kn); diff --git a/queue-7.0/x86-mm-disable-broadcast-tlb-flush-when-pcid-is-disabled.patch b/queue-7.0/x86-mm-disable-broadcast-tlb-flush-when-pcid-is-disabled.patch new file mode 100644 index 0000000000..316d552a70 --- /dev/null +++ b/queue-7.0/x86-mm-disable-broadcast-tlb-flush-when-pcid-is-disabled.patch @@ -0,0 +1,68 @@ +From 44126343d58c68adaa8343fbf1c07dd20078c35e Mon Sep 17 00:00:00 2001 +From: Tom Lendacky +Date: Wed, 20 May 2026 12:00:50 -0500 +Subject: x86/mm: Disable broadcast TLB flush when PCID is disabled + +From: Tom Lendacky + +commit 44126343d58c68adaa8343fbf1c07dd20078c35e upstream. + +Booting with "nopcid" clears X86_FEATURE_PCID and keeps CR4.PCIDE from being +set to one. On AMD CPUs that support INVLPGB, broadcast TLB flushing remains +enabled. + +There are two checks that decide whether the global ASID code runs, +mm_global_asid() and consider_global_asid(), that key off of the +X86_FEATURE_INVLPGB feature. Once an mm becomes active on more than three +CPUs, consider_global_asid() assigns it a global ASID, after which +flush_tlb_mm_range() takes the broadcast_tlb_flush() path using a non-zero +PCID. Issuing an INVLPGB with a non-zero PCID while CR4.PCIDE is not set +results in a #GP: + + Oops: general protection fault, kernel NULL pointer dereference 0x1: 0000 [#1] SMP NOPTI + CPU: 158 UID: 0 PID: 3119 Comm: snap Not tainted 7.1.0-rc3 #1 PREEMPT(full) + Hardware name: ... + RIP: 0010:broadcast_tlb_flush + Code: ... 89 da 48 83 c8 07 <0f> 01 fe eb 08 cc cc cc ... + Call Trace: + + flush_tlb_mm_range + ptep_clear_flush + wp_page_copy + ? _raw_spin_unlock + __handle_mm_fault + handle_mm_fault + do_user_addr_fault + exc_page_fault + asm_exc_page_fault + +All processors that support broadcast TLB invalidation also have PCID support, +so it is only the "nopcid" scenario that is of concern. In this situation just +disable the broadcast TLB support using the CPUID dependency support by making +X86_FEATURE_INVLPGB dependent on X86_FEATURE_PCID. + + [ bp: Massage commit message. ] + +Fixes: 4afeb0ed1753 ("x86/mm: Enable broadcast TLB invalidation for multi-threaded processes") +Suggested-by: Dave Hansen +Assisted-by: Claude:claude-opus-4.7 +Signed-off-by: Tom Lendacky +Signed-off-by: Borislav Petkov (AMD) +Acked-by: Rik van Riel +Cc: +Link: https://patch.msgid.link/b915acfd63e8b2a094fdeb8dc608738072518764.1779296450.git.thomas.lendacky@amd.com +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/cpu/cpuid-deps.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/x86/kernel/cpu/cpuid-deps.c ++++ b/arch/x86/kernel/cpu/cpuid-deps.c +@@ -92,6 +92,7 @@ static const struct cpuid_dep cpuid_deps + { X86_FEATURE_FRED, X86_FEATURE_LKGS }, + { X86_FEATURE_SPEC_CTRL_SSBD, X86_FEATURE_SPEC_CTRL }, + { X86_FEATURE_LASS, X86_FEATURE_SMAP }, ++ { X86_FEATURE_INVLPGB, X86_FEATURE_PCID }, + {} + }; +