64 lines
2.5 KiB
Diff
64 lines
2.5 KiB
Diff
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
|
From: Liu Jian <liujian56@huawei.com>
|
||
|
Date: Tue, 9 Aug 2022 17:49:15 +0800
|
||
|
Subject: [PATCH] skmsg: Fix wrong last sg check in sk_msg_recvmsg()
|
||
|
|
||
|
[ Upstream commit 583585e48d965338e73e1eb383768d16e0922d73 ]
|
||
|
|
||
|
Fix one kernel NULL pointer dereference as below:
|
||
|
|
||
|
[ 224.462334] Call Trace:
|
||
|
[ 224.462394] __tcp_bpf_recvmsg+0xd3/0x380
|
||
|
[ 224.462441] ? sock_has_perm+0x78/0xa0
|
||
|
[ 224.462463] tcp_bpf_recvmsg+0x12e/0x220
|
||
|
[ 224.462494] inet_recvmsg+0x5b/0xd0
|
||
|
[ 224.462534] __sys_recvfrom+0xc8/0x130
|
||
|
[ 224.462574] ? syscall_trace_enter+0x1df/0x2e0
|
||
|
[ 224.462606] ? __do_page_fault+0x2de/0x500
|
||
|
[ 224.462635] __x64_sys_recvfrom+0x24/0x30
|
||
|
[ 224.462660] do_syscall_64+0x5d/0x1d0
|
||
|
[ 224.462709] entry_SYSCALL_64_after_hwframe+0x65/0xca
|
||
|
|
||
|
In commit 9974d37ea75f ("skmsg: Fix invalid last sg check in
|
||
|
sk_msg_recvmsg()"), we change last sg check to sg_is_last(),
|
||
|
but in sockmap redirection case (without stream_parser/stream_verdict/
|
||
|
skb_verdict), we did not mark the end of the scatterlist. Check the
|
||
|
sk_msg_alloc, sk_msg_page_add, and bpf_msg_push_data functions, they all
|
||
|
do not mark the end of sg. They are expected to use sg.end for end
|
||
|
judgment. So the judgment of '(i != msg_rx->sg.end)' is added back here.
|
||
|
|
||
|
Fixes: 9974d37ea75f ("skmsg: Fix invalid last sg check in sk_msg_recvmsg()")
|
||
|
Signed-off-by: Liu Jian <liujian56@huawei.com>
|
||
|
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
|
||
|
Acked-by: John Fastabend <john.fastabend@gmail.com>
|
||
|
Acked-by: Jakub Sitnicki <jakub@cloudflare.com>
|
||
|
Link: https://lore.kernel.org/bpf/20220809094915.150391-1-liujian56@huawei.com
|
||
|
Signed-off-by: Sasha Levin <sashal@kernel.org>
|
||
|
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
|
||
|
---
|
||
|
net/core/skmsg.c | 4 ++--
|
||
|
1 file changed, 2 insertions(+), 2 deletions(-)
|
||
|
|
||
|
diff --git a/net/core/skmsg.c b/net/core/skmsg.c
|
||
|
index f50f8d95b628..23d65fe160c3 100644
|
||
|
--- a/net/core/skmsg.c
|
||
|
+++ b/net/core/skmsg.c
|
||
|
@@ -462,7 +462,7 @@ int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg,
|
||
|
|
||
|
if (copied == len)
|
||
|
break;
|
||
|
- } while (!sg_is_last(sge));
|
||
|
+ } while ((i != msg_rx->sg.end) && !sg_is_last(sge));
|
||
|
|
||
|
if (unlikely(peek)) {
|
||
|
msg_rx = sk_psock_next_msg(psock, msg_rx);
|
||
|
@@ -472,7 +472,7 @@ int sk_msg_recvmsg(struct sock *sk, struct sk_psock *psock, struct msghdr *msg,
|
||
|
}
|
||
|
|
||
|
msg_rx->sg.start = i;
|
||
|
- if (!sge->length && sg_is_last(sge)) {
|
||
|
+ if (!sge->length && (i == msg_rx->sg.end || sg_is_last(sge))) {
|
||
|
msg_rx = sk_psock_dequeue_msg(psock);
|
||
|
kfree_sk_msg(msg_rx);
|
||
|
}
|