From: Sasha Levin Date: Wed, 5 Aug 2026 01:12:48 +0000 (-0400) Subject: Fixes for all trees X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for all trees Signed-off-by: Sasha Levin --- diff --git a/queue-5.10/ipv6-fib6-fix-null-deref-in-fib6_walk_continue-on-mu.patch b/queue-5.10/ipv6-fib6-fix-null-deref-in-fib6_walk_continue-on-mu.patch new file mode 100644 index 0000000000..7c377dd5e4 --- /dev/null +++ b/queue-5.10/ipv6-fib6-fix-null-deref-in-fib6_walk_continue-on-mu.patch @@ -0,0 +1,102 @@ +From 5a2558a0a55de1c29a14111b0d2d4076660d2855 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 19:46:54 +0800 +Subject: ipv6: fib6: fix NULL deref in fib6_walk_continue() on multi-batch + dump + +From: Pengfei Zhang + +commit 9facb861dc6b9b9ea9793ef5032a9a826f7a4229 upstream. + +inet6_dump_fib() saves its progress in cb->args[1] as a positional +index within the current hash chain. Between batches, a concurrent +fib6_new_table() can insert a new table at the chain head, shifting +all existing entries. The saved index then lands on a different +table, causing fib6_dump_table() to set w->root to the wrong table +while w->node still points into the previous one. +fib6_walk_continue() dereferences w->node->parent (NULL) and panics: + + BUG: kernel NULL pointer dereference, address: 0000000000000008 + RIP: 0010:fib6_walk_continue+0x6e/0x170 + Call Trace: + + fib6_dump_table.isra.0+0xc5/0x240 + inet6_dump_fib+0xf6/0x420 + rtnl_dumpit+0x30/0xa0 + netlink_dump+0x15b/0x460 + netlink_recvmsg+0x1d6/0x2a0 + ____sys_recvmsg+0x17a/0x190 + +Fix by storing tb->tb6_id in cb->args[1] instead of a positional +index. On resume, skip entries until the id matches; a concurrent +head-insert can never match the saved id, so the walker always +resumes on the correct table. + +Fixes: 1b43af5480c3 ("[IPV6]: Increase number of possible routing tables to 2^32") +Signed-off-by: Pengfei Zhang +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260625070517.965597-1-zhangfeionline@gmail.com +Signed-off-by: Jakub Kicinski +[Adapted to 5.10/6.1/6.6: inet6_dump_fib() there predates 22e36ea9f5d7 + and 5fc68320c1fb, so the return variable is "res" not "err" and the + RCU-protected hash walk exits via "out_unlock" instead of "unlock". + Context-only change; the fix itself is identical.] +Signed-off-by: Pengfei Zhang +Signed-off-by: Sasha Levin +--- + net/ipv6/ip6_fib.c | 17 ++++++++--------- + 1 file changed, 8 insertions(+), 9 deletions(-) + +diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c +index 83f15e930b57a..12568b7ab703a 100644 +--- a/net/ipv6/ip6_fib.c ++++ b/net/ipv6/ip6_fib.c +@@ -620,11 +620,11 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) + const struct nlmsghdr *nlh = cb->nlh; + struct net *net = sock_net(skb->sk); + unsigned int h, s_h; +- unsigned int e = 0, s_e; + struct fib6_walker *w; + struct fib6_table *tb; + struct hlist_head *head; + int res = 0; ++ u32 s_id; + + if (cb->strict_check) { + int err; +@@ -682,25 +682,24 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) + } + + s_h = cb->args[0]; +- s_e = cb->args[1]; ++ s_id = cb->args[1]; + + rcu_read_lock(); +- for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_e = 0) { +- e = 0; ++ for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_id = 0) { + head = &net->ipv6.fib_table_hash[h]; + hlist_for_each_entry_rcu(tb, head, tb6_hlist) { +- if (e < s_e) +- goto next; ++ if (s_id && tb->tb6_id != s_id) ++ continue; ++ ++ s_id = 0; ++ cb->args[1] = tb->tb6_id; + res = fib6_dump_table(tb, skb, cb); + if (res != 0) + goto out_unlock; +-next: +- e++; + } + } + out_unlock: + rcu_read_unlock(); +- cb->args[1] = e; + cb->args[0] = h; + out: + res = res < 0 ? res : skb->len; +-- +2.53.0 + diff --git a/queue-5.10/rhashtable-clear-stale-iter-p-on-table-restart.patch b/queue-5.10/rhashtable-clear-stale-iter-p-on-table-restart.patch new file mode 100644 index 0000000000..c142446d99 --- /dev/null +++ b/queue-5.10/rhashtable-clear-stale-iter-p-on-table-restart.patch @@ -0,0 +1,63 @@ +From 3241a8adf60c0a9fa675cf231b426b3d2e359166 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Jul 2026 12:41:15 -0400 +Subject: rhashtable: clear stale iter->p on table restart + +From: Cen Zhang (Microsoft) + +[ Upstream commit 8173f7e2ce67e6ca1d4763f3da14e5b01ce77456 ] + +rhashtable_walk_start_check() has two restart paths when resuming a walk. +When iter->walker.tbl is valid, it re-validates iter->p against the table +and sets iter->p = NULL if the object is gone. When iter->walker.tbl is +NULL (table was freed during resize), it resets slot and skip but forgets +to clear iter->p. + +rhashtable_walk_next() then dereferences the stale iter->p, reading +freed memory. This is a use-after-free. + +Any caller that does multi-fragment rhashtable walks across +walk_stop/walk_start boundaries is affected. Concrete cases include +netlink_diag (__netlink_diag_dump in net/netlink/diag.c) and TIPC +(tipc_nl_sk_walk in net/tipc/socket.c). + +Crash stack (netlink_diag): + BUG: KASAN: slab-use-after-free in rhashtable_walk_next+0x365/0x3c0 + Read of size 8 at addr ffff88801a9d2438 (freed kmalloc-2k, offset 1080) + Call Trace: + rhashtable_walk_next+0x365/0x3c0 (lib/rhashtable.c:1016) + __netlink_diag_dump+0x160/0x760 (net/netlink/diag.c:122) + netlink_diag_dump+0xc2/0x240 + netlink_dump+0x5bc/0x1270 + netlink_recvmsg+0x7a3/0x980 + sock_recvmsg+0x1bc/0x200 + __sys_recvfrom+0x1d4/0x2c0 + +Fixes: 5d240a8936f6 ("rhashtable: improve rhashtable_walk stability when stop/start used.") +Cc: +Reported-by: AutonomousCodeSecurity@microsoft.com +Reported-by: Yuan Tan +Closes: https://lore.kernel.org/linux-crypto/CAB8m9Wh559e+=n8z51gB8DrbEyCc2mc0MgGjrRR6_VXBmU=2AQ@mail.gmail.com +Signed-off-by: Cen Zhang (Microsoft) +Reviewed-by: NeilBrown +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + lib/rhashtable.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/rhashtable.c b/lib/rhashtable.c +index c949c1e3b87c1..4def63ec1f65f 100644 +--- a/lib/rhashtable.c ++++ b/lib/rhashtable.c +@@ -730,6 +730,7 @@ int rhashtable_walk_start_check(struct rhashtable_iter *iter) + iter->walker.tbl = rht_dereference_rcu(ht->tbl, ht); + iter->slot = 0; + iter->skip = 0; ++ iter->p = NULL; + return -EAGAIN; + } + +-- +2.53.0 + diff --git a/queue-5.10/series b/queue-5.10/series index 0e4690b6c6..fd7c373564 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -235,3 +235,5 @@ can-isotp-check-register_netdevice_notifier-error-in.patch tracing-mmiotrace-reset-dropped_count-in-mmio_reset_.patch octeontx2-pf-set-correct-sequence-for-carrier-off-an.patch qede-sync-udp_tunnel-ports-outside-qede_lock-in-the-.patch +ipv6-fib6-fix-null-deref-in-fib6_walk_continue-on-mu.patch +rhashtable-clear-stale-iter-p-on-table-restart.patch diff --git a/queue-5.15/rhashtable-clear-stale-iter-p-on-table-restart.patch b/queue-5.15/rhashtable-clear-stale-iter-p-on-table-restart.patch new file mode 100644 index 0000000000..2a0f5ac6b4 --- /dev/null +++ b/queue-5.15/rhashtable-clear-stale-iter-p-on-table-restart.patch @@ -0,0 +1,63 @@ +From 72416287fd320da0f97ce5a73da0782fea19dc5c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Jul 2026 12:41:15 -0400 +Subject: rhashtable: clear stale iter->p on table restart + +From: Cen Zhang (Microsoft) + +[ Upstream commit 8173f7e2ce67e6ca1d4763f3da14e5b01ce77456 ] + +rhashtable_walk_start_check() has two restart paths when resuming a walk. +When iter->walker.tbl is valid, it re-validates iter->p against the table +and sets iter->p = NULL if the object is gone. When iter->walker.tbl is +NULL (table was freed during resize), it resets slot and skip but forgets +to clear iter->p. + +rhashtable_walk_next() then dereferences the stale iter->p, reading +freed memory. This is a use-after-free. + +Any caller that does multi-fragment rhashtable walks across +walk_stop/walk_start boundaries is affected. Concrete cases include +netlink_diag (__netlink_diag_dump in net/netlink/diag.c) and TIPC +(tipc_nl_sk_walk in net/tipc/socket.c). + +Crash stack (netlink_diag): + BUG: KASAN: slab-use-after-free in rhashtable_walk_next+0x365/0x3c0 + Read of size 8 at addr ffff88801a9d2438 (freed kmalloc-2k, offset 1080) + Call Trace: + rhashtable_walk_next+0x365/0x3c0 (lib/rhashtable.c:1016) + __netlink_diag_dump+0x160/0x760 (net/netlink/diag.c:122) + netlink_diag_dump+0xc2/0x240 + netlink_dump+0x5bc/0x1270 + netlink_recvmsg+0x7a3/0x980 + sock_recvmsg+0x1bc/0x200 + __sys_recvfrom+0x1d4/0x2c0 + +Fixes: 5d240a8936f6 ("rhashtable: improve rhashtable_walk stability when stop/start used.") +Cc: +Reported-by: AutonomousCodeSecurity@microsoft.com +Reported-by: Yuan Tan +Closes: https://lore.kernel.org/linux-crypto/CAB8m9Wh559e+=n8z51gB8DrbEyCc2mc0MgGjrRR6_VXBmU=2AQ@mail.gmail.com +Signed-off-by: Cen Zhang (Microsoft) +Reviewed-by: NeilBrown +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + lib/rhashtable.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/rhashtable.c b/lib/rhashtable.c +index e12bbfb240b81..c977468291ea0 100644 +--- a/lib/rhashtable.c ++++ b/lib/rhashtable.c +@@ -730,6 +730,7 @@ int rhashtable_walk_start_check(struct rhashtable_iter *iter) + iter->walker.tbl = rht_dereference_rcu(ht->tbl, ht); + iter->slot = 0; + iter->skip = 0; ++ iter->p = NULL; + return -EAGAIN; + } + +-- +2.53.0 + diff --git a/queue-5.15/series b/queue-5.15/series index 818da74543..f8eba30e91 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -287,3 +287,4 @@ can-isotp-check-register_netdevice_notifier-error-in.patch tracing-mmiotrace-reset-dropped_count-in-mmio_reset_.patch octeontx2-pf-set-correct-sequence-for-carrier-off-an.patch qede-sync-udp_tunnel-ports-outside-qede_lock-in-the-.patch +rhashtable-clear-stale-iter-p-on-table-restart.patch diff --git a/queue-6.1/af_unix-give-up-gc-if-msg_peek-intervened.patch b/queue-6.1/af_unix-give-up-gc-if-msg_peek-intervened.patch new file mode 100644 index 0000000000..ace51dc9c0 --- /dev/null +++ b/queue-6.1/af_unix-give-up-gc-if-msg_peek-intervened.patch @@ -0,0 +1,259 @@ +From 7fa83e639477f13c5d899a5f277199b92b7cc4d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 18:28:41 +0000 +Subject: af_unix: Give up GC if MSG_PEEK intervened. + +From: Kuniyuki Iwashima + +[ Upstream commit e5b31d988a41549037b8d8721a3c3cae893d8670 ] + +Igor Ushakov reported that GC purged the receive queue of +an alive socket due to a race with MSG_PEEK with a nice repro. + +This is the exact same issue previously fixed by commit +cbcf01128d0a ("af_unix: fix garbage collect vs MSG_PEEK"). + +After GC was replaced with the current algorithm, the cited +commit removed the locking dance in unix_peek_fds() and +reintroduced the same issue. + +The problem is that MSG_PEEK bumps a file refcount without +interacting with GC. + +Consider an SCC containing sk-A and sk-B, where sk-A is +close()d but can be recv()ed via sk-B. + +The bad thing happens if sk-A is recv()ed with MSG_PEEK from +sk-B and sk-B is close()d while GC is checking unix_vertex_dead() +for sk-A and sk-B. + + GC thread User thread + --------- ----------- + unix_vertex_dead(sk-A) + -> true <------. + \ + `------ recv(sk-B, MSG_PEEK) + invalidate !! -> sk-A's file refcount : 1 -> 2 + + close(sk-B) + -> sk-B's file refcount : 2 -> 1 + unix_vertex_dead(sk-B) + -> true + +Initially, sk-A's file refcount is 1 by the inflight fd in sk-B +recvq. GC thinks sk-A is dead because the file refcount is the +same as the number of its inflight fds. + +However, sk-A's file refcount is bumped silently by MSG_PEEK, +which invalidates the previous evaluation. + +At this moment, sk-B's file refcount is 2; one by the open fd, +and one by the inflight fd in sk-A. The subsequent close() +releases one refcount by the former. + +Finally, GC incorrectly concludes that both sk-A and sk-B are dead. + +One option is to restore the locking dance in unix_peek_fds(), +but we can resolve this more elegantly thanks to the new algorithm. + +The point is that the issue does not occur without the subsequent +close() and we actually do not need to synchronise MSG_PEEK with +the dead SCC detection. + +When the issue occurs, close() and GC touch the same file refcount. +If GC sees the refcount being decremented by close(), it can just +give up garbage-collecting the SCC. + +Therefore, we only need to signal the race during MSG_PEEK with +a proper memory barrier to make it visible to the GC. + +Let's use seqcount_t to notify GC when MSG_PEEK occurs and let +it defer the SCC to the next run. + +This way no locking is needed on the MSG_PEEK side, and we can +avoid imposing a penalty on every MSG_PEEK unnecessarily. + +Note that we can retry within unix_scc_dead() if MSG_PEEK is +detected, but we do not do so to avoid hung task splat from +abusive MSG_PEEK calls. + +Fixes: 118f457da9ed ("af_unix: Remove lock dance in unix_peek_fds().") +Reported-by: Igor Ushakov +Signed-off-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260311054043.1231316-1-kuniyu@google.com +Signed-off-by: Jakub Kicinski +[ Using include/net/af_unix.h instead of net/unix/af_unix.h on 6.6 ] +Signed-off-by: Leon Chen +Signed-off-by: Sasha Levin +Signed-off-by: Todd Kjos +--- + include/net/af_unix.h | 1 + + net/unix/af_unix.c | 2 ++ + net/unix/garbage.c | 79 ++++++++++++++++++++++++++++--------------- + 3 files changed, 54 insertions(+), 28 deletions(-) + +diff --git a/include/net/af_unix.h b/include/net/af_unix.h +index b1f82d74339ef..339d41d9a5867 100644 +--- a/include/net/af_unix.h ++++ b/include/net/af_unix.h +@@ -23,6 +23,7 @@ void unix_del_edges(struct scm_fp_list *fpl); + void unix_update_edges(struct unix_sock *receiver); + int unix_prepare_fpl(struct scm_fp_list *fpl); + void unix_destroy_fpl(struct scm_fp_list *fpl); ++void unix_peek_fpl(struct scm_fp_list *fpl); + void unix_gc(void); + void wait_for_unix_gc(struct scm_fp_list *fpl); + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index 3e5dc698416f0..a4fa3c279a465 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -1778,6 +1778,8 @@ static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb) + static void unix_peek_fds(struct scm_cookie *scm, struct sk_buff *skb) + { + scm->fp = scm_fp_dup(UNIXCB(skb).fp); ++ ++ unix_peek_fpl(scm->fp); + } + + static void unix_destruct_scm(struct sk_buff *skb) +diff --git a/net/unix/garbage.c b/net/unix/garbage.c +index 38c8cae131671..fa6983dc3181d 100644 +--- a/net/unix/garbage.c ++++ b/net/unix/garbage.c +@@ -306,6 +306,25 @@ void unix_destroy_fpl(struct scm_fp_list *fpl) + unix_free_vertices(fpl); + } + ++static bool gc_in_progress; ++static seqcount_t unix_peek_seq = SEQCNT_ZERO(unix_peek_seq); ++ ++void unix_peek_fpl(struct scm_fp_list *fpl) ++{ ++ static DEFINE_SPINLOCK(unix_peek_lock); ++ ++ if (!fpl || !fpl->count_unix) ++ return; ++ ++ if (!READ_ONCE(gc_in_progress)) ++ return; ++ ++ /* Invalidate the final refcnt check in unix_vertex_dead(). */ ++ spin_lock(&unix_peek_lock); ++ raw_write_seqcount_barrier(&unix_peek_seq); ++ spin_unlock(&unix_peek_lock); ++} ++ + static bool unix_vertex_dead(struct unix_vertex *vertex) + { + struct unix_edge *edge; +@@ -339,6 +358,36 @@ static bool unix_vertex_dead(struct unix_vertex *vertex) + return true; + } + ++static LIST_HEAD(unix_visited_vertices); ++static unsigned long unix_vertex_grouped_index = UNIX_VERTEX_INDEX_MARK2; ++ ++static bool unix_scc_dead(struct list_head *scc, bool fast) ++{ ++ struct unix_vertex *vertex; ++ bool scc_dead = true; ++ unsigned int seq; ++ ++ seq = read_seqcount_begin(&unix_peek_seq); ++ ++ list_for_each_entry_reverse(vertex, scc, scc_entry) { ++ /* Don't restart DFS from this vertex. */ ++ list_move_tail(&vertex->entry, &unix_visited_vertices); ++ ++ /* Mark vertex as off-stack for __unix_walk_scc(). */ ++ if (!fast) ++ vertex->index = unix_vertex_grouped_index; ++ ++ if (scc_dead) ++ scc_dead = unix_vertex_dead(vertex); ++ } ++ ++ /* If MSG_PEEK intervened, defer this SCC to the next round. */ ++ if (read_seqcount_retry(&unix_peek_seq, seq)) ++ return false; ++ ++ return scc_dead; ++} ++ + static void unix_collect_skb(struct list_head *scc, struct sk_buff_head *hitlist) + { + struct unix_vertex *vertex; +@@ -392,9 +441,6 @@ static bool unix_scc_cyclic(struct list_head *scc) + return false; + } + +-static LIST_HEAD(unix_visited_vertices); +-static unsigned long unix_vertex_grouped_index = UNIX_VERTEX_INDEX_MARK2; +- + static void __unix_walk_scc(struct unix_vertex *vertex, unsigned long *last_index, + struct sk_buff_head *hitlist) + { +@@ -460,9 +506,7 @@ static void __unix_walk_scc(struct unix_vertex *vertex, unsigned long *last_inde + } + + if (vertex->index == vertex->scc_index) { +- struct unix_vertex *v; + struct list_head scc; +- bool scc_dead = true; + + /* SCC finalised. + * +@@ -471,18 +515,7 @@ static void __unix_walk_scc(struct unix_vertex *vertex, unsigned long *last_inde + */ + __list_cut_position(&scc, &vertex_stack, &vertex->scc_entry); + +- list_for_each_entry_reverse(v, &scc, scc_entry) { +- /* Don't restart DFS from this vertex in unix_walk_scc(). */ +- list_move_tail(&v->entry, &unix_visited_vertices); +- +- /* Mark vertex as off-stack. */ +- v->index = unix_vertex_grouped_index; +- +- if (scc_dead) +- scc_dead = unix_vertex_dead(v); +- } +- +- if (scc_dead) { ++ if (unix_scc_dead(&scc, false)) { + unix_collect_skb(&scc, hitlist); + } else { + if (unix_vertex_max_scc_index < vertex->scc_index) +@@ -530,19 +563,11 @@ static void unix_walk_scc_fast(struct sk_buff_head *hitlist) + while (!list_empty(&unix_unvisited_vertices)) { + struct unix_vertex *vertex; + struct list_head scc; +- bool scc_dead = true; + + vertex = list_first_entry(&unix_unvisited_vertices, typeof(*vertex), entry); + list_add(&scc, &vertex->scc_entry); + +- list_for_each_entry_reverse(vertex, &scc, scc_entry) { +- list_move_tail(&vertex->entry, &unix_visited_vertices); +- +- if (scc_dead) +- scc_dead = unix_vertex_dead(vertex); +- } +- +- if (scc_dead) ++ if (unix_scc_dead(&scc, true)) + unix_collect_skb(&scc, hitlist); + else if (!unix_graph_maybe_cyclic) + unix_graph_maybe_cyclic = unix_scc_cyclic(&scc); +@@ -553,8 +578,6 @@ static void unix_walk_scc_fast(struct sk_buff_head *hitlist) + list_replace_init(&unix_visited_vertices, &unix_unvisited_vertices); + } + +-static bool gc_in_progress; +- + static void __unix_gc(struct work_struct *work) + { + struct sk_buff_head hitlist; +-- +2.53.0 + diff --git a/queue-6.1/ipv6-fib6-fix-null-deref-in-fib6_walk_continue-on-mu.patch b/queue-6.1/ipv6-fib6-fix-null-deref-in-fib6_walk_continue-on-mu.patch new file mode 100644 index 0000000000..6c668fe557 --- /dev/null +++ b/queue-6.1/ipv6-fib6-fix-null-deref-in-fib6_walk_continue-on-mu.patch @@ -0,0 +1,102 @@ +From f783e3d60490bc480089c1da82417195bb517d8f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 19:46:54 +0800 +Subject: ipv6: fib6: fix NULL deref in fib6_walk_continue() on multi-batch + dump + +From: Pengfei Zhang + +commit 9facb861dc6b9b9ea9793ef5032a9a826f7a4229 upstream. + +inet6_dump_fib() saves its progress in cb->args[1] as a positional +index within the current hash chain. Between batches, a concurrent +fib6_new_table() can insert a new table at the chain head, shifting +all existing entries. The saved index then lands on a different +table, causing fib6_dump_table() to set w->root to the wrong table +while w->node still points into the previous one. +fib6_walk_continue() dereferences w->node->parent (NULL) and panics: + + BUG: kernel NULL pointer dereference, address: 0000000000000008 + RIP: 0010:fib6_walk_continue+0x6e/0x170 + Call Trace: + + fib6_dump_table.isra.0+0xc5/0x240 + inet6_dump_fib+0xf6/0x420 + rtnl_dumpit+0x30/0xa0 + netlink_dump+0x15b/0x460 + netlink_recvmsg+0x1d6/0x2a0 + ____sys_recvmsg+0x17a/0x190 + +Fix by storing tb->tb6_id in cb->args[1] instead of a positional +index. On resume, skip entries until the id matches; a concurrent +head-insert can never match the saved id, so the walker always +resumes on the correct table. + +Fixes: 1b43af5480c3 ("[IPV6]: Increase number of possible routing tables to 2^32") +Signed-off-by: Pengfei Zhang +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260625070517.965597-1-zhangfeionline@gmail.com +Signed-off-by: Jakub Kicinski +[Adapted to 5.10/6.1/6.6: inet6_dump_fib() there predates 22e36ea9f5d7 + and 5fc68320c1fb, so the return variable is "res" not "err" and the + RCU-protected hash walk exits via "out_unlock" instead of "unlock". + Context-only change; the fix itself is identical.] +Signed-off-by: Pengfei Zhang +Signed-off-by: Sasha Levin +--- + net/ipv6/ip6_fib.c | 17 ++++++++--------- + 1 file changed, 8 insertions(+), 9 deletions(-) + +diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c +index bb51a911a6ce7..b1276c247190f 100644 +--- a/net/ipv6/ip6_fib.c ++++ b/net/ipv6/ip6_fib.c +@@ -625,11 +625,11 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) + const struct nlmsghdr *nlh = cb->nlh; + struct net *net = sock_net(skb->sk); + unsigned int h, s_h; +- unsigned int e = 0, s_e; + struct fib6_walker *w; + struct fib6_table *tb; + struct hlist_head *head; + int res = 0; ++ u32 s_id; + + if (cb->strict_check) { + int err; +@@ -687,25 +687,24 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) + } + + s_h = cb->args[0]; +- s_e = cb->args[1]; ++ s_id = cb->args[1]; + + rcu_read_lock(); +- for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_e = 0) { +- e = 0; ++ for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_id = 0) { + head = &net->ipv6.fib_table_hash[h]; + hlist_for_each_entry_rcu(tb, head, tb6_hlist) { +- if (e < s_e) +- goto next; ++ if (s_id && tb->tb6_id != s_id) ++ continue; ++ ++ s_id = 0; ++ cb->args[1] = tb->tb6_id; + res = fib6_dump_table(tb, skb, cb); + if (res != 0) + goto out_unlock; +-next: +- e++; + } + } + out_unlock: + rcu_read_unlock(); +- cb->args[1] = e; + cb->args[0] = h; + out: + res = res < 0 ? res : skb->len; +-- +2.53.0 + diff --git a/queue-6.1/rhashtable-clear-stale-iter-p-on-table-restart.patch b/queue-6.1/rhashtable-clear-stale-iter-p-on-table-restart.patch new file mode 100644 index 0000000000..9e1065e792 --- /dev/null +++ b/queue-6.1/rhashtable-clear-stale-iter-p-on-table-restart.patch @@ -0,0 +1,63 @@ +From b4561c56b960f63e8dea132e059753be18c7e94d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Jul 2026 12:41:15 -0400 +Subject: rhashtable: clear stale iter->p on table restart + +From: Cen Zhang (Microsoft) + +[ Upstream commit 8173f7e2ce67e6ca1d4763f3da14e5b01ce77456 ] + +rhashtable_walk_start_check() has two restart paths when resuming a walk. +When iter->walker.tbl is valid, it re-validates iter->p against the table +and sets iter->p = NULL if the object is gone. When iter->walker.tbl is +NULL (table was freed during resize), it resets slot and skip but forgets +to clear iter->p. + +rhashtable_walk_next() then dereferences the stale iter->p, reading +freed memory. This is a use-after-free. + +Any caller that does multi-fragment rhashtable walks across +walk_stop/walk_start boundaries is affected. Concrete cases include +netlink_diag (__netlink_diag_dump in net/netlink/diag.c) and TIPC +(tipc_nl_sk_walk in net/tipc/socket.c). + +Crash stack (netlink_diag): + BUG: KASAN: slab-use-after-free in rhashtable_walk_next+0x365/0x3c0 + Read of size 8 at addr ffff88801a9d2438 (freed kmalloc-2k, offset 1080) + Call Trace: + rhashtable_walk_next+0x365/0x3c0 (lib/rhashtable.c:1016) + __netlink_diag_dump+0x160/0x760 (net/netlink/diag.c:122) + netlink_diag_dump+0xc2/0x240 + netlink_dump+0x5bc/0x1270 + netlink_recvmsg+0x7a3/0x980 + sock_recvmsg+0x1bc/0x200 + __sys_recvfrom+0x1d4/0x2c0 + +Fixes: 5d240a8936f6 ("rhashtable: improve rhashtable_walk stability when stop/start used.") +Cc: +Reported-by: AutonomousCodeSecurity@microsoft.com +Reported-by: Yuan Tan +Closes: https://lore.kernel.org/linux-crypto/CAB8m9Wh559e+=n8z51gB8DrbEyCc2mc0MgGjrRR6_VXBmU=2AQ@mail.gmail.com +Signed-off-by: Cen Zhang (Microsoft) +Reviewed-by: NeilBrown +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + lib/rhashtable.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/rhashtable.c b/lib/rhashtable.c +index e12bbfb240b81..c977468291ea0 100644 +--- a/lib/rhashtable.c ++++ b/lib/rhashtable.c +@@ -730,6 +730,7 @@ int rhashtable_walk_start_check(struct rhashtable_iter *iter) + iter->walker.tbl = rht_dereference_rcu(ht->tbl, ht); + iter->slot = 0; + iter->skip = 0; ++ iter->p = NULL; + return -EAGAIN; + } + +-- +2.53.0 + diff --git a/queue-6.1/series b/queue-6.1/series index f5e3f3595c..1a743cffeb 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -376,3 +376,6 @@ octeontx2-pf-set-correct-sequence-for-carrier-off-an.patch qede-sync-udp_tunnel-ports-outside-qede_lock-in-the-.patch ksmbd-return-success-for-deferred-final-close.patch ksmbd-fix-use-after-free-in-__close_file_table_ids.patch +ipv6-fib6-fix-null-deref-in-fib6_walk_continue-on-mu.patch +af_unix-give-up-gc-if-msg_peek-intervened.patch +rhashtable-clear-stale-iter-p-on-table-restart.patch diff --git a/queue-6.12/rhashtable-clear-stale-iter-p-on-table-restart.patch b/queue-6.12/rhashtable-clear-stale-iter-p-on-table-restart.patch new file mode 100644 index 0000000000..b85d6f8543 --- /dev/null +++ b/queue-6.12/rhashtable-clear-stale-iter-p-on-table-restart.patch @@ -0,0 +1,63 @@ +From 4e46982f4fc96cc437acbffc293830b2fb8f002f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Jul 2026 12:41:15 -0400 +Subject: rhashtable: clear stale iter->p on table restart + +From: Cen Zhang (Microsoft) + +[ Upstream commit 8173f7e2ce67e6ca1d4763f3da14e5b01ce77456 ] + +rhashtable_walk_start_check() has two restart paths when resuming a walk. +When iter->walker.tbl is valid, it re-validates iter->p against the table +and sets iter->p = NULL if the object is gone. When iter->walker.tbl is +NULL (table was freed during resize), it resets slot and skip but forgets +to clear iter->p. + +rhashtable_walk_next() then dereferences the stale iter->p, reading +freed memory. This is a use-after-free. + +Any caller that does multi-fragment rhashtable walks across +walk_stop/walk_start boundaries is affected. Concrete cases include +netlink_diag (__netlink_diag_dump in net/netlink/diag.c) and TIPC +(tipc_nl_sk_walk in net/tipc/socket.c). + +Crash stack (netlink_diag): + BUG: KASAN: slab-use-after-free in rhashtable_walk_next+0x365/0x3c0 + Read of size 8 at addr ffff88801a9d2438 (freed kmalloc-2k, offset 1080) + Call Trace: + rhashtable_walk_next+0x365/0x3c0 (lib/rhashtable.c:1016) + __netlink_diag_dump+0x160/0x760 (net/netlink/diag.c:122) + netlink_diag_dump+0xc2/0x240 + netlink_dump+0x5bc/0x1270 + netlink_recvmsg+0x7a3/0x980 + sock_recvmsg+0x1bc/0x200 + __sys_recvfrom+0x1d4/0x2c0 + +Fixes: 5d240a8936f6 ("rhashtable: improve rhashtable_walk stability when stop/start used.") +Cc: +Reported-by: AutonomousCodeSecurity@microsoft.com +Reported-by: Yuan Tan +Closes: https://lore.kernel.org/linux-crypto/CAB8m9Wh559e+=n8z51gB8DrbEyCc2mc0MgGjrRR6_VXBmU=2AQ@mail.gmail.com +Signed-off-by: Cen Zhang (Microsoft) +Reviewed-by: NeilBrown +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + lib/rhashtable.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/rhashtable.c b/lib/rhashtable.c +index 0e9a1d4cf89be..16d2ce87c22e2 100644 +--- a/lib/rhashtable.c ++++ b/lib/rhashtable.c +@@ -742,6 +742,7 @@ int rhashtable_walk_start_check(struct rhashtable_iter *iter) + iter->walker.tbl = rht_dereference_rcu(ht->tbl, ht); + iter->slot = 0; + iter->skip = 0; ++ iter->p = NULL; + return -EAGAIN; + } + +-- +2.53.0 + diff --git a/queue-6.12/series b/queue-6.12/series index d33c8c5b54..daa6b85397 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -125,3 +125,4 @@ sched-deadline-use-revised-wakeup-rule-only-for-runn.patch qede-sync-udp_tunnel-ports-outside-qede_lock-in-the-.patch ksmbd-return-success-for-deferred-final-close.patch ksmbd-fix-use-after-free-in-__close_file_table_ids.patch +rhashtable-clear-stale-iter-p-on-table-restart.patch diff --git a/queue-6.6/ipv6-fib6-fix-null-deref-in-fib6_walk_continue-on-mu.patch b/queue-6.6/ipv6-fib6-fix-null-deref-in-fib6_walk_continue-on-mu.patch new file mode 100644 index 0000000000..d79423e965 --- /dev/null +++ b/queue-6.6/ipv6-fib6-fix-null-deref-in-fib6_walk_continue-on-mu.patch @@ -0,0 +1,102 @@ +From 4e2eca658419b47a1c5b231b1c15c193f452f387 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Aug 2026 19:46:54 +0800 +Subject: ipv6: fib6: fix NULL deref in fib6_walk_continue() on multi-batch + dump + +From: Pengfei Zhang + +commit 9facb861dc6b9b9ea9793ef5032a9a826f7a4229 upstream. + +inet6_dump_fib() saves its progress in cb->args[1] as a positional +index within the current hash chain. Between batches, a concurrent +fib6_new_table() can insert a new table at the chain head, shifting +all existing entries. The saved index then lands on a different +table, causing fib6_dump_table() to set w->root to the wrong table +while w->node still points into the previous one. +fib6_walk_continue() dereferences w->node->parent (NULL) and panics: + + BUG: kernel NULL pointer dereference, address: 0000000000000008 + RIP: 0010:fib6_walk_continue+0x6e/0x170 + Call Trace: + + fib6_dump_table.isra.0+0xc5/0x240 + inet6_dump_fib+0xf6/0x420 + rtnl_dumpit+0x30/0xa0 + netlink_dump+0x15b/0x460 + netlink_recvmsg+0x1d6/0x2a0 + ____sys_recvmsg+0x17a/0x190 + +Fix by storing tb->tb6_id in cb->args[1] instead of a positional +index. On resume, skip entries until the id matches; a concurrent +head-insert can never match the saved id, so the walker always +resumes on the correct table. + +Fixes: 1b43af5480c3 ("[IPV6]: Increase number of possible routing tables to 2^32") +Signed-off-by: Pengfei Zhang +Reviewed-by: Ido Schimmel +Link: https://patch.msgid.link/20260625070517.965597-1-zhangfeionline@gmail.com +Signed-off-by: Jakub Kicinski +[Adapted to 5.10/6.1/6.6: inet6_dump_fib() there predates 22e36ea9f5d7 + and 5fc68320c1fb, so the return variable is "res" not "err" and the + RCU-protected hash walk exits via "out_unlock" instead of "unlock". + Context-only change; the fix itself is identical.] +Signed-off-by: Pengfei Zhang +Signed-off-by: Sasha Levin +--- + net/ipv6/ip6_fib.c | 17 ++++++++--------- + 1 file changed, 8 insertions(+), 9 deletions(-) + +diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c +index 7a28807ca4464..383b07269a499 100644 +--- a/net/ipv6/ip6_fib.c ++++ b/net/ipv6/ip6_fib.c +@@ -627,11 +627,11 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) + const struct nlmsghdr *nlh = cb->nlh; + struct net *net = sock_net(skb->sk); + unsigned int h, s_h; +- unsigned int e = 0, s_e; + struct fib6_walker *w; + struct fib6_table *tb; + struct hlist_head *head; + int res = 0; ++ u32 s_id; + + if (cb->strict_check) { + int err; +@@ -689,25 +689,24 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) + } + + s_h = cb->args[0]; +- s_e = cb->args[1]; ++ s_id = cb->args[1]; + + rcu_read_lock(); +- for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_e = 0) { +- e = 0; ++ for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_id = 0) { + head = &net->ipv6.fib_table_hash[h]; + hlist_for_each_entry_rcu(tb, head, tb6_hlist) { +- if (e < s_e) +- goto next; ++ if (s_id && tb->tb6_id != s_id) ++ continue; ++ ++ s_id = 0; ++ cb->args[1] = tb->tb6_id; + res = fib6_dump_table(tb, skb, cb); + if (res != 0) + goto out_unlock; +-next: +- e++; + } + } + out_unlock: + rcu_read_unlock(); +- cb->args[1] = e; + cb->args[0] = h; + out: + res = res < 0 ? res : skb->len; +-- +2.53.0 + diff --git a/queue-6.6/rhashtable-clear-stale-iter-p-on-table-restart.patch b/queue-6.6/rhashtable-clear-stale-iter-p-on-table-restart.patch new file mode 100644 index 0000000000..ab5b04b4d7 --- /dev/null +++ b/queue-6.6/rhashtable-clear-stale-iter-p-on-table-restart.patch @@ -0,0 +1,63 @@ +From 7003d2e3ee54cbff40a0f1c1ec5fda319bf3dfff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Jul 2026 12:41:15 -0400 +Subject: rhashtable: clear stale iter->p on table restart + +From: Cen Zhang (Microsoft) + +[ Upstream commit 8173f7e2ce67e6ca1d4763f3da14e5b01ce77456 ] + +rhashtable_walk_start_check() has two restart paths when resuming a walk. +When iter->walker.tbl is valid, it re-validates iter->p against the table +and sets iter->p = NULL if the object is gone. When iter->walker.tbl is +NULL (table was freed during resize), it resets slot and skip but forgets +to clear iter->p. + +rhashtable_walk_next() then dereferences the stale iter->p, reading +freed memory. This is a use-after-free. + +Any caller that does multi-fragment rhashtable walks across +walk_stop/walk_start boundaries is affected. Concrete cases include +netlink_diag (__netlink_diag_dump in net/netlink/diag.c) and TIPC +(tipc_nl_sk_walk in net/tipc/socket.c). + +Crash stack (netlink_diag): + BUG: KASAN: slab-use-after-free in rhashtable_walk_next+0x365/0x3c0 + Read of size 8 at addr ffff88801a9d2438 (freed kmalloc-2k, offset 1080) + Call Trace: + rhashtable_walk_next+0x365/0x3c0 (lib/rhashtable.c:1016) + __netlink_diag_dump+0x160/0x760 (net/netlink/diag.c:122) + netlink_diag_dump+0xc2/0x240 + netlink_dump+0x5bc/0x1270 + netlink_recvmsg+0x7a3/0x980 + sock_recvmsg+0x1bc/0x200 + __sys_recvfrom+0x1d4/0x2c0 + +Fixes: 5d240a8936f6 ("rhashtable: improve rhashtable_walk stability when stop/start used.") +Cc: +Reported-by: AutonomousCodeSecurity@microsoft.com +Reported-by: Yuan Tan +Closes: https://lore.kernel.org/linux-crypto/CAB8m9Wh559e+=n8z51gB8DrbEyCc2mc0MgGjrRR6_VXBmU=2AQ@mail.gmail.com +Signed-off-by: Cen Zhang (Microsoft) +Reviewed-by: NeilBrown +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + lib/rhashtable.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/rhashtable.c b/lib/rhashtable.c +index 6ae2ba8e06a21..4071bf4e81b0d 100644 +--- a/lib/rhashtable.c ++++ b/lib/rhashtable.c +@@ -734,6 +734,7 @@ int rhashtable_walk_start_check(struct rhashtable_iter *iter) + iter->walker.tbl = rht_dereference_rcu(ht->tbl, ht); + iter->slot = 0; + iter->skip = 0; ++ iter->p = NULL; + return -EAGAIN; + } + +-- +2.53.0 + diff --git a/queue-6.6/series b/queue-6.6/series index e9d5e7c094..9c5b91e1c6 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -83,3 +83,5 @@ octeontx2-pf-set-correct-sequence-for-carrier-off-an.patch qede-sync-udp_tunnel-ports-outside-qede_lock-in-the-.patch ksmbd-return-success-for-deferred-final-close.patch ksmbd-fix-use-after-free-in-__close_file_table_ids.patch +ipv6-fib6-fix-null-deref-in-fib6_walk_continue-on-mu.patch +rhashtable-clear-stale-iter-p-on-table-restart.patch