From: John Fastabend john.fastabend@gmail.com
mainline inclusion from mainline-v5.16-rc5 commit c0d95d3380ee099d735e08618c0d599e72f6c8b0 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I65HYE
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
---------------------------
When a sock is added to a sock map we evaluate what proto op hooks need to be used. However, when the program is removed from the sock map we have not been evaluating if that changes the required program layout.
Before the patch listed in the 'fixes' tag this was not causing failures because the base program set handles all cases. Specifically, the case with a stream parser and the case with out a stream parser are both handled. With the fix below we identified a race when running with a proto op that attempts to read skbs off both the stream parser and the skb->receive_queue. Namely, that a race existed where when the stream parser is empty checking the skb->receive_queue from recvmsg at the precies moment when the parser is paused and the receive_queue is not empty could result in skipping the stream parser. This may break a RX policy depending on the parser to run.
The fix tag then loads a specific proto ops that resolved this race. But, we missed removing that proto ops recv hook when the sock is removed from the sockmap. The result is the stream parser is stopped so no more skbs will be aggregated there, but the hook and BPF program continues to be attached on the psock. User space will then get an EBUSY when trying to read the socket because the recvmsg() handler is now waiting on a stopped stream parser.
To fix we rerun the proto ops init() function which will look at the new set of progs attached to the psock and rest the proto ops hook to the correct handlers. And in the above case where we remove the sock from the sock map the RX prog will no longer be listed so the proto ops is removed.
Fixes: c5d2177a72a16 ("bpf, sockmap: Fix race in ingress receive verdict with redirect to self") Signed-off-by: John Fastabend john.fastabend@gmail.com Signed-off-by: Daniel Borkmann daniel@iogearbox.net Link: https://lore.kernel.org/bpf/20211119181418.353932-3-john.fastabend@gmail.com (cherry picked from commit c0d95d3380ee099d735e08618c0d599e72f6c8b0) Signed-off-by: Liu Jian liujian56@huawei.com
Conflicts: net/core/skmsg.c Reviewed-by: Yue Haibing yuehaibing@huawei.com Signed-off-by: Jialin Zhang zhangjialin11@huawei.com --- net/core/skmsg.c | 4 ++++ net/core/sock_map.c | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/net/core/skmsg.c b/net/core/skmsg.c index 545181a1ae04..cdf1c2a25ad9 100644 --- a/net/core/skmsg.c +++ b/net/core/skmsg.c @@ -1056,6 +1056,8 @@ void sk_psock_stop_strp(struct sock *sk, struct sk_psock *psock) { struct sk_psock_parser *parser = &psock->parser;
+ psock_set_prog(&psock->progs.skb_verdict, NULL); + if (!parser->enabled) return;
@@ -1069,6 +1071,8 @@ void sk_psock_stop_verdict(struct sock *sk, struct sk_psock *psock) { struct sk_psock_parser *parser = &psock->parser;
+ psock_set_prog(&psock->progs.skb_parser, NULL); + if (!parser->enabled) return;
diff --git a/net/core/sock_map.c b/net/core/sock_map.c index 5254fba8d4da..a44de18b4a56 100644 --- a/net/core/sock_map.c +++ b/net/core/sock_map.c @@ -145,6 +145,8 @@ static void sock_map_add_link(struct sk_psock *psock, spin_unlock_bh(&psock->link_lock); }
+static int sock_map_init_proto(struct sock *sk, struct sk_psock *psock); + static void sock_map_del_link(struct sock *sk, struct sk_psock *psock, void *link_raw) { @@ -170,8 +172,10 @@ static void sock_map_del_link(struct sock *sk, write_lock_bh(&sk->sk_callback_lock); if (strp_stop) sk_psock_stop_strp(sk, psock); - else + if (verdict_stop) sk_psock_stop_verdict(sk, psock); + + sock_map_init_proto(sk, psock); write_unlock_bh(&sk->sk_callback_lock); } }