[ Upstream commit 
a351d6087bf7d3d8440d58d3bf244ec64b89394a ]
When redirecting, we use sk_msg_to_ingress() to get the BPF_F_INGRESS
flag from the msg->flags. If apply_bytes is used and it is larger than
the current data being processed, sk_psock_msg_verdict() will not be
called when sendmsg() is called again. At this time, the msg->flags is 0,
and we lost the BPF_F_INGRESS flag.
So we need to save the BPF_F_INGRESS flag in sk_psock and use it when
redirection.
Fixes: 8934ce2fd081 ("bpf: sockmap redirect ingress support")
Signed-off-by: Pengcheng Yang <yangpc@wangsu.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Jakub Sitnicki <jakub@cloudflare.com>
Link: https://lore.kernel.org/bpf/1669718441-2654-3-git-send-email-yangpc@wangsu.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
        u32                             apply_bytes;
        u32                             cork_bytes;
        u32                             eval;
+       bool                            redir_ingress; /* undefined if sk_redir is null */
        struct sk_msg                   *cork;
        struct sk_psock_progs           progs;
 #if IS_ENABLED(CONFIG_BPF_STREAM_PARSER)
 
 void tcp_bpf_clone(const struct sock *sk, struct sock *newsk);
 #endif /* CONFIG_BPF_SYSCALL */
 
-int tcp_bpf_sendmsg_redir(struct sock *sk, struct sk_msg *msg, u32 bytes,
-                         int flags);
+int tcp_bpf_sendmsg_redir(struct sock *sk, bool ingress,
+                         struct sk_msg *msg, u32 bytes, int flags);
 #endif /* CONFIG_NET_SOCK_MSG */
 
 #if !defined(CONFIG_BPF_SYSCALL) || !defined(CONFIG_NET_SOCK_MSG)
 
        ret = sk_psock_map_verd(ret, msg->sk_redir);
        psock->apply_bytes = msg->apply_bytes;
        if (ret == __SK_REDIRECT) {
-               if (psock->sk_redir)
+               if (psock->sk_redir) {
                        sock_put(psock->sk_redir);
-               psock->sk_redir = msg->sk_redir;
-               if (!psock->sk_redir) {
+                       psock->sk_redir = NULL;
+               }
+               if (!msg->sk_redir) {
                        ret = __SK_DROP;
                        goto out;
                }
+               psock->redir_ingress = sk_msg_to_ingress(msg);
+               psock->sk_redir = msg->sk_redir;
                sock_hold(psock->sk_redir);
        }
 out:
 
        return ret;
 }
 
-int tcp_bpf_sendmsg_redir(struct sock *sk, struct sk_msg *msg,
-                         u32 bytes, int flags)
+int tcp_bpf_sendmsg_redir(struct sock *sk, bool ingress,
+                         struct sk_msg *msg, u32 bytes, int flags)
 {
-       bool ingress = sk_msg_to_ingress(msg);
        struct sk_psock *psock = sk_psock_get(sk);
        int ret;
 
 static int tcp_bpf_send_verdict(struct sock *sk, struct sk_psock *psock,
                                struct sk_msg *msg, int *copied, int flags)
 {
-       bool cork = false, enospc = sk_msg_full(msg);
+       bool cork = false, enospc = sk_msg_full(msg), redir_ingress;
        struct sock *sk_redir;
        u32 tosend, origsize, sent, delta = 0;
        u32 eval;
                sk_msg_apply_bytes(psock, tosend);
                break;
        case __SK_REDIRECT:
+               redir_ingress = psock->redir_ingress;
                sk_redir = psock->sk_redir;
                sk_msg_apply_bytes(psock, tosend);
                if (!psock->apply_bytes) {
                release_sock(sk);
 
                origsize = msg->sg.size;
-               ret = tcp_bpf_sendmsg_redir(sk_redir, msg, tosend, flags);
+               ret = tcp_bpf_sendmsg_redir(sk_redir, redir_ingress,
+                                           msg, tosend, flags);
                sent = origsize - msg->sg.size;
 
                if (eval == __SK_REDIRECT)
 
        struct sk_psock *psock;
        struct sock *sk_redir;
        struct tls_rec *rec;
-       bool enospc, policy;
+       bool enospc, policy, redir_ingress;
        int err = 0, send;
        u32 delta = 0;
 
                }
                break;
        case __SK_REDIRECT:
+               redir_ingress = psock->redir_ingress;
                sk_redir = psock->sk_redir;
                memcpy(&msg_redir, msg, sizeof(*msg));
                if (msg->apply_bytes < send)
                sk_msg_return_zero(sk, msg, send);
                msg->sg.size -= send;
                release_sock(sk);
-               err = tcp_bpf_sendmsg_redir(sk_redir, &msg_redir, send, flags);
+               err = tcp_bpf_sendmsg_redir(sk_redir, redir_ingress,
+                                           &msg_redir, send, flags);
                lock_sock(sk);
                if (err < 0) {
                        *copied -= sk_msg_free_nocharge(sk, &msg_redir);