FAILED: patch "[PATCH] net: cdc_ncm: correct overhead in delayed_ndp_size" failed to apply to 4.4-stable tree
[email protected]
maintainerThe patch below does not apply to the 4.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]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 7a68d725e4ea384977445e0bcaed3d7de83ab5b3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jouni=20K=2E=20Sepp=C3=A4nen?= <[email protected]>
Date: Tue, 5 Jan 2021 06:52:49 +0200
Subject: [PATCH] net: cdc_ncm: correct overhead in delayed_ndp_size
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Aligning to tx_ndp_modulus is not sufficient because the next align call can be cdc_ncm_align_tail, which can add up to ctx->tx_modulus + ctx->tx_remainder - 1 bytes. This used to lead to occasional crashes on a Huawei 909s-120 LTE module as follows:
- the condition marked /* if there is a remaining skb [...] */ is true so the swaps happen
- skb_out is set from ctx->tx_curr_skb
- skb_out->len is exactly 0x3f52
- ctx->tx_curr_size is 0x4000 and delayed_ndp_size is 0xac (note that the sum of skb_out->len and delayed_ndp_size is 0x3ffe)
- the for loop over n is executed once
- the cdc_ncm_align_tail call marked /* align beginning of next frame */ increases skb_out->len to 0x3f56 (the sum is now 0x4002)
- the condition marked /* check if we had enough room left [...] */ is false so we break out of the loop
- the condition marked /* If requested, put NDP at end of frame. */ is true so the NDP is written into skb_out
- now skb_out->len is 0x4002, so padding_count is minus two interpreted as an unsigned number, which is used as the length argument to memset, leading to a crash with various symptoms but usually including
Quoted 5 lines
Call Trace: <IRQ> cdc_ncm_fill_tx_frame+0x83a/0x970 [cdc_ncm] cdc_mbim_tx_fixup+0x1d9/0x240 [cdc_mbim] usbnet_start_xmit+0x5d/0x720 [usbnet]
The cdc_ncm_align_tail call first aligns on a ctx->tx_modulus boundary (adding at most ctx->tx_modulus-1 bytes), then adds ctx->tx_remainder bytes. Alternatively, the next alignment call can occur in cdc_ncm_ndp16 or cdc_ncm_ndp32, in which case at most ctx->tx_ndp_modulus-1 bytes are added.
A similar problem has occurred before, and the code is nontrivial to reason about, so add a guard before the crashing call. By that time it is too late to prevent any memory corruption (we'll have written past the end of the buffer already) but we can at least try to get a warning written into an on-disk log by avoiding the hard crash caused by padding past the buffer with a huge number of zeros.
drivers/net/usb/cdc_ncm.c +6 -2
@@ -1199,7 +1199,10 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)* accordingly. Otherwise, we should check here. */ if (ctx->drvflags &CDC_NCM_FLAG_NDP_TO_END ) - delayed_ndp_size =ALIGN (ctx->max_ndp_size, ctx->tx_ndp_modulus); + delayed_ndp_size = ctx->max_ndp_size + +max_t (u32, + ctx->tx_ndp_modulus, + ctx->tx_modulus + ctx->tx_remainder) -1 ;else delayed_ndp_size =0 ;
@@ -1410,7 +1413,8 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)if (!(dev->driver_info->flags &FLAG_SEND_ZLP ) && skb_out->len > ctx->min_tx_pkt) { padding_count = ctx->tx_curr_size - skb_out->len; -skb_put_zero (skb_out, padding_count); +if (!WARN_ON (padding_count > ctx->tx_curr_size)) +skb_put_zero (skb_out, padding_count); }else if (skb_out->len < ctx->tx_curr_size && (skb_out->len % dev->maxpacket) ==0 ) {skb_put_u8 (skb_out,0 );/* force short packet */
[BACKPORT 4.4.y, 4.9.y] net: cdc_ncm: correct overhead in delayed_ndp_size
From: Jouni K. Seppänen <[email protected]>
commit 7a68d725e4ea384977445e0bcaed3d7de83ab5b3 upstream.
Aligning to tx_ndp_modulus is not sufficient because the next align call can be cdc_ncm_align_tail, which can add up to ctx->tx_modulus + ctx->tx_remainder - 1 bytes. This used to lead to occasional crashes on a Huawei 909s-120 LTE module as follows:
- the condition marked /* if there is a remaining skb [...] */ is true so the swaps happen
- skb_out is set from ctx->tx_curr_skb
- skb_out->len is exactly 0x3f52
- ctx->tx_curr_size is 0x4000 and delayed_ndp_size is 0xac (note that the sum of skb_out->len and delayed_ndp_size is 0x3ffe)
- the for loop over n is executed once
- the cdc_ncm_align_tail call marked /* align beginning of next frame */ increases skb_out->len to 0x3f56 (the sum is now 0x4002)
- the condition marked /* check if we had enough room left [...] */ is false so we break out of the loop
- the condition marked /* If requested, put NDP at end of frame. */ is true so the NDP is written into skb_out
- now skb_out->len is 0x4002, so padding_count is minus two interpreted as an unsigned number, which is used as the length argument to memset, leading to a crash with various symptoms but usually including
Quoted 5 lines
Call Trace: <IRQ> cdc_ncm_fill_tx_frame+0x83a/0x970 [cdc_ncm] cdc_mbim_tx_fixup+0x1d9/0x240 [cdc_mbim] usbnet_start_xmit+0x5d/0x720 [usbnet]
The cdc_ncm_align_tail call first aligns on a ctx->tx_modulus boundary (adding at most ctx->tx_modulus-1 bytes), then adds ctx->tx_remainder bytes. Alternatively, the next alignment call can occur in cdc_ncm_ndp16 or cdc_ncm_ndp32, in which case at most ctx->tx_ndp_modulus-1 bytes are added.
A similar problem has occurred before, and the code is nontrivial to reason about, so add a guard before the crashing call. By that time it is too late to prevent any memory corruption (we'll have written past the end of the buffer already) but we can at least try to get a warning written into an on-disk log by avoiding the hard crash caused by padding past the buffer with a huge number of zeros.
---
Backport to 4.4.y and 4.9.y: there is no skb_put_zero or ctx->tx_curr_size so use memset(skb_put(...)) and ctx->tx_max, respectively.
drivers/net/usb/cdc_ncm.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/net/usb/cdc_ncm.c +6 -2
@@ -1079,7 +1079,10 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)* accordingly. Otherwise, we should check here. */ if (ctx->drvflags &CDC_NCM_FLAG_NDP_TO_END ) - delayed_ndp_size =ALIGN (ctx->max_ndp_size, ctx->tx_ndp_modulus); + delayed_ndp_size = ctx->max_ndp_size + +max_t (u32, + ctx->tx_ndp_modulus, + ctx->tx_modulus + ctx->tx_remainder) -1 ;else delayed_ndp_size =0 ;
@@ -1232,7 +1235,8 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)if (!(dev->driver_info->flags &FLAG_SEND_ZLP ) && skb_out->len > ctx->min_tx_pkt) { padding_count = ctx->tx_max - skb_out->len; -memset (skb_put (skb_out, padding_count),0 , padding_count); +if (!WARN_ON (padding_count > ctx->tx_max)) +memset (skb_put (skb_out, padding_count),0 , padding_count); }else if (skb_out->len < ctx->tx_max && (skb_out->len % dev->maxpacket) ==0 ) { *skb_put (skb_out,1 ) =0 ;/* force short packet */
--
2.20.1
Re: [BACKPORT 4.4.y, 4.9.y] net: cdc_ncm: correct overhead in delayed_ndp_size
Quoted 53 lines · Jouni Seppänen
From: Jouni K. Seppänen <[email protected]>
commit
7a68d725e4ea384977445e0bcaed3d7de83ab5b3upstream.Aligning to
tx_ndp_modulusis not sufficient because the next align call can becdc_ncm_align_tail, which can add up toctx->tx_modulus+ctx->tx_remainder- 1 bytes. This used to lead to occasional crashes on a Huawei 909s-120 LTE module as follows:- the condition marked /* if there is a remaining skb [...] */ is true so the swaps happen
-skb_outis set fromctx->tx_curr_skb
-skb_out->lenis exactly0x3f52
-ctx->tx_curr_sizeis0x4000anddelayed_ndp_sizeis0xac(note that the sum ofskb_out->lenanddelayed_ndp_sizeis0x3ffe)
- the for loop over n is executed once
- thecdc_ncm_align_tailcall marked /* align beginning of next frame */ increasesskb_out->lento0x3f56(the sum is now0x4002)
- the condition marked /* check if we had enough room left [...] */ is false so we break out of the loop
- the condition marked /* If requested, put NDP at end of frame. */ is true so the NDP is written intoskb_out
- nowskb_out->lenis0x4002, sopadding_countis minus two interpreted as an unsigned number, which is used as the length argument to memset, leading to a crash with various symptoms but usually includingQuoted 5 lines
Call Trace: <IRQ> cdc_ncm_fill_tx_frame+0x83a/0x970 [cdc_ncm] cdc_mbim_tx_fixup+0x1d9/0x240 [cdc_mbim] usbnet_start_xmit+0x5d/0x720 [usbnet]The
cdc_ncm_align_tailcall first aligns on actx->tx_modulusboundary (adding at most ctx->tx_modulus-1 bytes), then addsctx->tx_remainderbytes. Alternatively, the next alignment call can occur incdc_ncm_ndp16orcdc_ncm_ndp32, in which case at most ctx->tx_ndp_modulus-1 bytes are added.A similar problem has occurred before, and the code is nontrivial to reason about, so add a guard before the crashing call. By that time it is too late to prevent any memory corruption (we'll have written past the end of the buffer already) but we can at least try to get a warning written into an on-disk log by avoiding the hard crash caused by padding past the buffer with a huge number of zeros.
Signed-off-by Jouni K. Seppänen <[email protected]>Fixes 4a0e3e989d66 ("cdc_ncm: Add support for moving NDP to end of NCM frame")Reported-by kernel test robot <[email protected]>Reviewed-by Bjørn Mork <[email protected]>Signed-off-by David S. Miller <[email protected]>[[email protected]: backport to 4.4.y, 4.9.y]Signed-off-by Jouni K. Seppänen <[email protected]>
Quoted 3 lines
---
Backport to 4.4.y and 4.9.y: there is noskb_put_zeroorctx->tx_curr_sizeso use memset(skb_put(...)) andctx->tx_max, respectively.
Thanks for the backport, now queued up.
greg k-h