mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-02 16:44:10 +08:00
USB: gadget: f_ncm: add bounds checks to ncm_unwrap_ntb()
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: Ilja Van Sprundel <ivansprundel@ioactive.com> Signed-off-by: Brooke Basile <brookebasile@gmail.com> Acked-by: Felipe Balbi <balbi@kernel.org> Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
b1cd1b65af
commit
2b74b0a04d
@ -1181,12 +1181,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) {
|
||||
@ -1205,25 +1208,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");
|
||||
@ -1234,14 +1249,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;
|
||||
@ -1258,8 +1274,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;
|
||||
@ -1283,6 +1312,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
|
||||
@ -1299,9 +1359,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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user