--- /dev/null
+From 7a68d725e4ea384977445e0bcaed3d7de83ab5b3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jouni=20K=2E=20Sepp=C3=A4nen?= <jks@iki.fi>
+Date: Tue, 5 Jan 2021 06:52:49 +0200
+Subject: net: cdc_ncm: correct overhead in delayed_ndp_size
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Jouni K. Seppänen <jks@iki.fi>
+
+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
+
+> 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.
+
+Signed-off-by: Jouni K. Seppänen <jks@iki.fi>
+Fixes: 4a0e3e989d66 ("cdc_ncm: Add support for moving NDP to end of NCM frame")
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=209407
+Reported-by: kernel test robot <lkp@intel.com>
+Reviewed-by: Bjørn Mork <bjorn@mork.no>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+[jks@iki.fi: backport to 4.4.y, 4.9.y]
+Signed-off-by: Jouni K. Seppänen <jks@iki.fi>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/usb/cdc_ncm.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/usb/cdc_ncm.c
++++ b/drivers/net/usb/cdc_ncm.c
+@@ -1128,7 +1128,10 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev
+ * 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;
+
+@@ -1281,7 +1284,8 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev
+ 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 */