Commit 47afe93c authored by Luiz Augusto von Dentz's avatar Luiz Augusto von Dentz Committed by Marcel Holtmann
Browse files

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: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 12cfe417
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -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;
+24 −15
Original line number Diff line number Diff line
@@ -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);