[PATCH] usb: gadget: f_ncm: validate NTB datagram bounds
From: Guangshuo Li
Date: Wed Jul 08 2026 - 08:33:05 EST
ncm_unwrap_ntb() parses the NTB block length from the host supplied NCM
header and then uses it as the boundary for NDP and datagram offsets.
The block length is checked against the configured NTB maximum size, but
it is not checked against the amount of data actually present in the
received skb. A malformed host can therefore declare a block length that
is larger than the received transfer and make later offset checks pass
against bytes that are not present in the skb.
The parser also validates that a datagram index is inside the declared
NTB and that the datagram length is within the maximum Ethernet frame
size, but it does not verify that the datagram end still fits inside the
current NTB before reading the optional CRC or copying the datagram data.
Reject NTBs whose declared block length exceeds the remaining received
data. Also reject NDPs and datagrams whose declared lengths extend past
the end of the current NTB.
Fixes: 9f6ce4240a2b ("usb: gadget: f_ncm.c added")
Signed-off-by: Guangshuo Li <lgs201920130244@xxxxxxxxx>
---
drivers/usb/gadget/function/f_ncm.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c
index c5bf8a448d64..186e0f48cb8c 100644
--- a/drivers/usb/gadget/function/f_ncm.c
+++ b/drivers/usb/gadget/function/f_ncm.c
@@ -1210,7 +1210,9 @@ static int ncm_unwrap_ntb(struct gether *port,
block_len = get_ncm(&tmp, opts->block_length);
/* (d)wBlockLength */
- if ((block_len < opts->nth_size + opts->ndp_size) || (block_len > ntb_max)) {
+ if ((block_len < opts->nth_size + opts->ndp_size) ||
+ (block_len > ntb_max) ||
+ (block_len > to_process)) {
INFO(port->func.config->cdev, "Bad block length: %#X\n", block_len);
goto err;
}
@@ -1254,7 +1256,8 @@ static int ncm_unwrap_ntb(struct gether *port,
*/
if ((ndp_len < opts->ndp_size
+ 2 * 2 * (opts->dgram_item_len * 2)) ||
- (ndp_len % opts->ndplen_align != 0)) {
+ (ndp_len % opts->ndplen_align != 0) ||
+ (ndp_len > block_len - ndp_index)) {
INFO(port->func.config->cdev, "Bad NDP length: %#X\n",
ndp_len);
goto err;
@@ -1290,6 +1293,14 @@ static int ncm_unwrap_ntb(struct gether *port,
"Bad dgram length: %#X\n", dg_len);
goto err;
}
+
+ if (dg_len > block_len - index) {
+ INFO(port->func.config->cdev,
+ "Datagram exceeds NTB bounds: index %#X length %#X\n",
+ index, dg_len);
+ goto err;
+ }
+
if (ncm->is_crc) {
uint32_t crc, crc2;
--
2.43.0