]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bpf, skmsg: fix verdict sk_data_ready racing with ktls rx
authorXingwang Xiang <v3rdant.xiang@gmail.com>
Sun, 17 May 2026 14:56:26 +0000 (23:56 +0900)
committerJakub Kicinski <kuba@kernel.org>
Thu, 21 May 2026 00:21:21 +0000 (17:21 -0700)
sk_psock_strp_data_ready() already checks tls_sw_has_ctx_rx() and
defers to psock->saved_data_ready when a TLS RX context is present,
avoiding a conflict with the TLS strparser's ownership of the receive
queue (commit e91de6afa81c, "bpf: Fix running sk_skb program types
with ktls").

sk_psock_verdict_data_ready() has no equivalent guard.  When a socket
is inserted into a sockmap (BPF_SK_SKB_VERDICT) before TLS RX is
configured, tls_sw_strparser_arm() saves sk_psock_verdict_data_ready
as rx_ctx->saved_data_ready.  On data arrival:

  tls_data_ready -> tls_strp_data_ready -> tls_rx_msg_ready
    -> saved_data_ready() = sk_psock_verdict_data_ready()
      -> tcp_read_skb() drains sk_receive_queue via __skb_unlink()
         without calling tcp_eat_skb(), so copied_seq is not advanced.

tls_strp_msg_load() then finds tcp_inq() >= full_len (stale), calls
tcp_recv_skb() on the now-empty queue, hits WARN_ON_ONCE(!first), and
returns with rx_ctx->strp.anchor.frag_list pointing at a psock-owned
(potentially freed) skb.  tls_decrypt_sg() subsequently walks that
frag_list: use-after-free.

Apply the same fix as sk_psock_strp_data_ready(): if a TLS RX context
is present, call psock->saved_data_ready (sock_def_readable) to wake
recv() waiters and return immediately, leaving the receive queue
untouched.  TLS retains sole ownership of the queue and decrypts the
record normally through tls_sw_recvmsg().

Fixes: ef5659280eb1 ("bpf, sockmap: Allow skipping sk_skb parser program")
Signed-off-by: Xingwang Xiang <v3rdant.xiang@gmail.com>
Link: https://patch.msgid.link/20260517145630.20521-2-v3rdant.xiang@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/core/skmsg.c

index 6187a83bd7411b7932ec76fe93d3159ad4d3a96c..e1850caf1a71a0b5f950330db451bfddd9e17a22 100644 (file)
@@ -1268,12 +1268,19 @@ out:
 static void sk_psock_verdict_data_ready(struct sock *sk)
 {
        const struct proto_ops *ops = NULL;
+       struct sk_psock *psock;
        struct socket *sock;
        int copied;
 
        trace_sk_data_ready(sk);
 
        rcu_read_lock();
+       psock = sk_psock(sk);
+       if (psock && tls_sw_has_ctx_rx(sk)) {
+               psock->saved_data_ready(sk);
+               rcu_read_unlock();
+               return;
+       }
        sock = READ_ONCE(sk->sk_socket);
        if (likely(sock))
                ops = READ_ONCE(sock->ops);
@@ -1283,8 +1290,6 @@ static void sk_psock_verdict_data_ready(struct sock *sk)
 
        copied = ops->read_skb(sk, sk_psock_verdict_recv);
        if (copied >= 0) {
-               struct sk_psock *psock;
-
                rcu_read_lock();
                psock = sk_psock(sk);
                if (psock)