From de3f9df5aad2a5d514719ce320bb50dcb89182cd Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 30 Jan 2024 11:31:55 +0800 Subject: [PATCH] tcp: add sanity checks to rx zerocopy maillist inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8ZTOK Reference: https://lore.kernel.org/all/20240125103317.2334989-1-edumazet@google.com/ -------------------------------- 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 Conflicts: net/ipv4/tcp.c Signed-off-by: Zhengchao Shao --- net/ipv4/tcp.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index dcbc5ec00da87..bb74fc0aa2d20 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1917,6 +1917,8 @@ static int tcp_zerocopy_receive(struct sock *sk, ret = 0; curr_addr = address; while (length + PAGE_SIZE <= zc->length) { + struct page *page; + if (zc->recv_skip_hint < PAGE_SIZE) { u32 offset_frag; @@ -1944,7 +1946,10 @@ static int tcp_zerocopy_receive(struct sock *sk, if (!frags || offset_frag) break; } - if (skb_frag_size(frags) != PAGE_SIZE || skb_frag_off(frags)) { + + page = skb_frag_page(frags); + if (skb_frag_size(frags) != PAGE_SIZE || skb_frag_off(frags) || + PageCompound(page) || page->mapping) { int remaining = zc->recv_skip_hint; while (remaining && (skb_frag_size(frags) != PAGE_SIZE || @@ -1955,7 +1960,7 @@ static int tcp_zerocopy_receive(struct sock *sk, zc->recv_skip_hint -= remaining; break; } - pages[pg_idx] = skb_frag_page(frags); + pages[pg_idx] = page; pg_idx++; length += PAGE_SIZE; zc->recv_skip_hint -= PAGE_SIZE; -- Gitee