]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
nfc: st-nci: fix incorrect sizing calculations in EVT_TRANSACTION
authorMartin Faltesek <mfaltesek@google.com>
Tue, 22 Nov 2022 00:42:46 +0000 (18:42 -0600)
committerJakub Kicinski <kuba@kernel.org>
Thu, 24 Nov 2022 04:01:50 +0000 (20:01 -0800)
The transaction buffer is allocated by using the size of the packet buf,
and subtracting two which seems intended to remove the two tags which are
not present in the target structure. This calculation leads to under
counting memory because of differences between the packet contents and the
target structure. The aid_len field is a u8 in the packet, but a u32 in
the structure, resulting in at least 3 bytes always being under counted.
Further, the aid data is a variable length field in the packet, but fixed
in the structure, so if this field is less than the max, the difference is
added to the under counting.

To fix, perform validation checks progressively to safely reach the
next field, to determine the size of both buffers and verify both tags.
Once all validation checks pass, allocate the buffer and copy the data.
This eliminates freeing memory on the error path, as validation checks are
moved ahead of memory allocation.

Reported-by: Denis Efremov <denis.e.efremov@oracle.com>
Reviewed-by: Guenter Roeck <groeck@google.com>
Fixes: 5d1ceb7f5e56 ("NFC: st21nfcb: Add HCI transaction event support")
Signed-off-by: Martin Faltesek <mfaltesek@google.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/nfc/st-nci/se.c

index fc59916ae5aec00b26fdf988f9b8f0c0b936527b..ec87dd21e054ad934e443c086789972baf51c9e8 100644 (file)
@@ -312,6 +312,8 @@ static int st_nci_hci_connectivity_event_received(struct nci_dev *ndev,
        int r = 0;
        struct device *dev = &ndev->nfc_dev->dev;
        struct nfc_evt_transaction *transaction;
+       u32 aid_len;
+       u8 params_len;
 
        pr_debug("connectivity gate event: %x\n", event);
 
@@ -325,28 +327,47 @@ static int st_nci_hci_connectivity_event_received(struct nci_dev *ndev,
                 * Description  Tag     Length
                 * AID          81      5 to 16
                 * PARAMETERS   82      0 to 255
+                *
+                * The key differences are aid storage length is variably sized
+                * in the packet, but fixed in nfc_evt_transaction, and that
+                * the aid_len is u8 in the packet, but u32 in the structure,
+                * and the tags in the packet are not included in
+                * nfc_evt_transaction.
+                *
+                * size(b):  1          1       5-16 1             1           0-255
+                * offset:   0          1       2    aid_len + 2   aid_len + 3 aid_len + 4
+                * mem name: aid_tag(M) aid_len aid  params_tag(M) params_len  params
+                * example:  0x81       5-16    X    0x82          0-255       X
                 */
-               if (skb->len < NFC_MIN_AID_LENGTH + 2 ||
-                   skb->data[0] != NFC_EVT_TRANSACTION_AID_TAG)
+               if (skb->len < 2 || skb->data[0] != NFC_EVT_TRANSACTION_AID_TAG)
                        return -EPROTO;
 
-               transaction = devm_kzalloc(dev, skb->len - 2, GFP_KERNEL);
-               if (!transaction)
-                       return -ENOMEM;
+               aid_len = skb->data[1];
 
-               transaction->aid_len = skb->data[1];
-               memcpy(transaction->aid, &skb->data[2], transaction->aid_len);
+               if (skb->len < aid_len + 4 ||
+                   aid_len > sizeof(transaction->aid))
+                       return -EPROTO;
 
-               /* Check next byte is PARAMETERS tag (82) */
-               if (skb->data[transaction->aid_len + 2] !=
-                   NFC_EVT_TRANSACTION_PARAMS_TAG) {
-                       devm_kfree(dev, transaction);
+               params_len = skb->data[aid_len + 3];
+
+               /* Verify PARAMETERS tag is (82), and final check that there is
+                * enough space in the packet to read everything.
+                */
+               if (skb->data[aid_len + 2] != NFC_EVT_TRANSACTION_PARAMS_TAG ||
+                   skb->len < aid_len + 4 + params_len)
                        return -EPROTO;
-               }
 
-               transaction->params_len = skb->data[transaction->aid_len + 3];
-               memcpy(transaction->params, skb->data +
-                      transaction->aid_len + 4, transaction->params_len);
+               transaction = devm_kzalloc(dev, sizeof(*transaction) +
+                                          params_len, GFP_KERNEL);
+               if (!transaction)
+                       return -ENOMEM;
+
+               transaction->aid_len = aid_len;
+               transaction->params_len = params_len;
+
+               memcpy(transaction->aid, &skb->data[2], aid_len);
+               memcpy(transaction->params, &skb->data[aid_len + 4],
+                      params_len);
 
                r = nfc_se_transaction(ndev->nfc_dev, host, transaction);
                break;