From 2eba65d71484bdecd49062a437c08bfdcef2012a Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Fri, 24 Jul 2026 06:59:05 -0400 Subject: [PATCH] Fixes for all trees Signed-off-by: Sasha Levin --- ...ug-bound-hotplug-states-sysfs-output.patch | 54 +++ ...d-an-unset-mac-header-in-macsec_encr.patch | 53 +++ staging-5.10/series | 2 + ...ckup-in-requeue-pi-during-signal-tim.patch | 103 +++++ ...d-an-unset-mac-header-in-macsec_encr.patch | 53 +++ staging-5.15/series | 2 + ...et-gc_in_progress-to-true-in-unix_gc.patch | 66 +++ ...6-amd-brs-fix-kernel-address-leakage.patch | 92 ++++ staging-6.1/series | 2 + ...ind-failure-path-analysis-in-subprog.patch | 71 +++ ...eadlock-in-display_info_cb-by-removi.patch | 82 ++++ ...-fix-make_uffd_wp_huge_pte-prot-upda.patch | 124 +++++ ...les-revert-commit_mutex-usage-in-res.patch | 424 ++++++++++++++++++ ...ounter-serialize-reset-with-spinlock.patch | 86 ++++ ...ft_quota-use-atomic64_xchg-for-reset.patch | 61 +++ ...d-tests-for-ld_-abs-ind-failure-path.patch | 200 +++++++++ staging-6.12/series | 7 + ...ind-failure-path-analysis-in-subprog.patch | 71 +++ ...eadlock-in-display_info_cb-by-removi.patch | 82 ++++ ...-fix-make_uffd_wp_huge_pte-prot-upda.patch | 124 +++++ ...les-revert-commit_mutex-usage-in-res.patch | 424 ++++++++++++++++++ ...ounter-serialize-reset-with-spinlock.patch | 86 ++++ ...ft_quota-use-atomic64_xchg-for-reset.patch | 61 +++ ...d-tests-for-ld_-abs-ind-failure-path.patch | 200 +++++++++ staging-6.18/series | 7 + ...ind-failure-path-analysis-in-subprog.patch | 71 +++ ...eadlock-in-display_info_cb-by-removi.patch | 82 ++++ ...-pmc-avoid-logging-null-for-dmi-valu.patch | 56 +++ ...-pmc-don-t-log-during-intermediate-w.patch | 124 +++++ ...d-tests-for-ld_-abs-ind-failure-path.patch | 200 +++++++++ staging-6.6/series | 5 + ...eadlock-in-display_info_cb-by-removi.patch | 82 ++++ staging-7.1/series | 1 + 33 files changed, 3158 insertions(+) create mode 100644 staging-5.10/cpu-hotplug-bound-hotplug-states-sysfs-output.patch create mode 100644 staging-5.10/macsec-don-t-read-an-unset-mac-header-in-macsec_encr.patch create mode 100644 staging-5.15/futex-prevent-lockup-in-requeue-pi-during-signal-tim.patch create mode 100644 staging-5.15/macsec-don-t-read-an-unset-mac-header-in-macsec_encr.patch create mode 100644 staging-6.1/af_unix-set-gc_in_progress-to-true-in-unix_gc.patch create mode 100644 staging-6.1/perf-x86-amd-brs-fix-kernel-address-leakage.patch create mode 100644 staging-6.12/bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch create mode 100644 staging-6.12/drm-virtio-fix-deadlock-in-display_info_cb-by-removi.patch create mode 100644 staging-6.12/fs-proc-task_mmu-fix-make_uffd_wp_huge_pte-prot-upda.patch create mode 100644 staging-6.12/netfilter-nf_tables-revert-commit_mutex-usage-in-res.patch create mode 100644 staging-6.12/netfilter-nft_counter-serialize-reset-with-spinlock.patch create mode 100644 staging-6.12/netfilter-nft_quota-use-atomic64_xchg-for-reset.patch create mode 100644 staging-6.12/selftests-bpf-add-tests-for-ld_-abs-ind-failure-path.patch create mode 100644 staging-6.18/bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch create mode 100644 staging-6.18/drm-virtio-fix-deadlock-in-display_info_cb-by-removi.patch create mode 100644 staging-6.18/fs-proc-task_mmu-fix-make_uffd_wp_huge_pte-prot-upda.patch create mode 100644 staging-6.18/netfilter-nf_tables-revert-commit_mutex-usage-in-res.patch create mode 100644 staging-6.18/netfilter-nft_counter-serialize-reset-with-spinlock.patch create mode 100644 staging-6.18/netfilter-nft_quota-use-atomic64_xchg-for-reset.patch create mode 100644 staging-6.18/selftests-bpf-add-tests-for-ld_-abs-ind-failure-path.patch create mode 100644 staging-6.6/bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch create mode 100644 staging-6.6/drm-virtio-fix-deadlock-in-display_info_cb-by-removi.patch create mode 100644 staging-6.6/platform-x86-amd-pmc-avoid-logging-null-for-dmi-valu.patch create mode 100644 staging-6.6/platform-x86-amd-pmc-don-t-log-during-intermediate-w.patch create mode 100644 staging-6.6/selftests-bpf-add-tests-for-ld_-abs-ind-failure-path.patch create mode 100644 staging-7.1/drm-virtio-fix-deadlock-in-display_info_cb-by-removi.patch diff --git a/staging-5.10/cpu-hotplug-bound-hotplug-states-sysfs-output.patch b/staging-5.10/cpu-hotplug-bound-hotplug-states-sysfs-output.patch new file mode 100644 index 0000000000..4e8b2534fa --- /dev/null +++ b/staging-5.10/cpu-hotplug-bound-hotplug-states-sysfs-output.patch @@ -0,0 +1,54 @@ +From 4a5de2475370434b4d74c680145d3071f4621b5e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Jul 2026 20:38:51 +0200 +Subject: cpu: hotplug: Bound hotplug states sysfs output + +From: Bradley Morgan + +commit 86f436567f2516a0083b210bedc933544826a2c3 upstream. + +states_show() adds CPU hotplug state names into a single sysfs buffer +using sprintf(). With enough registered states, this can write past the +end of the PAGE_SIZE buffer. + +Use sysfs_emit_at() so output is bounded. + +Fixes: 98f8cdce1db5 ("cpu/hotplug: Add sysfs state interface") +Signed-off-by: Bradley Morgan +Signed-off-by: Thomas Gleixner +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20260619163719.12103-2-include@grrlz.net +Signed-off-by: Sasha Levin +--- + kernel/cpu.c | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +diff --git a/kernel/cpu.c b/kernel/cpu.c +index 08c2b2e30f23f1..69c7be3706f15b 100644 +--- a/kernel/cpu.c ++++ b/kernel/cpu.c +@@ -2319,18 +2319,15 @@ static const struct attribute_group cpuhp_cpu_attr_group = { + static ssize_t show_cpuhp_states(struct device *dev, + struct device_attribute *attr, char *buf) + { +- ssize_t cur, res = 0; ++ ssize_t res = 0; + int i; + + mutex_lock(&cpuhp_state_mutex); + for (i = CPUHP_OFFLINE; i <= CPUHP_ONLINE; i++) { + struct cpuhp_step *sp = cpuhp_get_step(i); + +- if (sp->name) { +- cur = sprintf(buf, "%3d: %s\n", i, sp->name); +- buf += cur; +- res += cur; +- } ++ if (sp->name) ++ res += sysfs_emit_at(buf, res, "%3d: %s\n", i, sp->name); + } + mutex_unlock(&cpuhp_state_mutex); + return res; +-- +2.53.0 + diff --git a/staging-5.10/macsec-don-t-read-an-unset-mac-header-in-macsec_encr.patch b/staging-5.10/macsec-don-t-read-an-unset-mac-header-in-macsec_encr.patch new file mode 100644 index 0000000000..718a9e4e97 --- /dev/null +++ b/staging-5.10/macsec-don-t-read-an-unset-mac-header-in-macsec_encr.patch @@ -0,0 +1,53 @@ +From 2d0256ad2a9abc32a8d058158523e32fce9b3653 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Jul 2026 08:41:53 +0900 +Subject: macsec: don't read an unset MAC header in macsec_encrypt() + +From: Daehyeon Ko <4ncienth@gmail.com> + +commit f5089008f90c0a7c5520dff3934e0af00adf322d upstream. + +macsec_encrypt() reads the Ethernet header via eth_hdr(skb) +(skb->head + skb->mac_header) to memmove() the 12 source/destination MAC +bytes forward and make room for the SecTAG. + +On the AF_PACKET SOCK_RAW + PACKET_QDISC_BYPASS transmit path the skb +reaches the macsec ndo_start_xmit() with the MAC header unset, so +eth_hdr(skb) resolves to skb->head + (u16)~0 and the read is out of +bounds: a 12-byte heap over-read that is also emitted on the wire as the +frame's outer source/destination MAC. KASAN reports a slab-out-of-bounds +read in macsec_start_xmit() on 6.0; on current mainline a CONFIG_DEBUG_NET +build flags it as an unset mac header in skb_mac_header(). + +On the TX path the L2 header is at skb->data, so use skb_eth_hdr(), added +by commit 96cc4b69581d ("macvlan: do not assume mac_header is set in +macvlan_broadcast()") for exactly this purpose. + +Fixes: c09440f7dcb3 ("macsec: introduce IEEE 802.1AE driver") +Cc: stable@vger.kernel.org +Signed-off-by: Daehyeon Ko <4ncienth@gmail.com> +Reviewed-by: Sabrina Dubroca +Link: https://patch.msgid.link/20260703083634.2035145-1-4ncienth@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Daehyeon Ko <4ncienth@gmail.com> +Signed-off-by: Sasha Levin +--- + drivers/net/macsec.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c +index d19b5b1c1aca11..d07dba76940a9d 100644 +--- a/drivers/net/macsec.c ++++ b/drivers/net/macsec.c +@@ -666,7 +666,7 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb, + } + + unprotected_len = skb->len; +- eth = eth_hdr(skb); ++ eth = skb_eth_hdr(skb); + sci_present = send_sci(secy); + hh = skb_push(skb, macsec_extra_len(sci_present)); + memmove(hh, eth, 2 * ETH_ALEN); +-- +2.53.0 + diff --git a/staging-5.10/series b/staging-5.10/series index 632f68e799..5e01f56936 100644 --- a/staging-5.10/series +++ b/staging-5.10/series @@ -1 +1,3 @@ nvmet-tcp-fix-potential-uaf-when-ddgst-mismatch.patch +cpu-hotplug-bound-hotplug-states-sysfs-output.patch +macsec-don-t-read-an-unset-mac-header-in-macsec_encr.patch diff --git a/staging-5.15/futex-prevent-lockup-in-requeue-pi-during-signal-tim.patch b/staging-5.15/futex-prevent-lockup-in-requeue-pi-during-signal-tim.patch new file mode 100644 index 0000000000..3b7ac453c3 --- /dev/null +++ b/staging-5.15/futex-prevent-lockup-in-requeue-pi-during-signal-tim.patch @@ -0,0 +1,103 @@ +From d8061ac076105b4a44a8c8e8327752017d8309e1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Jul 2026 20:47:48 +0000 +Subject: futex: Prevent lockup in requeue-PI during signal/ timeout wakeup + +From: Sebastian Andrzej Siewior + +[ Upstream commit bc7304f3ae20972d11db6e0b1b541c63feda5f05 ] + +During wait-requeue-pi (task A) and requeue-PI (task B) the following +race can happen: + + Task A Task B + futex_wait_requeue_pi() + futex_setup_timer() + futex_do_wait() + futex_requeue() + CLASS(hb, hb1)(&key1); + CLASS(hb, hb2)(&key2); + *timeout* + futex_requeue_pi_wakeup_sync() + requeue_state = Q_REQUEUE_PI_IGNORE + + *blocks on hb->lock* + + futex_proxy_trylock_atomic() + futex_requeue_pi_prepare() + Q_REQUEUE_PI_IGNORE => -EAGAIN + double_unlock_hb(hb1, hb2) + *retry* + +Task B acquires both hb locks and attempts to acquire the PI-lock of the +top most waiter (task B). Task A is leaving early due to a signal/ +timeout and started removing itself from the queue. It updates its +requeue_state but can not remove it from the list because this requires +the hb lock which is owned by task B. + +Usually task A is able to swoop the lock after task B unlocked it. +However if task B is of higher priority then task A may not be able to +wake up in time and acquire the lock before task B gets it again. +Especially on a UP system where A is never scheduled. + +As a result task A blocks on the lock and task B busy loops, trying to +make progress but live locks the system instead. Tragic. + +This can be fixed by removing the top most waiter from the list in this +case. This allows task B to grab the next top waiter (if any) in the +next iteration and make progress. + +Remove the top most waiter if futex_requeue_pi_prepare() fails. +Let the waiter conditionally remove itself from the list in +handle_early_requeue_pi_wakeup(). + +Fixes: 07d91ef510fb1 ("futex: Prevent requeue_pi() lock nesting issue on RT") +Reported-by: Moritz Klammler +Signed-off-by: Sebastian Andrzej Siewior +Signed-off-by: Thomas Gleixner +Link: https://patch.msgid.link/20260428103425.dywXyPd3@linutronix.de +Closes: https://lore.kernel.org/all/VE1PR06MB6894BE61C173D802365BE19DFF4CA@VE1PR06MB6894.eurprd06.prod.outlook.com +[cmllamas: adapt to 5.15, apply hunk to kernel/futex/core.c prior to the + requeue code split and use hb_waiters_dec() before the helper rename] +Signed-off-by: Carlos Llamas +Signed-off-by: Sasha Levin +--- + kernel/futex/core.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/kernel/futex/core.c b/kernel/futex/core.c +index 42cd8f2b6da813..8b4af13b8d262a 100644 +--- a/kernel/futex/core.c ++++ b/kernel/futex/core.c +@@ -2078,8 +2078,11 @@ futex_proxy_trylock_atomic(u32 __user *pifutex, struct futex_hash_bucket *hb1, + return -EINVAL; + + /* Ensure that this does not race against an early wakeup */ +- if (!futex_requeue_pi_prepare(top_waiter, NULL)) ++ if (!futex_requeue_pi_prepare(top_waiter, NULL)) { ++ plist_del(&top_waiter->list, &hb1->chain); ++ hb_waiters_dec(hb1); + return -EAGAIN; ++ } + + /* + * Try to take the lock for top_waiter and set the FUTEX_WAITERS bit +@@ -3360,10 +3363,12 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb, + + /* + * We were woken prior to requeue by a timeout or a signal. +- * Unqueue the futex_q and determine which it was. ++ * Conditionally unqueue the futex_q and determine which it was. + */ +- plist_del(&q->list, &hb->chain); +- hb_waiters_dec(hb); ++ if (!plist_node_empty(&q->list)) { ++ plist_del(&q->list, &hb->chain); ++ hb_waiters_dec(hb); ++ } + + /* Handle spurious wakeups gracefully */ + ret = -EWOULDBLOCK; +-- +2.53.0 + diff --git a/staging-5.15/macsec-don-t-read-an-unset-mac-header-in-macsec_encr.patch b/staging-5.15/macsec-don-t-read-an-unset-mac-header-in-macsec_encr.patch new file mode 100644 index 0000000000..f83f485af3 --- /dev/null +++ b/staging-5.15/macsec-don-t-read-an-unset-mac-header-in-macsec_encr.patch @@ -0,0 +1,53 @@ +From e1c95a05572050f1ffdcd33881131a04a3809995 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Jul 2026 08:40:44 +0900 +Subject: macsec: don't read an unset MAC header in macsec_encrypt() + +From: Daehyeon Ko <4ncienth@gmail.com> + +commit f5089008f90c0a7c5520dff3934e0af00adf322d upstream. + +macsec_encrypt() reads the Ethernet header via eth_hdr(skb) +(skb->head + skb->mac_header) to memmove() the 12 source/destination MAC +bytes forward and make room for the SecTAG. + +On the AF_PACKET SOCK_RAW + PACKET_QDISC_BYPASS transmit path the skb +reaches the macsec ndo_start_xmit() with the MAC header unset, so +eth_hdr(skb) resolves to skb->head + (u16)~0 and the read is out of +bounds: a 12-byte heap over-read that is also emitted on the wire as the +frame's outer source/destination MAC. KASAN reports a slab-out-of-bounds +read in macsec_start_xmit() on 6.0; on current mainline a CONFIG_DEBUG_NET +build flags it as an unset mac header in skb_mac_header(). + +On the TX path the L2 header is at skb->data, so use skb_eth_hdr(), added +by commit 96cc4b69581d ("macvlan: do not assume mac_header is set in +macvlan_broadcast()") for exactly this purpose. + +Fixes: c09440f7dcb3 ("macsec: introduce IEEE 802.1AE driver") +Cc: stable@vger.kernel.org +Signed-off-by: Daehyeon Ko <4ncienth@gmail.com> +Reviewed-by: Sabrina Dubroca +Link: https://patch.msgid.link/20260703083634.2035145-1-4ncienth@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Daehyeon Ko <4ncienth@gmail.com> +Signed-off-by: Sasha Levin +--- + drivers/net/macsec.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c +index 9b0cb78507384b..5de940761ebf1e 100644 +--- a/drivers/net/macsec.c ++++ b/drivers/net/macsec.c +@@ -662,7 +662,7 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb, + } + + unprotected_len = skb->len; +- eth = eth_hdr(skb); ++ eth = skb_eth_hdr(skb); + sci_present = send_sci(secy); + hh = skb_push(skb, macsec_extra_len(sci_present)); + memmove(hh, eth, 2 * ETH_ALEN); +-- +2.53.0 + diff --git a/staging-5.15/series b/staging-5.15/series index 632f68e799..754bba0d55 100644 --- a/staging-5.15/series +++ b/staging-5.15/series @@ -1 +1,3 @@ nvmet-tcp-fix-potential-uaf-when-ddgst-mismatch.patch +futex-prevent-lockup-in-requeue-pi-during-signal-tim.patch +macsec-don-t-read-an-unset-mac-header-in-macsec_encr.patch diff --git a/staging-6.1/af_unix-set-gc_in_progress-to-true-in-unix_gc.patch b/staging-6.1/af_unix-set-gc_in_progress-to-true-in-unix_gc.patch new file mode 100644 index 0000000000..3757306bf8 --- /dev/null +++ b/staging-6.1/af_unix-set-gc_in_progress-to-true-in-unix_gc.patch @@ -0,0 +1,66 @@ +From 72289fce6d99033c398b3f0fb634511a5c80b39b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Jul 2026 00:27:09 +0000 +Subject: af_unix: Set gc_in_progress to true in unix_gc(). + +From: Kuniyuki Iwashima + +[ Upstream commit d82ba05263c69fa2437fe93e4e561cc40f4c03af ] + +Igor Ushakov reported that unix_gc() could run with gc_in_progress +being false if the work is scheduled while running: + + Thread 1 Thread 2 Thread 3 + -------- -------- -------- + unix_schedule_gc() unix_schedule_gc() + `- if (!gc_in_progress) `- if (!gc_in_progress) + |- gc_in_progress = true | + `- queue_work() | + unix_gc() <----------------/ | + | |- gc_in_progress = true + ... `- queue_work() + | | + `- gc_in_progress = false | + | + unix_gc() <---------------------------------------------' + | + ... /* gc_in_progress == false */ + | + `- gc_in_progress = false + +unix_peek_fpl() relies on gc_in_progress not to confuse GC +by MSG_PEEK. + +Let's set gc_in_progress to true in unix_gc(). + +Fixes: 8b90a9f819dc ("af_unix: Run GC on only one CPU.") +Reported-by: Igor Ushakov +Signed-off-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260501073945.1884564-1-kuniyu@google.com +Signed-off-by: Jakub Kicinski +[ Add setting gc_in_progress in __unix_gc(). Keep the existing + set in unix_gc() for wait_for_unix_gc() over-limit throttling. ] +Signed-off-by: Igor Ushakov +Signed-off-by: Sasha Levin +Signed-off-by: Jay Wang +Signed-off-by: Sasha Levin +--- + net/unix/garbage.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/unix/garbage.c b/net/unix/garbage.c +index 66fd606c43f45d..38c8cae1316716 100644 +--- a/net/unix/garbage.c ++++ b/net/unix/garbage.c +@@ -560,6 +560,8 @@ static void __unix_gc(struct work_struct *work) + struct sk_buff_head hitlist; + struct sk_buff *skb; + ++ WRITE_ONCE(gc_in_progress, true); ++ + spin_lock(&unix_gc_lock); + + if (!unix_graph_maybe_cyclic) { +-- +2.53.0 + diff --git a/staging-6.1/perf-x86-amd-brs-fix-kernel-address-leakage.patch b/staging-6.1/perf-x86-amd-brs-fix-kernel-address-leakage.patch new file mode 100644 index 0000000000..cb9691a08a --- /dev/null +++ b/staging-6.1/perf-x86-amd-brs-fix-kernel-address-leakage.patch @@ -0,0 +1,92 @@ +From 54d42f00be1a39f947e46af6b913e28e17756e10 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Jul 2026 15:39:00 +0530 +Subject: perf/x86/amd/brs: Fix kernel address leakage + +From: Sandipan Das + +commit 47915e855fb38b42133e31ba917d99565f862154 upstream. + +A user-only branch stack can contain branches that originate from +the kernel. As a result, kernel addresses are exposed to user space +even when PERF_SAMPLE_BRANCH_USER is requested. On AMD processors +supporting X86_FEATURE_BRS (Zen 3 only), perf can still report entries +such as SYSRET/interrupt returns for which the branch-from addresses +are in the kernel. + +E.g. + + $ perf record -j any,u -c 4000 -e branch-brs -o - -- \ + perf bench syscall basic --loop 1000 | \ + perf script -i - -F brstack|tr ' ' '\n'| \ + grep -E '0x[89a-f][0-9a-f]{15}' + + ... + 0xffffffff810001c4/0x72e2e32955eb/-/-/-/0//- + 0xffffffff810001c4/0x72e2d94a9821/-/-/-/0//- + 0xffffffff810001c4/0x72e2d94ffa1b/-/-/-/0//- + ... + +BRS provides no hardware branch filtering, so privilege level +filtering is performed entirely in software. However, amd_brs_match_plm() +only validates the branch-to address against the requested privilege +levels. For branches from the kernel to user space, the branch-from +address is left unchecked and is leaked. Extend the software filter to +also validate the branch-from address, so that any branch record whose +branch-from address is in the kernel is dropped when +PERF_SAMPLE_BRANCH_USER is requested. + +Fixes: 8910075d61a3 ("perf/x86/amd: Enable branch sampling priv level filtering") +Reported-by: Sashiko +Signed-off-by: Sandipan Das +Signed-off-by: Ingo Molnar +Cc: stable@vger.kernel.org +Cc: Peter Zijlstra +Cc: Stephane Eranian +Link: https://patch.msgid.link/f05931c4f89a146c364bd5dc6b8170b1ac611c65.1783701239.git.sandipan.das@amd.com +Closes: https://lore.kernel.org/all/20260710110235.F3FD81F000E9@smtp.kernel.org/ +[sandipan: backport to linux-6.1.y] +Signed-off-by: Sandipan Das +Signed-off-by: Sasha Levin +--- + arch/x86/events/amd/brs.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/arch/x86/events/amd/brs.c b/arch/x86/events/amd/brs.c +index f1bff153d94578..fd46e73cb8e716 100644 +--- a/arch/x86/events/amd/brs.c ++++ b/arch/x86/events/amd/brs.c +@@ -262,13 +262,13 @@ void amd_brs_disable_all(void) + amd_brs_disable(); + } + +-static bool amd_brs_match_plm(struct perf_event *event, u64 to) ++static bool amd_brs_match_plm(struct perf_event *event, u64 from, u64 to) + { + int type = event->attr.branch_sample_type; + int plm_k = PERF_SAMPLE_BRANCH_KERNEL | PERF_SAMPLE_BRANCH_HV; + int plm_u = PERF_SAMPLE_BRANCH_USER; + +- if (!(type & plm_k) && kernel_ip(to)) ++ if (!(type & plm_k) && (kernel_ip(to) || kernel_ip(from))) + return 0; + + if (!(type & plm_u) && !kernel_ip(to)) +@@ -341,11 +341,11 @@ void amd_brs_drain(void) + */ + to = (u64)(((s64)to << shift) >> shift); + +- if (!amd_brs_match_plm(event, to)) +- continue; +- + rdmsrl(brs_from(brs_idx), from); + ++ if (!amd_brs_match_plm(event, from, to)) ++ continue; ++ + perf_clear_branch_entry_bitfields(br+nr); + + br[nr].from = from; +-- +2.53.0 + diff --git a/staging-6.1/series b/staging-6.1/series index 07ddd9b506..8dd80c6d81 100644 --- a/staging-6.1/series +++ b/staging-6.1/series @@ -1 +1,3 @@ platform-x86-intel-uncore-freq-fix-current_freq_khz-.patch +af_unix-set-gc_in_progress-to-true-in-unix_gc.patch +perf-x86-amd-brs-fix-kernel-address-leakage.patch diff --git a/staging-6.12/bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch b/staging-6.12/bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch new file mode 100644 index 0000000000..c7e8175474 --- /dev/null +++ b/staging-6.12/bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch @@ -0,0 +1,71 @@ +From f485839978a7381a4d7cbc551f827fdd7f32698d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Jul 2026 15:39:07 +0800 +Subject: bpf: Fix ld_{abs,ind} failure path analysis in subprogs + +From: Daniel Borkmann + +commit ee861486e377edc55361c08dcbceab3f6b6577bd upstream. + +Usage of ld_{abs,ind} instructions got extended into subprogs some time +ago via commit 09b28d76eac4 ("bpf: Add abnormal return checks."). These +are only allowed in subprograms when the latter are BTF annotated and +have scalar return types. + +The code generator in bpf_gen_ld_abs() has an abnormal exit path (r0=0 + +exit) from legacy cBPF times. While the enforcement is on scalar return +types, the verifier must also simulate the path of abnormal exit if the +packet data load via ld_{abs,ind} failed. + +This is currently not the case. Fix it by having the verifier simulate +both success and failure paths, and extend it in similar ways as we do +for tail calls. The success path (r0=unknown, continue to next insn) is +pushed onto stack for later validation and the r0=0 and return to the +caller is done on the fall-through side. + +Fixes: 09b28d76eac4 ("bpf: Add abnormal return checks.") +Reported-by: STAR Labs SG +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260408191242.526279-2-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +[ Dropped visit_abnormal_return_insn changes: depends on 7.0 symbols from + e40f5a6bf88a ("bpf: correct stack liveness for tail calls"); + Hunk1: adapted IS_ERR/PTR_ERR to !branch/-EFAULT to match push_stack() + NULL-on-failure convention. ] +Signed-off-by: Philo Lu +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 7f1144486a8c4a..8c3c4ab989a053 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -16100,6 +16100,23 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn) + mark_reg_unknown(env, regs, BPF_REG_0); + /* ld_abs load up to 32-bit skb data. */ + regs[BPF_REG_0].subreg_def = env->insn_idx + 1; ++ /* ++ * See bpf_gen_ld_abs() which emits a hidden BPF_EXIT with r0=0 ++ * which must be explored by the verifier when in a subprog. ++ */ ++ if (env->cur_state->curframe) { ++ struct bpf_verifier_state *branch; ++ ++ mark_reg_scratched(env, BPF_REG_0); ++ branch = push_stack(env, env->insn_idx + 1, env->insn_idx, false); ++ if (!branch) ++ return -EFAULT; ++ mark_reg_known_zero(env, regs, BPF_REG_0); ++ err = prepare_func_exit(env, &env->insn_idx); ++ if (err) ++ return err; ++ env->insn_idx--; ++ } + return 0; + } + +-- +2.53.0 + diff --git a/staging-6.12/drm-virtio-fix-deadlock-in-display_info_cb-by-removi.patch b/staging-6.12/drm-virtio-fix-deadlock-in-display_info_cb-by-removi.patch new file mode 100644 index 0000000000..cc1cc9be15 --- /dev/null +++ b/staging-6.12/drm-virtio-fix-deadlock-in-display_info_cb-by-removi.patch @@ -0,0 +1,82 @@ +From f6e03317c14058ea9a9ea6805191794eb40df13d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Jul 2026 22:01:00 +0900 +Subject: drm/virtio: fix deadlock in display_info_cb by removing hotplug from + dequeue worker + +From: Ryosuke Yasuoka + +[ Upstream commit d1b894c5bbb3fee0012bd14356286dc2384e8213 ] + +A probe-time deadlock can occur between the dequeue worker and +drm_client_register(). During probe, drm_client_register() holds +clientlist_mutex and calls the fbdev hotplug callback, which triggers an +atomic commit that ends up sleeping in virtio_gpu_queue_ctrl_sgs() +waiting for virtqueue space. The dequeue worker that would free that +space calls virtio_gpu_cmd_get_display_info_cb(), which invokes +drm_kms_helper_hotplug_event() -> drm_client_dev_hotplug(), attempting +to acquire the same clientlist_mutex. Since wake_up() is only called +after the resp_cb loop, the probe thread is never woken and both threads +deadlock. + +Fix this by removing the hotplug notification from +virtio_gpu_cmd_get_display_info_cb(). The display data (outputs[i].info) +is still updated synchronously in the callback. + +For the init path, drm_client_register() already fires an initial +hotplug when the client is registered, which picks up the connector +state updated by display_info_cb. + +For the runtime config_changed path, add a wait_event_timeout() in +config_changed_work_func() so that display_info_cb updates the connector +data before the hotplug notification is sent. Also replace +drm_helper_hpd_irq_event() with drm_kms_helper_hotplug_event() since +virtio-gpu never calls drm_kms_helper_poll_init() and thus +drm_helper_hpd_irq_event() always returns false without doing anything. + +Fixes: 27655b9bb9f0 ("drm/client: Send hotplug event after registering a client") +Closes: https://syzkaller.appspot.com/bug?id=d6dd6f86d3aaf7eebe7406e45c1c6e549453f224 +Closes: https://syzkaller.appspot.com/bug?id=908bd910da5dd79b88de4cf7baf376cc873a922e +Suggested-by: Dmitry Osipenko +Signed-off-by: Ryosuke Yasuoka +Signed-off-by: Dmitry Osipenko +Link: https://patch.msgid.link/20260713-virtiogpu_syzbot-v2-1-2958fa37d46d@redhat.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/virtio/virtgpu_kms.c | 5 ++++- + drivers/gpu/drm/virtio/virtgpu_vq.c | 3 --- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c +index 7dfb2006c561ca..ec31a41d33d678 100644 +--- a/drivers/gpu/drm/virtio/virtgpu_kms.c ++++ b/drivers/gpu/drm/virtio/virtgpu_kms.c +@@ -48,7 +48,10 @@ static void virtio_gpu_config_changed_work_func(struct work_struct *work) + virtio_gpu_cmd_get_edids(vgdev); + virtio_gpu_cmd_get_display_info(vgdev); + virtio_gpu_notify(vgdev); +- drm_helper_hpd_irq_event(vgdev->ddev); ++ wait_event_timeout(vgdev->resp_wq, ++ !vgdev->display_info_pending, ++ 5 * HZ); ++ drm_kms_helper_hotplug_event(vgdev->ddev); + } + events_clear |= VIRTIO_GPU_EVENT_DISPLAY; + } +diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c +index 0d3d0d09f39b9f..bcc070b478d30e 100644 +--- a/drivers/gpu/drm/virtio/virtgpu_vq.c ++++ b/drivers/gpu/drm/virtio/virtgpu_vq.c +@@ -669,9 +669,6 @@ static void virtio_gpu_cmd_get_display_info_cb(struct virtio_gpu_device *vgdev, + vgdev->display_info_pending = false; + spin_unlock(&vgdev->display_info_lock); + wake_up(&vgdev->resp_wq); +- +- if (!drm_helper_hpd_irq_event(vgdev->ddev)) +- drm_kms_helper_hotplug_event(vgdev->ddev); + } + + static void virtio_gpu_cmd_get_capset_info_cb(struct virtio_gpu_device *vgdev, +-- +2.53.0 + diff --git a/staging-6.12/fs-proc-task_mmu-fix-make_uffd_wp_huge_pte-prot-upda.patch b/staging-6.12/fs-proc-task_mmu-fix-make_uffd_wp_huge_pte-prot-upda.patch new file mode 100644 index 0000000000..7976d34119 --- /dev/null +++ b/staging-6.12/fs-proc-task_mmu-fix-make_uffd_wp_huge_pte-prot-upda.patch @@ -0,0 +1,124 @@ +From c40153ad06ebf9c980f59259f025b8bbdb5c0981 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Jul 2026 12:01:20 +0100 +Subject: fs/proc/task_mmu: fix make_uffd_wp_huge_pte() prot-update race + +From: Kiryl Shutsemau + +commit 04718f7c9290f95385f0dd328758753dc1c36dec upstream. + +Patch series "userfaultfd/pagemap: pre-existing fixes". + +These are pre-existing bug fixes that were carried at the front of the +userfaultfd RWP working-set-tracking series up to v5 [1]. Per review +feedback that fixes should not sit in the middle of a feature series, they +are split out and sent on their own; the RWP series is reposted rebased on +top of this. + +All six were flagged by the Sashiko AI review of the RWP series and carry +Reported-by: Sashiko AI review . They are +independent of RWP, apply to mm-new directly, and carry Cc: stable@. + + 1: fs/proc/task_mmu: a missing huge_ptep_modify_prot_start() in + make_uffd_wp_huge_pte() can lose hardware Dirty/Accessed updates + when PAGEMAP_SCAN write-protects a hugetlb PTE. + + 2: fs/proc/task_mmu: pagemap_scan_hugetlb_entry() compares the range + against HPAGE_SIZE rather than the hstate page size, so it never + write-protects gigantic hugetlb pages. + + 3: fs/proc/task_mmu: PAGEMAP_SCAN with PM_SCAN_WP_MATCHING over an + unpopulated hugetlb range self-deadlocks -- pagemap_scan_pte_hole() + calls uffd_wp_range() while walk_hugetlb_range() holds the hugetlb + vma lock for read, and hugetlb_change_protection() then takes it + for write. Install the marker inline instead. + + 4: mm/huge_memory: change_non_present_huge_pmd() drops pmd_swp_uffd_wp + on a device-private PMD permission downgrade, silently losing the + uffd-wp marker. + + 5: userfaultfd: must_wait() applies pte_write() to a locklessly read + PTE without checking pte_present(), so swap/migration entries + decode random offset bits and a thread can stay parked on a stale + fault. + + 6: userfaultfd: __VMA_UFFD_FLAGS feeds VMA_UFFD_MINOR_BIT (41) to + mk_vma_flags() unconditionally, an out-of-bounds write into the + single-word vma_flags_t on 32-bit. Build the mask from config-gated + per-mode masks so an unavailable bit is never materialised. + +This patch (of 6): + +make_uffd_wp_huge_pte() arms the UFFD_WP bit on a present HugeTLB PTE by +calling huge_ptep_modify_prot_commit() with a ptent snapshot that was +fetched without the corresponding huge_ptep_modify_prot_start(). The +start helper is what atomically clears the entry so the kernel-owned +snapshot stays consistent until the commit; without it, the hardware may +set Dirty or Accessed in the live PTE between the original read and the +commit, and huge_ptep_modify_prot_commit() (whose generic implementation +just calls set_huge_pte_at()) then writes the stale snapshot back over the +live hardware bits, losing the update. + +The non-hugetlb sibling make_uffd_wp_pte() does this correctly via +ptep_modify_prot_start() / ptep_modify_prot_commit(). Mirror that pattern +for the present-PTE branch. The migration case stays as-is -- migration +entries are non-present, so there's no hardware update to race against. + +Link: https://lore.kernel.org/20260529172331.356655-1-kas@kernel.org +Link: https://lore.kernel.org/20260529172331.356655-2-kas@kernel.org +Link: https://lore.kernel.org/all/20260526130509.2748441-1-kirill@shutemov.name/ [1] +Fixes: 52526ca7fdb9 ("fs/proc/task_mmu: implement IOCTL to get and optionally clear info about PTEs") +Signed-off-by: Kiryl Shutsemau +Reported-by: Sashiko AI review +Reviewed-by: Lorenzo Stoakes +Reviewed-by: Dev Jain +Cc: David Hildenbrand +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Peter Xu +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Cc: Balbir Singh +Cc: +Signed-off-by: Andrew Morton +[ kas: adapt to the pre-softleaf idiom; apply the + huge_ptep_modify_prot_start()/commit() fix to the present-PTE + (!huge_pte_none()) branch ] +Signed-off-by: Kiryl Shutsemau (Meta) +Signed-off-by: Sasha Levin +--- + fs/proc/task_mmu.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c +index 673b7d0fcfd8fa..bc127f1ad4bb28 100644 +--- a/fs/proc/task_mmu.c ++++ b/fs/proc/task_mmu.c +@@ -2254,15 +2254,19 @@ static void make_uffd_wp_huge_pte(struct vm_area_struct *vma, + + psize = huge_page_size(hstate_vma(vma)); + +- if (is_hugetlb_entry_migration(ptent)) ++ if (is_hugetlb_entry_migration(ptent)) { + set_huge_pte_at(vma->vm_mm, addr, ptep, + pte_swp_mkuffd_wp(ptent), psize); +- else if (!huge_pte_none(ptent)) +- huge_ptep_modify_prot_commit(vma, addr, ptep, ptent, +- huge_pte_mkuffd_wp(ptent)); +- else ++ } else if (!huge_pte_none(ptent)) { ++ pte_t old_pte, new_pte; ++ ++ old_pte = huge_ptep_modify_prot_start(vma, addr, ptep); ++ new_pte = huge_pte_mkuffd_wp(old_pte); ++ huge_ptep_modify_prot_commit(vma, addr, ptep, old_pte, new_pte); ++ } else { + set_huge_pte_at(vma->vm_mm, addr, ptep, + make_pte_marker(PTE_MARKER_UFFD_WP), psize); ++ } + } + #endif /* CONFIG_HUGETLB_PAGE */ + +-- +2.53.0 + diff --git a/staging-6.12/netfilter-nf_tables-revert-commit_mutex-usage-in-res.patch b/staging-6.12/netfilter-nf_tables-revert-commit_mutex-usage-in-res.patch new file mode 100644 index 0000000000..0fc138d4ec --- /dev/null +++ b/staging-6.12/netfilter-nf_tables-revert-commit_mutex-usage-in-res.patch @@ -0,0 +1,424 @@ +From c521ebd5e8627de5d903243604cca0f039c1f967 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 14:26:36 -0600 +Subject: netfilter: nf_tables: revert commit_mutex usage in reset path + +From: Brian Witte + +[ Upstream commit 7f261bb906bf527c4a6e2a646e2d5f3679f2a8bc ] + +It causes circular lock dependency between commit_mutex, nfnl_subsys_ipset +and nlk_cb_mutex when nft reset, ipset list, and iptables-nft with '-m set' +rule run at the same time. + +Previous patches made it safe to run individual reset handlers concurrently +so commit_mutex is no longer required to prevent this. + +Fixes: bd662c4218f9 ("netfilter: nf_tables: Add locking for NFT_MSG_GETOBJ_RESET requests") +Fixes: 3d483faa6663 ("netfilter: nf_tables: Add locking for NFT_MSG_GETSETELEM_RESET requests") +Fixes: 3cb03edb4de3 ("netfilter: nf_tables: Add locking for NFT_MSG_GETRULE_RESET requests") +Link: https://lore.kernel.org/all/aUh_3mVRV8OrGsVo@strlen.de/ +Reported-by: +Closes: https://syzkaller.appspot.com/bug?extid=ff16b505ec9152e5f448 +Signed-off-by: Brian Witte +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_tables_api.c | 248 ++++++---------------------------- + 1 file changed, 42 insertions(+), 206 deletions(-) + +diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c +index 838c9f49e4e01a..09969379c43a73 100644 +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -3719,23 +3719,6 @@ static int nf_tables_dump_rules(struct sk_buff *skb, + return skb->len; + } + +-static int nf_tables_dumpreset_rules(struct sk_buff *skb, +- struct netlink_callback *cb) +-{ +- struct nftables_pernet *nft_net = nft_pernet(sock_net(skb->sk)); +- int ret; +- +- /* Mutex is held is to prevent that two concurrent dump-and-reset calls +- * do not underrun counters and quotas. The commit_mutex is used for +- * the lack a better lock, this is not transaction path. +- */ +- mutex_lock(&nft_net->commit_mutex); +- ret = nf_tables_dump_rules(skb, cb); +- mutex_unlock(&nft_net->commit_mutex); +- +- return ret; +-} +- + static int nf_tables_dump_rules_start(struct netlink_callback *cb) + { + struct nft_rule_dump_ctx *ctx = (void *)cb->ctx; +@@ -3755,16 +3738,10 @@ static int nf_tables_dump_rules_start(struct netlink_callback *cb) + return -ENOMEM; + } + } +- return 0; +-} +- +-static int nf_tables_dumpreset_rules_start(struct netlink_callback *cb) +-{ +- struct nft_rule_dump_ctx *ctx = (void *)cb->ctx; +- +- ctx->reset = true; ++ if (NFNL_MSG_TYPE(cb->nlh->nlmsg_type) == NFT_MSG_GETRULE_RESET) ++ ctx->reset = true; + +- return nf_tables_dump_rules_start(cb); ++ return 0; + } + + static int nf_tables_dump_rules_done(struct netlink_callback *cb) +@@ -3830,6 +3807,8 @@ static int nf_tables_getrule(struct sk_buff *skb, const struct nfnl_info *info, + u32 portid = NETLINK_CB(skb).portid; + struct net *net = info->net; + struct sk_buff *skb2; ++ bool reset = false; ++ char *buf; + + if (info->nlh->nlmsg_flags & NLM_F_DUMP) { + struct netlink_dump_control c = { +@@ -3843,47 +3822,16 @@ static int nf_tables_getrule(struct sk_buff *skb, const struct nfnl_info *info, + return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c); + } + +- skb2 = nf_tables_getrule_single(portid, info, nla, false); +- if (IS_ERR(skb2)) +- return PTR_ERR(skb2); +- +- return nfnetlink_unicast(skb2, net, portid); +-} +- +-static int nf_tables_getrule_reset(struct sk_buff *skb, +- const struct nfnl_info *info, +- const struct nlattr * const nla[]) +-{ +- struct nftables_pernet *nft_net = nft_pernet(info->net); +- u32 portid = NETLINK_CB(skb).portid; +- struct net *net = info->net; +- struct sk_buff *skb2; +- char *buf; +- +- if (info->nlh->nlmsg_flags & NLM_F_DUMP) { +- struct netlink_dump_control c = { +- .start= nf_tables_dumpreset_rules_start, +- .dump = nf_tables_dumpreset_rules, +- .done = nf_tables_dump_rules_done, +- .module = THIS_MODULE, +- .data = (void *)nla, +- }; +- +- return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c); +- } +- +- if (!try_module_get(THIS_MODULE)) +- return -EINVAL; +- rcu_read_unlock(); +- mutex_lock(&nft_net->commit_mutex); +- skb2 = nf_tables_getrule_single(portid, info, nla, true); +- mutex_unlock(&nft_net->commit_mutex); +- rcu_read_lock(); +- module_put(THIS_MODULE); ++ if (NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_GETRULE_RESET) ++ reset = true; + ++ skb2 = nf_tables_getrule_single(portid, info, nla, reset); + if (IS_ERR(skb2)) + return PTR_ERR(skb2); + ++ if (!reset) ++ return nfnetlink_unicast(skb2, net, portid); ++ + buf = kasprintf(GFP_ATOMIC, "%.*s:%u", + nla_len(nla[NFTA_RULE_TABLE]), + (char *)nla_data(nla[NFTA_RULE_TABLE]), +@@ -6107,6 +6055,10 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb) + nla_nest_end(skb, nest); + nlmsg_end(skb, nlh); + ++ if (dump_ctx->reset && args.iter.count > args.iter.skip) ++ audit_log_nft_set_reset(table, cb->seq, ++ args.iter.count - args.iter.skip); ++ + rcu_read_unlock(); + + if (args.iter.err && args.iter.err != -EMSGSIZE) +@@ -6122,26 +6074,6 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb) + return -ENOSPC; + } + +-static int nf_tables_dumpreset_set(struct sk_buff *skb, +- struct netlink_callback *cb) +-{ +- struct nftables_pernet *nft_net = nft_pernet(sock_net(skb->sk)); +- struct nft_set_dump_ctx *dump_ctx = cb->data; +- int ret, skip = cb->args[0]; +- +- mutex_lock(&nft_net->commit_mutex); +- +- ret = nf_tables_dump_set(skb, cb); +- +- if (cb->args[0] > skip) +- audit_log_nft_set_reset(dump_ctx->ctx.table, cb->seq, +- cb->args[0] - skip); +- +- mutex_unlock(&nft_net->commit_mutex); +- +- return ret; +-} +- + static int nf_tables_dump_set_start(struct netlink_callback *cb) + { + struct nft_set_dump_ctx *dump_ctx = cb->data; +@@ -6385,8 +6317,13 @@ static int nf_tables_getsetelem(struct sk_buff *skb, + { + struct netlink_ext_ack *extack = info->extack; + struct nft_set_dump_ctx dump_ctx; ++ int rem, err = 0, nelems = 0; ++ struct net *net = info->net; + struct nlattr *attr; +- int rem, err = 0; ++ bool reset = false; ++ ++ if (NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_GETSETELEM_RESET) ++ reset = true; + + if (info->nlh->nlmsg_flags & NLM_F_DUMP) { + struct netlink_dump_control c = { +@@ -6396,7 +6333,7 @@ static int nf_tables_getsetelem(struct sk_buff *skb, + .module = THIS_MODULE, + }; + +- err = nft_set_dump_ctx_init(&dump_ctx, skb, info, nla, false); ++ err = nft_set_dump_ctx_init(&dump_ctx, skb, info, nla, reset); + if (err) + return err; + +@@ -6407,75 +6344,21 @@ static int nf_tables_getsetelem(struct sk_buff *skb, + if (!nla[NFTA_SET_ELEM_LIST_ELEMENTS]) + return -EINVAL; + +- err = nft_set_dump_ctx_init(&dump_ctx, skb, info, nla, false); ++ err = nft_set_dump_ctx_init(&dump_ctx, skb, info, nla, reset); + if (err) + return err; + + nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) { +- err = nft_get_set_elem(&dump_ctx.ctx, dump_ctx.set, attr, false); +- if (err < 0) { +- NL_SET_BAD_ATTR(extack, attr); +- break; +- } +- } +- +- return err; +-} +- +-static int nf_tables_getsetelem_reset(struct sk_buff *skb, +- const struct nfnl_info *info, +- const struct nlattr * const nla[]) +-{ +- struct nftables_pernet *nft_net = nft_pernet(info->net); +- struct netlink_ext_ack *extack = info->extack; +- struct nft_set_dump_ctx dump_ctx; +- int rem, err = 0, nelems = 0; +- struct nlattr *attr; +- +- if (info->nlh->nlmsg_flags & NLM_F_DUMP) { +- struct netlink_dump_control c = { +- .start = nf_tables_dump_set_start, +- .dump = nf_tables_dumpreset_set, +- .done = nf_tables_dump_set_done, +- .module = THIS_MODULE, +- }; +- +- err = nft_set_dump_ctx_init(&dump_ctx, skb, info, nla, true); +- if (err) +- return err; +- +- c.data = &dump_ctx; +- return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c); +- } +- +- if (!nla[NFTA_SET_ELEM_LIST_ELEMENTS]) +- return -EINVAL; +- +- if (!try_module_get(THIS_MODULE)) +- return -EINVAL; +- rcu_read_unlock(); +- mutex_lock(&nft_net->commit_mutex); +- rcu_read_lock(); +- +- err = nft_set_dump_ctx_init(&dump_ctx, skb, info, nla, true); +- if (err) +- goto out_unlock; +- +- nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) { +- err = nft_get_set_elem(&dump_ctx.ctx, dump_ctx.set, attr, true); ++ err = nft_get_set_elem(&dump_ctx.ctx, dump_ctx.set, attr, reset); + if (err < 0) { + NL_SET_BAD_ATTR(extack, attr); + break; + } + nelems++; + } +- audit_log_nft_set_reset(dump_ctx.ctx.table, nft_base_seq(info->net), nelems); +- +-out_unlock: +- rcu_read_unlock(); +- mutex_unlock(&nft_net->commit_mutex); +- rcu_read_lock(); +- module_put(THIS_MODULE); ++ if (reset) ++ audit_log_nft_set_reset(dump_ctx.ctx.table, nft_base_seq(net), ++ nelems); + + return err; + } +@@ -8182,19 +8065,6 @@ static int nf_tables_dump_obj(struct sk_buff *skb, struct netlink_callback *cb) + return skb->len; + } + +-static int nf_tables_dumpreset_obj(struct sk_buff *skb, +- struct netlink_callback *cb) +-{ +- struct nftables_pernet *nft_net = nft_pernet(sock_net(skb->sk)); +- int ret; +- +- mutex_lock(&nft_net->commit_mutex); +- ret = nf_tables_dump_obj(skb, cb); +- mutex_unlock(&nft_net->commit_mutex); +- +- return ret; +-} +- + static int nf_tables_dump_obj_start(struct netlink_callback *cb) + { + struct nft_obj_dump_ctx *ctx = (void *)cb->ctx; +@@ -8211,16 +8081,10 @@ static int nf_tables_dump_obj_start(struct netlink_callback *cb) + if (nla[NFTA_OBJ_TYPE]) + ctx->type = ntohl(nla_get_be32(nla[NFTA_OBJ_TYPE])); + +- return 0; +-} +- +-static int nf_tables_dumpreset_obj_start(struct netlink_callback *cb) +-{ +- struct nft_obj_dump_ctx *ctx = (void *)cb->ctx; +- +- ctx->reset = true; ++ if (NFNL_MSG_TYPE(cb->nlh->nlmsg_type) == NFT_MSG_GETOBJ_RESET) ++ ctx->reset = true; + +- return nf_tables_dump_obj_start(cb); ++ return 0; + } + + static int nf_tables_dump_obj_done(struct netlink_callback *cb) +@@ -8282,42 +8146,16 @@ nf_tables_getobj_single(u32 portid, const struct nfnl_info *info, + static int nf_tables_getobj(struct sk_buff *skb, const struct nfnl_info *info, + const struct nlattr * const nla[]) + { +- u32 portid = NETLINK_CB(skb).portid; +- struct sk_buff *skb2; +- +- if (info->nlh->nlmsg_flags & NLM_F_DUMP) { +- struct netlink_dump_control c = { +- .start = nf_tables_dump_obj_start, +- .dump = nf_tables_dump_obj, +- .done = nf_tables_dump_obj_done, +- .module = THIS_MODULE, +- .data = (void *)nla, +- }; +- +- return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c); +- } +- +- skb2 = nf_tables_getobj_single(portid, info, nla, false); +- if (IS_ERR(skb2)) +- return PTR_ERR(skb2); +- +- return nfnetlink_unicast(skb2, info->net, portid); +-} +- +-static int nf_tables_getobj_reset(struct sk_buff *skb, +- const struct nfnl_info *info, +- const struct nlattr * const nla[]) +-{ +- struct nftables_pernet *nft_net = nft_pernet(info->net); + u32 portid = NETLINK_CB(skb).portid; + struct net *net = info->net; + struct sk_buff *skb2; ++ bool reset = false; + char *buf; + + if (info->nlh->nlmsg_flags & NLM_F_DUMP) { + struct netlink_dump_control c = { +- .start = nf_tables_dumpreset_obj_start, +- .dump = nf_tables_dumpreset_obj, ++ .start = nf_tables_dump_obj_start, ++ .dump = nf_tables_dump_obj, + .done = nf_tables_dump_obj_done, + .module = THIS_MODULE, + .data = (void *)nla, +@@ -8326,18 +8164,16 @@ static int nf_tables_getobj_reset(struct sk_buff *skb, + return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c); + } + +- if (!try_module_get(THIS_MODULE)) +- return -EINVAL; +- rcu_read_unlock(); +- mutex_lock(&nft_net->commit_mutex); +- skb2 = nf_tables_getobj_single(portid, info, nla, true); +- mutex_unlock(&nft_net->commit_mutex); +- rcu_read_lock(); +- module_put(THIS_MODULE); ++ if (NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_GETOBJ_RESET) ++ reset = true; + ++ skb2 = nf_tables_getobj_single(portid, info, nla, reset); + if (IS_ERR(skb2)) + return PTR_ERR(skb2); + ++ if (!reset) ++ return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid); ++ + buf = kasprintf(GFP_ATOMIC, "%.*s:%u", + nla_len(nla[NFTA_OBJ_TABLE]), + (char *)nla_data(nla[NFTA_OBJ_TABLE]), +@@ -9540,7 +9376,7 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = { + .policy = nft_rule_policy, + }, + [NFT_MSG_GETRULE_RESET] = { +- .call = nf_tables_getrule_reset, ++ .call = nf_tables_getrule, + .type = NFNL_CB_RCU, + .attr_count = NFTA_RULE_MAX, + .policy = nft_rule_policy, +@@ -9594,7 +9430,7 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = { + .policy = nft_set_elem_list_policy, + }, + [NFT_MSG_GETSETELEM_RESET] = { +- .call = nf_tables_getsetelem_reset, ++ .call = nf_tables_getsetelem, + .type = NFNL_CB_RCU, + .attr_count = NFTA_SET_ELEM_LIST_MAX, + .policy = nft_set_elem_list_policy, +@@ -9640,7 +9476,7 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = { + .policy = nft_obj_policy, + }, + [NFT_MSG_GETOBJ_RESET] = { +- .call = nf_tables_getobj_reset, ++ .call = nf_tables_getobj, + .type = NFNL_CB_RCU, + .attr_count = NFTA_OBJ_MAX, + .policy = nft_obj_policy, +-- +2.53.0 + diff --git a/staging-6.12/netfilter-nft_counter-serialize-reset-with-spinlock.patch b/staging-6.12/netfilter-nft_counter-serialize-reset-with-spinlock.patch new file mode 100644 index 0000000000..9160a8f7dd --- /dev/null +++ b/staging-6.12/netfilter-nft_counter-serialize-reset-with-spinlock.patch @@ -0,0 +1,86 @@ +From 47bbfcce532ae34c10759d24a321b19bb7571299 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 14:26:37 -0600 +Subject: netfilter: nft_counter: serialize reset with spinlock + +From: Brian Witte + +[ Upstream commit 779c60a5190c42689534172f4b49e927c9959e4e ] + +Add a global static spinlock to serialize counter fetch+reset +operations, preventing concurrent dump-and-reset from underrunning +values. + +The lock is taken before fetching the total so that two parallel +resets cannot both read the same counter values and then both +subtract them. + +A global lock is used for simplicity since resets are infrequent. +If this becomes a bottleneck, it can be replaced with a per-net +lock later. + +Fixes: bd662c4218f9 ("netfilter: nf_tables: Add locking for NFT_MSG_GETOBJ_RESET requests") +Fixes: 3d483faa6663 ("netfilter: nf_tables: Add locking for NFT_MSG_GETSETELEM_RESET requests") +Fixes: 3cb03edb4de3 ("netfilter: nf_tables: Add locking for NFT_MSG_GETRULE_RESET requests") +Suggested-by: Florian Westphal +Signed-off-by: Brian Witte +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_counter.c | 20 ++++++++++++++++---- + 1 file changed, 16 insertions(+), 4 deletions(-) + +diff --git a/net/netfilter/nft_counter.c b/net/netfilter/nft_counter.c +index 0d70325280cc57..169ae93688bcc5 100644 +--- a/net/netfilter/nft_counter.c ++++ b/net/netfilter/nft_counter.c +@@ -32,6 +32,9 @@ struct nft_counter_percpu_priv { + + static DEFINE_PER_CPU(struct u64_stats_sync, nft_counter_sync); + ++/* control plane only: sync fetch+reset */ ++static DEFINE_SPINLOCK(nft_counter_lock); ++ + static inline void nft_counter_do_eval(struct nft_counter_percpu_priv *priv, + struct nft_regs *regs, + const struct nft_pktinfo *pkt) +@@ -148,13 +151,25 @@ static void nft_counter_fetch(struct nft_counter_percpu_priv *priv, + } + } + ++static void nft_counter_fetch_and_reset(struct nft_counter_percpu_priv *priv, ++ struct nft_counter_tot *total) ++{ ++ spin_lock(&nft_counter_lock); ++ nft_counter_fetch(priv, total); ++ nft_counter_reset(priv, total); ++ spin_unlock(&nft_counter_lock); ++} ++ + static int nft_counter_do_dump(struct sk_buff *skb, + struct nft_counter_percpu_priv *priv, + bool reset) + { + struct nft_counter_tot total; + +- nft_counter_fetch(priv, &total); ++ if (unlikely(reset)) ++ nft_counter_fetch_and_reset(priv, &total); ++ else ++ nft_counter_fetch(priv, &total); + + if (nla_put_be64(skb, NFTA_COUNTER_BYTES, cpu_to_be64(total.bytes), + NFTA_COUNTER_PAD) || +@@ -162,9 +177,6 @@ static int nft_counter_do_dump(struct sk_buff *skb, + NFTA_COUNTER_PAD)) + goto nla_put_failure; + +- if (reset) +- nft_counter_reset(priv, &total); +- + return 0; + + nla_put_failure: +-- +2.53.0 + diff --git a/staging-6.12/netfilter-nft_quota-use-atomic64_xchg-for-reset.patch b/staging-6.12/netfilter-nft_quota-use-atomic64_xchg-for-reset.patch new file mode 100644 index 0000000000..97f3dc63db --- /dev/null +++ b/staging-6.12/netfilter-nft_quota-use-atomic64_xchg-for-reset.patch @@ -0,0 +1,61 @@ +From 07749809d6857f884e1b16aa556cef9b83f13efe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 14:26:38 -0600 +Subject: netfilter: nft_quota: use atomic64_xchg for reset + +From: Brian Witte + +[ Upstream commit 30c4d7fb59ac4c8d7fa7937df11eed10b368fa11 ] + +Use atomic64_xchg() to atomically read and zero the consumed value +on reset, which is simpler than the previous read+sub pattern and +doesn't require lock serialization. + +Fixes: bd662c4218f9 ("netfilter: nf_tables: Add locking for NFT_MSG_GETOBJ_RESET requests") +Fixes: 3d483faa6663 ("netfilter: nf_tables: Add locking for NFT_MSG_GETSETELEM_RESET requests") +Fixes: 3cb03edb4de3 ("netfilter: nf_tables: Add locking for NFT_MSG_GETRULE_RESET requests") +Suggested-by: Pablo Neira Ayuso +Signed-off-by: Brian Witte +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_quota.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/net/netfilter/nft_quota.c b/net/netfilter/nft_quota.c +index df0798da2329b9..cb6c0e04ff6755 100644 +--- a/net/netfilter/nft_quota.c ++++ b/net/netfilter/nft_quota.c +@@ -140,11 +140,16 @@ static int nft_quota_do_dump(struct sk_buff *skb, struct nft_quota *priv, + u64 consumed, consumed_cap, quota; + u32 flags = priv->flags; + +- /* Since we inconditionally increment consumed quota for each packet ++ /* Since we unconditionally increment consumed quota for each packet + * that we see, don't go over the quota boundary in what we send to + * userspace. + */ +- consumed = atomic64_read(priv->consumed); ++ if (reset) { ++ consumed = atomic64_xchg(priv->consumed, 0); ++ clear_bit(NFT_QUOTA_DEPLETED_BIT, &priv->flags); ++ } else { ++ consumed = atomic64_read(priv->consumed); ++ } + quota = atomic64_read(&priv->quota); + if (consumed >= quota) { + consumed_cap = quota; +@@ -160,10 +165,6 @@ static int nft_quota_do_dump(struct sk_buff *skb, struct nft_quota *priv, + nla_put_be32(skb, NFTA_QUOTA_FLAGS, htonl(flags))) + goto nla_put_failure; + +- if (reset) { +- atomic64_sub(consumed, priv->consumed); +- clear_bit(NFT_QUOTA_DEPLETED_BIT, &priv->flags); +- } + return 0; + + nla_put_failure: +-- +2.53.0 + diff --git a/staging-6.12/selftests-bpf-add-tests-for-ld_-abs-ind-failure-path.patch b/staging-6.12/selftests-bpf-add-tests-for-ld_-abs-ind-failure-path.patch new file mode 100644 index 0000000000..757107887c --- /dev/null +++ b/staging-6.12/selftests-bpf-add-tests-for-ld_-abs-ind-failure-path.patch @@ -0,0 +1,200 @@ +From 49c4710cc0804c5d854b37a3a6e18297ca4a17bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Jul 2026 15:39:08 +0800 +Subject: selftests/bpf: Add tests for ld_{abs,ind} failure path in subprogs + +From: Daniel Borkmann + +commit e0fcb42bc6f41bab2895757d6610616b3820eff7 upstream. + +Extend the verifier_ld_ind BPF selftests with subprogs containing +ld_{abs,ind} and craft the test in a way where the invalid register +read is rejected in the fixed case. Also add a success case each, +and add additional coverage related to the BTF return type enforcement. + + # LDLIBS=-static PKG_CONFIG='pkg-config --static' ./vmtest.sh -- ./test_progs -t verifier_ld_ind + [...] + #611/1 verifier_ld_ind/ld_ind: check calling conv, r1:OK + #611/2 verifier_ld_ind/ld_ind: check calling conv, r1 @unpriv:OK + #611/3 verifier_ld_ind/ld_ind: check calling conv, r2:OK + #611/4 verifier_ld_ind/ld_ind: check calling conv, r2 @unpriv:OK + #611/5 verifier_ld_ind/ld_ind: check calling conv, r3:OK + #611/6 verifier_ld_ind/ld_ind: check calling conv, r3 @unpriv:OK + #611/7 verifier_ld_ind/ld_ind: check calling conv, r4:OK + #611/8 verifier_ld_ind/ld_ind: check calling conv, r4 @unpriv:OK + #611/9 verifier_ld_ind/ld_ind: check calling conv, r5:OK + #611/10 verifier_ld_ind/ld_ind: check calling conv, r5 @unpriv:OK + #611/11 verifier_ld_ind/ld_ind: check calling conv, r7:OK + #611/12 verifier_ld_ind/ld_ind: check calling conv, r7 @unpriv:OK + #611/13 verifier_ld_ind/ld_abs: subprog early exit on ld_abs failure:OK + #611/14 verifier_ld_ind/ld_ind: subprog early exit on ld_ind failure:OK + #611/15 verifier_ld_ind/ld_abs: subprog with both paths safe:OK + #611/16 verifier_ld_ind/ld_ind: subprog with both paths safe:OK + #611/17 verifier_ld_ind/ld_abs: reject void return subprog:OK + #611/18 verifier_ld_ind/ld_ind: reject void return subprog:OK + #611 verifier_ld_ind:OK + Summary: 1/18 PASSED, 0 SKIPPED, 0 FAILED + +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260408191242.526279-4-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Philo Lu +Signed-off-by: Sasha Levin +--- + .../selftests/bpf/progs/verifier_ld_ind.c | 142 ++++++++++++++++++ + 1 file changed, 142 insertions(+) + +diff --git a/tools/testing/selftests/bpf/progs/verifier_ld_ind.c b/tools/testing/selftests/bpf/progs/verifier_ld_ind.c +index c925ba9a2e74c2..09e81b99eecb4e 100644 +--- a/tools/testing/selftests/bpf/progs/verifier_ld_ind.c ++++ b/tools/testing/selftests/bpf/progs/verifier_ld_ind.c +@@ -107,4 +107,146 @@ __naked void ind_check_calling_conv_r7(void) + : __clobber_all); + } + ++/* ++ * ld_{abs,ind} subprog that always sets r0=1 on the success path. ++ * bpf_gen_ld_abs() emits a hidden exit with r0=0 when the load helper ++ * fails. The verifier must model this failure return so that callers ++ * account for r0=0 as a possible return value. ++ */ ++__naked __noinline __used ++static int ldabs_subprog(void) ++{ ++ asm volatile ( ++ "r6 = r1;" ++ ".8byte %[ld_abs];" ++ "r0 = 1;" ++ "exit;" ++ : ++ : __imm_insn(ld_abs, BPF_LD_ABS(BPF_W, 0)) ++ : __clobber_all); ++} ++ ++__naked __noinline __used ++static int ldind_subprog(void) ++{ ++ asm volatile ( ++ "r6 = r1;" ++ "r7 = 0;" ++ ".8byte %[ld_ind];" ++ "r0 = 1;" ++ "exit;" ++ : ++ : __imm_insn(ld_ind, BPF_LD_IND(BPF_W, BPF_REG_7, 0)) ++ : __clobber_all); ++} ++ ++SEC("socket") ++__description("ld_abs: subprog early exit on ld_abs failure") ++__failure __msg("R9 !read_ok") ++__naked void ld_abs_subprog_early_exit(void) ++{ ++ asm volatile ( ++ "call ldabs_subprog;" ++ "if r0 != 0 goto l_exit_%=;" ++ "r0 = r9;" ++ "l_exit_%=:" ++ "r0 = 0;" ++ "exit;" ++ ::: __clobber_all); ++} ++ ++SEC("socket") ++__description("ld_ind: subprog early exit on ld_ind failure") ++__failure __msg("R9 !read_ok") ++__naked void ld_ind_subprog_early_exit(void) ++{ ++ asm volatile ( ++ "call ldind_subprog;" ++ "if r0 != 0 goto l_exit_%=;" ++ "r0 = r9;" ++ "l_exit_%=:" ++ "r0 = 0;" ++ "exit;" ++ ::: __clobber_all); ++} ++ ++SEC("socket") ++__description("ld_abs: subprog with both paths safe") ++__success ++__naked void ld_abs_subprog_both_paths_safe(void) ++{ ++ asm volatile ( ++ "call ldabs_subprog;" ++ "r0 = 0;" ++ "exit;" ++ ::: __clobber_all); ++} ++ ++SEC("socket") ++__description("ld_ind: subprog with both paths safe") ++__success ++__naked void ld_ind_subprog_both_paths_safe(void) ++{ ++ asm volatile ( ++ "call ldind_subprog;" ++ "r0 = 0;" ++ "exit;" ++ ::: __clobber_all); ++} ++ ++/* ++ * ld_{abs,ind} in subprogs require scalar (int) return type in BTF. ++ * A test with void return must be rejected. ++ */ ++__naked __noinline __used ++static void ldabs_void_subprog(void) ++{ ++ asm volatile ( ++ "r6 = r1;" ++ ".8byte %[ld_abs];" ++ "r0 = 1;" ++ "exit;" ++ : ++ : __imm_insn(ld_abs, BPF_LD_ABS(BPF_W, 0)) ++ : __clobber_all); ++} ++ ++SEC("socket") ++__description("ld_abs: reject void return subprog") ++__failure __msg("LD_ABS is only allowed in functions that return 'int'") ++__naked void ld_abs_void_subprog_reject(void) ++{ ++ asm volatile ( ++ "call ldabs_void_subprog;" ++ "r0 = 0;" ++ "exit;" ++ ::: __clobber_all); ++} ++ ++__naked __noinline __used ++static void ldind_void_subprog(void) ++{ ++ asm volatile ( ++ "r6 = r1;" ++ "r7 = 0;" ++ ".8byte %[ld_ind];" ++ "r0 = 1;" ++ "exit;" ++ : ++ : __imm_insn(ld_ind, BPF_LD_IND(BPF_W, BPF_REG_7, 0)) ++ : __clobber_all); ++} ++ ++SEC("socket") ++__description("ld_ind: reject void return subprog") ++__failure __msg("LD_ABS is only allowed in functions that return 'int'") ++__naked void ld_ind_void_subprog_reject(void) ++{ ++ asm volatile ( ++ "call ldind_void_subprog;" ++ "r0 = 0;" ++ "exit;" ++ ::: __clobber_all); ++} ++ + char _license[] SEC("license") = "GPL"; +-- +2.53.0 + diff --git a/staging-6.12/series b/staging-6.12/series index e3628cf8d9..03317ced8e 100644 --- a/staging-6.12/series +++ b/staging-6.12/series @@ -1,3 +1,10 @@ platform-x86-intel-uncore-freq-fix-current_freq_khz-.patch net-airoha-move-airoha_eth-driver-in-a-dedicated-fol.patch net-airoha-fix-skb-priority-underflow-in-airoha_dev_.patch +bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch +selftests-bpf-add-tests-for-ld_-abs-ind-failure-path.patch +netfilter-nft_counter-serialize-reset-with-spinlock.patch +netfilter-nft_quota-use-atomic64_xchg-for-reset.patch +netfilter-nf_tables-revert-commit_mutex-usage-in-res.patch +drm-virtio-fix-deadlock-in-display_info_cb-by-removi.patch +fs-proc-task_mmu-fix-make_uffd_wp_huge_pte-prot-upda.patch diff --git a/staging-6.18/bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch b/staging-6.18/bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch new file mode 100644 index 0000000000..f538b39ef1 --- /dev/null +++ b/staging-6.18/bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch @@ -0,0 +1,71 @@ +From 8b3a33ebf9bf89cca304a2e10fef5916d1203c34 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Jul 2026 15:39:07 +0800 +Subject: bpf: Fix ld_{abs,ind} failure path analysis in subprogs + +From: Daniel Borkmann + +commit ee861486e377edc55361c08dcbceab3f6b6577bd upstream. + +Usage of ld_{abs,ind} instructions got extended into subprogs some time +ago via commit 09b28d76eac4 ("bpf: Add abnormal return checks."). These +are only allowed in subprograms when the latter are BTF annotated and +have scalar return types. + +The code generator in bpf_gen_ld_abs() has an abnormal exit path (r0=0 + +exit) from legacy cBPF times. While the enforcement is on scalar return +types, the verifier must also simulate the path of abnormal exit if the +packet data load via ld_{abs,ind} failed. + +This is currently not the case. Fix it by having the verifier simulate +both success and failure paths, and extend it in similar ways as we do +for tail calls. The success path (r0=unknown, continue to next insn) is +pushed onto stack for later validation and the r0=0 and return to the +caller is done on the fall-through side. + +Fixes: 09b28d76eac4 ("bpf: Add abnormal return checks.") +Reported-by: STAR Labs SG +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260408191242.526279-2-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +[ Dropped visit_abnormal_return_insn changes: depends on 7.0 symbols from + e40f5a6bf88a ("bpf: correct stack liveness for tail calls"); + Hunk1: adapted IS_ERR/PTR_ERR to !branch/-EFAULT to match push_stack() + NULL-on-failure convention. ] +Signed-off-by: Philo Lu +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index d1c51d812f3b66..463455180a8e35 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -17402,6 +17402,23 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn) + mark_reg_unknown(env, regs, BPF_REG_0); + /* ld_abs load up to 32-bit skb data. */ + regs[BPF_REG_0].subreg_def = env->insn_idx + 1; ++ /* ++ * See bpf_gen_ld_abs() which emits a hidden BPF_EXIT with r0=0 ++ * which must be explored by the verifier when in a subprog. ++ */ ++ if (env->cur_state->curframe) { ++ struct bpf_verifier_state *branch; ++ ++ mark_reg_scratched(env, BPF_REG_0); ++ branch = push_stack(env, env->insn_idx + 1, env->insn_idx, false); ++ if (!branch) ++ return -EFAULT; ++ mark_reg_known_zero(env, regs, BPF_REG_0); ++ err = prepare_func_exit(env, &env->insn_idx); ++ if (err) ++ return err; ++ env->insn_idx--; ++ } + return 0; + } + +-- +2.53.0 + diff --git a/staging-6.18/drm-virtio-fix-deadlock-in-display_info_cb-by-removi.patch b/staging-6.18/drm-virtio-fix-deadlock-in-display_info_cb-by-removi.patch new file mode 100644 index 0000000000..0ad65b6737 --- /dev/null +++ b/staging-6.18/drm-virtio-fix-deadlock-in-display_info_cb-by-removi.patch @@ -0,0 +1,82 @@ +From 60c0c4cffc2072c69dfde68e5c6e40b82d9c9b0a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Jul 2026 22:01:00 +0900 +Subject: drm/virtio: fix deadlock in display_info_cb by removing hotplug from + dequeue worker + +From: Ryosuke Yasuoka + +[ Upstream commit d1b894c5bbb3fee0012bd14356286dc2384e8213 ] + +A probe-time deadlock can occur between the dequeue worker and +drm_client_register(). During probe, drm_client_register() holds +clientlist_mutex and calls the fbdev hotplug callback, which triggers an +atomic commit that ends up sleeping in virtio_gpu_queue_ctrl_sgs() +waiting for virtqueue space. The dequeue worker that would free that +space calls virtio_gpu_cmd_get_display_info_cb(), which invokes +drm_kms_helper_hotplug_event() -> drm_client_dev_hotplug(), attempting +to acquire the same clientlist_mutex. Since wake_up() is only called +after the resp_cb loop, the probe thread is never woken and both threads +deadlock. + +Fix this by removing the hotplug notification from +virtio_gpu_cmd_get_display_info_cb(). The display data (outputs[i].info) +is still updated synchronously in the callback. + +For the init path, drm_client_register() already fires an initial +hotplug when the client is registered, which picks up the connector +state updated by display_info_cb. + +For the runtime config_changed path, add a wait_event_timeout() in +config_changed_work_func() so that display_info_cb updates the connector +data before the hotplug notification is sent. Also replace +drm_helper_hpd_irq_event() with drm_kms_helper_hotplug_event() since +virtio-gpu never calls drm_kms_helper_poll_init() and thus +drm_helper_hpd_irq_event() always returns false without doing anything. + +Fixes: 27655b9bb9f0 ("drm/client: Send hotplug event after registering a client") +Closes: https://syzkaller.appspot.com/bug?id=d6dd6f86d3aaf7eebe7406e45c1c6e549453f224 +Closes: https://syzkaller.appspot.com/bug?id=908bd910da5dd79b88de4cf7baf376cc873a922e +Suggested-by: Dmitry Osipenko +Signed-off-by: Ryosuke Yasuoka +Signed-off-by: Dmitry Osipenko +Link: https://patch.msgid.link/20260713-virtiogpu_syzbot-v2-1-2958fa37d46d@redhat.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/virtio/virtgpu_kms.c | 5 ++++- + drivers/gpu/drm/virtio/virtgpu_vq.c | 3 --- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c +index 1c15cbf326b78c..4a25347734fda4 100644 +--- a/drivers/gpu/drm/virtio/virtgpu_kms.c ++++ b/drivers/gpu/drm/virtio/virtgpu_kms.c +@@ -48,7 +48,10 @@ static void virtio_gpu_config_changed_work_func(struct work_struct *work) + virtio_gpu_cmd_get_edids(vgdev); + virtio_gpu_cmd_get_display_info(vgdev); + virtio_gpu_notify(vgdev); +- drm_helper_hpd_irq_event(vgdev->ddev); ++ wait_event_timeout(vgdev->resp_wq, ++ !vgdev->display_info_pending, ++ 5 * HZ); ++ drm_kms_helper_hotplug_event(vgdev->ddev); + } + events_clear |= VIRTIO_GPU_EVENT_DISPLAY; + } +diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c +index 8181b22b9b46a1..412384e16daea4 100644 +--- a/drivers/gpu/drm/virtio/virtgpu_vq.c ++++ b/drivers/gpu/drm/virtio/virtgpu_vq.c +@@ -839,9 +839,6 @@ static void virtio_gpu_cmd_get_display_info_cb(struct virtio_gpu_device *vgdev, + vgdev->display_info_pending = false; + spin_unlock(&vgdev->display_info_lock); + wake_up(&vgdev->resp_wq); +- +- if (!drm_helper_hpd_irq_event(vgdev->ddev)) +- drm_kms_helper_hotplug_event(vgdev->ddev); + } + + static void virtio_gpu_cmd_get_capset_info_cb(struct virtio_gpu_device *vgdev, +-- +2.53.0 + diff --git a/staging-6.18/fs-proc-task_mmu-fix-make_uffd_wp_huge_pte-prot-upda.patch b/staging-6.18/fs-proc-task_mmu-fix-make_uffd_wp_huge_pte-prot-upda.patch new file mode 100644 index 0000000000..a86e2bed5b --- /dev/null +++ b/staging-6.18/fs-proc-task_mmu-fix-make_uffd_wp_huge_pte-prot-upda.patch @@ -0,0 +1,124 @@ +From 1fb7b87252e9b6ba3e250edddcba62956e2226fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Jul 2026 12:01:23 +0100 +Subject: fs/proc/task_mmu: fix make_uffd_wp_huge_pte() prot-update race + +From: Kiryl Shutsemau + +commit 04718f7c9290f95385f0dd328758753dc1c36dec upstream. + +Patch series "userfaultfd/pagemap: pre-existing fixes". + +These are pre-existing bug fixes that were carried at the front of the +userfaultfd RWP working-set-tracking series up to v5 [1]. Per review +feedback that fixes should not sit in the middle of a feature series, they +are split out and sent on their own; the RWP series is reposted rebased on +top of this. + +All six were flagged by the Sashiko AI review of the RWP series and carry +Reported-by: Sashiko AI review . They are +independent of RWP, apply to mm-new directly, and carry Cc: stable@. + + 1: fs/proc/task_mmu: a missing huge_ptep_modify_prot_start() in + make_uffd_wp_huge_pte() can lose hardware Dirty/Accessed updates + when PAGEMAP_SCAN write-protects a hugetlb PTE. + + 2: fs/proc/task_mmu: pagemap_scan_hugetlb_entry() compares the range + against HPAGE_SIZE rather than the hstate page size, so it never + write-protects gigantic hugetlb pages. + + 3: fs/proc/task_mmu: PAGEMAP_SCAN with PM_SCAN_WP_MATCHING over an + unpopulated hugetlb range self-deadlocks -- pagemap_scan_pte_hole() + calls uffd_wp_range() while walk_hugetlb_range() holds the hugetlb + vma lock for read, and hugetlb_change_protection() then takes it + for write. Install the marker inline instead. + + 4: mm/huge_memory: change_non_present_huge_pmd() drops pmd_swp_uffd_wp + on a device-private PMD permission downgrade, silently losing the + uffd-wp marker. + + 5: userfaultfd: must_wait() applies pte_write() to a locklessly read + PTE without checking pte_present(), so swap/migration entries + decode random offset bits and a thread can stay parked on a stale + fault. + + 6: userfaultfd: __VMA_UFFD_FLAGS feeds VMA_UFFD_MINOR_BIT (41) to + mk_vma_flags() unconditionally, an out-of-bounds write into the + single-word vma_flags_t on 32-bit. Build the mask from config-gated + per-mode masks so an unavailable bit is never materialised. + +This patch (of 6): + +make_uffd_wp_huge_pte() arms the UFFD_WP bit on a present HugeTLB PTE by +calling huge_ptep_modify_prot_commit() with a ptent snapshot that was +fetched without the corresponding huge_ptep_modify_prot_start(). The +start helper is what atomically clears the entry so the kernel-owned +snapshot stays consistent until the commit; without it, the hardware may +set Dirty or Accessed in the live PTE between the original read and the +commit, and huge_ptep_modify_prot_commit() (whose generic implementation +just calls set_huge_pte_at()) then writes the stale snapshot back over the +live hardware bits, losing the update. + +The non-hugetlb sibling make_uffd_wp_pte() does this correctly via +ptep_modify_prot_start() / ptep_modify_prot_commit(). Mirror that pattern +for the present-PTE branch. The migration case stays as-is -- migration +entries are non-present, so there's no hardware update to race against. + +Link: https://lore.kernel.org/20260529172331.356655-1-kas@kernel.org +Link: https://lore.kernel.org/20260529172331.356655-2-kas@kernel.org +Link: https://lore.kernel.org/all/20260526130509.2748441-1-kirill@shutemov.name/ [1] +Fixes: 52526ca7fdb9 ("fs/proc/task_mmu: implement IOCTL to get and optionally clear info about PTEs") +Signed-off-by: Kiryl Shutsemau +Reported-by: Sashiko AI review +Reviewed-by: Lorenzo Stoakes +Reviewed-by: Dev Jain +Cc: David Hildenbrand +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Peter Xu +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Cc: Balbir Singh +Cc: +Signed-off-by: Andrew Morton +[ kas: adapt to the pre-softleaf idiom; apply the + huge_ptep_modify_prot_start()/commit() fix to the present-PTE + (!huge_pte_none()) branch ] +Signed-off-by: Kiryl Shutsemau (Meta) +Signed-off-by: Sasha Levin +--- + fs/proc/task_mmu.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c +index 38b9d47426ca99..858b11009c269e 100644 +--- a/fs/proc/task_mmu.c ++++ b/fs/proc/task_mmu.c +@@ -2485,15 +2485,19 @@ static void make_uffd_wp_huge_pte(struct vm_area_struct *vma, + + psize = huge_page_size(hstate_vma(vma)); + +- if (is_hugetlb_entry_migration(ptent)) ++ if (is_hugetlb_entry_migration(ptent)) { + set_huge_pte_at(vma->vm_mm, addr, ptep, + pte_swp_mkuffd_wp(ptent), psize); +- else if (!huge_pte_none(ptent)) +- huge_ptep_modify_prot_commit(vma, addr, ptep, ptent, +- huge_pte_mkuffd_wp(ptent)); +- else ++ } else if (!huge_pte_none(ptent)) { ++ pte_t old_pte, new_pte; ++ ++ old_pte = huge_ptep_modify_prot_start(vma, addr, ptep); ++ new_pte = huge_pte_mkuffd_wp(old_pte); ++ huge_ptep_modify_prot_commit(vma, addr, ptep, old_pte, new_pte); ++ } else { + set_huge_pte_at(vma->vm_mm, addr, ptep, + make_pte_marker(PTE_MARKER_UFFD_WP), psize); ++ } + } + #endif /* CONFIG_HUGETLB_PAGE */ + +-- +2.53.0 + diff --git a/staging-6.18/netfilter-nf_tables-revert-commit_mutex-usage-in-res.patch b/staging-6.18/netfilter-nf_tables-revert-commit_mutex-usage-in-res.patch new file mode 100644 index 0000000000..95481ac9e4 --- /dev/null +++ b/staging-6.18/netfilter-nf_tables-revert-commit_mutex-usage-in-res.patch @@ -0,0 +1,424 @@ +From 6b1304757f523ace8898896505d3108bbcc89a70 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 14:26:36 -0600 +Subject: netfilter: nf_tables: revert commit_mutex usage in reset path + +From: Brian Witte + +[ Upstream commit 7f261bb906bf527c4a6e2a646e2d5f3679f2a8bc ] + +It causes circular lock dependency between commit_mutex, nfnl_subsys_ipset +and nlk_cb_mutex when nft reset, ipset list, and iptables-nft with '-m set' +rule run at the same time. + +Previous patches made it safe to run individual reset handlers concurrently +so commit_mutex is no longer required to prevent this. + +Fixes: bd662c4218f9 ("netfilter: nf_tables: Add locking for NFT_MSG_GETOBJ_RESET requests") +Fixes: 3d483faa6663 ("netfilter: nf_tables: Add locking for NFT_MSG_GETSETELEM_RESET requests") +Fixes: 3cb03edb4de3 ("netfilter: nf_tables: Add locking for NFT_MSG_GETRULE_RESET requests") +Link: https://lore.kernel.org/all/aUh_3mVRV8OrGsVo@strlen.de/ +Reported-by: +Closes: https://syzkaller.appspot.com/bug?extid=ff16b505ec9152e5f448 +Signed-off-by: Brian Witte +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_tables_api.c | 248 ++++++---------------------------- + 1 file changed, 42 insertions(+), 206 deletions(-) + +diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c +index 0842916c19f503..c82c16bd4257e4 100644 +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -3908,23 +3908,6 @@ static int nf_tables_dump_rules(struct sk_buff *skb, + return skb->len; + } + +-static int nf_tables_dumpreset_rules(struct sk_buff *skb, +- struct netlink_callback *cb) +-{ +- struct nftables_pernet *nft_net = nft_pernet(sock_net(skb->sk)); +- int ret; +- +- /* Mutex is held is to prevent that two concurrent dump-and-reset calls +- * do not underrun counters and quotas. The commit_mutex is used for +- * the lack a better lock, this is not transaction path. +- */ +- mutex_lock(&nft_net->commit_mutex); +- ret = nf_tables_dump_rules(skb, cb); +- mutex_unlock(&nft_net->commit_mutex); +- +- return ret; +-} +- + static int nf_tables_dump_rules_start(struct netlink_callback *cb) + { + struct nft_rule_dump_ctx *ctx = (void *)cb->ctx; +@@ -3944,16 +3927,10 @@ static int nf_tables_dump_rules_start(struct netlink_callback *cb) + return -ENOMEM; + } + } +- return 0; +-} +- +-static int nf_tables_dumpreset_rules_start(struct netlink_callback *cb) +-{ +- struct nft_rule_dump_ctx *ctx = (void *)cb->ctx; +- +- ctx->reset = true; ++ if (NFNL_MSG_TYPE(cb->nlh->nlmsg_type) == NFT_MSG_GETRULE_RESET) ++ ctx->reset = true; + +- return nf_tables_dump_rules_start(cb); ++ return 0; + } + + static int nf_tables_dump_rules_done(struct netlink_callback *cb) +@@ -4019,6 +3996,8 @@ static int nf_tables_getrule(struct sk_buff *skb, const struct nfnl_info *info, + u32 portid = NETLINK_CB(skb).portid; + struct net *net = info->net; + struct sk_buff *skb2; ++ bool reset = false; ++ char *buf; + + if (info->nlh->nlmsg_flags & NLM_F_DUMP) { + struct netlink_dump_control c = { +@@ -4032,47 +4011,16 @@ static int nf_tables_getrule(struct sk_buff *skb, const struct nfnl_info *info, + return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c); + } + +- skb2 = nf_tables_getrule_single(portid, info, nla, false); +- if (IS_ERR(skb2)) +- return PTR_ERR(skb2); +- +- return nfnetlink_unicast(skb2, net, portid); +-} +- +-static int nf_tables_getrule_reset(struct sk_buff *skb, +- const struct nfnl_info *info, +- const struct nlattr * const nla[]) +-{ +- struct nftables_pernet *nft_net = nft_pernet(info->net); +- u32 portid = NETLINK_CB(skb).portid; +- struct net *net = info->net; +- struct sk_buff *skb2; +- char *buf; +- +- if (info->nlh->nlmsg_flags & NLM_F_DUMP) { +- struct netlink_dump_control c = { +- .start= nf_tables_dumpreset_rules_start, +- .dump = nf_tables_dumpreset_rules, +- .done = nf_tables_dump_rules_done, +- .module = THIS_MODULE, +- .data = (void *)nla, +- }; +- +- return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c); +- } +- +- if (!try_module_get(THIS_MODULE)) +- return -EINVAL; +- rcu_read_unlock(); +- mutex_lock(&nft_net->commit_mutex); +- skb2 = nf_tables_getrule_single(portid, info, nla, true); +- mutex_unlock(&nft_net->commit_mutex); +- rcu_read_lock(); +- module_put(THIS_MODULE); ++ if (NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_GETRULE_RESET) ++ reset = true; + ++ skb2 = nf_tables_getrule_single(portid, info, nla, reset); + if (IS_ERR(skb2)) + return PTR_ERR(skb2); + ++ if (!reset) ++ return nfnetlink_unicast(skb2, net, portid); ++ + buf = kasprintf(GFP_ATOMIC, "%.*s:%u", + nla_len(nla[NFTA_RULE_TABLE]), + (char *)nla_data(nla[NFTA_RULE_TABLE]), +@@ -6332,6 +6280,10 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb) + nla_nest_end(skb, nest); + nlmsg_end(skb, nlh); + ++ if (dump_ctx->reset && args.iter.count > args.iter.skip) ++ audit_log_nft_set_reset(table, cb->seq, ++ args.iter.count - args.iter.skip); ++ + rcu_read_unlock(); + + if (args.iter.err && args.iter.err != -EMSGSIZE) +@@ -6347,26 +6299,6 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb) + return -ENOSPC; + } + +-static int nf_tables_dumpreset_set(struct sk_buff *skb, +- struct netlink_callback *cb) +-{ +- struct nftables_pernet *nft_net = nft_pernet(sock_net(skb->sk)); +- struct nft_set_dump_ctx *dump_ctx = cb->data; +- int ret, skip = cb->args[0]; +- +- mutex_lock(&nft_net->commit_mutex); +- +- ret = nf_tables_dump_set(skb, cb); +- +- if (cb->args[0] > skip) +- audit_log_nft_set_reset(dump_ctx->ctx.table, cb->seq, +- cb->args[0] - skip); +- +- mutex_unlock(&nft_net->commit_mutex); +- +- return ret; +-} +- + static int nf_tables_dump_set_start(struct netlink_callback *cb) + { + struct nft_set_dump_ctx *dump_ctx = cb->data; +@@ -6613,8 +6545,13 @@ static int nf_tables_getsetelem(struct sk_buff *skb, + { + struct netlink_ext_ack *extack = info->extack; + struct nft_set_dump_ctx dump_ctx; ++ int rem, err = 0, nelems = 0; ++ struct net *net = info->net; + struct nlattr *attr; +- int rem, err = 0; ++ bool reset = false; ++ ++ if (NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_GETSETELEM_RESET) ++ reset = true; + + if (info->nlh->nlmsg_flags & NLM_F_DUMP) { + struct netlink_dump_control c = { +@@ -6624,7 +6561,7 @@ static int nf_tables_getsetelem(struct sk_buff *skb, + .module = THIS_MODULE, + }; + +- err = nft_set_dump_ctx_init(&dump_ctx, skb, info, nla, false); ++ err = nft_set_dump_ctx_init(&dump_ctx, skb, info, nla, reset); + if (err) + return err; + +@@ -6635,75 +6572,21 @@ static int nf_tables_getsetelem(struct sk_buff *skb, + if (!nla[NFTA_SET_ELEM_LIST_ELEMENTS]) + return -EINVAL; + +- err = nft_set_dump_ctx_init(&dump_ctx, skb, info, nla, false); ++ err = nft_set_dump_ctx_init(&dump_ctx, skb, info, nla, reset); + if (err) + return err; + + nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) { +- err = nft_get_set_elem(&dump_ctx.ctx, dump_ctx.set, attr, false); +- if (err < 0) { +- NL_SET_BAD_ATTR(extack, attr); +- break; +- } +- } +- +- return err; +-} +- +-static int nf_tables_getsetelem_reset(struct sk_buff *skb, +- const struct nfnl_info *info, +- const struct nlattr * const nla[]) +-{ +- struct nftables_pernet *nft_net = nft_pernet(info->net); +- struct netlink_ext_ack *extack = info->extack; +- struct nft_set_dump_ctx dump_ctx; +- int rem, err = 0, nelems = 0; +- struct nlattr *attr; +- +- if (info->nlh->nlmsg_flags & NLM_F_DUMP) { +- struct netlink_dump_control c = { +- .start = nf_tables_dump_set_start, +- .dump = nf_tables_dumpreset_set, +- .done = nf_tables_dump_set_done, +- .module = THIS_MODULE, +- }; +- +- err = nft_set_dump_ctx_init(&dump_ctx, skb, info, nla, true); +- if (err) +- return err; +- +- c.data = &dump_ctx; +- return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c); +- } +- +- if (!nla[NFTA_SET_ELEM_LIST_ELEMENTS]) +- return -EINVAL; +- +- if (!try_module_get(THIS_MODULE)) +- return -EINVAL; +- rcu_read_unlock(); +- mutex_lock(&nft_net->commit_mutex); +- rcu_read_lock(); +- +- err = nft_set_dump_ctx_init(&dump_ctx, skb, info, nla, true); +- if (err) +- goto out_unlock; +- +- nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) { +- err = nft_get_set_elem(&dump_ctx.ctx, dump_ctx.set, attr, true); ++ err = nft_get_set_elem(&dump_ctx.ctx, dump_ctx.set, attr, reset); + if (err < 0) { + NL_SET_BAD_ATTR(extack, attr); + break; + } + nelems++; + } +- audit_log_nft_set_reset(dump_ctx.ctx.table, nft_base_seq(info->net), nelems); +- +-out_unlock: +- rcu_read_unlock(); +- mutex_unlock(&nft_net->commit_mutex); +- rcu_read_lock(); +- module_put(THIS_MODULE); ++ if (reset) ++ audit_log_nft_set_reset(dump_ctx.ctx.table, nft_base_seq(net), ++ nelems); + + return err; + } +@@ -8567,19 +8450,6 @@ static int nf_tables_dump_obj(struct sk_buff *skb, struct netlink_callback *cb) + return skb->len; + } + +-static int nf_tables_dumpreset_obj(struct sk_buff *skb, +- struct netlink_callback *cb) +-{ +- struct nftables_pernet *nft_net = nft_pernet(sock_net(skb->sk)); +- int ret; +- +- mutex_lock(&nft_net->commit_mutex); +- ret = nf_tables_dump_obj(skb, cb); +- mutex_unlock(&nft_net->commit_mutex); +- +- return ret; +-} +- + static int nf_tables_dump_obj_start(struct netlink_callback *cb) + { + struct nft_obj_dump_ctx *ctx = (void *)cb->ctx; +@@ -8596,16 +8466,10 @@ static int nf_tables_dump_obj_start(struct netlink_callback *cb) + if (nla[NFTA_OBJ_TYPE]) + ctx->type = ntohl(nla_get_be32(nla[NFTA_OBJ_TYPE])); + +- return 0; +-} +- +-static int nf_tables_dumpreset_obj_start(struct netlink_callback *cb) +-{ +- struct nft_obj_dump_ctx *ctx = (void *)cb->ctx; +- +- ctx->reset = true; ++ if (NFNL_MSG_TYPE(cb->nlh->nlmsg_type) == NFT_MSG_GETOBJ_RESET) ++ ctx->reset = true; + +- return nf_tables_dump_obj_start(cb); ++ return 0; + } + + static int nf_tables_dump_obj_done(struct netlink_callback *cb) +@@ -8667,42 +8531,16 @@ nf_tables_getobj_single(u32 portid, const struct nfnl_info *info, + static int nf_tables_getobj(struct sk_buff *skb, const struct nfnl_info *info, + const struct nlattr * const nla[]) + { +- u32 portid = NETLINK_CB(skb).portid; +- struct sk_buff *skb2; +- +- if (info->nlh->nlmsg_flags & NLM_F_DUMP) { +- struct netlink_dump_control c = { +- .start = nf_tables_dump_obj_start, +- .dump = nf_tables_dump_obj, +- .done = nf_tables_dump_obj_done, +- .module = THIS_MODULE, +- .data = (void *)nla, +- }; +- +- return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c); +- } +- +- skb2 = nf_tables_getobj_single(portid, info, nla, false); +- if (IS_ERR(skb2)) +- return PTR_ERR(skb2); +- +- return nfnetlink_unicast(skb2, info->net, portid); +-} +- +-static int nf_tables_getobj_reset(struct sk_buff *skb, +- const struct nfnl_info *info, +- const struct nlattr * const nla[]) +-{ +- struct nftables_pernet *nft_net = nft_pernet(info->net); + u32 portid = NETLINK_CB(skb).portid; + struct net *net = info->net; + struct sk_buff *skb2; ++ bool reset = false; + char *buf; + + if (info->nlh->nlmsg_flags & NLM_F_DUMP) { + struct netlink_dump_control c = { +- .start = nf_tables_dumpreset_obj_start, +- .dump = nf_tables_dumpreset_obj, ++ .start = nf_tables_dump_obj_start, ++ .dump = nf_tables_dump_obj, + .done = nf_tables_dump_obj_done, + .module = THIS_MODULE, + .data = (void *)nla, +@@ -8711,18 +8549,16 @@ static int nf_tables_getobj_reset(struct sk_buff *skb, + return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c); + } + +- if (!try_module_get(THIS_MODULE)) +- return -EINVAL; +- rcu_read_unlock(); +- mutex_lock(&nft_net->commit_mutex); +- skb2 = nf_tables_getobj_single(portid, info, nla, true); +- mutex_unlock(&nft_net->commit_mutex); +- rcu_read_lock(); +- module_put(THIS_MODULE); ++ if (NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_GETOBJ_RESET) ++ reset = true; + ++ skb2 = nf_tables_getobj_single(portid, info, nla, reset); + if (IS_ERR(skb2)) + return PTR_ERR(skb2); + ++ if (!reset) ++ return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid); ++ + buf = kasprintf(GFP_ATOMIC, "%.*s:%u", + nla_len(nla[NFTA_OBJ_TABLE]), + (char *)nla_data(nla[NFTA_OBJ_TABLE]), +@@ -10030,7 +9866,7 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = { + .policy = nft_rule_policy, + }, + [NFT_MSG_GETRULE_RESET] = { +- .call = nf_tables_getrule_reset, ++ .call = nf_tables_getrule, + .type = NFNL_CB_RCU, + .attr_count = NFTA_RULE_MAX, + .policy = nft_rule_policy, +@@ -10084,7 +9920,7 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = { + .policy = nft_set_elem_list_policy, + }, + [NFT_MSG_GETSETELEM_RESET] = { +- .call = nf_tables_getsetelem_reset, ++ .call = nf_tables_getsetelem, + .type = NFNL_CB_RCU, + .attr_count = NFTA_SET_ELEM_LIST_MAX, + .policy = nft_set_elem_list_policy, +@@ -10130,7 +9966,7 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = { + .policy = nft_obj_policy, + }, + [NFT_MSG_GETOBJ_RESET] = { +- .call = nf_tables_getobj_reset, ++ .call = nf_tables_getobj, + .type = NFNL_CB_RCU, + .attr_count = NFTA_OBJ_MAX, + .policy = nft_obj_policy, +-- +2.53.0 + diff --git a/staging-6.18/netfilter-nft_counter-serialize-reset-with-spinlock.patch b/staging-6.18/netfilter-nft_counter-serialize-reset-with-spinlock.patch new file mode 100644 index 0000000000..e2846bb0ee --- /dev/null +++ b/staging-6.18/netfilter-nft_counter-serialize-reset-with-spinlock.patch @@ -0,0 +1,86 @@ +From 4a9110c30d5e1af7349390950df0bc7e9b4a14cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 14:26:37 -0600 +Subject: netfilter: nft_counter: serialize reset with spinlock + +From: Brian Witte + +[ Upstream commit 779c60a5190c42689534172f4b49e927c9959e4e ] + +Add a global static spinlock to serialize counter fetch+reset +operations, preventing concurrent dump-and-reset from underrunning +values. + +The lock is taken before fetching the total so that two parallel +resets cannot both read the same counter values and then both +subtract them. + +A global lock is used for simplicity since resets are infrequent. +If this becomes a bottleneck, it can be replaced with a per-net +lock later. + +Fixes: bd662c4218f9 ("netfilter: nf_tables: Add locking for NFT_MSG_GETOBJ_RESET requests") +Fixes: 3d483faa6663 ("netfilter: nf_tables: Add locking for NFT_MSG_GETSETELEM_RESET requests") +Fixes: 3cb03edb4de3 ("netfilter: nf_tables: Add locking for NFT_MSG_GETRULE_RESET requests") +Suggested-by: Florian Westphal +Signed-off-by: Brian Witte +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_counter.c | 20 ++++++++++++++++---- + 1 file changed, 16 insertions(+), 4 deletions(-) + +diff --git a/net/netfilter/nft_counter.c b/net/netfilter/nft_counter.c +index 0d70325280cc57..169ae93688bcc5 100644 +--- a/net/netfilter/nft_counter.c ++++ b/net/netfilter/nft_counter.c +@@ -32,6 +32,9 @@ struct nft_counter_percpu_priv { + + static DEFINE_PER_CPU(struct u64_stats_sync, nft_counter_sync); + ++/* control plane only: sync fetch+reset */ ++static DEFINE_SPINLOCK(nft_counter_lock); ++ + static inline void nft_counter_do_eval(struct nft_counter_percpu_priv *priv, + struct nft_regs *regs, + const struct nft_pktinfo *pkt) +@@ -148,13 +151,25 @@ static void nft_counter_fetch(struct nft_counter_percpu_priv *priv, + } + } + ++static void nft_counter_fetch_and_reset(struct nft_counter_percpu_priv *priv, ++ struct nft_counter_tot *total) ++{ ++ spin_lock(&nft_counter_lock); ++ nft_counter_fetch(priv, total); ++ nft_counter_reset(priv, total); ++ spin_unlock(&nft_counter_lock); ++} ++ + static int nft_counter_do_dump(struct sk_buff *skb, + struct nft_counter_percpu_priv *priv, + bool reset) + { + struct nft_counter_tot total; + +- nft_counter_fetch(priv, &total); ++ if (unlikely(reset)) ++ nft_counter_fetch_and_reset(priv, &total); ++ else ++ nft_counter_fetch(priv, &total); + + if (nla_put_be64(skb, NFTA_COUNTER_BYTES, cpu_to_be64(total.bytes), + NFTA_COUNTER_PAD) || +@@ -162,9 +177,6 @@ static int nft_counter_do_dump(struct sk_buff *skb, + NFTA_COUNTER_PAD)) + goto nla_put_failure; + +- if (reset) +- nft_counter_reset(priv, &total); +- + return 0; + + nla_put_failure: +-- +2.53.0 + diff --git a/staging-6.18/netfilter-nft_quota-use-atomic64_xchg-for-reset.patch b/staging-6.18/netfilter-nft_quota-use-atomic64_xchg-for-reset.patch new file mode 100644 index 0000000000..46f8477c36 --- /dev/null +++ b/staging-6.18/netfilter-nft_quota-use-atomic64_xchg-for-reset.patch @@ -0,0 +1,61 @@ +From a3ef9fe7d75aac0a74fabd11231e810069a54360 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Feb 2026 14:26:38 -0600 +Subject: netfilter: nft_quota: use atomic64_xchg for reset + +From: Brian Witte + +[ Upstream commit 30c4d7fb59ac4c8d7fa7937df11eed10b368fa11 ] + +Use atomic64_xchg() to atomically read and zero the consumed value +on reset, which is simpler than the previous read+sub pattern and +doesn't require lock serialization. + +Fixes: bd662c4218f9 ("netfilter: nf_tables: Add locking for NFT_MSG_GETOBJ_RESET requests") +Fixes: 3d483faa6663 ("netfilter: nf_tables: Add locking for NFT_MSG_GETSETELEM_RESET requests") +Fixes: 3cb03edb4de3 ("netfilter: nf_tables: Add locking for NFT_MSG_GETRULE_RESET requests") +Suggested-by: Pablo Neira Ayuso +Signed-off-by: Brian Witte +Signed-off-by: Florian Westphal +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_quota.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/net/netfilter/nft_quota.c b/net/netfilter/nft_quota.c +index df0798da2329b9..cb6c0e04ff6755 100644 +--- a/net/netfilter/nft_quota.c ++++ b/net/netfilter/nft_quota.c +@@ -140,11 +140,16 @@ static int nft_quota_do_dump(struct sk_buff *skb, struct nft_quota *priv, + u64 consumed, consumed_cap, quota; + u32 flags = priv->flags; + +- /* Since we inconditionally increment consumed quota for each packet ++ /* Since we unconditionally increment consumed quota for each packet + * that we see, don't go over the quota boundary in what we send to + * userspace. + */ +- consumed = atomic64_read(priv->consumed); ++ if (reset) { ++ consumed = atomic64_xchg(priv->consumed, 0); ++ clear_bit(NFT_QUOTA_DEPLETED_BIT, &priv->flags); ++ } else { ++ consumed = atomic64_read(priv->consumed); ++ } + quota = atomic64_read(&priv->quota); + if (consumed >= quota) { + consumed_cap = quota; +@@ -160,10 +165,6 @@ static int nft_quota_do_dump(struct sk_buff *skb, struct nft_quota *priv, + nla_put_be32(skb, NFTA_QUOTA_FLAGS, htonl(flags))) + goto nla_put_failure; + +- if (reset) { +- atomic64_sub(consumed, priv->consumed); +- clear_bit(NFT_QUOTA_DEPLETED_BIT, &priv->flags); +- } + return 0; + + nla_put_failure: +-- +2.53.0 + diff --git a/staging-6.18/selftests-bpf-add-tests-for-ld_-abs-ind-failure-path.patch b/staging-6.18/selftests-bpf-add-tests-for-ld_-abs-ind-failure-path.patch new file mode 100644 index 0000000000..8d881a3066 --- /dev/null +++ b/staging-6.18/selftests-bpf-add-tests-for-ld_-abs-ind-failure-path.patch @@ -0,0 +1,200 @@ +From d3b6095a981698eb7d0e7c72ff6ade902bcdedff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Jul 2026 15:39:08 +0800 +Subject: selftests/bpf: Add tests for ld_{abs,ind} failure path in subprogs + +From: Daniel Borkmann + +commit e0fcb42bc6f41bab2895757d6610616b3820eff7 upstream. + +Extend the verifier_ld_ind BPF selftests with subprogs containing +ld_{abs,ind} and craft the test in a way where the invalid register +read is rejected in the fixed case. Also add a success case each, +and add additional coverage related to the BTF return type enforcement. + + # LDLIBS=-static PKG_CONFIG='pkg-config --static' ./vmtest.sh -- ./test_progs -t verifier_ld_ind + [...] + #611/1 verifier_ld_ind/ld_ind: check calling conv, r1:OK + #611/2 verifier_ld_ind/ld_ind: check calling conv, r1 @unpriv:OK + #611/3 verifier_ld_ind/ld_ind: check calling conv, r2:OK + #611/4 verifier_ld_ind/ld_ind: check calling conv, r2 @unpriv:OK + #611/5 verifier_ld_ind/ld_ind: check calling conv, r3:OK + #611/6 verifier_ld_ind/ld_ind: check calling conv, r3 @unpriv:OK + #611/7 verifier_ld_ind/ld_ind: check calling conv, r4:OK + #611/8 verifier_ld_ind/ld_ind: check calling conv, r4 @unpriv:OK + #611/9 verifier_ld_ind/ld_ind: check calling conv, r5:OK + #611/10 verifier_ld_ind/ld_ind: check calling conv, r5 @unpriv:OK + #611/11 verifier_ld_ind/ld_ind: check calling conv, r7:OK + #611/12 verifier_ld_ind/ld_ind: check calling conv, r7 @unpriv:OK + #611/13 verifier_ld_ind/ld_abs: subprog early exit on ld_abs failure:OK + #611/14 verifier_ld_ind/ld_ind: subprog early exit on ld_ind failure:OK + #611/15 verifier_ld_ind/ld_abs: subprog with both paths safe:OK + #611/16 verifier_ld_ind/ld_ind: subprog with both paths safe:OK + #611/17 verifier_ld_ind/ld_abs: reject void return subprog:OK + #611/18 verifier_ld_ind/ld_ind: reject void return subprog:OK + #611 verifier_ld_ind:OK + Summary: 1/18 PASSED, 0 SKIPPED, 0 FAILED + +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260408191242.526279-4-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Philo Lu +Signed-off-by: Sasha Levin +--- + .../selftests/bpf/progs/verifier_ld_ind.c | 142 ++++++++++++++++++ + 1 file changed, 142 insertions(+) + +diff --git a/tools/testing/selftests/bpf/progs/verifier_ld_ind.c b/tools/testing/selftests/bpf/progs/verifier_ld_ind.c +index c925ba9a2e74c2..09e81b99eecb4e 100644 +--- a/tools/testing/selftests/bpf/progs/verifier_ld_ind.c ++++ b/tools/testing/selftests/bpf/progs/verifier_ld_ind.c +@@ -107,4 +107,146 @@ __naked void ind_check_calling_conv_r7(void) + : __clobber_all); + } + ++/* ++ * ld_{abs,ind} subprog that always sets r0=1 on the success path. ++ * bpf_gen_ld_abs() emits a hidden exit with r0=0 when the load helper ++ * fails. The verifier must model this failure return so that callers ++ * account for r0=0 as a possible return value. ++ */ ++__naked __noinline __used ++static int ldabs_subprog(void) ++{ ++ asm volatile ( ++ "r6 = r1;" ++ ".8byte %[ld_abs];" ++ "r0 = 1;" ++ "exit;" ++ : ++ : __imm_insn(ld_abs, BPF_LD_ABS(BPF_W, 0)) ++ : __clobber_all); ++} ++ ++__naked __noinline __used ++static int ldind_subprog(void) ++{ ++ asm volatile ( ++ "r6 = r1;" ++ "r7 = 0;" ++ ".8byte %[ld_ind];" ++ "r0 = 1;" ++ "exit;" ++ : ++ : __imm_insn(ld_ind, BPF_LD_IND(BPF_W, BPF_REG_7, 0)) ++ : __clobber_all); ++} ++ ++SEC("socket") ++__description("ld_abs: subprog early exit on ld_abs failure") ++__failure __msg("R9 !read_ok") ++__naked void ld_abs_subprog_early_exit(void) ++{ ++ asm volatile ( ++ "call ldabs_subprog;" ++ "if r0 != 0 goto l_exit_%=;" ++ "r0 = r9;" ++ "l_exit_%=:" ++ "r0 = 0;" ++ "exit;" ++ ::: __clobber_all); ++} ++ ++SEC("socket") ++__description("ld_ind: subprog early exit on ld_ind failure") ++__failure __msg("R9 !read_ok") ++__naked void ld_ind_subprog_early_exit(void) ++{ ++ asm volatile ( ++ "call ldind_subprog;" ++ "if r0 != 0 goto l_exit_%=;" ++ "r0 = r9;" ++ "l_exit_%=:" ++ "r0 = 0;" ++ "exit;" ++ ::: __clobber_all); ++} ++ ++SEC("socket") ++__description("ld_abs: subprog with both paths safe") ++__success ++__naked void ld_abs_subprog_both_paths_safe(void) ++{ ++ asm volatile ( ++ "call ldabs_subprog;" ++ "r0 = 0;" ++ "exit;" ++ ::: __clobber_all); ++} ++ ++SEC("socket") ++__description("ld_ind: subprog with both paths safe") ++__success ++__naked void ld_ind_subprog_both_paths_safe(void) ++{ ++ asm volatile ( ++ "call ldind_subprog;" ++ "r0 = 0;" ++ "exit;" ++ ::: __clobber_all); ++} ++ ++/* ++ * ld_{abs,ind} in subprogs require scalar (int) return type in BTF. ++ * A test with void return must be rejected. ++ */ ++__naked __noinline __used ++static void ldabs_void_subprog(void) ++{ ++ asm volatile ( ++ "r6 = r1;" ++ ".8byte %[ld_abs];" ++ "r0 = 1;" ++ "exit;" ++ : ++ : __imm_insn(ld_abs, BPF_LD_ABS(BPF_W, 0)) ++ : __clobber_all); ++} ++ ++SEC("socket") ++__description("ld_abs: reject void return subprog") ++__failure __msg("LD_ABS is only allowed in functions that return 'int'") ++__naked void ld_abs_void_subprog_reject(void) ++{ ++ asm volatile ( ++ "call ldabs_void_subprog;" ++ "r0 = 0;" ++ "exit;" ++ ::: __clobber_all); ++} ++ ++__naked __noinline __used ++static void ldind_void_subprog(void) ++{ ++ asm volatile ( ++ "r6 = r1;" ++ "r7 = 0;" ++ ".8byte %[ld_ind];" ++ "r0 = 1;" ++ "exit;" ++ : ++ : __imm_insn(ld_ind, BPF_LD_IND(BPF_W, BPF_REG_7, 0)) ++ : __clobber_all); ++} ++ ++SEC("socket") ++__description("ld_ind: reject void return subprog") ++__failure __msg("LD_ABS is only allowed in functions that return 'int'") ++__naked void ld_ind_void_subprog_reject(void) ++{ ++ asm volatile ( ++ "call ldind_void_subprog;" ++ "r0 = 0;" ++ "exit;" ++ ::: __clobber_all); ++} ++ + char _license[] SEC("license") = "GPL"; +-- +2.53.0 + diff --git a/staging-6.18/series b/staging-6.18/series index a69a51ccf5..b0d818b02e 100644 --- a/staging-6.18/series +++ b/staging-6.18/series @@ -1,3 +1,10 @@ posix-timers-expand-timer_-re-arm-callbacks-with-a-b.patch posix-cpu-timers-prevent-uaf-caused-by-non-leader-ex.patch platform-x86-intel-uncore-freq-fix-current_freq_khz-.patch +bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch +selftests-bpf-add-tests-for-ld_-abs-ind-failure-path.patch +netfilter-nft_counter-serialize-reset-with-spinlock.patch +netfilter-nft_quota-use-atomic64_xchg-for-reset.patch +netfilter-nf_tables-revert-commit_mutex-usage-in-res.patch +drm-virtio-fix-deadlock-in-display_info_cb-by-removi.patch +fs-proc-task_mmu-fix-make_uffd_wp_huge_pte-prot-upda.patch diff --git a/staging-6.6/bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch b/staging-6.6/bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch new file mode 100644 index 0000000000..d82aa92244 --- /dev/null +++ b/staging-6.6/bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch @@ -0,0 +1,71 @@ +From 477e3f08c9d4e470f508dc8f21a8699830f01176 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Jul 2026 15:39:07 +0800 +Subject: bpf: Fix ld_{abs,ind} failure path analysis in subprogs + +From: Daniel Borkmann + +commit ee861486e377edc55361c08dcbceab3f6b6577bd upstream. + +Usage of ld_{abs,ind} instructions got extended into subprogs some time +ago via commit 09b28d76eac4 ("bpf: Add abnormal return checks."). These +are only allowed in subprograms when the latter are BTF annotated and +have scalar return types. + +The code generator in bpf_gen_ld_abs() has an abnormal exit path (r0=0 + +exit) from legacy cBPF times. While the enforcement is on scalar return +types, the verifier must also simulate the path of abnormal exit if the +packet data load via ld_{abs,ind} failed. + +This is currently not the case. Fix it by having the verifier simulate +both success and failure paths, and extend it in similar ways as we do +for tail calls. The success path (r0=unknown, continue to next insn) is +pushed onto stack for later validation and the r0=0 and return to the +caller is done on the fall-through side. + +Fixes: 09b28d76eac4 ("bpf: Add abnormal return checks.") +Reported-by: STAR Labs SG +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260408191242.526279-2-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +[ Dropped visit_abnormal_return_insn changes: depends on 7.0 symbols from + e40f5a6bf88a ("bpf: correct stack liveness for tail calls"); + Hunk1: adapted IS_ERR/PTR_ERR to !branch/-EFAULT to match push_stack() + NULL-on-failure convention. ] +Signed-off-by: Philo Lu +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 1da0092122c1db..5e094c12fc94c5 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -15120,6 +15120,23 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn) + mark_reg_unknown(env, regs, BPF_REG_0); + /* ld_abs load up to 32-bit skb data. */ + regs[BPF_REG_0].subreg_def = env->insn_idx + 1; ++ /* ++ * See bpf_gen_ld_abs() which emits a hidden BPF_EXIT with r0=0 ++ * which must be explored by the verifier when in a subprog. ++ */ ++ if (env->cur_state->curframe) { ++ struct bpf_verifier_state *branch; ++ ++ mark_reg_scratched(env, BPF_REG_0); ++ branch = push_stack(env, env->insn_idx + 1, env->insn_idx, false); ++ if (!branch) ++ return -EFAULT; ++ mark_reg_known_zero(env, regs, BPF_REG_0); ++ err = prepare_func_exit(env, &env->insn_idx); ++ if (err) ++ return err; ++ env->insn_idx--; ++ } + return 0; + } + +-- +2.53.0 + diff --git a/staging-6.6/drm-virtio-fix-deadlock-in-display_info_cb-by-removi.patch b/staging-6.6/drm-virtio-fix-deadlock-in-display_info_cb-by-removi.patch new file mode 100644 index 0000000000..44755d1e8f --- /dev/null +++ b/staging-6.6/drm-virtio-fix-deadlock-in-display_info_cb-by-removi.patch @@ -0,0 +1,82 @@ +From 09ef4b7a3b15ae1f5471cf07728820c038354e3a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Jul 2026 22:01:00 +0900 +Subject: drm/virtio: fix deadlock in display_info_cb by removing hotplug from + dequeue worker + +From: Ryosuke Yasuoka + +[ Upstream commit d1b894c5bbb3fee0012bd14356286dc2384e8213 ] + +A probe-time deadlock can occur between the dequeue worker and +drm_client_register(). During probe, drm_client_register() holds +clientlist_mutex and calls the fbdev hotplug callback, which triggers an +atomic commit that ends up sleeping in virtio_gpu_queue_ctrl_sgs() +waiting for virtqueue space. The dequeue worker that would free that +space calls virtio_gpu_cmd_get_display_info_cb(), which invokes +drm_kms_helper_hotplug_event() -> drm_client_dev_hotplug(), attempting +to acquire the same clientlist_mutex. Since wake_up() is only called +after the resp_cb loop, the probe thread is never woken and both threads +deadlock. + +Fix this by removing the hotplug notification from +virtio_gpu_cmd_get_display_info_cb(). The display data (outputs[i].info) +is still updated synchronously in the callback. + +For the init path, drm_client_register() already fires an initial +hotplug when the client is registered, which picks up the connector +state updated by display_info_cb. + +For the runtime config_changed path, add a wait_event_timeout() in +config_changed_work_func() so that display_info_cb updates the connector +data before the hotplug notification is sent. Also replace +drm_helper_hpd_irq_event() with drm_kms_helper_hotplug_event() since +virtio-gpu never calls drm_kms_helper_poll_init() and thus +drm_helper_hpd_irq_event() always returns false without doing anything. + +Fixes: 27655b9bb9f0 ("drm/client: Send hotplug event after registering a client") +Closes: https://syzkaller.appspot.com/bug?id=d6dd6f86d3aaf7eebe7406e45c1c6e549453f224 +Closes: https://syzkaller.appspot.com/bug?id=908bd910da5dd79b88de4cf7baf376cc873a922e +Suggested-by: Dmitry Osipenko +Signed-off-by: Ryosuke Yasuoka +Signed-off-by: Dmitry Osipenko +Link: https://patch.msgid.link/20260713-virtiogpu_syzbot-v2-1-2958fa37d46d@redhat.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/virtio/virtgpu_kms.c | 5 ++++- + drivers/gpu/drm/virtio/virtgpu_vq.c | 3 --- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c +index 5a3b5aaed1f361..c88456bc9fcc00 100644 +--- a/drivers/gpu/drm/virtio/virtgpu_kms.c ++++ b/drivers/gpu/drm/virtio/virtgpu_kms.c +@@ -48,7 +48,10 @@ static void virtio_gpu_config_changed_work_func(struct work_struct *work) + virtio_gpu_cmd_get_edids(vgdev); + virtio_gpu_cmd_get_display_info(vgdev); + virtio_gpu_notify(vgdev); +- drm_helper_hpd_irq_event(vgdev->ddev); ++ wait_event_timeout(vgdev->resp_wq, ++ !vgdev->display_info_pending, ++ 5 * HZ); ++ drm_kms_helper_hotplug_event(vgdev->ddev); + } + events_clear |= VIRTIO_GPU_EVENT_DISPLAY; + } +diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c +index b1a00c0c25a70b..fbafa44a726453 100644 +--- a/drivers/gpu/drm/virtio/virtgpu_vq.c ++++ b/drivers/gpu/drm/virtio/virtgpu_vq.c +@@ -669,9 +669,6 @@ static void virtio_gpu_cmd_get_display_info_cb(struct virtio_gpu_device *vgdev, + vgdev->display_info_pending = false; + spin_unlock(&vgdev->display_info_lock); + wake_up(&vgdev->resp_wq); +- +- if (!drm_helper_hpd_irq_event(vgdev->ddev)) +- drm_kms_helper_hotplug_event(vgdev->ddev); + } + + static void virtio_gpu_cmd_get_capset_info_cb(struct virtio_gpu_device *vgdev, +-- +2.53.0 + diff --git a/staging-6.6/platform-x86-amd-pmc-avoid-logging-null-for-dmi-valu.patch b/staging-6.6/platform-x86-amd-pmc-avoid-logging-null-for-dmi-valu.patch new file mode 100644 index 0000000000..c65d083a26 --- /dev/null +++ b/staging-6.6/platform-x86-amd-pmc-avoid-logging-null-for-dmi-valu.patch @@ -0,0 +1,56 @@ +From 295d1cf7e341d3d27dccefd8775ad6d71ad0ac93 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Jul 2026 18:54:02 +0200 +Subject: platform/x86/amd/pmc: Avoid logging "(null)" for DMI values +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Daniel Gibson + +commit a0738abd042f7406edd2175a819cf2e66388ed97 upstream. + +dmi_get_system_info(...) can return NULL. Using that as %s arguments +of dev_info() would log "(null)" (as part of a message like +'... System Vendor: "(null)", Product Name: "(null)" ...'), which may +be confusing for users. + +Use Elvis operator to print "(Unknown)" instead. + +Fixes: 428b9fd2dce5 ("platform/x86/amd/pmc: Add delay_suspend module parameter") +Reported-by: kernel test robot +Closes: https://lore.kernel.org/oe-kbuild-all/202606251540.Nr2BtaNu-lkp@intel.com/ +Suggested-by: Ilpo Järvinen +Signed-off-by: Daniel Gibson +Link: https://patch.msgid.link/20260626220210.1761783-2-daniel@gibson.sh +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/amd/pmc/pmc.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c +index b0951236887797..bf6c7ca247e243 100644 +--- a/drivers/platform/x86/amd/pmc/pmc.c ++++ b/drivers/platform/x86/amd/pmc/pmc.c +@@ -852,11 +852,11 @@ static bool amd_pmc_want_suspend_delay(struct amd_pmc_dev *pdev) + } else if (delay_suspend == 1) { + if (!intermediate_wakeup) + dev_info(pdev->dev, "Delaying suspend by 2.5s because delay_suspend=1. If this solves problems on your machine, please report this whole line to: platform-driver-x86@vger.kernel.org so it can be automatically detected as affected in the future. System Vendor: \"%s\" Product Name: \"%s\" Product Family: \"%s\" Board Vendor: \"%s\" Board Name: \"%s\"\n", +- dmi_get_system_info(DMI_SYS_VENDOR), +- dmi_get_system_info(DMI_PRODUCT_NAME), +- dmi_get_system_info(DMI_PRODUCT_FAMILY), +- dmi_get_system_info(DMI_BOARD_VENDOR), +- dmi_get_system_info(DMI_BOARD_NAME)); ++ dmi_get_system_info(DMI_SYS_VENDOR) ?: "(Unknown)", ++ dmi_get_system_info(DMI_PRODUCT_NAME) ?: "(Unknown)", ++ dmi_get_system_info(DMI_PRODUCT_FAMILY) ?: "(Unknown)", ++ dmi_get_system_info(DMI_BOARD_VENDOR) ?: "(Unknown)", ++ dmi_get_system_info(DMI_BOARD_NAME) ?: "(Unknown)"); + return true; + } + return false; +-- +2.53.0 + diff --git a/staging-6.6/platform-x86-amd-pmc-don-t-log-during-intermediate-w.patch b/staging-6.6/platform-x86-amd-pmc-don-t-log-during-intermediate-w.patch new file mode 100644 index 0000000000..21aaac08c4 --- /dev/null +++ b/staging-6.6/platform-x86-amd-pmc-don-t-log-during-intermediate-w.patch @@ -0,0 +1,124 @@ +From c5e4d6584db2775f800e78be3e2b442957eb7c40 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Jul 2026 18:54:01 +0200 +Subject: platform/x86/amd/pmc: Don't log during intermediate wakeups +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Daniel Gibson + +commit 037f0b03c663a247366673a807834389107995b7 upstream. + +The ECs in the IdeaPads that need the delay_suspend quirk send lots +of messages when charging, which not only causes intermediate wakeups +when suspended, but also prevents the device from reaching the deepest +suspend state. + +Because of this amd_pmc_intermediate_wakeup_need_delay() returns false +during intermediate wakeups and amd_pmc_want_suspend_delay() is called. +So far it always logged its "Delaying suspend by 2.5s ..." messages +then, which spams dmesg. This commit makes sure that those messages are +only logged once per suspend. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=221383 +Reviewed-by: Hans de Goede +Signed-off-by: Daniel Gibson +Link: https://patch.msgid.link/20260611150426.3683372-5-daniel@gibson.sh +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/amd/pmc/pmc.c | 39 ++++++++++++++++++++++++------ + drivers/platform/x86/amd/pmc/pmc.h | 1 + + 2 files changed, 32 insertions(+), 8 deletions(-) + +diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c +index d5b543f74a22db..b0951236887797 100644 +--- a/drivers/platform/x86/amd/pmc/pmc.c ++++ b/drivers/platform/x86/amd/pmc/pmc.c +@@ -811,6 +811,20 @@ static bool amd_pmc_intermediate_wakeup_need_delay(struct amd_pmc_dev *pdev) + + static bool amd_pmc_want_suspend_delay(struct amd_pmc_dev *pdev) + { ++ /* ++ * intermediate_wakeup implies that the machine didn't get to deepest sleep ++ * state before - otherwise this function isn't called in amd_pmc_s2idle_check() ++ * because amd_pmc_intermediate_wakeup_need_delay() returns true first. ++ * On some IdeaPads that happens when charging, because the EC seems ++ * to send lots of messages then that wake the machine. ++ * ++ * But even in that case, the sleep here is necessary (on those IdeaPads), ++ * otherwise they wake up completely (resume) after a few seconds. ++ * So this variable is only used to avoid spamming dmesg on each ++ * intermediate wakeup. ++ */ ++ bool intermediate_wakeup = !pdev->is_first_check_after_suspend; ++ + /* + * Some Lenovo Laptops (like different IdeaPad 3 Slims) need some + * me-time before sleeping or they get uncooperative after waking +@@ -829,17 +843,20 @@ static bool amd_pmc_want_suspend_delay(struct amd_pmc_dev *pdev) + * disabled with disable_workarounds or delay_suspend=0 + */ + if (delay_suspend == 1 || (delay_suspend == -1 && !disable_workarounds)) { +- dev_info(pdev->dev, "Delaying suspend by 2.5s to avoid platform bug\n"); ++ if (!intermediate_wakeup) ++ dev_info(pdev->dev, "Delaying suspend by 2.5s to avoid platform bug\n"); + return true; + } +- dev_info(pdev->dev, "Not delaying suspend because of module parameter, even though your device is assumed to need it!\n"); ++ if (!intermediate_wakeup) ++ dev_info(pdev->dev, "Not delaying suspend because of module parameter, even though your device is assumed to need it!\n"); + } else if (delay_suspend == 1) { +- dev_info(pdev->dev, "Delaying suspend by 2.5s because delay_suspend=1. If this solves problems on your machine, please report this whole line to: platform-driver-x86@vger.kernel.org so it can be automatically detected as affected in the future. System Vendor: \"%s\" Product Name: \"%s\" Product Family: \"%s\" Board Vendor: \"%s\" Board Name: \"%s\"\n", +- dmi_get_system_info(DMI_SYS_VENDOR), +- dmi_get_system_info(DMI_PRODUCT_NAME), +- dmi_get_system_info(DMI_PRODUCT_FAMILY), +- dmi_get_system_info(DMI_BOARD_VENDOR), +- dmi_get_system_info(DMI_BOARD_NAME)); ++ if (!intermediate_wakeup) ++ dev_info(pdev->dev, "Delaying suspend by 2.5s because delay_suspend=1. If this solves problems on your machine, please report this whole line to: platform-driver-x86@vger.kernel.org so it can be automatically detected as affected in the future. System Vendor: \"%s\" Product Name: \"%s\" Product Family: \"%s\" Board Vendor: \"%s\" Board Name: \"%s\"\n", ++ dmi_get_system_info(DMI_SYS_VENDOR), ++ dmi_get_system_info(DMI_PRODUCT_NAME), ++ dmi_get_system_info(DMI_PRODUCT_FAMILY), ++ dmi_get_system_info(DMI_BOARD_VENDOR), ++ dmi_get_system_info(DMI_BOARD_NAME)); + return true; + } + return false; +@@ -852,6 +869,9 @@ static void amd_pmc_s2idle_prepare(void) + u8 msg; + u32 arg = 1; + ++ /* Reset this variable because this is a fresh suspend */ ++ pdev->is_first_check_after_suspend = true; ++ + /* Reset and Start SMU logging - to monitor the s0i3 stats */ + amd_pmc_setup_smu_logging(pdev); + +@@ -891,6 +911,9 @@ static void amd_pmc_s2idle_check(void) + rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_S2IDLE_CHECK); + if (rc) + dev_err(pdev->dev, "error writing to STB: %d\n", rc); ++ ++ /* remember that first check after suspend is done (until next prepare) */ ++ pdev->is_first_check_after_suspend = false; + } + + static int amd_pmc_dump_data(struct amd_pmc_dev *pdev) +diff --git a/drivers/platform/x86/amd/pmc/pmc.h b/drivers/platform/x86/amd/pmc/pmc.h +index 5e7b8d5dc5d624..bea65810de5ab6 100644 +--- a/drivers/platform/x86/amd/pmc/pmc.h ++++ b/drivers/platform/x86/amd/pmc/pmc.h +@@ -37,6 +37,7 @@ struct amd_pmc_dev { + struct dentry *dbgfs_dir; + struct quirk_entry *quirks; + bool disable_8042_wakeup; ++ bool is_first_check_after_suspend; + }; + + void amd_pmc_process_restore_quirks(struct amd_pmc_dev *dev); +-- +2.53.0 + diff --git a/staging-6.6/selftests-bpf-add-tests-for-ld_-abs-ind-failure-path.patch b/staging-6.6/selftests-bpf-add-tests-for-ld_-abs-ind-failure-path.patch new file mode 100644 index 0000000000..6b05514f6f --- /dev/null +++ b/staging-6.6/selftests-bpf-add-tests-for-ld_-abs-ind-failure-path.patch @@ -0,0 +1,200 @@ +From 0ccd05109e62f37f8364fcfe1f962026cda29a77 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Jul 2026 15:39:08 +0800 +Subject: selftests/bpf: Add tests for ld_{abs,ind} failure path in subprogs + +From: Daniel Borkmann + +commit e0fcb42bc6f41bab2895757d6610616b3820eff7 upstream. + +Extend the verifier_ld_ind BPF selftests with subprogs containing +ld_{abs,ind} and craft the test in a way where the invalid register +read is rejected in the fixed case. Also add a success case each, +and add additional coverage related to the BTF return type enforcement. + + # LDLIBS=-static PKG_CONFIG='pkg-config --static' ./vmtest.sh -- ./test_progs -t verifier_ld_ind + [...] + #611/1 verifier_ld_ind/ld_ind: check calling conv, r1:OK + #611/2 verifier_ld_ind/ld_ind: check calling conv, r1 @unpriv:OK + #611/3 verifier_ld_ind/ld_ind: check calling conv, r2:OK + #611/4 verifier_ld_ind/ld_ind: check calling conv, r2 @unpriv:OK + #611/5 verifier_ld_ind/ld_ind: check calling conv, r3:OK + #611/6 verifier_ld_ind/ld_ind: check calling conv, r3 @unpriv:OK + #611/7 verifier_ld_ind/ld_ind: check calling conv, r4:OK + #611/8 verifier_ld_ind/ld_ind: check calling conv, r4 @unpriv:OK + #611/9 verifier_ld_ind/ld_ind: check calling conv, r5:OK + #611/10 verifier_ld_ind/ld_ind: check calling conv, r5 @unpriv:OK + #611/11 verifier_ld_ind/ld_ind: check calling conv, r7:OK + #611/12 verifier_ld_ind/ld_ind: check calling conv, r7 @unpriv:OK + #611/13 verifier_ld_ind/ld_abs: subprog early exit on ld_abs failure:OK + #611/14 verifier_ld_ind/ld_ind: subprog early exit on ld_ind failure:OK + #611/15 verifier_ld_ind/ld_abs: subprog with both paths safe:OK + #611/16 verifier_ld_ind/ld_ind: subprog with both paths safe:OK + #611/17 verifier_ld_ind/ld_abs: reject void return subprog:OK + #611/18 verifier_ld_ind/ld_ind: reject void return subprog:OK + #611 verifier_ld_ind:OK + Summary: 1/18 PASSED, 0 SKIPPED, 0 FAILED + +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260408191242.526279-4-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Philo Lu +Signed-off-by: Sasha Levin +--- + .../selftests/bpf/progs/verifier_ld_ind.c | 142 ++++++++++++++++++ + 1 file changed, 142 insertions(+) + +diff --git a/tools/testing/selftests/bpf/progs/verifier_ld_ind.c b/tools/testing/selftests/bpf/progs/verifier_ld_ind.c +index c925ba9a2e74c2..09e81b99eecb4e 100644 +--- a/tools/testing/selftests/bpf/progs/verifier_ld_ind.c ++++ b/tools/testing/selftests/bpf/progs/verifier_ld_ind.c +@@ -107,4 +107,146 @@ __naked void ind_check_calling_conv_r7(void) + : __clobber_all); + } + ++/* ++ * ld_{abs,ind} subprog that always sets r0=1 on the success path. ++ * bpf_gen_ld_abs() emits a hidden exit with r0=0 when the load helper ++ * fails. The verifier must model this failure return so that callers ++ * account for r0=0 as a possible return value. ++ */ ++__naked __noinline __used ++static int ldabs_subprog(void) ++{ ++ asm volatile ( ++ "r6 = r1;" ++ ".8byte %[ld_abs];" ++ "r0 = 1;" ++ "exit;" ++ : ++ : __imm_insn(ld_abs, BPF_LD_ABS(BPF_W, 0)) ++ : __clobber_all); ++} ++ ++__naked __noinline __used ++static int ldind_subprog(void) ++{ ++ asm volatile ( ++ "r6 = r1;" ++ "r7 = 0;" ++ ".8byte %[ld_ind];" ++ "r0 = 1;" ++ "exit;" ++ : ++ : __imm_insn(ld_ind, BPF_LD_IND(BPF_W, BPF_REG_7, 0)) ++ : __clobber_all); ++} ++ ++SEC("socket") ++__description("ld_abs: subprog early exit on ld_abs failure") ++__failure __msg("R9 !read_ok") ++__naked void ld_abs_subprog_early_exit(void) ++{ ++ asm volatile ( ++ "call ldabs_subprog;" ++ "if r0 != 0 goto l_exit_%=;" ++ "r0 = r9;" ++ "l_exit_%=:" ++ "r0 = 0;" ++ "exit;" ++ ::: __clobber_all); ++} ++ ++SEC("socket") ++__description("ld_ind: subprog early exit on ld_ind failure") ++__failure __msg("R9 !read_ok") ++__naked void ld_ind_subprog_early_exit(void) ++{ ++ asm volatile ( ++ "call ldind_subprog;" ++ "if r0 != 0 goto l_exit_%=;" ++ "r0 = r9;" ++ "l_exit_%=:" ++ "r0 = 0;" ++ "exit;" ++ ::: __clobber_all); ++} ++ ++SEC("socket") ++__description("ld_abs: subprog with both paths safe") ++__success ++__naked void ld_abs_subprog_both_paths_safe(void) ++{ ++ asm volatile ( ++ "call ldabs_subprog;" ++ "r0 = 0;" ++ "exit;" ++ ::: __clobber_all); ++} ++ ++SEC("socket") ++__description("ld_ind: subprog with both paths safe") ++__success ++__naked void ld_ind_subprog_both_paths_safe(void) ++{ ++ asm volatile ( ++ "call ldind_subprog;" ++ "r0 = 0;" ++ "exit;" ++ ::: __clobber_all); ++} ++ ++/* ++ * ld_{abs,ind} in subprogs require scalar (int) return type in BTF. ++ * A test with void return must be rejected. ++ */ ++__naked __noinline __used ++static void ldabs_void_subprog(void) ++{ ++ asm volatile ( ++ "r6 = r1;" ++ ".8byte %[ld_abs];" ++ "r0 = 1;" ++ "exit;" ++ : ++ : __imm_insn(ld_abs, BPF_LD_ABS(BPF_W, 0)) ++ : __clobber_all); ++} ++ ++SEC("socket") ++__description("ld_abs: reject void return subprog") ++__failure __msg("LD_ABS is only allowed in functions that return 'int'") ++__naked void ld_abs_void_subprog_reject(void) ++{ ++ asm volatile ( ++ "call ldabs_void_subprog;" ++ "r0 = 0;" ++ "exit;" ++ ::: __clobber_all); ++} ++ ++__naked __noinline __used ++static void ldind_void_subprog(void) ++{ ++ asm volatile ( ++ "r6 = r1;" ++ "r7 = 0;" ++ ".8byte %[ld_ind];" ++ "r0 = 1;" ++ "exit;" ++ : ++ : __imm_insn(ld_ind, BPF_LD_IND(BPF_W, BPF_REG_7, 0)) ++ : __clobber_all); ++} ++ ++SEC("socket") ++__description("ld_ind: reject void return subprog") ++__failure __msg("LD_ABS is only allowed in functions that return 'int'") ++__naked void ld_ind_void_subprog_reject(void) ++{ ++ asm volatile ( ++ "call ldind_void_subprog;" ++ "r0 = 0;" ++ "exit;" ++ ::: __clobber_all); ++} ++ + char _license[] SEC("license") = "GPL"; +-- +2.53.0 + diff --git a/staging-6.6/series b/staging-6.6/series index 07ddd9b506..0f8f13d4f5 100644 --- a/staging-6.6/series +++ b/staging-6.6/series @@ -1 +1,6 @@ platform-x86-intel-uncore-freq-fix-current_freq_khz-.patch +bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch +selftests-bpf-add-tests-for-ld_-abs-ind-failure-path.patch +drm-virtio-fix-deadlock-in-display_info_cb-by-removi.patch +platform-x86-amd-pmc-don-t-log-during-intermediate-w.patch +platform-x86-amd-pmc-avoid-logging-null-for-dmi-valu.patch diff --git a/staging-7.1/drm-virtio-fix-deadlock-in-display_info_cb-by-removi.patch b/staging-7.1/drm-virtio-fix-deadlock-in-display_info_cb-by-removi.patch new file mode 100644 index 0000000000..269f69b7ff --- /dev/null +++ b/staging-7.1/drm-virtio-fix-deadlock-in-display_info_cb-by-removi.patch @@ -0,0 +1,82 @@ +From 29b70c650570e1fad7a5efe475d0376eadc4f1e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Jul 2026 22:01:00 +0900 +Subject: drm/virtio: fix deadlock in display_info_cb by removing hotplug from + dequeue worker + +From: Ryosuke Yasuoka + +[ Upstream commit d1b894c5bbb3fee0012bd14356286dc2384e8213 ] + +A probe-time deadlock can occur between the dequeue worker and +drm_client_register(). During probe, drm_client_register() holds +clientlist_mutex and calls the fbdev hotplug callback, which triggers an +atomic commit that ends up sleeping in virtio_gpu_queue_ctrl_sgs() +waiting for virtqueue space. The dequeue worker that would free that +space calls virtio_gpu_cmd_get_display_info_cb(), which invokes +drm_kms_helper_hotplug_event() -> drm_client_dev_hotplug(), attempting +to acquire the same clientlist_mutex. Since wake_up() is only called +after the resp_cb loop, the probe thread is never woken and both threads +deadlock. + +Fix this by removing the hotplug notification from +virtio_gpu_cmd_get_display_info_cb(). The display data (outputs[i].info) +is still updated synchronously in the callback. + +For the init path, drm_client_register() already fires an initial +hotplug when the client is registered, which picks up the connector +state updated by display_info_cb. + +For the runtime config_changed path, add a wait_event_timeout() in +config_changed_work_func() so that display_info_cb updates the connector +data before the hotplug notification is sent. Also replace +drm_helper_hpd_irq_event() with drm_kms_helper_hotplug_event() since +virtio-gpu never calls drm_kms_helper_poll_init() and thus +drm_helper_hpd_irq_event() always returns false without doing anything. + +Fixes: 27655b9bb9f0 ("drm/client: Send hotplug event after registering a client") +Closes: https://syzkaller.appspot.com/bug?id=d6dd6f86d3aaf7eebe7406e45c1c6e549453f224 +Closes: https://syzkaller.appspot.com/bug?id=908bd910da5dd79b88de4cf7baf376cc873a922e +Suggested-by: Dmitry Osipenko +Signed-off-by: Ryosuke Yasuoka +Signed-off-by: Dmitry Osipenko +Link: https://patch.msgid.link/20260713-virtiogpu_syzbot-v2-1-2958fa37d46d@redhat.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/virtio/virtgpu_kms.c | 5 ++++- + drivers/gpu/drm/virtio/virtgpu_vq.c | 3 --- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c +index 80ba69b4860bc5..b79fd8350b6a47 100644 +--- a/drivers/gpu/drm/virtio/virtgpu_kms.c ++++ b/drivers/gpu/drm/virtio/virtgpu_kms.c +@@ -49,7 +49,10 @@ static void virtio_gpu_config_changed_work_func(struct work_struct *work) + virtio_gpu_cmd_get_edids(vgdev); + virtio_gpu_cmd_get_display_info(vgdev); + virtio_gpu_notify(vgdev); +- drm_helper_hpd_irq_event(vgdev->ddev); ++ wait_event_timeout(vgdev->resp_wq, ++ !vgdev->display_info_pending, ++ 5 * HZ); ++ drm_kms_helper_hotplug_event(vgdev->ddev); + } + events_clear |= VIRTIO_GPU_EVENT_DISPLAY; + } +diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c +index 67865810a2e708..337189b15ad01b 100644 +--- a/drivers/gpu/drm/virtio/virtgpu_vq.c ++++ b/drivers/gpu/drm/virtio/virtgpu_vq.c +@@ -840,9 +840,6 @@ static void virtio_gpu_cmd_get_display_info_cb(struct virtio_gpu_device *vgdev, + vgdev->display_info_pending = false; + spin_unlock(&vgdev->display_info_lock); + wake_up(&vgdev->resp_wq); +- +- if (!drm_helper_hpd_irq_event(vgdev->ddev)) +- drm_kms_helper_hotplug_event(vgdev->ddev); + } + + static void virtio_gpu_cmd_get_capset_info_cb(struct virtio_gpu_device *vgdev, +-- +2.53.0 + diff --git a/staging-7.1/series b/staging-7.1/series index 1487d9b4e0..b81e4ac3cc 100644 --- a/staging-7.1/series +++ b/staging-7.1/series @@ -1,2 +1,3 @@ platform-x86-intel-uncore-freq-fix-current_freq_khz-.patch sched_ext-skip-ops.set_weight-for-disabled-tasks.patch +drm-virtio-fix-deadlock-in-display_info_cb-by-removi.patch -- 2.47.3