With the previous patch, bpf prog cannot access unix_sk(sk)->peer. struct unix_sock has two pointers to struct sock, and another pointer unix_sk(sk)->listener also has the same problem mentioned in the previous patch. unix_sk(sk)->listener is set by unix_stream_connect() and cleared by unix_update_edges() during accept(), and both are done under unix_state_lock(). There are some functions where unix_sk(sk)->peer is passed and bpf prog can access unix_sk(unix_sk(sk)->peer)->listener locklessly, which is unsafe. (e.g. unix_maybe_add_creds()) Let's reject bpf access to unix_sk(sk)->listener too. Fixes: aed6ecef55d7 ("af_unix: Save listener for embryo socket.") Signed-off-by: Kuniyuki Iwashima --- kernel/bpf/verifier.c | 1 + .../selftests/bpf/progs/verifier_sock.c | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index b328a1640c82..2ffc6eff5584 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -7157,6 +7157,7 @@ BTF_TYPE_SAFE_TRUSTED_OR_NULL(struct vm_area_struct) { BTF_TYPE_SAFE_UNTRUSTED(struct unix_sock) { struct sock *peer; + struct sock *listener; }; static bool type_is_rcu(struct bpf_verifier_env *env, diff --git a/tools/testing/selftests/bpf/progs/verifier_sock.c b/tools/testing/selftests/bpf/progs/verifier_sock.c index 8de4d3ed98d4..730850e93d6d 100644 --- a/tools/testing/selftests/bpf/progs/verifier_sock.c +++ b/tools/testing/selftests/bpf/progs/verifier_sock.c @@ -1191,4 +1191,28 @@ int BPF_PROG(trace_unix_dgram_sendmsg, struct socket *sock, struct msghdr *msg, return 0; } +SEC("fentry/unix_maybe_add_creds") +__failure __msg("R1 type=untrusted_ptr_ expected=sock_common, sock, tcp_sock, xdp_sock, ptr_, trusted_ptr_") +int BPF_PROG(trace_unix_maybe_add_creds, struct sk_buff *skb, + const struct sock *sk, struct sock *other) +{ + struct unix_sock *u_other, *u_listener; + + if (!other) + return 0; + + u_other = bpf_skc_to_unix_sock(other); + if (!u_other) + return 0; + + /* unix_accept() could clear u_other->listener + * and the listener could be close()d. + */ + u_listener = bpf_skc_to_unix_sock(u_other->listener); + if (!u_listener) + return 0; + + return 0; +} + char _license[] SEC("license") = "GPL"; -- 2.53.0.rc2.204.g2597b5adb4-goog