Skip to content

Commit 577e443

Browse files
edumazetdavem330
authored andcommitted
tcp: add sanity checks to rx zerocopy
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: 93ab6cc ("tcp: implement mmap() for zero copy receive") Link: https://lore.kernel.org/netdev/[email protected]/T/ Reported-and-bisected-by: ZhangPeng <[email protected]> Signed-off-by: Eric Dumazet <[email protected]> Cc: Arjun Roy <[email protected]> Cc: Matthew Wilcox <[email protected]> Cc: [email protected] Cc: Andrew Morton <[email protected]> Cc: [email protected] Signed-off-by: David S. Miller <[email protected]>
1 parent bfb007a commit 577e443

File tree

1 file changed

+11
-1
lines changed

1 file changed

+11
-1
lines changed

net/ipv4/tcp.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1786,7 +1786,17 @@ static skb_frag_t *skb_advance_to_frag(struct sk_buff *skb, u32 offset_skb,
17861786

17871787
static bool can_map_frag(const skb_frag_t *frag)
17881788
{
1789-
return skb_frag_size(frag) == PAGE_SIZE && !skb_frag_off(frag);
1789+
struct page *page;
1790+
1791+
if (skb_frag_size(frag) != PAGE_SIZE || skb_frag_off(frag))
1792+
return false;
1793+
1794+
page = skb_frag_page(frag);
1795+
1796+
if (PageCompound(page) || page->mapping)
1797+
return false;
1798+
1799+
return true;
17901800
}
17911801

17921802
static int find_next_mappable_frag(const skb_frag_t *frag,

0 commit comments

Comments
 (0)