Skip to content

Commit 0ab52a8

Browse files
mmhalgregkh
authored andcommitted
bpf: Fix bpf_sk_select_reuseport() memory leak
[ Upstream commit b3af609 ] As pointed out in the original comment, lookup in sockmap can return a TCP ESTABLISHED socket. Such TCP socket may have had SO_ATTACH_REUSEPORT_EBPF set before it was ESTABLISHED. In other words, a non-NULL sk_reuseport_cb does not imply a non-refcounted socket. Drop sk's reference in both error paths. unreferenced object 0xffff888101911800 (size 2048): comm "test_progs", pid 44109, jiffies 4297131437 hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 80 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace (crc 9336483b): __kmalloc_noprof+0x3bf/0x560 __reuseport_alloc+0x1d/0x40 reuseport_alloc+0xca/0x150 reuseport_attach_prog+0x87/0x140 sk_reuseport_attach_bpf+0xc8/0x100 sk_setsockopt+0x1181/0x1990 do_sock_setsockopt+0x12b/0x160 __sys_setsockopt+0x7b/0xc0 __x64_sys_setsockopt+0x1b/0x30 do_syscall_64+0x93/0x180 entry_SYSCALL_64_after_hwframe+0x76/0x7e Fixes: 64d8529 ("bpf: Allow bpf_map_lookup_elem for SOCKMAP and SOCKHASH") Signed-off-by: Michal Luczaj <mhal@rbox.co> Reviewed-by: Martin KaFai Lau <martin.lau@kernel.org> Link: https://patch.msgid.link/20250110-reuseport-memleak-v1-1-fa1ddab0adfe@rbox.co Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 9bb2617 commit 0ab52a8

File tree

1 file changed

+18
-12
lines changed

1 file changed

+18
-12
lines changed

net/core/filter.c

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10509,42 +10509,48 @@ BPF_CALL_4(sk_select_reuseport, struct sk_reuseport_kern *, reuse_kern,
1050910509
bool is_sockarray = map->map_type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY;
1051010510
struct sock_reuseport *reuse;
1051110511
struct sock *selected_sk;
10512+
int err;
1051210513

1051310514
selected_sk = map->ops->map_lookup_elem(map, key);
1051410515
if (!selected_sk)
1051510516
return -ENOENT;
1051610517

1051710518
reuse = rcu_dereference(selected_sk->sk_reuseport_cb);
1051810519
if (!reuse) {
10519-
/* Lookup in sock_map can return TCP ESTABLISHED sockets. */
10520-
if (sk_is_refcounted(selected_sk))
10521-
sock_put(selected_sk);
10522-
1052310520
/* reuseport_array has only sk with non NULL sk_reuseport_cb.
1052410521
* The only (!reuse) case here is - the sk has already been
1052510522
* unhashed (e.g. by close()), so treat it as -ENOENT.
1052610523
*
1052710524
* Other maps (e.g. sock_map) do not provide this guarantee and
1052810525
* the sk may never be in the reuseport group to begin with.
1052910526
*/
10530-
return is_sockarray ? -ENOENT : -EINVAL;
10527+
err = is_sockarray ? -ENOENT : -EINVAL;
10528+
goto error;
1053110529
}
1053210530

1053310531
if (unlikely(reuse->reuseport_id != reuse_kern->reuseport_id)) {
1053410532
struct sock *sk = reuse_kern->sk;
1053510533

10536-
if (sk->sk_protocol != selected_sk->sk_protocol)
10537-
return -EPROTOTYPE;
10538-
else if (sk->sk_family != selected_sk->sk_family)
10539-
return -EAFNOSUPPORT;
10540-
10541-
/* Catch all. Likely bound to a different sockaddr. */
10542-
return -EBADFD;
10534+
if (sk->sk_protocol != selected_sk->sk_protocol) {
10535+
err = -EPROTOTYPE;
10536+
} else if (sk->sk_family != selected_sk->sk_family) {
10537+
err = -EAFNOSUPPORT;
10538+
} else {
10539+
/* Catch all. Likely bound to a different sockaddr. */
10540+
err = -EBADFD;
10541+
}
10542+
goto error;
1054310543
}
1054410544

1054510545
reuse_kern->selected_sk = selected_sk;
1054610546

1054710547
return 0;
10548+
error:
10549+
/* Lookup in sock_map can return TCP ESTABLISHED sockets. */
10550+
if (sk_is_refcounted(selected_sk))
10551+
sock_put(selected_sk);
10552+
10553+
return err;
1054810554
}
1054910555

1055010556
static const struct bpf_func_proto sk_select_reuseport_proto = {

0 commit comments

Comments
 (0)