[PATCH v4] Bluetooth: btnxpuart: Validate the FW dump header length
Neeraj Kale <[email protected]>
| Newsgroups | org.kernel.vger.linux-bluetooth,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <AS4PR04MB96924AB37F9DD74A9F07F67AE7A42@AS4PR04MB9692.eurprd04.prod.outlook.com> |
Hi Ali, Luiz This v4 approach looks correct - header preserved in skb->data for hci_devcd_append() and dump aborted cleanly on the error path. Reviewed-by: Neeraj Kale [email protected] Thanks, Neeraj > nxp_process_fw_dump() pulls the ACL header off the frame and then reads > seq_num and buf_len from a struct nxp_fw_dump_hdr placed at skb->data > without checking that the ACL payload is long enough to contain it. > > h4_recv_buf() collects HCI_ACL_HDR_SIZE bytes of header followed by the > number of payload bytes named in that header, so skb->len is 4 + dlen with > dlen supplied by the controller and possibly smaller than the 8 byte dump > header, or zero. A short frame with connection handle 0xfff can therefore > read both fields beyond the received data. > > This is not only an out-of-bounds read. buf_len is also what terminates a > dump, so a value of zero makes the driver call hci_devcd_complete() and > reset the controller. A truncated frame can therefore end a dump early. > > Check that the payload is long enough before reading the header. The header > is not pulled from the skb because the skb is cloned for > hci_devcd_append() afterwards and the NXP FW dump analyzer expects > nxp_fw_dump_hdr at the beginning of each chunk in the dump. > > Abort the dump when a chunk is too short to contain the header. The > firmware is not expected to generate such chunks, so receiving one means > something already went wrong and the rest of the dump can no longer be > trusted. Dropping it silently would leave userspace with a dump that looks > complete even though a chunk went missing from it. > > hci_devcd_abort() still reports the data collected so far and records > HCI_DEVCOREDUMP_ABORT in the State line of the dump header, so > userspace can tell that the dump is truncated. The controller is reset as on the > completion path because BTNXPUART_FW_DUMP_IN_PROGRESS makes > nxp_enqueue() reject commands until the reset clears it. > > Fixes: 998e447f443f ("Bluetooth: btnxpuart: Add support for HCI coredump > feature") > Suggested-by: Luiz Augusto von Dentz <[email protected]> > Link: > https://lore.ke/ > rnel.org%2Flinux- > bluetooth%2FAS4PR04MB9692EC13E3176B6D7525D097E7A72%40AS4PR04M > B9692.eurprd04.prod.outlook.com%2F&data=05%7C02%7Cneeraj.sanjaykale > %40nxp.com%7C6bcc0ce20725451b167f08defd666c70%7C686ea1d3bc2b4c6f > a92cd99c5c301635%7C0%7C0%7C639226813511440640%7CUnknown%7CTW > FpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW > 4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=YympY > uys6asrlyl5WTAQitOSv2dLGy6jf%2By0Usf%2BRqQ%3D&reserved=0 > Signed-off-by: Ali Ahmet Memis <[email protected]> > --- > v4: Restore the v2 approach of checking the length without pulling the > header. skb_pull_data() in v3 also advances skb->data, so the clone > passed to hci_devcd_append() lost the nxp_fw_dump_hdr that the NXP > dump analyzer expects, as Neeraj pointed out. On top of that, abort > the dump when a chunk is too short, as suggested by Luiz. > > Sent as a new version rather than as an incremental fix on top of > 1fcf216462ec, since you mentioned folding it in. It applies to > 1fcf216462ec^. If you would rather keep 1fcf216462ec and take a > delta on top, let me know and I will send that instead. > > Dropped Neeraj's Reviewed-by from v2 and from the follow-up patch, > since the abort handling is new here. > > https://lore.ke/ > rnel.org%2Flinux-bluetooth%2F20260818080104.563675-1- > ali%40iusegentoo.com%2F&data=05%7C02%7Cneeraj.sanjaykale%40nxp.com > %7C6bcc0ce20725451b167f08defd666c70%7C686ea1d3bc2b4c6fa92cd99c5c3 > 01635%7C0%7C0%7C639226813511473591%7CUnknown%7CTWFpbGZsb3d8 > eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIj > oiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=H27cFkiatrKCHHeu > %2BWxL%2FoJwwj1mnO8tClM3KoP9TgE%3D&reserved=0 > > v3: Use skb_pull_data() to validate and pull the FW dump header, as > suggested by Luiz. > > v2: Warn on the early exit path instead of dropping the frame silently, > as suggested by Neeraj. Dropped the trailing newline from the > suggested message, since bt_dev_warn() already appends one. > > v1: > https://lore.ke/ > rnel.org%2Fall%2F20260814081221.913676-1- > ali%40iusegentoo.com%2F&data=05%7C02%7Cneeraj.sanjaykale%40nxp.com > %7C6bcc0ce20725451b167f08defd666c70%7C686ea1d3bc2b4c6fa92cd99c5c3 > 01635%7C0%7C0%7C639226813511491888%7CUnknown%7CTWFpbGZsb3d8 > eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIj > oiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=jH6B1H5Yho2fVz7it > 5H8k31dQGGcX%2BU2Zm5JOGG%2F7G8%3D&reserved=0 > > drivers/bluetooth/btnxpuart.c | 17 +++++++++++++++-- > 1 file changed, 15 insertions(+), 2 deletions(-) > > diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c > index e2b8f7997e4e..f6d08942a91e 100644 > --- a/drivers/bluetooth/btnxpuart.c > +++ b/drivers/bluetooth/btnxpuart.c > @@ -1361,10 +1361,23 @@ static int nxp_process_fw_dump(struct hci_dev > *hdev, struct sk_buff *skb) > sizeof(*acl_hdr)); > struct nxp_fw_dump_hdr *fw_dump_hdr = (struct nxp_fw_dump_hdr > *)skb->data; > struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); > - __u16 seq_num = __le16_to_cpu(fw_dump_hdr->seq_num); > - __u16 buf_len = __le16_to_cpu(fw_dump_hdr->buf_len); > + __u16 seq_num; > + __u16 buf_len; > int err; > > + /* The ACL payload must be long enough to hold the FW dump header > */ > + if (skb->len < sizeof(*fw_dump_hdr)) { > + bt_dev_warn(hdev, "FW dump: invalid or corrupt fw dump chunk"); > + if (fw_dump_in_progress(nxpdev)) { > + hci_devcd_abort(hdev); > + nxp_set_ind_reset(hdev, NULL); > + } > + goto free_skb; > + } > + > + seq_num = __le16_to_cpu(fw_dump_hdr->seq_num); > + buf_len = __le16_to_cpu(fw_dump_hdr->buf_len); > + > if (seq_num == 0x0001) { > if (test_and_set_bit(BTNXPUART_FW_DUMP_IN_PROGRESS, > &nxpdev->tx_state)) { > bt_dev_err(hdev, "FW dump already in progress"); > > base-commit: c519ffc1e2c669296b976d11f5e7a79d2f82debb > -- > 2.55.0 NXP Confidential