[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20190321061208.16163-3-xiyou.wangcong@gmail.com>
Date: Wed, 20 Mar 2019 23:12:07 -0700
From: Cong Wang <xiyou.wangcong@...il.com>
To: netdev@...r.kernel.org
Cc: Cong Wang <xiyou.wangcong@...il.com>,
Marcel Holtmann <marcel@...tmann.org>,
Johan Hedberg <johan.hedberg@...il.com>
Subject: [Patch net v2 2/3] bluetooth: validate HCI_EV_LE_META packet carefully
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 <marcel@...tmann.org>
Cc: Johan Hedberg <johan.hedberg@...il.com>
Signed-off-by: Cong Wang <xiyou.wangcong@...il.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
Powered by blists - more mailing lists