Bluetooth: HCI: Use skb_pull_data to parse LE Advertising Report event

This uses skb_pull_data to check the LE Advertising Report events
received have the minimum required length.

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
Luiz Augusto von Dentz 2021-12-01 10:55:00 -08:00 committed by Marcel Holtmann
parent 12cfe4176a
commit 47afe93c91
2 changed files with 30 additions and 16 deletions

View File

@ -2445,13 +2445,18 @@ struct hci_ev_le_conn_complete {
#define HCI_EV_LE_ADVERTISING_REPORT 0x02
struct hci_ev_le_advertising_info {
__u8 evt_type;
__u8 type;
__u8 bdaddr_type;
bdaddr_t bdaddr;
__u8 length;
__u8 data[];
} __packed;
struct hci_ev_le_advertising_report {
__u8 num;
struct hci_ev_le_advertising_info info[];
} __packed;
#define HCI_EV_LE_CONN_UPDATE_COMPLETE 0x03
struct hci_ev_le_conn_update_complete {
__u8 status;

View File

@ -6564,31 +6564,40 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
u8 num_reports = skb->data[0];
void *ptr = &skb->data[1];
struct hci_ev_le_advertising_report *ev;
ev = hci_le_ev_skb_pull(hdev, skb, HCI_EV_LE_ADVERTISING_REPORT,
sizeof(*ev));
if (!ev)
return;
if (!ev->num)
return;
hci_dev_lock(hdev);
while (num_reports--) {
struct hci_ev_le_advertising_info *ev = ptr;
while (ev->num--) {
struct hci_ev_le_advertising_info *info;
s8 rssi;
if (ptr > (void *)skb_tail_pointer(skb) - sizeof(*ev)) {
bt_dev_err(hdev, "Malicious advertising data.");
info = hci_le_ev_skb_pull(hdev, skb,
HCI_EV_LE_ADVERTISING_REPORT,
sizeof(*info));
if (!info)
break;
}
if (ev->length <= HCI_MAX_AD_LENGTH &&
ev->data + ev->length <= skb_tail_pointer(skb)) {
rssi = ev->data[ev->length];
process_adv_report(hdev, ev->evt_type, &ev->bdaddr,
ev->bdaddr_type, NULL, 0, rssi,
ev->data, ev->length, false);
if (!hci_le_ev_skb_pull(hdev, skb, HCI_EV_LE_ADVERTISING_REPORT,
info->length + 1))
break;
if (info->length <= HCI_MAX_AD_LENGTH) {
rssi = info->data[info->length];
process_adv_report(hdev, info->type, &info->bdaddr,
info->bdaddr_type, NULL, 0, rssi,
info->data, info->length, false);
} else {
bt_dev_err(hdev, "Dropping invalid advertising data");
}
ptr += sizeof(*ev) + ev->length + 1;
}
hci_dev_unlock(hdev);