Commit b67daf1b authored by Pengcheng Yang's avatar Pengcheng Yang Committed by Liu Jian
Browse files

bpf, sockmap: Fix missing BPF_F_INGRESS flag when using apply_bytes

mainline inclusion
from mainline-v6.2-rc1
commit a351d608
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I65HYE
CVE: NA

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=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: 8934ce2f ("bpf: sockmap redirect ingress support")
Signed-off-by: default avatarPengcheng Yang <yangpc@wangsu.com>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Acked-by: default avatarJakub Sitnicki <jakub@cloudflare.com>
Link: https://lore.kernel.org/bpf/1669718441-2654-3-git-send-email-yangpc@wangsu.com


Signed-off-by: default avatarLiu Jian <liujian56@huawei.com>

Conflicts:
	include/net/tcp.h
parent 48c7aa19
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -94,6 +94,7 @@ struct sk_psock {
	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;
	struct sk_psock_parser		parser;
+2 −2
Original line number Diff line number Diff line
@@ -2238,8 +2238,8 @@ static inline void tcp_bpf_clone(const struct sock *sk, struct sock *newsk)
#endif /* CONFIG_BPF_STREAM_PARSER */

#ifdef CONFIG_NET_SOCK_MSG
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);
int __tcp_bpf_recvmsg(struct sock *sk, struct sk_psock *psock,
		      struct msghdr *msg, int len, int flags);
#endif /* CONFIG_NET_SOCK_MSG */
+6 −3
Original line number Diff line number Diff line
@@ -784,13 +784,16 @@ int sk_psock_msg_verdict(struct sock *sk, struct sk_psock *psock,
	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:
+6 −5
Original line number Diff line number Diff line
@@ -213,10 +213,9 @@ static int tcp_bpf_push_locked(struct sock *sk, struct sk_msg *msg,
	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;

@@ -383,7 +382,7 @@ static int tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
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;
@@ -429,6 +428,7 @@ static int tcp_bpf_send_verdict(struct sock *sk, struct sk_psock *psock,
		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) {
@@ -445,7 +445,8 @@ static int tcp_bpf_send_verdict(struct sock *sk, struct sk_psock *psock,
		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)
+4 −2
Original line number Diff line number Diff line
@@ -807,7 +807,7 @@ static int bpf_exec_tx_verdict(struct sk_msg *msg, struct sock *sk,
	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;

@@ -852,6 +852,7 @@ static int bpf_exec_tx_verdict(struct sk_msg *msg, struct sock *sk,
		}
		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)
@@ -861,7 +862,8 @@ static int bpf_exec_tx_verdict(struct sk_msg *msg, struct sock *sk,
		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);