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 too.

Cc: Marcel Holtmann <mar...@holtmann.org>
Cc: Johan Hedberg <johan.hedb...@gmail.com>
Signed-off-by: Cong Wang <xiyou.wangc...@gmail.com>
---
 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

Reply via email to