From 4c62d6f969d0bb27b05d739f0624c8262f271148 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 24 Mar 2024 15:46:31 +0800 Subject: [PATCH] tcp: add sanity checks to rx zerocopy mainline inclusion from mainline-v6.8-rc3 commit 577e4432f3ac810049cb7e6b71f4d96ec7c6e894 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/I99JO6 CVE: CVE-2024-26640 -------------------------------- TCP rx zerocopy intent is to map pages initially allocated from NIC drivers, not pages owned by a fs. This patch adds to can_map_frag() these additional checks: - Page must not be a compound one. - page->mapping must be NULL. This fixes the panic reported by ZhangPeng. syzbot was able to loopback packets built with sendfile(), mapping pages owned by an ext4 file to TCP rx zerocopy. r3 = socket$inet_tcp(0x2, 0x1, 0x0) mmap(&(0x7f0000ff9000/0x4000)=nil, 0x4000, 0x0, 0x12, r3, 0x0) r4 = socket$inet_tcp(0x2, 0x1, 0x0) bind$inet(r4, &(0x7f0000000000)={0x2, 0x4e24, @multicast1}, 0x10) connect$inet(r4, &(0x7f00000006c0)={0x2, 0x4e24, @empty}, 0x10) r5 = openat$dir(0xffffffffffffff9c, &(0x7f00000000c0)='./file0\x00', 0x181e42, 0x0) fallocate(r5, 0x0, 0x0, 0x85b8) sendfile(r4, r5, 0x0, 0x8ba0) getsockopt$inet_tcp_TCP_ZEROCOPY_RECEIVE(r4, 0x6, 0x23, &(0x7f00000001c0)={&(0x7f0000ffb000/0x3000)=nil, 0x3000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &(0x7f0000000440)=0x40) r6 = openat$dir(0xffffffffffffff9c, &(0x7f00000000c0)='./file0\x00', 0x181e42, 0x0) Fixes: 93ab6cc69162 ("tcp: implement mmap() for zero copy receive") Link: https://lore.kernel.org/netdev/5106a58e-04da-372a-b836-9d3d0bd2507b@huawei.com/T/ Reported-and-bisected-by: ZhangPeng Signed-off-by: Eric Dumazet Cc: Arjun Roy Cc: Matthew Wilcox Cc: linux-mm@vger.kernel.org Cc: Andrew Morton Cc: linux-fsdevel@vger.kernel.org Signed-off-by: David S. Miller Conflicts: net/ipv4/tcp.c Signed-off-by: Ziyang Xuan --- net/ipv4/tcp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index fb2b55894b8d..4416d1c24dbb 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1810,6 +1810,8 @@ static int tcp_zerocopy_receive(struct sock *sk, zc->recv_skip_hint = 0; ret = 0; while (length + PAGE_SIZE <= zc->length) { + struct page *page; + if (zc->recv_skip_hint < PAGE_SIZE) { if (skb) { skb = skb->next; @@ -1830,7 +1832,9 @@ static int tcp_zerocopy_receive(struct sock *sk, frags++; } } - if (frags->size != PAGE_SIZE || frags->page_offset) + page = skb_frag_page(frags); + if (frags->size != PAGE_SIZE || frags->page_offset || + PageCompound(page) || page->mapping) break; ret = vm_insert_page(vma, address + length, skb_frag_page(frags)); -- Gitee