From: Greg Kroah-Hartman Date: Thu, 28 May 2026 08:46:20 +0000 (+0200) Subject: 6.6-stable patches X-Git-Tag: v5.10.258~43 X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=5b28c01138a16c145714bbf18cdacfafd5f6b707;p=thirdparty%2Fkernel%2Fstable-queue.git 6.6-stable patches added patches: alsa-asihpi-fix-potential-oob-array-access-at-reading-cache.patch alsa-pcm-don-t-setup-bogus-iov_iter-for-silencing.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_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-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 ksmbd-fix-null-pointer-dereference-in-compare_guid_key.patch ksmbd-fix-sid-memory-leak-in-set_posix_acl_entries_dacl-on-overflow.patch mm-damon-sysfs-schemes-call-missing-mem_cgroup_iter_break.patch net-bcmgenet-keep-rbuf-eee-pm-disabled.patch net-ifb-report-ethtool-stats-over-num_tx_queues.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 smb-client-protect-tc_count-increment-in-smb2_find_smb_sess_tcon_unlocked.patch smb-server-promote-s_del_on_cls-to-s_del_pending-when-close.patch sysfs-don-t-remove-existing-directory-on-update-failure.patch --- diff --git a/queue-6.6/alsa-asihpi-fix-potential-oob-array-access-at-reading-cache.patch b/queue-6.6/alsa-asihpi-fix-potential-oob-array-access-at-reading-cache.patch new file mode 100644 index 0000000000..c6877a4a2b --- /dev/null +++ b/queue-6.6/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-6.6/alsa-pcm-don-t-setup-bogus-iov_iter-for-silencing.patch b/queue-6.6/alsa-pcm-don-t-setup-bogus-iov_iter-for-silencing.patch new file mode 100644 index 0000000000..90e788f781 --- /dev/null +++ b/queue-6.6/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 +@@ -2074,6 +2074,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-6.6/alsa-ua101-reject-too-short-usb-descriptors.patch b/queue-6.6/alsa-ua101-reject-too-short-usb-descriptors.patch new file mode 100644 index 0000000000..25c42706ab --- /dev/null +++ b/queue-6.6/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 +@@ -914,8 +914,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-6.6/bluetooth-bnep-fix-uaf-read-of-dev-name.patch b/queue-6.6/bluetooth-bnep-fix-uaf-read-of-dev-name.patch new file mode 100644 index 0000000000..6a21f2441e --- /dev/null +++ b/queue-6.6/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-6.6/bluetooth-fix-uaf-in-l2cap_sock_cleanup_listen-vs-l2cap_conn_del.patch b/queue-6.6/bluetooth-fix-uaf-in-l2cap_sock_cleanup_listen-vs-l2cap_conn_del.patch new file mode 100644 index 0000000000..37b9c3de4d --- /dev/null +++ b/queue-6.6/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 +@@ -306,6 +306,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 +@@ -692,6 +692,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 stands for a PA sync connection, +@@ -1146,8 +1148,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 +@@ -348,8 +348,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; +@@ -1441,22 +1446,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; +@@ -496,8 +498,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 +@@ -432,6 +432,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; +@@ -704,8 +706,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-6.6/bluetooth-hci_uart-fix-uafs-and-race-conditions-in-close-and-init-paths.patch b/queue-6.6/bluetooth-hci_uart-fix-uafs-and-race-conditions-in-close-and-init-paths.patch new file mode 100644 index 0000000000..ab6133675b --- /dev/null +++ b/queue-6.6/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; +@@ -528,6 +540,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); + +@@ -537,24 +550,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); + +@@ -622,11 +649,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); + } + +@@ -692,6 +720,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-6.6/bluetooth-iso-drop-iso_end-frames-received-without-prior-iso_start.patch b/queue-6.6/bluetooth-iso-drop-iso_end-frames-received-without-prior-iso_start.patch new file mode 100644 index 0000000000..8973349673 --- /dev/null +++ b/queue-6.6/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 +@@ -2107,6 +2107,11 @@ void iso_recv(struct hci_conn *hcon, str + 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-6.6/bluetooth-mgmt-validate-add-extended-advertising-data-length.patch b/queue-6.6/bluetooth-mgmt-validate-add-extended-advertising-data-length.patch new file mode 100644 index 0000000000..a231411c29 --- /dev/null +++ b/queue-6.6/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 +@@ -9140,9 +9140,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-6.6/bluetooth-serialize-accept_q-access.patch b/queue-6.6/bluetooth-serialize-accept_q-access.patch new file mode 100644 index 0000000000..1042b0f823 --- /dev/null +++ b/queue-6.6/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 +@@ -380,6 +380,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 +@@ -151,6 +151,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); + +@@ -211,6 +212,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); + +@@ -221,9 +223,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. + */ +@@ -241,8 +247,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); + +@@ -251,45 +255,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); + +@@ -317,6 +348,8 @@ restart: + sock_hold(sk); + + release_sock(sk); ++ if (next) ++ sock_put(next); + return sk; + } + +@@ -518,18 +551,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-6.6/drivers-base-memory-fix-memory-block-reference-leak-in-poison-accounting.patch b/queue-6.6/drivers-base-memory-fix-memory-block-reference-leak-in-poison-accounting.patch new file mode 100644 index 0000000000..7e7dcfca90 --- /dev/null +++ b/queue-6.6/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 +@@ -1211,8 +1211,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) +@@ -1220,8 +1222,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-6.6/efi-allocate-runtime-workqueue-before-acpi-init.patch b/queue-6.6/efi-allocate-runtime-workqueue-before-acpi-init.patch new file mode 100644 index 0000000000..2344509749 --- /dev/null +++ b/queue-6.6/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 +@@ -371,21 +371,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 +@@ -397,9 +387,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-6.6/hwmon-pmbus-adm1266-widen-blackbox-info-buffer-to-i2c_smbus_block_max.patch b/queue-6.6/hwmon-pmbus-adm1266-widen-blackbox-info-buffer-to-i2c_smbus_block_max.patch new file mode 100644 index 0000000000..a5192d35be --- /dev/null +++ b/queue-6.6/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-6.6/ksmbd-fix-null-pointer-dereference-in-compare_guid_key.patch b/queue-6.6/ksmbd-fix-null-pointer-dereference-in-compare_guid_key.patch new file mode 100644 index 0000000000..a542a53127 --- /dev/null +++ b/queue-6.6/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-6.6/ksmbd-fix-sid-memory-leak-in-set_posix_acl_entries_dacl-on-overflow.patch b/queue-6.6/ksmbd-fix-sid-memory-leak-in-set_posix_acl_entries_dacl-on-overflow.patch new file mode 100644 index 0000000000..62e3436e40 --- /dev/null +++ b/queue-6.6/ksmbd-fix-sid-memory-leak-in-set_posix_acl_entries_dacl-on-overflow.patch @@ -0,0 +1,81 @@ +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(-) + +diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c +index c1d1f34581d6..9161e9d7ed24 100644 +--- a/fs/smb/server/smbacl.c ++++ b/fs/smb/server/smbacl.c +@@ -643,8 +643,10 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap, + 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(struct mnt_idmap *idmap, + 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 |= +-- +2.54.0 + diff --git a/queue-6.6/mm-damon-sysfs-schemes-call-missing-mem_cgroup_iter_break.patch b/queue-6.6/mm-damon-sysfs-schemes-call-missing-mem_cgroup_iter_break.patch new file mode 100644 index 0000000000..3bafc8832c --- /dev/null +++ b/queue-6.6/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 +@@ -1539,6 +1539,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-6.6/net-bcmgenet-keep-rbuf-eee-pm-disabled.patch b/queue-6.6/net-bcmgenet-keep-rbuf-eee-pm-disabled.patch new file mode 100644 index 0000000000..da5a2da691 --- /dev/null +++ b/queue-6.6/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 +@@ -1326,13 +1326,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-6.6/net-ifb-report-ethtool-stats-over-num_tx_queues.patch b/queue-6.6/net-ifb-report-ethtool-stats-over-num_tx_queues.patch new file mode 100644 index 0000000000..9770fe349b --- /dev/null +++ b/queue-6.6/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-6.6/net-wwan-iosm-fix-potential-memory-leaks-in-ipc_imem_init.patch b/queue-6.6/net-wwan-iosm-fix-potential-memory-leaks-in-ipc_imem_init.patch new file mode 100644 index 0000000000..d841b92464 --- /dev/null +++ b/queue-6.6/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 +@@ -1430,6 +1430,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-6.6/netfilter-ip6t_hbh-reject-oversized-option-lists.patch b/queue-6.6/netfilter-ip6t_hbh-reject-oversized-option-lists.patch new file mode 100644 index 0000000000..89f34c5f05 --- /dev/null +++ b/queue-6.6/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-6.6/netfilter-ipset-stop-hash-range-iteration-at-end.patch b/queue-6.6/netfilter-ipset-stop-hash-range-iteration-at-end.patch new file mode 100644 index 0000000000..1e328a5889 --- /dev/null +++ b/queue-6.6/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-6.6/netfilter-nf_queue-hold-bridge-skb-dev-while-queued.patch b/queue-6.6/netfilter-nf_queue-hold-bridge-skb-dev-while-queued.patch new file mode 100644 index 0000000000..03cccce7ee --- /dev/null +++ b/queue-6.6/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 +@@ -12,6 +12,7 @@ + struct nf_queue_entry { + struct list_head list; + 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 +@@ -972,6 +972,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-6.6/netfilter-nft_inner-fix-ipv6-inner_thoff-desync.patch b/queue-6.6/netfilter-nft_inner-fix-ipv6-inner_thoff-desync.patch new file mode 100644 index 0000000000..6fffe13f35 --- /dev/null +++ b/queue-6.6/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 +@@ -156,7 +156,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-6.6/phonet-pep-disable-bh-around-forwarded-sk_receive_skb.patch b/queue-6.6/phonet-pep-disable-bh-around-forwarded-sk_receive_skb.patch new file mode 100644 index 0000000000..ebcd6077a1 --- /dev/null +++ b/queue-6.6/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-6.6/series b/queue-6.6/series index de80bd7178..9f60d6bf5f 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -19,3 +19,29 @@ revert-ice-remove-jumbo_remove-step-from-tx-path.patch revert-s390-cio-update-purge-function-to-unregister-.patch revert-af_unix-reject-siocatmark-on-non-stream-socke.patch i3c-mipi-i3c-hci-correct-ring_ctrl_abort-handling-in.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-sid-memory-leak-in-set_posix_acl_entries_dacl-on-overflow.patch +smb-client-protect-tc_count-increment-in-smb2_find_smb_sess_tcon_unlocked.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 +efi-allocate-runtime-workqueue-before-acpi-init.patch +drivers-base-memory-fix-memory-block-reference-leak-in-poison-accounting.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-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-ifb-report-ethtool-stats-over-num_tx_queues.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-6.6/smb-client-protect-tc_count-increment-in-smb2_find_smb_sess_tcon_unlocked.patch b/queue-6.6/smb-client-protect-tc_count-increment-in-smb2_find_smb_sess_tcon_unlocked.patch new file mode 100644 index 0000000000..9e81602250 --- /dev/null +++ b/queue-6.6/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 +@@ -214,7 +214,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-6.6/smb-server-promote-s_del_on_cls-to-s_del_pending-when-close.patch b/queue-6.6/smb-server-promote-s_del_on_cls-to-s_del_pending-when-close.patch new file mode 100644 index 0000000000..e1de1355d6 --- /dev/null +++ b/queue-6.6/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 +@@ -118,7 +118,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; +@@ -134,7 +134,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; +@@ -302,12 +302,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-6.6/sysfs-don-t-remove-existing-directory-on-update-failure.patch b/queue-6.6/sysfs-don-t-remove-existing-directory-on-update-failure.patch new file mode 100644 index 0000000000..1d3a6d68b6 --- /dev/null +++ b/queue-6.6/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 +@@ -151,7 +151,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);