Skip to content

Commit

Permalink
usb: gadget: ncm: Handle decoding of multiple NTB's in unwrap call
Browse files Browse the repository at this point in the history
commit 427694c upstream.

When NCM is used with hosts like Windows PC, it is observed that there are
multiple NTB's contained in one usb request giveback. Since the driver
unwraps the obtained request data assuming only one NTB is present, we
loose the subsequent NTB's present resulting in data loss.

Fix this by checking the parsed block length with the obtained data
length in usb request and continue parsing after the last byte of current
NTB.

Cc: stable@vger.kernel.org
Fixes: 9f6ce42 ("usb: gadget: f_ncm.c added")
Signed-off-by: Krishna Kurapati <quic_kriskura@quicinc.com>
Reviewed-by: Maciej Żenczykowski <maze@google.com>
Link: https://lore.kernel.org/r/20230927105858.12950-1-quic_kriskura@quicinc.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Krishna Kurapati authored and Greg Kroah-Hartman committed Oct 25, 2023
1 parent a906f2e commit 17c653d
Showing 1 changed file with 19 additions and 7 deletions.
26 changes: 19 additions & 7 deletions drivers/usb/gadget/function/f_ncm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1180,7 +1180,8 @@ static int ncm_unwrap_ntb(struct gether *port,
struct sk_buff_head *list)
{
struct f_ncm *ncm = func_to_ncm(&port->func);
__le16 *tmp = (void *) skb->data;
unsigned char *ntb_ptr = skb->data;
__le16 *tmp;
unsigned index, index2;
int ndp_index;
unsigned dg_len, dg_len2;
Expand All @@ -1193,6 +1194,10 @@ static int ncm_unwrap_ntb(struct gether *port,
const struct ndp_parser_opts *opts = ncm->parser_opts;
unsigned crc_len = ncm->is_crc ? sizeof(uint32_t) : 0;
int dgram_counter;
int to_process = skb->len;

parse_ntb:
tmp = (__le16 *)ntb_ptr;

/* dwSignature */
if (get_unaligned_le32(tmp) != opts->nth_sign) {
Expand Down Expand Up @@ -1239,7 +1244,7 @@ static int ncm_unwrap_ntb(struct gether *port,
* walk through NDP
* dwSignature
*/
tmp = (void *)(skb->data + ndp_index);
tmp = (__le16 *)(ntb_ptr + ndp_index);
if (get_unaligned_le32(tmp) != ncm->ndp_sign) {
INFO(port->func.config->cdev, "Wrong NDP SIGN\n");
goto err;
Expand Down Expand Up @@ -1296,11 +1301,11 @@ static int ncm_unwrap_ntb(struct gether *port,
if (ncm->is_crc) {
uint32_t crc, crc2;

crc = get_unaligned_le32(skb->data +
crc = get_unaligned_le32(ntb_ptr +
index + dg_len -
crc_len);
crc2 = ~crc32_le(~0,
skb->data + index,
ntb_ptr + index,
dg_len - crc_len);
if (crc != crc2) {
INFO(port->func.config->cdev,
Expand All @@ -1327,7 +1332,7 @@ static int ncm_unwrap_ntb(struct gether *port,
dg_len - crc_len);
if (skb2 == NULL)
goto err;
skb_put_data(skb2, skb->data + index,
skb_put_data(skb2, ntb_ptr + index,
dg_len - crc_len);

skb_queue_tail(list, skb2);
Expand All @@ -1340,10 +1345,17 @@ static int ncm_unwrap_ntb(struct gether *port,
} while (ndp_len > 2 * (opts->dgram_item_len * 2));
} while (ndp_index);

dev_consume_skb_any(skb);

VDBG(port->func.config->cdev,
"Parsed NTB with %d frames\n", dgram_counter);

to_process -= block_len;
if (to_process != 0) {
ntb_ptr = (unsigned char *)(ntb_ptr + block_len);
goto parse_ntb;
}

dev_consume_skb_any(skb);

return 0;
err:
skb_queue_purge(list);
Expand Down

0 comments on commit 17c653d

Please sign in to comment.