Re: [PATCH v3 bpf/net 6/6] sockmap: Fix broken memory accounting for UDP.
From: bot+bpf-ci@kernel.org
Date: 2026-02-19 18:10:59
Also in:
bpf
quoted hunk ↗ jump to hunk
diff --git a/net/core/skmsg.c b/net/core/skmsg.c --- a/net/core/skmsg.c +++ b/net/core/skmsg.c
[ ... ]
quoted hunk ↗ jump to hunk
@@ -576,6 +577,7 @@ static int sk_psock_skb_ingress(struct sk_psock *psock, struct sk_buff *skb, u32 off, u32 len, gfp_t gfp_flags, bool take_ref) { struct sock *sk = psock->sk; + bool is_udp = sk_is_udp(sk); struct sk_msg *msg; int err = -EAGAIN;@@ -583,12 +585,15 @@ static int sk_psock_skb_ingress(struct sk_psock *psock, struct sk_buff *skb, if (!msg) goto out; - if (skb->sk != sk) { + if (is_udp) + spin_lock_bh(&sk->sk_receive_queue.lock); + + if (skb->sk != sk || is_udp) { if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf) - goto free; + goto unlock; if (!sk_rmem_schedule(sk, skb, skb->truesize)) - goto free; + goto unlock; }
[ ... ]
skb_set_owner_r(skb, sk);
^^^
If sk_psock_skb_ingress_enqueue() fails after this point (for
example, skb_to_sgvec() fails and skb_linearize() also fails under
GFP_ATOMIC memory pressure), the error path frees msg and returns
-EAGAIN, but the skb is kept with skb->destructor set to
udp_sock_rfree.
The caller sk_psock_verdict_apply() then queues this skb onto
psock->ingress_skb for retry via sk_psock_backlog().
On retry, sk_psock_handle_skb() calls sk_psock_skb_ingress()
again. The function acquires sk->sk_receive_queue.lock, then calls
skb_set_owner_r() which calls skb_orphan(). skb_orphan() invokes
the current skb->destructor, which is now udp_sock_rfree():
sk_psock_skb_ingress()
spin_lock_bh(&sk->sk_receive_queue.lock) <-- held
skb_set_owner_r(skb, sk)
skb_orphan(skb)
skb->destructor(skb) [= udp_sock_rfree]
spin_lock_bh(&sk->sk_receive_queue.lock) <-- deadlock
Could this self-deadlock on the receive queue lock?
+ if (is_udp) {
+ skb->destructor = udp_sock_rfree;
+ spin_unlock_bh(&sk->sk_receive_queue.lock);
+ }
+
err = sk_psock_skb_ingress_enqueue(skb, off, len, psock, sk, msg, take_ref);
if (err < 0)
goto free;
out:
return err;
+
+unlock:
+ if (is_udp)
+ spin_unlock_bh(&sk->sk_receive_queue.lock);
free:
kfree(msg);
goto out;quoted hunk ↗ jump to hunk
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c
[ ... ]
+void udp_sock_rfree(struct sk_buff *skb)
+{
+ struct sock *sk = skb->sk;
+
+ spin_lock_bh(&sk->sk_receive_queue.lock);
+ sock_rfree(skb);
+ spin_unlock_bh(&sk->sk_receive_queue.lock);
+}--- AI reviewed your patch. Please fix the bug or email reply why it's not a bug. See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md CI run summary: https://github.com/kernel-patches/bpf/actions/runs/22193327667 AI-authorship-score: low AI-authorship-explanation: The commit demonstrates deep understanding of UDP memory accounting internals and references a specific syzbot report, consistent with an experienced kernel networking developer. issues-found: 1 issue-severity-score: high issue-severity-explanation: Self-deadlock on sk->sk_receive_queue.lock when sk_psock_skb_ingress is retried after enqueue failure for UDP, causing a system hang.