Skip to content

Commit 9cd62f0

Browse files
edumazetgregkh
authored andcommitted
tcp: fix skb_copy_ubufs() vs BIG TCP
[ Upstream commit 7e692df ] David Ahern reported crashes in skb_copy_ubufs() caused by TCP tx zerocopy using hugepages, and skb length bigger than ~68 KB. skb_copy_ubufs() assumed it could copy all payload using up to MAX_SKB_FRAGS order-0 pages. This assumption broke when BIG TCP was able to put up to 512 KB per skb. We did not hit this bug at Google because we use CONFIG_MAX_SKB_FRAGS=45 and limit gso_max_size to 180000. A solution is to use higher order pages if needed. v2: add missing __GFP_COMP, or we leak memory. Fixes: 7c4e983 ("net: allow gso_max_size to exceed 65536") Reported-by: David Ahern <dsahern@kernel.org> Link: https://lore.kernel.org/netdev/c70000f6-baa4-4a05-46d0-4b3e0dc1ccc8@gmail.com/T/ Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Xin Long <lucien.xin@gmail.com> Cc: Willem de Bruijn <willemb@google.com> Cc: Coco Li <lixiaoyan@google.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 27d5e46 commit 9cd62f0

1 file changed

Lines changed: 14 additions & 6 deletions

File tree

net/core/skbuff.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1705,7 +1705,7 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
17051705
{
17061706
int num_frags = skb_shinfo(skb)->nr_frags;
17071707
struct page *page, *head = NULL;
1708-
int i, new_frags;
1708+
int i, order, psize, new_frags;
17091709
u32 d_off;
17101710

17111711
if (skb_shared(skb) || skb_unclone(skb, gfp_mask))
@@ -1714,9 +1714,17 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
17141714
if (!num_frags)
17151715
goto release;
17161716

1717-
new_frags = (__skb_pagelen(skb) + PAGE_SIZE - 1) >> PAGE_SHIFT;
1717+
/* We might have to allocate high order pages, so compute what minimum
1718+
* page order is needed.
1719+
*/
1720+
order = 0;
1721+
while ((PAGE_SIZE << order) * MAX_SKB_FRAGS < __skb_pagelen(skb))
1722+
order++;
1723+
psize = (PAGE_SIZE << order);
1724+
1725+
new_frags = (__skb_pagelen(skb) + psize - 1) >> (PAGE_SHIFT + order);
17181726
for (i = 0; i < new_frags; i++) {
1719-
page = alloc_page(gfp_mask);
1727+
page = alloc_pages(gfp_mask | __GFP_COMP, order);
17201728
if (!page) {
17211729
while (head) {
17221730
struct page *next = (struct page *)page_private(head);
@@ -1743,11 +1751,11 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
17431751
vaddr = kmap_atomic(p);
17441752

17451753
while (done < p_len) {
1746-
if (d_off == PAGE_SIZE) {
1754+
if (d_off == psize) {
17471755
d_off = 0;
17481756
page = (struct page *)page_private(page);
17491757
}
1750-
copy = min_t(u32, PAGE_SIZE - d_off, p_len - done);
1758+
copy = min_t(u32, psize - d_off, p_len - done);
17511759
memcpy(page_address(page) + d_off,
17521760
vaddr + p_off + done, copy);
17531761
done += copy;
@@ -1763,7 +1771,7 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
17631771

17641772
/* skb frags point to kernel buffers */
17651773
for (i = 0; i < new_frags - 1; i++) {
1766-
__skb_fill_page_desc(skb, i, head, 0, PAGE_SIZE);
1774+
__skb_fill_page_desc(skb, i, head, 0, psize);
17671775
head = (struct page *)page_private(head);
17681776
}
17691777
__skb_fill_page_desc(skb, new_frags - 1, head, 0, d_off);

0 commit comments

Comments
 (0)