Commit b507828c7b61 for kernel

commit b507828c7b6135ff7a4b69eba6e33502b4839fb9
Author: Jiahao Xu <xujiahao@cmss.chinamobile.com>
Date:   Wed Nov 11 12:41:56 2026 +0800

    net: usb: cdc_ncm: don't underflow the NDP room check

    cdc_ncm_ndp16() and cdc_ncm_ndp32() verify that the new NDP and the
    datagram fit into the NTB with an unsigned subtraction:

            if ((ctx->tx_curr_size - skb->len - reserve) < ctx->max_ndp_size)
                    return NULL;

    Nothing guarantees that skb->len plus the reserve stays below
    tx_curr_size, and when it does not the subtraction wraps around to a
    huge value, the check passes, and the skb_put_zero() of max_ndp_size
    bytes that follows overruns the NTB:

      skbuff: skb_over_panic: text:ffff80000db33558 len:428 put:172
      head:ffff0000c2c66100 tail:0x1ac end:0x140
      kernel BUG at net/core/skbuff.c:200
      skb_put_zero include/linux/skbuff.h:2595 [inline]
      cdc_ncm_ndp16 drivers/net/usb/cdc_ncm.c:1132 [inline]
      cdc_ncm_fill_tx_frame+0xdf0/0x30e0 drivers/net/usb/cdc_ncm.c:1309

    Here tx_curr_size is 0x140 = 320, skb->len is already 256 and the
    skb_put_zero() wants another 172 bytes.

    Two device controlled settings make this reachable:

      - dwNtbOutMaxSize = 320 caps tx_max at 320.  The lower bound computed
        in cdc_ncm_check_tx_max() is max_datagram_size + max_ndp_size + the
        NTH header, but cdc_ncm_setup() clamps tx_max before
        cdc_ncm_set_dgram_size() runs, so max_datagram_size is still 0 and
        the bound is only max_ndp_size + the NTH header.  It does not
        reserve room for one datagram plus one NDP.

      - wNdpOutAlignment = 256 is accepted by cdc_ncm_fix_modulus() as long
        as it is smaller than tx_max, and cdc_ncm_align_tail() then pads the
        12 byte NTH header up to 256 bytes right before this check.

    An NDP can also be added to an NTB that already holds datagrams through
    cdc_mbim_tx_fixup(), which uses a different signature per MBIM session.
    On plain cdc_ncm the chain lookup in cdc_ncm_ndp16() returns the
    existing NDP for the single signature, so there the create path is
    normally reached for the first datagram of each NTB.

    Rewrite the test as an addition, which cannot underflow and gives the
    same answer whenever the original subtraction did not wrap.

    Fixes: c78b7c586657 ("net: cdc_ncm: refactoring for tx multiplexing")
    Fixes: 0fa81b304a79 ("cdc_ncm: Implement the 32-bit version of NCM Transfer Block")
    Reported-by: syzbot+1994e2ecf323ed90f255@syzkaller.appspotmail.com
    Closes: https://syzkaller.appspot.com/bug?extid=1994e2ecf323ed90f255
    Signed-off-by: Jiahao Xu <xujiahao@cmss.chinamobile.com>
    Link: https://patch.msgid.link/20261111124156.637661-1-xujiahao@cmss.chinamobile.com
    Signed-off-by: Jakub Kicinski <kuba@kernel.org>

diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 19db5a668dcb..e92dc7f011ea 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -1125,7 +1125,7 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm_ndp16(struct cdc_ncm_ctx *ctx, struct s
 		cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_curr_size);

 	/* verify that there is room for the NDP and the datagram (reserve) */
-	if ((ctx->tx_curr_size - skb->len - reserve) < ctx->max_ndp_size)
+	if (skb->len + reserve + ctx->max_ndp_size > ctx->tx_curr_size)
 		return NULL;

 	/* link to it */
@@ -1180,7 +1180,7 @@ static struct usb_cdc_ncm_ndp32 *cdc_ncm_ndp32(struct cdc_ncm_ctx *ctx, struct s
 		cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_curr_size);

 	/* verify that there is room for the NDP and the datagram (reserve) */
-	if ((ctx->tx_curr_size - skb->len - reserve) < ctx->max_ndp_size)
+	if (skb->len + reserve + ctx->max_ndp_size > ctx->tx_curr_size)
 		return NULL;

 	/* link to it */