Similarly, we need to check skb->data boundary for HCI_EV_LE_META event too. Note, hci_le_adv_report_evt() and hci_le_ext_adv_report_evt() are slightly complicated, as they read the length of the field from the packet as well. Cc: Marcel Holtmann <marcel@xxxxxxxxxxxx> Cc: Johan Hedberg <johan.hedberg@xxxxxxxxx> Cc: Dan Carpenter <dan.carpenter@xxxxxxxxxx> Reviewed-by: Tomas Bortoli <tomasbortoli@xxxxxxxxx> Signed-off-by: Cong Wang <xiyou.wangcong@xxxxxxxxx> --- net/bluetooth/hci_event.c | 107 +++++++++++++++++++++++++++++++------- 1 file changed, 87 insertions(+), 20 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 2fef70c0bffe..31aef14dd838 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -5147,7 +5147,11 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status, static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { - struct hci_ev_le_conn_complete *ev = (void *) skb->data; + struct hci_ev_le_conn_complete *ev; + + if (unlikely(!pskb_may_pull(skb, sizeof(*ev)))) + return; + ev = (void *)skb->data; BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); @@ -5161,7 +5165,11 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) static void hci_le_enh_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { - struct hci_ev_le_enh_conn_complete *ev = (void *) skb->data; + struct hci_ev_le_enh_conn_complete *ev; + + if (unlikely(!pskb_may_pull(skb, sizeof(*ev)))) + return; + ev = (void *)skb->data; BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); @@ -5174,9 +5182,13 @@ static void hci_le_enh_conn_complete_evt(struct hci_dev *hdev, static void hci_le_ext_adv_term_evt(struct hci_dev *hdev, struct sk_buff *skb) { - struct hci_evt_le_ext_adv_set_term *ev = (void *) skb->data; + struct hci_evt_le_ext_adv_set_term *ev; struct hci_conn *conn; + if (unlikely(!pskb_may_pull(skb, sizeof(*ev)))) + return; + ev = (void *)skb->data; + BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); if (ev->status) @@ -5203,9 +5215,13 @@ static void hci_le_ext_adv_term_evt(struct hci_dev *hdev, struct sk_buff *skb) static void hci_le_conn_update_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { - struct hci_ev_le_conn_update_complete *ev = (void *) skb->data; + struct hci_ev_le_conn_update_complete *ev; struct hci_conn *conn; + if (unlikely(!pskb_may_pull(skb, sizeof(*ev)))) + return; + ev = (void *)skb->data; + BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); if (ev->status) @@ -5511,15 +5527,29 @@ 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]; + unsigned int len; + u8 num_reports; + + if (unlikely(!pskb_may_pull(skb, 1))) + return; + num_reports = skb->data[0]; + len = 1; hci_dev_lock(hdev); while (num_reports--) { - struct hci_ev_le_advertising_info *ev = ptr; + struct hci_ev_le_advertising_info *ev; + u8 ev_len; s8 rssi; + if (unlikely(!pskb_may_pull(skb, len + sizeof(*ev)))) + break; + ev = (void *)skb->data + len; + ev_len = ev->length + 1; + if (unlikely(!pskb_may_pull(skb, len + sizeof(*ev) + ev_len))) + break; + ev = (void *)skb->data + len; + if (ev->length <= HCI_MAX_AD_LENGTH) { rssi = ev->data[ev->length]; process_adv_report(hdev, ev->evt_type, &ev->bdaddr, @@ -5529,7 +5559,7 @@ static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb) bt_dev_err(hdev, "Dropping invalid advertising data"); } - ptr += sizeof(*ev) + ev->length + 1; + len += sizeof(*ev) + ev_len; } hci_dev_unlock(hdev); @@ -5583,15 +5613,29 @@ static u8 ext_evt_type_to_legacy(u16 evt_type) static void hci_le_ext_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb) { - u8 num_reports = skb->data[0]; - void *ptr = &skb->data[1]; + unsigned int len; + u8 num_reports; + + if (unlikely(!pskb_may_pull(skb, 1))) + return; + num_reports = skb->data[0]; + len = 1; hci_dev_lock(hdev); while (num_reports--) { - struct hci_ev_le_ext_adv_report *ev = ptr; + struct hci_ev_le_ext_adv_report *ev; u8 legacy_evt_type; u16 evt_type; + u8 ev_len; + + if (unlikely(!pskb_may_pull(skb, len + sizeof(*ev)))) + break; + ev = (void *)skb->data + len; + ev_len = ev->length + 1; + if (unlikely(!pskb_may_pull(skb, len + sizeof(*ev) + ev_len))) + break; + ev = (void *)skb->data + len; evt_type = __le16_to_cpu(ev->evt_type); legacy_evt_type = ext_evt_type_to_legacy(evt_type); @@ -5601,7 +5645,7 @@ static void hci_le_ext_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb) ev->data, ev->length); } - ptr += sizeof(*ev) + ev->length + 1; + len += sizeof(*ev) + ev_len; } hci_dev_unlock(hdev); @@ -5610,9 +5654,13 @@ static void hci_le_ext_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb) static void hci_le_remote_feat_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { - struct hci_ev_le_remote_feat_complete *ev = (void *)skb->data; + struct hci_ev_le_remote_feat_complete *ev; struct hci_conn *conn; + if (unlikely(!pskb_may_pull(skb, sizeof(*ev)))) + return; + ev = (void *)skb->data; + BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); hci_dev_lock(hdev); @@ -5651,12 +5699,16 @@ static void hci_le_remote_feat_complete_evt(struct hci_dev *hdev, static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb) { - struct hci_ev_le_ltk_req *ev = (void *) skb->data; + struct hci_ev_le_ltk_req *ev; struct hci_cp_le_ltk_reply cp; struct hci_cp_le_ltk_neg_reply neg; struct hci_conn *conn; struct smp_ltk *ltk; + if (unlikely(!pskb_may_pull(skb, sizeof(*ev)))) + return; + ev = (void *)skb->data; + BT_DBG("%s handle 0x%4.4x", hdev->name, __le16_to_cpu(ev->handle)); hci_dev_lock(hdev); @@ -5728,11 +5780,15 @@ static void send_conn_param_neg_reply(struct hci_dev *hdev, u16 handle, static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, struct sk_buff *skb) { - struct hci_ev_le_remote_conn_param_req *ev = (void *) skb->data; + struct hci_ev_le_remote_conn_param_req *ev; struct hci_cp_le_conn_param_req_reply cp; struct hci_conn *hcon; u16 handle, min, max, latency, timeout; + if (unlikely(!pskb_may_pull(skb, sizeof(*ev)))) + return; + ev = (void *)skb->data; + handle = le16_to_cpu(ev->handle); min = le16_to_cpu(ev->interval_min); max = le16_to_cpu(ev->interval_max); @@ -5786,19 +5842,27 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, static void hci_le_direct_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb) { - u8 num_reports = skb->data[0]; - void *ptr = &skb->data[1]; + unsigned int len; + u8 num_reports; + + if (unlikely(!pskb_may_pull(skb, 1))) + return; + num_reports = skb->data[0]; + len = 1; hci_dev_lock(hdev); while (num_reports--) { - struct hci_ev_le_direct_adv_info *ev = ptr; + struct hci_ev_le_direct_adv_info *ev; + if (unlikely(!pskb_may_pull(skb, len + sizeof(*ev)))) + break; + ev = (void *)skb->data + len; process_adv_report(hdev, ev->evt_type, &ev->bdaddr, ev->bdaddr_type, &ev->direct_addr, ev->direct_addr_type, ev->rssi, NULL, 0); - ptr += sizeof(*ev); + len += sizeof(*ev); } hci_dev_unlock(hdev); @@ -5806,8 +5870,11 @@ static void hci_le_direct_adv_report_evt(struct hci_dev *hdev, static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb) { - struct hci_ev_le_meta *le_ev = (void *) skb->data; + struct hci_ev_le_meta *le_ev; + if (unlikely(!pskb_may_pull(skb, sizeof(*le_ev)))) + return; + le_ev = (void *)skb->data; skb_pull(skb, sizeof(*le_ev)); switch (le_ev->subevent) { -- 2.20.1