]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
usb: gadget: ncm: Handle decoding of multiple NTB's in unwrap call
authorKrishna Kurapati <quic_kriskura@quicinc.com>
Wed, 27 Sep 2023 10:58:58 +0000 (16:28 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 25 Oct 2023 09:13:31 +0000 (11:13 +0200)
commit 427694cfaafa565a3db5c5ea71df6bc095dca92f 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: 9f6ce4240a2b ("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>
drivers/usb/gadget/function/f_ncm.c

index 24a8e01e34fa7d39edd679f2af38eceb1b7eab48..47d1f4e960cbe5a8079583fb4da44192bc140e65 100644 (file)
@@ -1201,7 +1201,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;
@@ -1214,6 +1215,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) {
@@ -1260,7 +1265,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;
@@ -1317,11 +1322,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,
@@ -1348,7 +1353,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);
@@ -1361,10 +1366,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);