skb frags are either page_pool pages tracked via pp_ref_count (released by napi_pp_put_page()), or regular pages tracked via _refcount (released by put_netmem()). skb->pp_recycle was unbalanced and caused the underflow that hit BUG(). Fix by taking the share with page_pool_ref_page(), matching skb_pp_frag_ref() in skb_try_coalesce(). Reproduced by sharing the same page_pool frag into two extra skbs, releasing both before the page rotates out, then forcing rotation -- trips WARN_ON(ret < 0) in page_pool_unref_netmem() with the bug, silent with the fix. [ 113.863676] ------------[ cut here ]------------ [ 113.863687] WARNING: ./include/net/page_pool/helpers.h:297 at page_pool_put_netmem.constprop.0+0x1f/0x40, CPU#0: swapper/0/0 [ 113.863706] CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted 7.2.0-rc2-00235-gddb06ebf175f-dirty #5 PREEMPT(full) [ 113.863713] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-debian-1.16.2-1 04/01/2014 [ 113.863718] RIP: 0010:page_pool_put_netmem.constprop.0+0x1f/0x40 [ 113.863725] Code: 90 90 90 90 90 90 90 90 90 90 90 48 89 f0 48 83 e0 fe 48 8b 48 28 48 ff c9 74 20 48 83 c9 ff f0 48 0f c1 48 28 48 ff c9 79 07 <0f> 0b c3 cc cc cc cc 75 13 48 c7 40 28 01 00 00 00 0f b6 ca 83 ca [ 113.863731] RSP: 0018:ffffc90000003c98 EFLAGS: 00010296 [ 113.863738] RAX: ffffea0004192d80 RBX: ffff8881017e1200 RCX: ffffffffffffffff [ 113.863742] RDX: 0000000000000001 RSI: ffffea0004192d80 RDI: ffff888101ce2000 [ 113.863746] RBP: 000000000000000c R08: 000000000000003c R09: 0000000000000a00 [ 113.863750] R10: 0000000000000001 R11: 00000000000007e0 R12: 0000000000000000 [ 113.863754] R13: ffff888101ce3000 R14: ffffea0004192d80 R15: ffff888100a779c0 [ 113.863763] FS: 0000000000000000(0000) GS:ffff8881f8a8b000(0000) knlGS:0000000000000000 [ 113.863768] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 113.863773] CR2: 00007ff837b28000 CR3: 0000000106e91005 CR4: 0000000000170eb0 [ 113.863777] Call Trace: [ 113.863784] [ 113.863787] page_to_skb+0x1f3/0x210 [ 113.863798] receive_buf+0x712/0xca0 [ 113.863807] ? detach_buf_split_in_order+0x5d/0x110 [ 113.863819] virtnet_poll+0x1da/0x460 [ 113.863829] __napi_poll.constprop.0+0x2a/0x120 [ 113.863838] net_rx_action+0x11a/0x230 [ 113.863847] ? raise_softirq_irqoff+0x5/0x20 [ 113.863857] ? __napi_schedule+0x31/0x50 [ 113.863864] ? vring_interrupt+0x77/0x90 [ 113.863871] handle_softirqs+0x127/0x260 [ 113.863880] __irq_exit_rcu+0x50/0xf0 [ 113.863888] common_interrupt+0x95/0xc0 [ 113.863910] [ 113.863914] [ 113.863917] asm_common_interrupt+0x22/0x40 [ 113.863924] RIP: 0010:default_idle+0xb/0x20 [ 113.863932] Code: 00 4d 29 c8 4c 01 c7 4c 29 c2 e9 6e ff ff ff 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 eb 07 0f 00 2d 9d d0 03 00 fb f4 c3 cc cc cc cc 66 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 90 [ 113.863937] RSP: 0018:ffffffff82803e98 EFLAGS: 00000206 [ 113.863943] RAX: 0000000000000000 RBX: ffffffff8280b400 RCX: 00000000ffff49ff [ 113.863947] RDX: 0000000000000000 RSI: ffffffff821f82b0 RDI: 000000000003e4f4 [ 113.863951] RBP: 0000000000000000 R08: 0000000000000002 R09: 0000000000000000 [ 113.863955] R10: 000000581b92d59c R11: 0000000000000000 R12: 0000000000000000 [ 113.863959] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000013a90 [ 113.863966] default_idle_call+0x3c/0x70 [ 113.863973] do_idle+0xdc/0x200 [ 113.863987] cpu_startup_entry+0x29/0x30 [ 113.863995] rest_init+0xbd/0xc0 [ 113.864002] start_kernel+0x5fd/0x600 [ 113.864018] x86_64_start_reservations+0x20/0x20 [ 113.864029] x86_64_start_kernel+0xc9/0xd0 [ 113.864036] common_startup_64+0x129/0x148 [ 113.864048] [ 113.864051] ---[ end trace 0000000000000000 ]--- the above warning repeated several times, 8 in this run, and then hit BUG. [ 146.743192] ------------[ cut here ]------------ [ 146.743200] kernel BUG at net/core/skbuff.c:5289! [ 146.745219] Oops: invalid opcode: 0000 [#1] SMP NOPTI [ 146.747359] CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Tainted: G W 7.2.0-rc2-00235-gddb06ebf175f-dirty #5 PREEMPT(full) [ 146.752482] Tainted: [W]=WARN [ 146.753718] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-debian-1.16.2-1 04/01/2014 [ 146.757698] RIP: 0010:__skb_to_sgvec+0x226/0x260 [ 146.759646] Code: e6 89 4c 24 08 e8 fa fd ff ff 85 c0 78 2e 8b 4c 24 08 41 01 c7 29 cb 74 26 01 cd 4d 8b 6d 00 44 8b 74 24 04 eb 86 85 db 74 15 <0f> 0b 41 bf a6 ff ff ff eb 0b 41 bf 01 00 00 00 eb 03 41 89 c7 48 [ 146.767755] RSP: 0018:ffffc90000003c78 EFLAGS: 00010206 [ 146.769965] RAX: 0000000000000001 RBX: 0000000000000078 RCX: ffff8881060ebec0 [ 146.773018] RDX: 0000000000000001 RSI: 0000000000000001 RDI: ffffea00041b7200 [ 146.775910] RBP: 000000000000006c R08: 0000000000000000 R09: 0000000000000000 [ 146.778716] R10: 0000000000000058 R11: 00000000000007e0 R12: ffff888100b25eb0 [ 146.781355] R13: 0000000000000000 R14: 000000000000006c R15: 0000000000000002 [ 146.783911] FS: 0000000000000000(0000) GS:ffff8881f8a8b000(0000) knlGS:0000000000000000 [ 146.786704] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 146.788578] CR2: 00007f9245e088a0 CR3: 0000000106575006 CR4: 0000000000170eb0 [ 146.790880] Call Trace: [ 146.791601] [ 146.792190] skb_to_sgvec+0x11/0x40 [ 146.793267] esp_output_tail+0x184/0x420 [ 146.794450] esp_output+0x12e/0x160 [ 146.795407] xfrm_output_resume+0xb22/0xe10 [ 146.796571] ? __memcg_slab_free_hook+0x50/0xe0 [ 146.797842] ? iptfs_delay_timer+0x8a3/0x920 [ 146.798987] ? kmem_cache_free+0x210/0x270 [ 146.800061] iptfs_delay_timer+0x5dc/0x920 [ 146.801135] ? net_rx_action+0x1fc/0x230 [ 146.802172] ? rb_erase_linked+0x3b/0x60 [ 146.803175] ? __pfx_iptfs_delay_timer+0x10/0x10 [ 146.804346] __hrtimer_run_queues+0x117/0x1b0 [ 146.805452] hrtimer_run_softirq+0x43/0x90 [ 146.806474] handle_softirqs+0x127/0x260 [ 146.807421] __irq_exit_rcu+0x50/0xf0 [ 146.808304] common_interrupt+0x95/0xc0 [ 146.809229] [ 146.809733] [ 146.810200] asm_common_interrupt+0x22/0x40 [ 146.811176] RIP: 0010:default_idle+0xb/0x20 [ 146.812154] Code: 00 4d 29 c8 4c 01 c7 4c 29 c2 e9 6e ff ff ff 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 eb 07 0f 00 2d 9d d0 03 00 fb f4 c3 cc cc cc cc 66 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 90 [ 146.816515] RSP: 0018:ffffffff82803e98 EFLAGS: 00000206 [ 146.817661] RAX: 0000000000000000 RBX: ffffffff8280b400 RCX: 0000000000000000 [ 146.819210] RDX: 0000000000000000 RSI: ffffffff821f82b0 RDI: 0000000000050834 [ 146.820733] RBP: 0000000000000000 R08: 0000000000000002 R09: 0000000000000000 [ 146.822261] R10: 0000000000155cc0 R11: 0000000000000000 R12: 0000000000000000 [ 146.823751] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000013a90 [ 146.825225] default_idle_call+0x3c/0x70 [ 146.826032] do_idle+0xdc/0x200 [ 146.826645] cpu_startup_entry+0x29/0x30 [ 146.827412] rest_init+0xbd/0xc0 [ 146.828039] start_kernel+0x5fd/0x600 [ 146.828755] x86_64_start_reservations+0x20/0x20 [ 146.829677] x86_64_start_kernel+0xc9/0xd0 [ 146.830470] common_startup_64+0x129/0x148 [ 146.831247] [ 146.831661] ---[ end trace 0000000000000000 ]--- [ 146.832554] RIP: 0010:__skb_to_sgvec+0x226/0x260 [ 146.833442] Code: e6 89 4c 24 08 e8 fa fd ff ff 85 c0 78 2e 8b 4c 24 08 41 01 c7 29 cb 74 26 01 cd 4d 8b 6d 00 44 8b 74 24 04 eb 86 85 db 74 15 <0f> 0b 41 bf a6 ff ff ff eb 0b 41 bf 01 00 00 00 eb 03 41 89 c7 48 [ 146.837105] RSP: 0018:ffffc90000003c78 EFLAGS: 00010206 [ 146.838095] RAX: 0000000000000001 RBX: 0000000000000078 RCX: ffff8881060ebec0 [ 146.839418] RDX: 0000000000000001 RSI: 0000000000000001 RDI: ffffea00041b7200 Fixes: 5f2b6a909574 ("xfrm: iptfs: add skb-fragment sharing code") Fixes: b96ba312e21c ("xfrm: iptfs: share page fragments of inner packets") Signed-off-by: Antony Antony --- xfrm: iptfs fix --- net/xfrm/xfrm_iptfs.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/net/xfrm/xfrm_iptfs.c b/net/xfrm/xfrm_iptfs.c index 6920940a35b4..d3bca90e2c38 100644 --- a/net/xfrm/xfrm_iptfs.c +++ b/net/xfrm/xfrm_iptfs.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -486,7 +487,10 @@ static int iptfs_skb_add_frags(struct sk_buff *skb, tofrag->len -= offset; offset = 0; } - __skb_frag_ref(tofrag); + if (walk->pp_recycle) + page_pool_ref_page(skb_frag_page(tofrag)); + else + __skb_frag_ref(tofrag); shinfo->nr_frags++; shinfo->flags |= SKBFL_SHARED_FRAG; @@ -2171,7 +2175,11 @@ static void iptfs_consume_frags(struct sk_buff *to, struct sk_buff *from) new_truesize = SKB_TRUESIZE(skb_end_offset(from)); } else { iptfs_skb_head_to_frag(from, &toi->frags[toi->nr_frags]); - skb_frag_ref(to, toi->nr_frags++); + if (from->pp_recycle) + page_pool_ref_page(skb_frag_page(&toi->frags[toi->nr_frags])); + else + skb_frag_ref(to, toi->nr_frags); + toi->nr_frags++; new_truesize = SKB_DATA_ALIGN(sizeof(struct sk_buff)); } --- base-commit: 96f01b53c2d05e003b040892256de54a586e8529 change-id: xfrm-iptfs-pp_ref_count-underflow-063ee0302600 Best regards, -Antony