Skip to content

Commit 43a08e0

Browse files
Eric Dumazetdavem330
authored andcommitted
tun: fix tun_napi_alloc_frags() frag allocator
<Mark Rutland reported> While fuzzing arm64 v4.16-rc1 with Syzkaller, I've been hitting a misaligned atomic in __skb_clone:         atomic_inc(&(skb_shinfo(skb)->dataref)); where dataref doesn't have the required natural alignment, and the atomic operation faults. e.g. i often see it aligned to a single byte boundary rather than a four byte boundary. AFAICT, the skb_shared_info is misaligned at the instant it's allocated in __napi_alloc_skb() __napi_alloc_skb() </end of report> Problem is caused by tun_napi_alloc_frags() using napi_alloc_frag() with user provided seg sizes, leading to other users of this API getting unaligned page fragments. Since we would like to not necessarily add paddings or alignments to the frags that tun_napi_alloc_frags() attaches to the skb, switch to another page frag allocator. As a bonus skb_page_frag_refill() can use GFP_KERNEL allocations, meaning that we can not deplete memory reserves as easily. Fixes: 90e33d4 ("tun: enable napi_gro_frags() for TUN/TAP driver") Signed-off-by: Eric Dumazet <[email protected]> Reported-by: Mark Rutland <[email protected]> Tested-by: Mark Rutland <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 15f35d4 commit 43a08e0

File tree

1 file changed

+6
-10
lines changed

1 file changed

+6
-10
lines changed

drivers/net/tun.c

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1489,27 +1489,23 @@ static struct sk_buff *tun_napi_alloc_frags(struct tun_file *tfile,
14891489
skb->truesize += skb->data_len;
14901490

14911491
for (i = 1; i < it->nr_segs; i++) {
1492+
struct page_frag *pfrag = &current->task_frag;
14921493
size_t fragsz = it->iov[i].iov_len;
1493-
unsigned long offset;
1494-
struct page *page;
1495-
void *data;
14961494

14971495
if (fragsz == 0 || fragsz > PAGE_SIZE) {
14981496
err = -EINVAL;
14991497
goto free;
15001498
}
15011499

1502-
local_bh_disable();
1503-
data = napi_alloc_frag(fragsz);
1504-
local_bh_enable();
1505-
if (!data) {
1500+
if (!skb_page_frag_refill(fragsz, pfrag, GFP_KERNEL)) {
15061501
err = -ENOMEM;
15071502
goto free;
15081503
}
15091504

1510-
page = virt_to_head_page(data);
1511-
offset = data - page_address(page);
1512-
skb_fill_page_desc(skb, i - 1, page, offset, fragsz);
1505+
skb_fill_page_desc(skb, i - 1, pfrag->page,
1506+
pfrag->offset, fragsz);
1507+
page_ref_inc(pfrag->page);
1508+
pfrag->offset += fragsz;
15131509
}
15141510

15151511
return skb;

0 commit comments

Comments
 (0)