tipc_net_finalize() does not check the return value of tipc_nametbl_publish(). If the publish fails, for example on a GFP_ATOMIC allocation failure, the node state name never lands in cluster_scope, but tn->finalized is still set. A worker deferred by tipc_named_node_up() then wakes and calls named_distribute() with an empty list. That replays the same unguarded buf_msg(skb_peek_tail(list)) tail stamp, this time on the tipc_node_dist_bulk workqueue: KASAN: null-ptr-deref in range [0x00000000000000c8-0x00000000000000cf] RIP: 0010:named_distribute (net/tipc/name_distr.c:200) Workqueue: events tipc_node_dist_bulk Call Trace: tipc_named_dist_cluster_scope (net/tipc/name_distr.c:267) tipc_node_dist_bulk (net/tipc/node.c:403) process_one_work worker_thread Kernel panic - not syncing: Fatal exception in interrupt Check the publish result and warn on failure, but still set finalized, otherwise deferred workers would sleep forever. In tipc_named_dist_cluster_scope() re-check cluster_scope after the wait and skip the distribution when it is empty. This is a permanent condition, so return 0 instead of an error, otherwise the link would be bounced forever. Also guard the tail stamp in named_distribute() itself, so a caller that misses the precondition gets a warning and a link reset through the existing -ENOBUFS path instead of a crash. Reproducing this needs an allocation failure during finalize, so I verified it by stubbing out the publish call: both nodes log the failure, the workers skip the distribution, no crash, no link flap. The normal path is unchanged with the same two-node test. Fixes: cad2929dc432 ("tipc: update a binding service via broadcast") Reported-by: Xiang Mei Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Weiming Shi --- net/tipc/name_distr.c | 11 +++++++++++ net/tipc/net.c | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index b764274df758..5b0fb09226fc 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c @@ -193,6 +193,10 @@ static int named_distribute(struct net *net, struct sk_buff_head *list, skb_trim(skb, INT_H_SIZE + (msg_dsz - msg_rem)); __skb_queue_tail(list, skb); } + if (skb_queue_empty(list)) { + pr_warn("Bulk publication list empty, nothing to distribute\n"); + return 1; + } hdr = buf_msg(skb_peek_tail(list)); msg_set_last_bulk(hdr); msg_set_named_seqno(hdr, seqno); @@ -253,6 +257,13 @@ int tipc_named_dist_cluster_scope(struct net *net, u32 dnode) spin_unlock_bh(&tn->nametbl_lock); read_lock_bh(&nt->cluster_scope_lock); + if (unlikely(list_empty(&nt->cluster_scope))) { + /* finalize is done but nothing was published (publish + * failed): a permanent state, nothing to synchronize. + */ + read_unlock_bh(&nt->cluster_scope_lock); + return 0; + } if (named_distribute(net, &head, dnode, &nt->cluster_scope, seqno)) { read_unlock_bh(&nt->cluster_scope_lock); return -ENOBUFS; diff --git a/net/tipc/net.c b/net/tipc/net.c index 4c144e720ac1..2aa8812c551a 100644 --- a/net/tipc/net.c +++ b/net/tipc/net.c @@ -138,7 +138,8 @@ static void tipc_net_finalize(struct net *net, u32 addr) tipc_named_reinit(net); tipc_sk_reinit(net); tipc_mon_reinit_self(net); - tipc_nametbl_publish(net, &ua, &sk, addr); + if (!tipc_nametbl_publish(net, &ua, &sk, addr)) + pr_warn("Failed to publish own node state\n"); atomic_inc(&tn->finalized); wake_up_var(&tn->finalized); } -- 2.43.0