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