From: Alexei Starovoitov bpf_msg_redirect_{map,hash}() store the target in msg->sk_redir, without a reference. After the prog has run, sk_psock_msg_verdict() makes SK_PASS a redirect if this field is set. But tcp_bpf_send_verdict() runs the prog again on a cork, and on the rest of a partly sent message. Nothing clears the field between runs. Thus SK_PASS without a new target is a redirect to the old target. If that sock is already free, this is a use after free. Clear msg->sk_redir before each run, as the skb verdict paths do with skb_bpf_redirect_clear(). Only SK_PASS without a target changes. It now sends the data on psock->sk. Then sendmsg() can return another value. A redirect that applies to more bytes uses psock->sk_redir, with its own reference. The counts msg->apply_bytes and msg->cork_bytes stay as today. Fixes: e5cd3abcb31a ("bpf: sockmap, refactor sockmap routines to work with hashmap") Signed-off-by: Alexei Starovoitov --- net/core/skmsg.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/core/skmsg.c b/net/core/skmsg.c index a5d498982848..8a3b8536c0c2 100644 --- a/net/core/skmsg.c +++ b/net/core/skmsg.c @@ -936,6 +936,13 @@ int sk_psock_msg_verdict(struct sock *sk, struct sk_psock *psock, sk_msg_compute_data_pointers(msg); msg->sk = sk; + /* + * The prog may have run on this sk_msg before: it is a cork, or the + * rest of a message of which only a part was sent. The target of that + * run is not the target of this run, and the sk_msg holds no reference + * to it. + */ + msg->sk_redir = NULL; ret = bpf_prog_run_pin_on_cpu(prog, msg); msg->sk = NULL; ret = sk_psock_map_verd(ret, msg->sk_redir); -- 2.55.0