diff --git a/patches.kernel.org/6.2.12-074-skbuff-Fix-a-race-between-coalescing-and-relea.patch b/patches.kernel.org/6.2.12-074-skbuff-Fix-a-race-between-coalescing-and-relea.patch new file mode 100644 index 0000000..ebb2560 --- /dev/null +++ b/patches.kernel.org/6.2.12-074-skbuff-Fix-a-race-between-coalescing-and-relea.patch @@ -0,0 +1,99 @@ +From: Liang Chen +Date: Thu, 13 Apr 2023 17:03:53 +0800 +Subject: [PATCH] skbuff: Fix a race between coalescing and releasing SKBs +References: bsc#1012628 +Patch-mainline: 6.2.12 +Git-commit: 0646dc31ca886693274df5749cd0c8c1eaaeb5ca + +[ Upstream commit 0646dc31ca886693274df5749cd0c8c1eaaeb5ca ] + +Commit 1effe8ca4e34 ("skbuff: fix coalescing for page_pool fragment +recycling") allowed coalescing to proceed with non page pool page and page +pool page when @from is cloned, i.e. + +to->pp_recycle --> false +from->pp_recycle --> true +skb_cloned(from) --> true + +However, it actually requires skb_cloned(@from) to hold true until +coalescing finishes in this situation. If the other cloned SKB is +released while the merging is in process, from_shinfo->nr_frags will be +set to 0 toward the end of the function, causing the increment of frag +page _refcount to be unexpectedly skipped resulting in inconsistent +reference counts. Later when SKB(@to) is released, it frees the page +directly even though the page pool page is still in use, leading to +use-after-free or double-free errors. So it should be prohibited. + +The double-free error message below prompted us to investigate: +BUG: Bad page state in process swapper/1 pfn:0e0d1 +page:00000000c6548b28 refcount:-1 mapcount:0 mapping:0000000000000000 +index:0x2 pfn:0xe0d1 +flags: 0xfffffc0000000(node=0|zone=1|lastcpupid=0x1fffff) +raw: 000fffffc0000000 0000000000000000 ffffffff00000101 0000000000000000 +raw: 0000000000000002 0000000000000000 ffffffffffffffff 0000000000000000 +page dumped because: nonzero _refcount + +CPU: 1 PID: 0 Comm: swapper/1 Tainted: G E 6.2.0+ +Call Trace: + +dump_stack_lvl+0x32/0x50 +bad_page+0x69/0xf0 +free_pcp_prepare+0x260/0x2f0 +free_unref_page+0x20/0x1c0 +skb_release_data+0x10b/0x1a0 +napi_consume_skb+0x56/0x150 +net_rx_action+0xf0/0x350 +? __napi_schedule+0x79/0x90 +__do_softirq+0xc8/0x2b1 +__irq_exit_rcu+0xb9/0xf0 +common_interrupt+0x82/0xa0 + + +asm_common_interrupt+0x22/0x40 +RIP: 0010:default_idle+0xb/0x20 + +Fixes: 53e0961da1c7 ("page_pool: add frag page recycling support in page pool") +Signed-off-by: Liang Chen +Reviewed-by: Eric Dumazet +Link: https://lore.kernel.org/r/20230413090353.14448-1-liangchen.linux@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +Signed-off-by: Jiri Slaby +--- + net/core/skbuff.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index a31ff4d8..43e1b896 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -5475,18 +5475,18 @@ bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from, + if (skb_cloned(to)) + return false; + +- /* In general, avoid mixing slab allocated and page_pool allocated +- * pages within the same SKB. However when @to is not pp_recycle and +- * @from is cloned, we can transition frag pages from page_pool to +- * reference counted. +- * +- * On the other hand, don't allow coalescing two pp_recycle SKBs if +- * @from is cloned, in case the SKB is using page_pool fragment ++ /* In general, avoid mixing page_pool and non-page_pool allocated ++ * pages within the same SKB. Additionally avoid dealing with clones ++ * with page_pool pages, in case the SKB is using page_pool fragment + * references (PP_FLAG_PAGE_FRAG). Since we only take full page + * references for cloned SKBs at the moment that would result in + * inconsistent reference counts. ++ * In theory we could take full references if @from is cloned and ++ * !@to->pp_recycle but its tricky (due to potential race with ++ * the clone disappearing) and rare, so not worth dealing with. + */ +- if (to->pp_recycle != (from->pp_recycle && !skb_cloned(from))) ++ if (to->pp_recycle != from->pp_recycle || ++ (from->pp_recycle && skb_cloned(from))) + return false; + + if (len <= skb_tailroom(to)) { +-- +2.35.3 + diff --git a/series.conf b/series.conf index 1b74c13..cf8fa3b 100644 --- a/series.conf +++ b/series.conf @@ -2301,6 +2301,7 @@ patches.kernel.org/6.2.12-071-udp6-fix-potential-access-to-stale-information.patch patches.kernel.org/6.2.12-072-selftests-add-the-missing-CONFIG_IP_SCTP-in-ne.patch patches.kernel.org/6.2.12-073-net-macb-fix-a-memory-corruption-in-extended-b.patch + patches.kernel.org/6.2.12-074-skbuff-Fix-a-race-between-coalescing-and-relea.patch ######################################################## # Build fixes that apply to the vanilla kernel too.