FAILED: patch "[PATCH] net: cdc_ncm: Deal with too low values of dwNtbOutMaxSize" failed to apply to 5.4-stable tree
[email protected]
maintainerThe patch below does not apply to the 5.4-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.4.y
git checkout FETCH_HEAD
git cherry-pick -x 7e01c7f7046efc2c7c192c3619db43292b98e997
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2023052621-karaoke-try-d2ba@gregkh' --subject-prefix 'PATCH 5.4.y' HEAD^..
Possible dependencies:
7e01c7f7046e ("net: cdc_ncm: Deal with too low values of dwNtbOutMaxSize") 2be6d4d16a08 ("net: cdc_ncm: Allow for dwNtbOutMaxSize to be unset or zero") 0fa81b304a79 ("cdc_ncm: Implement the 32-bit version of NCM Transfer Block")
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 7e01c7f7046efc2c7c192c3619db43292b98e997 Mon Sep 17 00:00:00 2001
From: Tudor Ambarus <[email protected]>
Date: Wed, 17 May 2023 13:38:08 +0000
Subject: [PATCH] net: cdc_ncm: Deal with too low values of dwNtbOutMaxSize
Currently in cdc_ncm_check_tx_max(), if dwNtbOutMaxSize is lower than the calculated "min" value, but greater than zero, the logic sets tx_max to dwNtbOutMaxSize. This is then used to allocate a new SKB in cdc_ncm_fill_tx_frame() where all the data is handled.
For small values of dwNtbOutMaxSize the memory allocated during alloc_skb(dwNtbOutMaxSize, GFP_ATOMIC) will have the same size, due to how size is aligned at alloc time:
size = SKB_DATA_ALIGN(size);
size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));Thus we hit the same bug that we tried to squash with
commit 2be6d4d16a084 ("net: cdc_ncm: Allow for dwNtbOutMaxSize to be unset or zero")
Low values of dwNtbOutMaxSize do not cause an issue presently because at alloc_skb() time more memory (512b) is allocated than required for the SKB headers alone (320b), leaving some space (512b - 320b = 192b) for CDC data (172b).
However, if more elements (for example 3 x u64 = [24b]) were added to one of the SKB header structs, say 'struct skb_shared_info', increasing its original size (320b [320b aligned]) to something larger (344b [384b aligned]), then suddenly the CDC data (172b) no longer fits in the spare SKB data area (512b - 384b = 128b).
Consequently the SKB bounds checking semantics fails and panics:
skbuff: skb_over_panic: text:ffffffff831f755b len:184 put:172 head:ffff88811f1c6c00 data:ffff88811f1c6c00 tail:0xb8 end:0x80 dev:<NULL>
------------[ cut here ]------------ kernel BUG at net/core/skbuff.c:113! invalid opcode: 0000 [#1] PREEMPT SMP KASAN CPU: 0 PID: 57 Comm: kworker/0:2 Not tainted 5.15.106-syzkaller-00249-g19c0ed55a470 #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 04/14/2023 Workqueue: mld mld_ifc_work RIP: 0010:skb_panic net/core/skbuff.c:113 [inline] RIP: 0010:skb_over_panic+0x14c/0x150 net/core/skbuff.c:118 [snip] Call Trace: <TASK> skb_put+0x151/0x210 net/core/skbuff.c:2047 skb_put_zero include/linux/skbuff.h:2422 [inline] cdc_ncm_ndp16 drivers/net/usb/cdc_ncm.c:1131 [inline] cdc_ncm_fill_tx_frame+0x11ab/0x3da0 drivers/net/usb/cdc_ncm.c:1308 cdc_ncm_tx_fixup+0xa3/0x100
Deal with too low values of dwNtbOutMaxSize, clamp it in the range [USB_CDC_NCM_NTB_MIN_OUT_SIZE, CDC_NCM_NTB_MAX_SIZE_TX]. We ensure enough data space is allocated to handle CDC data by making sure dwNtbOutMaxSize is not smaller than USB_CDC_NCM_NTB_MIN_OUT_SIZE.
drivers/net/usb/cdc_ncm.c +15 -9
@@ -181,9 +181,12 @@ static u32 cdc_ncm_check_tx_max(struct usbnet *dev, u32 new_tx)else min = ctx->max_datagram_size + ctx->max_ndp_size +sizeof (struct usb_cdc_ncm_nth32 ); - max =min_t (u32,CDC_NCM_NTB_MAX_SIZE_TX ,le32_to_cpu (ctx->ncm_parm.dwNtbOutMaxSize)); -if (max ==0 ) +if (le32_to_cpu (ctx->ncm_parm.dwNtbOutMaxSize) ==0 ) max =CDC_NCM_NTB_MAX_SIZE_TX ;/* dwNtbOutMaxSize not set */ +else + max =clamp_t (u32,le32_to_cpu (ctx->ncm_parm.dwNtbOutMaxSize), +USB_CDC_NCM_NTB_MIN_OUT_SIZE , +CDC_NCM_NTB_MAX_SIZE_TX );/* some devices set dwNtbOutMaxSize too low for the above default */ min =min (min, max);
@@ -1244,6 +1247,9 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)* further. */ if (skb_out ==NULL ) { +/* If even the smallest allocation fails, abort. */ +if (ctx->tx_curr_size ==USB_CDC_NCM_NTB_MIN_OUT_SIZE ) + goto alloc_failed; ctx->tx_low_mem_max_cnt =min (ctx->tx_low_mem_max_cnt +1 , (unsigned )CDC_NCM_LOW_MEM_MAX_CNT ); ctx->tx_low_mem_val = ctx->tx_low_mem_max_cnt;
@@ -1262,13 +1268,8 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) skb_out =alloc_skb (ctx->tx_curr_size,GFP_ATOMIC );/* No allocation possible so we will abort */ -if (skb_out ==NULL ) { -if (skb !=NULL ) { -dev_kfree_skb_any (skb); - dev->net->stats.tx_dropped++; - } - goto exit_no_skb; - } +if (!skb_out) + goto alloc_failed; ctx->tx_low_mem_val--; }if (ctx->is_ndp16) {
@@ -1461,6 +1462,11 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)return skb_out; +alloc_failed: +if (skb) { +dev_kfree_skb_any (skb); + dev->net->stats.tx_dropped++; + } exit_no_skb:/* Start timer, if there is a remaining non-empty skb */ if (ctx->tx_curr_skb !=NULL && n >0 )