bpf: sk_msg, fix socket data_ready events
authorJohn Fastabend <john.fastabend@gmail.com>
Thu, 20 Dec 2018 19:35:33 +0000 (11:35 -0800)
committerDaniel Borkmann <daniel@iogearbox.net>
Thu, 20 Dec 2018 22:47:09 +0000 (23:47 +0100)
When a skb verdict program is in-use and either another BPF program
redirects to that socket or the new SK_PASS support is used the
data_ready callback does not wake up application. Instead because
the stream parser/verdict is using the sk data_ready callback we wake
up the stream parser/verdict block.

Fix this by adding a helper to check if the stream parser block is
enabled on the sk and if so call the saved pointer which is the
upper layers wake up function.

This fixes application stalls observed when an application is waiting
for data in a blocking read().

Fixes: d829e9c4112b ("tls: convert to generic sk_msg interface")
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
include/linux/skmsg.h
net/core/skmsg.c
net/ipv4/tcp_bpf.c

index dd57e6f408b180ee7a851041dc919d524f8ed64c..178a3933a71b871982a58b5052740ca38f4ea34a 100644 (file)
@@ -417,6 +417,14 @@ static inline void sk_psock_put(struct sock *sk, struct sk_psock *psock)
                sk_psock_drop(sk, psock);
 }
 
+static inline void sk_psock_data_ready(struct sock *sk, struct sk_psock *psock)
+{
+       if (psock->parser.enabled)
+               psock->parser.saved_data_ready(sk);
+       else
+               sk->sk_data_ready(sk);
+}
+
 static inline void psock_set_prog(struct bpf_prog **pprog,
                                  struct bpf_prog *prog)
 {
index 8a91a460de8f689d41507b84367831bb38830e6b..3df7627db4bb5728f822c8a8fa9c4753454bf79b 100644 (file)
@@ -403,7 +403,7 @@ static int sk_psock_skb_ingress(struct sk_psock *psock, struct sk_buff *skb)
        msg->skb = skb;
 
        sk_psock_queue_msg(psock, msg);
-       sk->sk_data_ready(sk);
+       sk_psock_data_ready(sk, psock);
        return copied;
 }
 
@@ -751,7 +751,7 @@ static int sk_psock_strp_parse(struct strparser *strp, struct sk_buff *skb)
 }
 
 /* Called with socket lock held. */
-static void sk_psock_data_ready(struct sock *sk)
+static void sk_psock_strp_data_ready(struct sock *sk)
 {
        struct sk_psock *psock;
 
@@ -799,7 +799,7 @@ void sk_psock_start_strp(struct sock *sk, struct sk_psock *psock)
                return;
 
        parser->saved_data_ready = sk->sk_data_ready;
-       sk->sk_data_ready = sk_psock_data_ready;
+       sk->sk_data_ready = sk_psock_strp_data_ready;
        sk->sk_write_space = sk_psock_write_space;
        parser->enabled = true;
 }
index a47c1cdf90fc26ea72532bd9601c1d243aed7fb6..87503343743d37c70485af6199187fe80420d4ef 100644 (file)
@@ -198,7 +198,7 @@ static int bpf_tcp_ingress(struct sock *sk, struct sk_psock *psock,
                msg->sg.start = i;
                msg->sg.size -= apply_bytes;
                sk_psock_queue_msg(psock, tmp);
-               sk->sk_data_ready(sk);
+               sk_psock_data_ready(sk, psock);
        } else {
                sk_msg_free(sk, tmp);
                kfree(tmp);