Commit f7e0611e authored by Brooke Basile's avatar Brooke Basile Committed by Greg Kroah-Hartman

USB: gadget: f_ncm: add bounds checks to ncm_unwrap_ntb()

commit 2b74b0a0 upstream.

Some values extracted by ncm_unwrap_ntb() could possibly lead to several
different out of bounds reads of memory.  Specifically the values passed
to netdev_alloc_skb_ip_align() need to be checked so that memory is not
overflowed.

Resolve this by applying bounds checking to a number of different
indexes and lengths of the structure parsing logic.
Reported-by: default avatarIlja Van Sprundel <ivansprundel@ioactive.com>
Signed-off-by: default avatarBrooke Basile <brookebasile@gmail.com>
Acked-by: default avatarFelipe Balbi <balbi@kernel.org>
Cc: stable <stable@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 849d2b00
......@@ -1209,12 +1209,15 @@ static int ncm_unwrap_ntb(struct gether *port,
int ndp_index;
unsigned dg_len, dg_len2;
unsigned ndp_len;
unsigned block_len;
struct sk_buff *skb2;
int ret = -EINVAL;
unsigned max_size = le32_to_cpu(ntb_parameters.dwNtbOutMaxSize);
unsigned ntb_max = le32_to_cpu(ntb_parameters.dwNtbOutMaxSize);
unsigned frame_max = le16_to_cpu(ecm_desc.wMaxSegmentSize);
const struct ndp_parser_opts *opts = ncm->parser_opts;
unsigned crc_len = ncm->is_crc ? sizeof(uint32_t) : 0;
int dgram_counter;
bool ndp_after_header;
/* dwSignature */
if (get_unaligned_le32(tmp) != opts->nth_sign) {
......@@ -1233,25 +1236,37 @@ static int ncm_unwrap_ntb(struct gether *port,
}
tmp++; /* skip wSequence */
block_len = get_ncm(&tmp, opts->block_length);
/* (d)wBlockLength */
if (get_ncm(&tmp, opts->block_length) > max_size) {
if (block_len > ntb_max) {
INFO(port->func.config->cdev, "OUT size exceeded\n");
goto err;
}
ndp_index = get_ncm(&tmp, opts->ndp_index);
ndp_after_header = false;
/* Run through all the NDP's in the NTB */
do {
/* NCM 3.2 */
if (((ndp_index % 4) != 0) &&
(ndp_index < opts->nth_size)) {
/*
* NCM 3.2
* dwNdpIndex
*/
if (((ndp_index % 4) != 0) ||
(ndp_index < opts->nth_size) ||
(ndp_index > (block_len -
opts->ndp_size))) {
INFO(port->func.config->cdev, "Bad index: %#X\n",
ndp_index);
goto err;
}
if (ndp_index == opts->nth_size)
ndp_after_header = true;
/* walk through NDP */
/*
* walk through NDP
* dwSignature
*/
tmp = (void *)(skb->data + ndp_index);
if (get_unaligned_le32(tmp) != ncm->ndp_sign) {
INFO(port->func.config->cdev, "Wrong NDP SIGN\n");
......@@ -1262,14 +1277,15 @@ static int ncm_unwrap_ntb(struct gether *port,
ndp_len = get_unaligned_le16(tmp++);
/*
* NCM 3.3.1
* wLength
* entry is 2 items
* item size is 16/32 bits, opts->dgram_item_len * 2 bytes
* minimal: struct usb_cdc_ncm_ndpX + normal entry + zero entry
* Each entry is a dgram index and a dgram length.
*/
if ((ndp_len < opts->ndp_size
+ 2 * 2 * (opts->dgram_item_len * 2))
|| (ndp_len % opts->ndplen_align != 0)) {
+ 2 * 2 * (opts->dgram_item_len * 2)) ||
(ndp_len % opts->ndplen_align != 0)) {
INFO(port->func.config->cdev, "Bad NDP length: %#X\n",
ndp_len);
goto err;
......@@ -1286,8 +1302,21 @@ static int ncm_unwrap_ntb(struct gether *port,
do {
index = index2;
/* wDatagramIndex[0] */
if ((index < opts->nth_size) ||
(index > block_len - opts->dpe_size)) {
INFO(port->func.config->cdev,
"Bad index: %#X\n", index);
goto err;
}
dg_len = dg_len2;
if (dg_len < 14 + crc_len) { /* ethernet hdr + crc */
/*
* wDatagramLength[0]
* ethernet hdr + crc or larger than max frame size
*/
if ((dg_len < 14 + crc_len) ||
(dg_len > frame_max)) {
INFO(port->func.config->cdev,
"Bad dgram length: %#X\n", dg_len);
goto err;
......@@ -1311,6 +1340,37 @@ static int ncm_unwrap_ntb(struct gether *port,
index2 = get_ncm(&tmp, opts->dgram_item_len);
dg_len2 = get_ncm(&tmp, opts->dgram_item_len);
if (index2 == 0 || dg_len2 == 0)
break;
/* wDatagramIndex[1] */
if (ndp_after_header) {
if (index2 < opts->nth_size + opts->ndp_size) {
INFO(port->func.config->cdev,
"Bad index: %#X\n", index2);
goto err;
}
} else {
if (index2 < opts->nth_size + opts->dpe_size) {
INFO(port->func.config->cdev,
"Bad index: %#X\n", index2);
goto err;
}
}
if (index2 > block_len - opts->dpe_size) {
INFO(port->func.config->cdev,
"Bad index: %#X\n", index2);
goto err;
}
/* wDatagramLength[1] */
if ((dg_len2 < 14 + crc_len) ||
(dg_len2 > frame_max)) {
INFO(port->func.config->cdev,
"Bad dgram length: %#X\n", dg_len);
goto err;
}
/*
* Copy the data into a new skb.
* This ensures the truesize is correct
......@@ -1327,9 +1387,6 @@ static int ncm_unwrap_ntb(struct gether *port,
ndp_len -= 2 * (opts->dgram_item_len * 2);
dgram_counter++;
if (index2 == 0 || dg_len2 == 0)
break;
} while (ndp_len > 2 * (opts->dgram_item_len * 2));
} while (ndp_index);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment