Re: [PATCH bpf v2 2/2] bpf: Unconditionally take socket references in lookup helpers
Michal Luczaj <[email protected]>
| Newsgroups | gmane.linux.network,gmane.linux.kernel.bpf,gmane.linux.kernel |
|---|---|
| Message-ID | <[email protected]> |
On 8/5/26 17:00, Michal Luczaj wrote: > On 8/4/26 03:58, Kuniyuki Iwashima wrote: >> On Mon, Aug 3, 2026 at 2:01 AM Michal Luczaj <[email protected]> wrote: >>> >>> Lookup helpers gate whether to acquire a socket reference on >>> sk_is_refcounted(), a check re-evaluated at release. An established socket >>> refcounted at acquire time can gain SOCK_RCU_FREE via >>> connect(AF_UNSPEC)+listen() before release runs; the release-side re-check >>> then reads sk_is_refcounted() == false and skips the put. The reference >>> leaks. >>> >>> Make acquire and release unconditional and symmetric: always take a >>> reference, always put it. Adapt sk_select_reuseport(). >>> >>> Fixes: 6acc9b432e67 ("bpf: Add helper to retrieve socket in BPF") >>> Fixes: 64d85290d79c ("bpf: Allow bpf_map_lookup_elem for SOCKMAP and SOCKHASH") >>> Reported-by: Sashiko <[email protected]> >>> Closes: https://lore.kernel.org/bpf/[email protected]/ >>> Signed-off-by: Michal Luczaj <[email protected]> >>> Reviewed-by: Emil Tsalapatis <[email protected]> >>> --- >>> TC bpf_sk_assign() has the same issue; it takes a reference only when >>> sk_is_refcounted() is true at assign time, but sock_pfree() (the skb >>> destructor it installs) re-checks sk_is_refcounted() independently at >>> release time. The same connect(AF_UNSPEC)+listen() transition leaks the >>> socket here too. I'd welcome suggestions on the right way to handle this. >> >> The same class of issue was reported by listen() + shutdown() + connect(). >> https://lore.kernel.org/netdev/[email protected]/ >> >> Can you test the diff in the thread ? > > Yeah, it does fix it for sk/sockmap lookups. But bpf_sk_assign() still > leaks; LLM devised a testcase that puts skb into NFQUEUE. Another way of > escaping the RCU section could probably involve bpf_skb_set_tstamp(). Ugh, I was wrong. It doesn't fix sockmap lookups, it just made the race window smaller: listen(): inet_hash() unhashed_state != TCP_LISTEN synchronize_rcu() sock_map_lookup(): rcu_read_lock() sock_map_lookup() sk_is_refcounted() == true refcount_inc_not_zero() sock_set_flag(SOCK_RCU_FREE) bpf_sk_release() sk_is_refcounted() == false put skipped, sock leaked