Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'bpf-sockmap-fix-af_unix-null-ptr-deref-in-proto-update'

Michal Luczaj says:

====================
bpf, sockmap: Fix af_unix null-ptr-deref in proto update

Updating sockmap/sockhash using a unix sock races unix_stream_connect():
when sock_map_sk_state_allowed() passes (sk_state == TCP_ESTABLISHED),
unix_peer(sk) in unix_stream_bpf_update_proto() may still return NULL.
====================

Link: https://patch.msgid.link/20260414-unix-proto-update-null-ptr-deref-v4-0-2af6fe97918e@rbox.co
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>

+20 -6
+2 -2
net/core/sock_map.c
··· 530 530 if (sk_is_tcp(sk)) 531 531 return sk->sk_state != TCP_LISTEN; 532 532 else 533 - return sk->sk_state == TCP_ESTABLISHED; 533 + return READ_ONCE(sk->sk_state) == TCP_ESTABLISHED; 534 534 } 535 535 536 536 static bool sock_map_sk_is_suitable(const struct sock *sk) ··· 543 543 if (sk_is_tcp(sk)) 544 544 return (1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_LISTEN); 545 545 if (sk_is_stream_unix(sk)) 546 - return (1 << sk->sk_state) & TCPF_ESTABLISHED; 546 + return (1 << READ_ONCE(sk->sk_state)) & TCPF_ESTABLISHED; 547 547 if (sk_is_vsock(sk) && 548 548 (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET)) 549 549 return (1 << sk->sk_state) & TCPF_ESTABLISHED;
+5 -4
net/unix/af_unix.c
··· 3735 3735 struct bpf_prog *prog; 3736 3736 struct sock *sk = v; 3737 3737 uid_t uid; 3738 - bool slow; 3739 3738 int ret; 3740 3739 3741 3740 if (v == SEQ_START_TOKEN) 3742 3741 return 0; 3743 3742 3744 - slow = lock_sock_fast(sk); 3743 + lock_sock(sk); 3744 + unix_state_lock(sk); 3745 3745 3746 - if (unlikely(sk_unhashed(sk))) { 3746 + if (unlikely(sock_flag(sk, SOCK_DEAD))) { 3747 3747 ret = SEQ_SKIP; 3748 3748 goto unlock; 3749 3749 } ··· 3753 3753 prog = bpf_iter_get_info(&meta, false); 3754 3754 ret = unix_prog_seq_show(prog, &meta, v, uid); 3755 3755 unlock: 3756 - unlock_sock_fast(sk, slow); 3756 + unix_state_unlock(sk); 3757 + release_sock(sk); 3757 3758 return ret; 3758 3759 } 3759 3760
+3
net/unix/unix_bpf.c
··· 185 185 */ 186 186 if (!psock->sk_pair) { 187 187 sk_pair = unix_peer(sk); 188 + if (unlikely(!sk_pair)) 189 + return -EINVAL; 190 + 188 191 sock_hold(sk_pair); 189 192 psock->sk_pair = sk_pair; 190 193 }
+10
tools/testing/selftests/bpf/progs/bpf_iter_unix.c
··· 7 7 8 8 char _license[] SEC("license") = "GPL"; 9 9 10 + SEC(".maps") struct { 11 + __uint(type, BPF_MAP_TYPE_SOCKMAP); 12 + __uint(max_entries, 1); 13 + __type(key, __u32); 14 + __type(value, __u64); 15 + } sockmap; 16 + 10 17 static long sock_i_ino(const struct sock *sk) 11 18 { 12 19 const struct socket *sk_socket = sk->sk_socket; ··· 82 75 } 83 76 84 77 BPF_SEQ_PRINTF(seq, "\n"); 78 + 79 + /* Test for deadlock. */ 80 + bpf_map_update_elem(&sockmap, &(int){0}, sk, 0); 85 81 86 82 return 0; 87 83 }