All of lore.kernel.org
 help / color / mirror / Atom feed
* [Patch net v2 0/3] bluetooth: validate packet boundary carefully
@ 2019-04-03 23:08 Cong Wang
  2019-04-03 23:08 ` [Patch net v2 1/3] bluetooth: validate HCI_EVENT_PKT packet carefully Cong Wang
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Cong Wang @ 2019-04-03 23:08 UTC (permalink / raw)
  To: netdev; +Cc: linux-bluetooth, Cong Wang

This patchset fixes the out-of-bound access in bluetooth stack.
Although it is large, all of them follow the same pattern, so
it should not be hard to review. I try to group them as much as
I can. This patchset should cover Dan's patch too.

Please check each patch for details.

(Resending v2 as it is lost in netdev mailing list.)

---

Cong Wang (3):
  bluetooth: validate HCI_EVENT_PKT packet carefully
  bluetooth: validate HCI_EV_LE_META packet carefully
  bluetooth: validate HCI_EV_CMD_COMPLETE packet carefully

 net/bluetooth/hci_event.c | 627 +++++++++++++++++++++++++++++++-------
 1 file changed, 520 insertions(+), 107 deletions(-)

-- 
2.20.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Patch net v2 1/3] bluetooth: validate HCI_EVENT_PKT packet carefully
  2019-04-03 23:08 [Patch net v2 0/3] bluetooth: validate packet boundary carefully Cong Wang
@ 2019-04-03 23:08 ` Cong Wang
  2019-04-23 19:42   ` Marcel Holtmann
  2019-04-03 23:08 ` [Patch net v2 2/3] bluetooth: validate HCI_EV_LE_META " Cong Wang
  2019-04-03 23:08 ` [Patch net v2 3/3] bluetooth: validate HCI_EV_CMD_COMPLETE " Cong Wang
  2 siblings, 1 reply; 10+ messages in thread
From: Cong Wang @ 2019-04-03 23:08 UTC (permalink / raw)
  To: netdev
  Cc: linux-bluetooth, Cong Wang, syzbot+cec7a50c412a2c03f8f5,
	syzbot+660883c56e2fa65d4497, Marcel Holtmann, Johan Hedberg,
	Dan Carpenter, Tomas Bortoli

hci_event_packet() blindly assumes all packets are sane, at least
for packets allocated via vhci_get_user() path this is not true.
We have to check if we access skb data out-of-bound with
pskb_may_pull() before each skb->data dereference on RX path.

Reported-and-tested-by: syzbot+cec7a50c412a2c03f8f5@syzkaller.appspotmail.com
Reported-and-tested-by: syzbot+660883c56e2fa65d4497@syzkaller.appspotmail.com
Cc: Marcel Holtmann <marcel@holtmann.org>
Cc: Johan Hedberg <johan.hedberg@gmail.com>
Cc: Dan Carpenter <dan.carpenter@oracle.com>
Reviewed-by: Tomas Bortoli <tomasbortoli@gmail.com>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
---
 net/bluetooth/hci_event.c | 262 +++++++++++++++++++++++++++++++-------
 1 file changed, 218 insertions(+), 44 deletions(-)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 609fd6871c5a..2fef70c0bffe 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2331,10 +2331,13 @@ static void hci_cs_switch_role(struct hci_dev *hdev, u8 status)
 
 static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	__u8 status = *((__u8 *) skb->data);
 	struct discovery_state *discov = &hdev->discovery;
 	struct inquiry_entry *e;
+	__u8 status;
 
+	if (unlikely(!pskb_may_pull(skb, 1)))
+		return;
+	status = *((__u8 *)skb->data);
 	BT_DBG("%s status 0x%2.2x", hdev->name, status);
 
 	hci_conn_check_pending(hdev);
@@ -2391,14 +2394,21 @@ static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct inquiry_data data;
-	struct inquiry_info *info = (void *) (skb->data + 1);
-	int num_rsp = *((__u8 *) skb->data);
+	struct inquiry_info *info;
+	int num_rsp;
 
 	BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
 
+	if (unlikely(!pskb_may_pull(skb, 1)))
+		return;
+	num_rsp = *((__u8 *)skb->data);
 	if (!num_rsp)
 		return;
 
+	if (unlikely(!pskb_may_pull(skb, 1 + num_rsp * sizeof(*info))))
+		return;
+	info = (void *)(skb->data + 1);
+
 	if (hci_dev_test_flag(hdev, HCI_PERIODIC_INQ))
 		return;
 
@@ -2428,11 +2438,15 @@ static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
 static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_conn_complete *ev = (void *) skb->data;
+	struct hci_ev_conn_complete *ev;
 	struct hci_conn *conn;
 
 	BT_DBG("%s", hdev->name);
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ev))))
+		return;
+	ev = (void *)skb->data;
+
 	hci_dev_lock(hdev);
 
 	conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
@@ -2522,12 +2536,16 @@ static void hci_reject_conn(struct hci_dev *hdev, bdaddr_t *bdaddr)
 
 static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_conn_request *ev = (void *) skb->data;
+	struct hci_ev_conn_request *ev;
 	int mask = hdev->link_mode;
 	struct inquiry_entry *ie;
 	struct hci_conn *conn;
 	__u8 flags = 0;
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ev))))
+		return;
+	ev = (void *)skb->data;
+
 	BT_DBG("%s bdaddr %pMR type 0x%x", hdev->name, &ev->bdaddr,
 	       ev->link_type);
 
@@ -2633,13 +2651,17 @@ static u8 hci_to_mgmt_reason(u8 err)
 
 static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_disconn_complete *ev = (void *) skb->data;
+	struct hci_ev_disconn_complete *ev;
 	u8 reason;
 	struct hci_conn_params *params;
 	struct hci_conn *conn;
 	bool mgmt_connected;
 	u8 type;
 
+	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);
@@ -2717,9 +2739,13 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
 static void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_auth_complete *ev = (void *) skb->data;
+	struct hci_ev_auth_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);
@@ -2787,11 +2813,15 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
 static void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_remote_name *ev = (void *) skb->data;
+	struct hci_ev_remote_name *ev;
 	struct hci_conn *conn;
 
 	BT_DBG("%s", hdev->name);
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ev))))
+		return;
+	ev = (void *)skb->data;
+
 	hci_conn_check_pending(hdev);
 
 	hci_dev_lock(hdev);
@@ -2885,9 +2915,13 @@ static void read_enc_key_size_complete(struct hci_dev *hdev, u8 status,
 
 static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_encrypt_change *ev = (void *) skb->data;
+	struct hci_ev_encrypt_change *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);
@@ -2992,9 +3026,13 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 static void hci_change_link_key_complete_evt(struct hci_dev *hdev,
 					     struct sk_buff *skb)
 {
-	struct hci_ev_change_link_key_complete *ev = (void *) skb->data;
+	struct hci_ev_change_link_key_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);
@@ -3015,9 +3053,13 @@ static void hci_change_link_key_complete_evt(struct hci_dev *hdev,
 static void hci_remote_features_evt(struct hci_dev *hdev,
 				    struct sk_buff *skb)
 {
-	struct hci_ev_remote_features *ev = (void *) skb->data;
+	struct hci_ev_remote_features *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);
@@ -3413,7 +3455,11 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb,
 			       hci_req_complete_t *req_complete,
 			       hci_req_complete_skb_t *req_complete_skb)
 {
-	struct hci_ev_cmd_status *ev = (void *) skb->data;
+	struct hci_ev_cmd_status *ev;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ev))))
+		return;
+	ev = (void *)skb->data;
 
 	skb_pull(skb, sizeof(*ev));
 
@@ -3517,7 +3563,11 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb,
 
 static void hci_hardware_error_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_hardware_error *ev = (void *) skb->data;
+	struct hci_ev_hardware_error *ev;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ev))))
+		return;
+	ev = (void *)skb->data;
 
 	hdev->hw_error_code = ev->code;
 
@@ -3526,9 +3576,13 @@ static void hci_hardware_error_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
 static void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_role_change *ev = (void *) skb->data;
+	struct hci_ev_role_change *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);
@@ -3687,9 +3741,13 @@ static void hci_num_comp_blocks_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
 static void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_mode_change *ev = (void *) skb->data;
+	struct hci_ev_mode_change *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);
@@ -3715,11 +3773,15 @@ static void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
 static void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_pin_code_req *ev = (void *) skb->data;
+	struct hci_ev_pin_code_req *ev;
 	struct hci_conn *conn;
 
 	BT_DBG("%s", hdev->name);
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ev))))
+		return;
+	ev = (void *)skb->data;
+
 	hci_dev_lock(hdev);
 
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
@@ -3785,13 +3847,17 @@ static void conn_set_key(struct hci_conn *conn, u8 key_type, u8 pin_len)
 
 static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_link_key_req *ev = (void *) skb->data;
+	struct hci_ev_link_key_req *ev;
 	struct hci_cp_link_key_reply cp;
 	struct hci_conn *conn;
 	struct link_key *key;
 
 	BT_DBG("%s", hdev->name);
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ev))))
+		return;
+	ev = (void *)skb->data;
+
 	if (!hci_dev_test_flag(hdev, HCI_MGMT))
 		return;
 
@@ -3845,7 +3911,7 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
 static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_link_key_notify *ev = (void *) skb->data;
+	struct hci_ev_link_key_notify *ev;
 	struct hci_conn *conn;
 	struct link_key *key;
 	bool persistent;
@@ -3853,6 +3919,10 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
 	BT_DBG("%s", hdev->name);
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ev))))
+		return;
+	ev = (void *)skb->data;
+
 	hci_dev_lock(hdev);
 
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
@@ -3905,9 +3975,13 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
 static void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_clock_offset *ev = (void *) skb->data;
+	struct hci_ev_clock_offset *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);
@@ -3928,9 +4002,13 @@ static void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
 static void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_pkt_type_change *ev = (void *) skb->data;
+	struct hci_ev_pkt_type_change *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);
@@ -3944,11 +4022,15 @@ static void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
 static void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_pscan_rep_mode *ev = (void *) skb->data;
+	struct hci_ev_pscan_rep_mode *ev;
 	struct inquiry_entry *ie;
 
 	BT_DBG("%s", hdev->name);
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ev))))
+		return;
+	ev = (void *)skb->data;
+
 	hci_dev_lock(hdev);
 
 	ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr);
@@ -3964,8 +4046,12 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev,
 					     struct sk_buff *skb)
 {
 	struct inquiry_data data;
-	int num_rsp = *((__u8 *) skb->data);
+	int num_rsp;
+
+	if (unlikely(!pskb_may_pull(skb, 1)))
+		return;
 
+	num_rsp = *((__u8 *)skb->data);
 	BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
 
 	if (!num_rsp)
@@ -3978,6 +4064,9 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev,
 
 	if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
 		struct inquiry_info_with_rssi_and_pscan_mode *info;
+
+		if (unlikely(!pskb_may_pull(skb, 1 + num_rsp * sizeof(*info))))
+			goto unlock;
 		info = (void *) (skb->data + 1);
 
 		for (; num_rsp; num_rsp--, info++) {
@@ -3999,7 +4088,11 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev,
 					  flags, NULL, 0, NULL, 0);
 		}
 	} else {
-		struct inquiry_info_with_rssi *info = (void *) (skb->data + 1);
+		struct inquiry_info_with_rssi *info;
+
+		if (unlikely(!pskb_may_pull(skb, 1 + num_rsp * sizeof(*info))))
+			goto unlock;
+		info = (void *)(skb->data + 1);
 
 		for (; num_rsp; num_rsp--, info++) {
 			u32 flags;
@@ -4021,17 +4114,22 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev,
 		}
 	}
 
+unlock:
 	hci_dev_unlock(hdev);
 }
 
 static void hci_remote_ext_features_evt(struct hci_dev *hdev,
 					struct sk_buff *skb)
 {
-	struct hci_ev_remote_ext_features *ev = (void *) skb->data;
+	struct hci_ev_remote_ext_features *ev;
 	struct hci_conn *conn;
 
 	BT_DBG("%s", hdev->name);
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ev))))
+		return;
+	ev = (void *)skb->data;
+
 	hci_dev_lock(hdev);
 
 	conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
@@ -4091,9 +4189,13 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev,
 static void hci_sync_conn_complete_evt(struct hci_dev *hdev,
 				       struct sk_buff *skb)
 {
-	struct hci_ev_sync_conn_complete *ev = (void *) skb->data;
+	struct hci_ev_sync_conn_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);
@@ -4176,14 +4278,21 @@ static void hci_extended_inquiry_result_evt(struct hci_dev *hdev,
 					    struct sk_buff *skb)
 {
 	struct inquiry_data data;
-	struct extended_inquiry_info *info = (void *) (skb->data + 1);
-	int num_rsp = *((__u8 *) skb->data);
+	struct extended_inquiry_info *info;
+	int num_rsp;
 	size_t eir_len;
 
+	if (unlikely(!pskb_may_pull(skb, 1)))
+		return;
+	num_rsp = *((__u8 *)skb->data);
+
 	BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
 
 	if (!num_rsp)
 		return;
+	if (unlikely(!pskb_may_pull(skb, 1 + num_rsp * sizeof(*info))))
+		return;
+	info = (void *)(skb->data + 1);
 
 	if (hci_dev_test_flag(hdev, HCI_PERIODIC_INQ))
 		return;
@@ -4225,9 +4334,13 @@ static void hci_extended_inquiry_result_evt(struct hci_dev *hdev,
 static void hci_key_refresh_complete_evt(struct hci_dev *hdev,
 					 struct sk_buff *skb)
 {
-	struct hci_ev_key_refresh_complete *ev = (void *) skb->data;
+	struct hci_ev_key_refresh_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 handle 0x%4.4x", hdev->name, ev->status,
 	       __le16_to_cpu(ev->handle));
 
@@ -4334,11 +4447,15 @@ static u8 bredr_oob_data_present(struct hci_conn *conn)
 
 static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_io_capa_request *ev = (void *) skb->data;
+	struct hci_ev_io_capa_request *ev;
 	struct hci_conn *conn;
 
 	BT_DBG("%s", hdev->name);
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ev))))
+		return;
+	ev = (void *)skb->data;
+
 	hci_dev_lock(hdev);
 
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
@@ -4403,11 +4520,15 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
 static void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_io_capa_reply *ev = (void *) skb->data;
+	struct hci_ev_io_capa_reply *ev;
 	struct hci_conn *conn;
 
 	BT_DBG("%s", hdev->name);
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ev))))
+		return;
+	ev = (void *)skb->data;
+
 	hci_dev_lock(hdev);
 
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
@@ -4424,12 +4545,16 @@ static void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *skb)
 static void hci_user_confirm_request_evt(struct hci_dev *hdev,
 					 struct sk_buff *skb)
 {
-	struct hci_ev_user_confirm_req *ev = (void *) skb->data;
+	struct hci_ev_user_confirm_req *ev;
 	int loc_mitm, rem_mitm, confirm_hint = 0;
 	struct hci_conn *conn;
 
 	BT_DBG("%s", hdev->name);
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ev))))
+		return;
+	ev = (void *)skb->data;
+
 	hci_dev_lock(hdev);
 
 	if (!hci_dev_test_flag(hdev, HCI_MGMT))
@@ -4499,10 +4624,13 @@ static void hci_user_confirm_request_evt(struct hci_dev *hdev,
 static void hci_user_passkey_request_evt(struct hci_dev *hdev,
 					 struct sk_buff *skb)
 {
-	struct hci_ev_user_passkey_req *ev = (void *) skb->data;
+	struct hci_ev_user_passkey_req *ev;
 
 	BT_DBG("%s", hdev->name);
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ev))))
+		return;
+	ev = (void *)skb->data;
 	if (hci_dev_test_flag(hdev, HCI_MGMT))
 		mgmt_user_passkey_request(hdev, &ev->bdaddr, ACL_LINK, 0);
 }
@@ -4510,11 +4638,15 @@ static void hci_user_passkey_request_evt(struct hci_dev *hdev,
 static void hci_user_passkey_notify_evt(struct hci_dev *hdev,
 					struct sk_buff *skb)
 {
-	struct hci_ev_user_passkey_notify *ev = (void *) skb->data;
+	struct hci_ev_user_passkey_notify *ev;
 	struct hci_conn *conn;
 
 	BT_DBG("%s", hdev->name);
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ev))))
+		return;
+	ev = (void *)skb->data;
+
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
 	if (!conn)
 		return;
@@ -4530,11 +4662,15 @@ static void hci_user_passkey_notify_evt(struct hci_dev *hdev,
 
 static void hci_keypress_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_keypress_notify *ev = (void *) skb->data;
+	struct hci_ev_keypress_notify *ev;
 	struct hci_conn *conn;
 
 	BT_DBG("%s", hdev->name);
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ev))))
+		return;
+	ev = (void *)skb->data;
+
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
 	if (!conn)
 		return;
@@ -4569,11 +4705,15 @@ static void hci_keypress_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
 static void hci_simple_pair_complete_evt(struct hci_dev *hdev,
 					 struct sk_buff *skb)
 {
-	struct hci_ev_simple_pair_complete *ev = (void *) skb->data;
+	struct hci_ev_simple_pair_complete *ev;
 	struct hci_conn *conn;
 
 	BT_DBG("%s", hdev->name);
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ev))))
+		return;
+	ev = (void *)skb->data;
+
 	hci_dev_lock(hdev);
 
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
@@ -4600,12 +4740,16 @@ static void hci_simple_pair_complete_evt(struct hci_dev *hdev,
 static void hci_remote_host_features_evt(struct hci_dev *hdev,
 					 struct sk_buff *skb)
 {
-	struct hci_ev_remote_host_features *ev = (void *) skb->data;
+	struct hci_ev_remote_host_features *ev;
 	struct inquiry_entry *ie;
 	struct hci_conn *conn;
 
 	BT_DBG("%s", hdev->name);
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ev))))
+		return;
+	ev = (void *)skb->data;
+
 	hci_dev_lock(hdev);
 
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
@@ -4622,11 +4766,15 @@ static void hci_remote_host_features_evt(struct hci_dev *hdev,
 static void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
 					    struct sk_buff *skb)
 {
-	struct hci_ev_remote_oob_data_request *ev = (void *) skb->data;
+	struct hci_ev_remote_oob_data_request *ev;
 	struct oob_data *data;
 
 	BT_DBG("%s", hdev->name);
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ev))))
+		return;
+	ev = (void *)skb->data;
+
 	hci_dev_lock(hdev);
 
 	if (!hci_dev_test_flag(hdev, HCI_MGMT))
@@ -4676,9 +4824,13 @@ static void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
 #if IS_ENABLED(CONFIG_BT_HS)
 static void hci_chan_selected_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_channel_selected *ev = (void *)skb->data;
+	struct hci_ev_channel_selected *ev;
 	struct hci_conn *hcon;
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ev))))
+		return;
+	ev = (void *)skb->data;
+
 	BT_DBG("%s handle 0x%2.2x", hdev->name, ev->phy_handle);
 
 	skb_pull(skb, sizeof(*ev));
@@ -4693,9 +4845,13 @@ static void hci_chan_selected_evt(struct hci_dev *hdev, struct sk_buff *skb)
 static void hci_phy_link_complete_evt(struct hci_dev *hdev,
 				      struct sk_buff *skb)
 {
-	struct hci_ev_phy_link_complete *ev = (void *) skb->data;
+	struct hci_ev_phy_link_complete *ev;
 	struct hci_conn *hcon, *bredr_hcon;
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ev))))
+		return;
+	ev = (void *)skb->data;
+
 	BT_DBG("%s handle 0x%2.2x status 0x%2.2x", hdev->name, ev->phy_handle,
 	       ev->status);
 
@@ -4732,11 +4888,15 @@ static void hci_phy_link_complete_evt(struct hci_dev *hdev,
 
 static void hci_loglink_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_ev_logical_link_complete *ev = (void *) skb->data;
+	struct hci_ev_logical_link_complete *ev;
 	struct hci_conn *hcon;
 	struct hci_chan *hchan;
 	struct amp_mgr *mgr;
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ev))))
+		return;
+	ev = (void *)skb->data;
+
 	BT_DBG("%s log_handle 0x%4.4x phy_handle 0x%2.2x status 0x%2.2x",
 	       hdev->name, le16_to_cpu(ev->handle), ev->phy_handle,
 	       ev->status);
@@ -4771,9 +4931,13 @@ static void hci_loglink_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 static void hci_disconn_loglink_complete_evt(struct hci_dev *hdev,
 					     struct sk_buff *skb)
 {
-	struct hci_ev_disconn_logical_link_complete *ev = (void *) skb->data;
+	struct hci_ev_disconn_logical_link_complete *ev;
 	struct hci_chan *hchan;
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ev))))
+		return;
+	ev = (void *)skb->data;
+
 	BT_DBG("%s log handle 0x%4.4x status 0x%2.2x", hdev->name,
 	       le16_to_cpu(ev->handle), ev->status);
 
@@ -4795,9 +4959,13 @@ static void hci_disconn_loglink_complete_evt(struct hci_dev *hdev,
 static void hci_disconn_phylink_complete_evt(struct hci_dev *hdev,
 					     struct sk_buff *skb)
 {
-	struct hci_ev_disconn_phy_link_complete *ev = (void *) skb->data;
+	struct hci_ev_disconn_phy_link_complete *ev;
 	struct hci_conn *hcon;
 
+	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)
@@ -5742,13 +5910,18 @@ static bool hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode,
 
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_event_hdr *hdr = (void *) skb->data;
+	struct hci_event_hdr *hdr;
 	hci_req_complete_t req_complete = NULL;
 	hci_req_complete_skb_t req_complete_skb = NULL;
 	struct sk_buff *orig_skb = NULL;
-	u8 status = 0, event = hdr->evt, req_evt = 0;
+	u8 status = 0, event, req_evt = 0;
 	u16 opcode = HCI_OP_NOP;
 
+	if (unlikely(!pskb_may_pull(skb,  HCI_EVENT_HDR_SIZE)))
+		goto free;
+	hdr = (void *)skb->data;
+	event = hdr->evt;
+
 	if (hdev->sent_cmd && bt_cb(hdev->sent_cmd)->hci.req_event == event) {
 		struct hci_command_hdr *cmd_hdr = (void *) hdev->sent_cmd->data;
 		opcode = __le16_to_cpu(cmd_hdr->opcode);
@@ -5960,6 +6133,7 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
 		req_complete_skb(hdev, status, opcode, orig_skb);
 	}
 
+free:
 	kfree_skb(orig_skb);
 	kfree_skb(skb);
 	hdev->stat.evt_rx++;
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Patch net v2 2/3] bluetooth: validate HCI_EV_LE_META packet carefully
  2019-04-03 23:08 [Patch net v2 0/3] bluetooth: validate packet boundary carefully Cong Wang
  2019-04-03 23:08 ` [Patch net v2 1/3] bluetooth: validate HCI_EVENT_PKT packet carefully Cong Wang
@ 2019-04-03 23:08 ` Cong Wang
  2019-04-04  8:34   ` Dan Carpenter
  2019-04-03 23:08 ` [Patch net v2 3/3] bluetooth: validate HCI_EV_CMD_COMPLETE " Cong Wang
  2 siblings, 1 reply; 10+ messages in thread
From: Cong Wang @ 2019-04-03 23:08 UTC (permalink / raw)
  To: netdev
  Cc: linux-bluetooth, Cong Wang, Marcel Holtmann, Johan Hedberg,
	Dan Carpenter, Tomas Bortoli

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@holtmann.org>
Cc: Johan Hedberg <johan.hedberg@gmail.com>
Cc: Dan Carpenter <dan.carpenter@oracle.com>
Reviewed-by: Tomas Bortoli <tomasbortoli@gmail.com>
Signed-off-by: Cong Wang <xiyou.wangcong@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


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Patch net v2 3/3] bluetooth: validate HCI_EV_CMD_COMPLETE packet carefully
  2019-04-03 23:08 [Patch net v2 0/3] bluetooth: validate packet boundary carefully Cong Wang
  2019-04-03 23:08 ` [Patch net v2 1/3] bluetooth: validate HCI_EVENT_PKT packet carefully Cong Wang
  2019-04-03 23:08 ` [Patch net v2 2/3] bluetooth: validate HCI_EV_LE_META " Cong Wang
@ 2019-04-03 23:08 ` Cong Wang
  2 siblings, 0 replies; 10+ messages in thread
From: Cong Wang @ 2019-04-03 23:08 UTC (permalink / raw)
  To: netdev
  Cc: linux-bluetooth, Cong Wang, Marcel Holtmann, Johan Hedberg,
	Dan Carpenter, Tomas Bortoli

Similarly, we need to check skb->data boundary for
HCI_EV_CMD_COMPLETE event too.

Cc: Marcel Holtmann <marcel@holtmann.org>
Cc: Johan Hedberg <johan.hedberg@gmail.com>
Cc: Dan Carpenter <dan.carpenter@oracle.com>
Reviewed-by: Tomas Bortoli <tomasbortoli@gmail.com>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
---
 net/bluetooth/hci_event.c | 258 +++++++++++++++++++++++++++++++-------
 1 file changed, 215 insertions(+), 43 deletions(-)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 31aef14dd838..63e14c49f617 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -100,9 +100,13 @@ static void hci_cc_remote_name_req_cancel(struct hci_dev *hdev,
 
 static void hci_cc_role_discovery(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_rp_role_discovery *rp = (void *) skb->data;
+	struct hci_rp_role_discovery *rp;
 	struct hci_conn *conn;
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
+
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
 	if (rp->status)
@@ -119,9 +123,13 @@ static void hci_cc_role_discovery(struct hci_dev *hdev, struct sk_buff *skb)
 
 static void hci_cc_read_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_rp_read_link_policy *rp = (void *) skb->data;
+	struct hci_rp_read_link_policy *rp;
 	struct hci_conn *conn;
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
+
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
 	if (rp->status)
@@ -138,10 +146,14 @@ static void hci_cc_read_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
 
 static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_rp_write_link_policy *rp = (void *) skb->data;
+	struct hci_rp_write_link_policy *rp;
 	struct hci_conn *conn;
 	void *sent;
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
+
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
 	if (rp->status)
@@ -163,7 +175,11 @@ static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
 static void hci_cc_read_def_link_policy(struct hci_dev *hdev,
 					struct sk_buff *skb)
 {
-	struct hci_rp_read_def_link_policy *rp = (void *) skb->data;
+	struct hci_rp_read_def_link_policy *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -227,9 +243,13 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
 static void hci_cc_read_stored_link_key(struct hci_dev *hdev,
 					struct sk_buff *skb)
 {
-	struct hci_rp_read_stored_link_key *rp = (void *)skb->data;
+	struct hci_rp_read_stored_link_key *rp;
 	struct hci_cp_read_stored_link_key *sent;
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
+
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
 	sent = hci_sent_cmd_data(hdev, HCI_OP_READ_STORED_LINK_KEY);
@@ -245,7 +265,11 @@ static void hci_cc_read_stored_link_key(struct hci_dev *hdev,
 static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,
 					  struct sk_buff *skb)
 {
-	struct hci_rp_delete_stored_link_key *rp = (void *)skb->data;
+	struct hci_rp_delete_stored_link_key *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -281,7 +305,11 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
 
 static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_rp_read_local_name *rp = (void *) skb->data;
+	struct hci_rp_read_local_name *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -381,7 +409,11 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
 
 static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_rp_read_class_of_dev *rp = (void *) skb->data;
+	struct hci_rp_read_class_of_dev *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -418,9 +450,13 @@ static void hci_cc_write_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
 
 static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_rp_read_voice_setting *rp = (void *) skb->data;
+	struct hci_rp_read_voice_setting *rp;
 	__u16 setting;
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
+
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
 	if (rp->status)
@@ -471,7 +507,11 @@ static void hci_cc_write_voice_setting(struct hci_dev *hdev,
 static void hci_cc_read_num_supported_iac(struct hci_dev *hdev,
 					  struct sk_buff *skb)
 {
-	struct hci_rp_read_num_supported_iac *rp = (void *) skb->data;
+	struct hci_rp_read_num_supported_iac *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -547,7 +587,11 @@ static void hci_cc_write_sc_support(struct hci_dev *hdev, struct sk_buff *skb)
 
 static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_rp_read_local_version *rp = (void *) skb->data;
+	struct hci_rp_read_local_version *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -567,7 +611,11 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
 static void hci_cc_read_local_commands(struct hci_dev *hdev,
 				       struct sk_buff *skb)
 {
-	struct hci_rp_read_local_commands *rp = (void *) skb->data;
+	struct hci_rp_read_local_commands *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -582,7 +630,11 @@ static void hci_cc_read_local_commands(struct hci_dev *hdev,
 static void hci_cc_read_local_features(struct hci_dev *hdev,
 				       struct sk_buff *skb)
 {
-	struct hci_rp_read_local_features *rp = (void *) skb->data;
+	struct hci_rp_read_local_features *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -632,7 +684,11 @@ static void hci_cc_read_local_features(struct hci_dev *hdev,
 static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
 					   struct sk_buff *skb)
 {
-	struct hci_rp_read_local_ext_features *rp = (void *) skb->data;
+	struct hci_rp_read_local_ext_features *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -649,7 +705,11 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
 static void hci_cc_read_flow_control_mode(struct hci_dev *hdev,
 					  struct sk_buff *skb)
 {
-	struct hci_rp_read_flow_control_mode *rp = (void *) skb->data;
+	struct hci_rp_read_flow_control_mode *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -661,7 +721,11 @@ static void hci_cc_read_flow_control_mode(struct hci_dev *hdev,
 
 static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_rp_read_buffer_size *rp = (void *) skb->data;
+	struct hci_rp_read_buffer_size *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -687,7 +751,11 @@ static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
 
 static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_rp_read_bd_addr *rp = (void *) skb->data;
+	struct hci_rp_read_bd_addr *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -704,7 +772,11 @@ static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
 static void hci_cc_read_page_scan_activity(struct hci_dev *hdev,
 					   struct sk_buff *skb)
 {
-	struct hci_rp_read_page_scan_activity *rp = (void *) skb->data;
+	struct hci_rp_read_page_scan_activity *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -739,7 +811,11 @@ static void hci_cc_write_page_scan_activity(struct hci_dev *hdev,
 static void hci_cc_read_page_scan_type(struct hci_dev *hdev,
 					   struct sk_buff *skb)
 {
-	struct hci_rp_read_page_scan_type *rp = (void *) skb->data;
+	struct hci_rp_read_page_scan_type *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -769,7 +845,11 @@ static void hci_cc_write_page_scan_type(struct hci_dev *hdev,
 static void hci_cc_read_data_block_size(struct hci_dev *hdev,
 					struct sk_buff *skb)
 {
-	struct hci_rp_read_data_block_size *rp = (void *) skb->data;
+	struct hci_rp_read_data_block_size *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -824,7 +904,11 @@ static void hci_cc_read_clock(struct hci_dev *hdev, struct sk_buff *skb)
 static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
 				       struct sk_buff *skb)
 {
-	struct hci_rp_read_local_amp_info *rp = (void *) skb->data;
+	struct hci_rp_read_local_amp_info *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -846,7 +930,11 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
 static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev,
 					 struct sk_buff *skb)
 {
-	struct hci_rp_read_inq_rsp_tx_power *rp = (void *) skb->data;
+	struct hci_rp_read_inq_rsp_tx_power *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -858,10 +946,14 @@ static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev,
 
 static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_rp_pin_code_reply *rp = (void *) skb->data;
+	struct hci_rp_pin_code_reply *rp;
 	struct hci_cp_pin_code_reply *cp;
 	struct hci_conn *conn;
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
+
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
 	hci_dev_lock(hdev);
@@ -886,7 +978,11 @@ static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)
 
 static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_rp_pin_code_neg_reply *rp = (void *) skb->data;
+	struct hci_rp_pin_code_neg_reply *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -902,7 +998,11 @@ static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
 static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
 				       struct sk_buff *skb)
 {
-	struct hci_rp_le_read_buffer_size *rp = (void *) skb->data;
+	struct hci_rp_le_read_buffer_size *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -920,7 +1020,11 @@ static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
 static void hci_cc_le_read_local_features(struct hci_dev *hdev,
 					  struct sk_buff *skb)
 {
-	struct hci_rp_le_read_local_features *rp = (void *) skb->data;
+	struct hci_rp_le_read_local_features *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -933,7 +1037,11 @@ static void hci_cc_le_read_local_features(struct hci_dev *hdev,
 static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev,
 					struct sk_buff *skb)
 {
-	struct hci_rp_le_read_adv_tx_power *rp = (void *) skb->data;
+	struct hci_rp_le_read_adv_tx_power *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -945,7 +1053,11 @@ static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev,
 
 static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
+	struct hci_rp_user_confirm_reply *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -961,7 +1073,11 @@ static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
 static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
 					  struct sk_buff *skb)
 {
-	struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
+	struct hci_rp_user_confirm_reply *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -976,7 +1092,11 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
 
 static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
+	struct hci_rp_user_confirm_reply *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -992,7 +1112,11 @@ static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb)
 static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
 					  struct sk_buff *skb)
 {
-	struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
+	struct hci_rp_user_confirm_reply *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -1008,7 +1132,11 @@ static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev,
 static void hci_cc_read_local_oob_data(struct hci_dev *hdev,
 				       struct sk_buff *skb)
 {
-	struct hci_rp_read_local_oob_data *rp = (void *) skb->data;
+	struct hci_rp_read_local_oob_data *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 }
@@ -1016,7 +1144,11 @@ static void hci_cc_read_local_oob_data(struct hci_dev *hdev,
 static void hci_cc_read_local_oob_ext_data(struct hci_dev *hdev,
 					   struct sk_buff *skb)
 {
-	struct hci_rp_read_local_oob_ext_data *rp = (void *) skb->data;
+	struct hci_rp_read_local_oob_ext_data *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 }
@@ -1333,7 +1465,11 @@ static void hci_cc_le_set_ext_scan_enable(struct hci_dev *hdev,
 static void hci_cc_le_read_num_adv_sets(struct hci_dev *hdev,
 				      struct sk_buff *skb)
 {
-	struct hci_rp_le_read_num_supported_adv_sets *rp = (void *) skb->data;
+	struct hci_rp_le_read_num_supported_adv_sets *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x No of Adv sets %u", hdev->name, rp->status,
 	       rp->num_of_sets);
@@ -1347,7 +1483,11 @@ static void hci_cc_le_read_num_adv_sets(struct hci_dev *hdev,
 static void hci_cc_le_read_white_list_size(struct hci_dev *hdev,
 					   struct sk_buff *skb)
 {
-	struct hci_rp_le_read_white_list_size *rp = (void *) skb->data;
+	struct hci_rp_le_read_white_list_size *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x size %u", hdev->name, rp->status, rp->size);
 
@@ -1411,7 +1551,11 @@ static void hci_cc_le_del_from_white_list(struct hci_dev *hdev,
 static void hci_cc_le_read_supported_states(struct hci_dev *hdev,
 					    struct sk_buff *skb)
 {
-	struct hci_rp_le_read_supported_states *rp = (void *) skb->data;
+	struct hci_rp_le_read_supported_states *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -1424,7 +1568,11 @@ static void hci_cc_le_read_supported_states(struct hci_dev *hdev,
 static void hci_cc_le_read_def_data_len(struct hci_dev *hdev,
 					struct sk_buff *skb)
 {
-	struct hci_rp_le_read_def_data_len *rp = (void *) skb->data;
+	struct hci_rp_le_read_def_data_len *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -1509,7 +1657,11 @@ static void hci_cc_le_clear_resolv_list(struct hci_dev *hdev,
 static void hci_cc_le_read_resolv_list_size(struct hci_dev *hdev,
 					   struct sk_buff *skb)
 {
-	struct hci_rp_le_read_resolv_list_size *rp = (void *) skb->data;
+	struct hci_rp_le_read_resolv_list_size *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x size %u", hdev->name, rp->status, rp->size);
 
@@ -1546,7 +1698,11 @@ static void hci_cc_le_set_addr_resolution_enable(struct hci_dev *hdev,
 static void hci_cc_le_read_max_data_len(struct hci_dev *hdev,
 					struct sk_buff *skb)
 {
-	struct hci_rp_le_read_max_data_len *rp = (void *) skb->data;
+	struct hci_rp_le_read_max_data_len *rp;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
@@ -1614,10 +1770,14 @@ static void hci_cc_set_adv_param(struct hci_dev *hdev, struct sk_buff *skb)
 
 static void hci_cc_set_ext_adv_param(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_rp_le_set_ext_adv_params *rp = (void *) skb->data;
+	struct hci_rp_le_set_ext_adv_params *rp;
 	struct hci_cp_le_set_ext_adv_params *cp;
 	struct adv_info *adv_instance;
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
+
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
 	if (rp->status)
@@ -1645,9 +1805,13 @@ static void hci_cc_set_ext_adv_param(struct hci_dev *hdev, struct sk_buff *skb)
 
 static void hci_cc_read_rssi(struct hci_dev *hdev, struct sk_buff *skb)
 {
-	struct hci_rp_read_rssi *rp = (void *) skb->data;
+	struct hci_rp_read_rssi *rp;
 	struct hci_conn *conn;
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
+
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
 	if (rp->status)
@@ -1665,9 +1829,13 @@ static void hci_cc_read_rssi(struct hci_dev *hdev, struct sk_buff *skb)
 static void hci_cc_read_tx_power(struct hci_dev *hdev, struct sk_buff *skb)
 {
 	struct hci_cp_read_tx_power *sent;
-	struct hci_rp_read_tx_power *rp = (void *) skb->data;
+	struct hci_rp_read_tx_power *rp;
 	struct hci_conn *conn;
 
+	if (unlikely(!pskb_may_pull(skb, sizeof(*rp))))
+		return;
+	rp = (void *)skb->data;
+
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
 	if (rp->status)
@@ -3108,7 +3276,11 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb,
 				 hci_req_complete_t *req_complete,
 				 hci_req_complete_skb_t *req_complete_skb)
 {
-	struct hci_ev_cmd_complete *ev = (void *) skb->data;
+	struct hci_ev_cmd_complete *ev;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ev) + 1)))
+		return;
+	ev = (void *)skb->data;
 
 	*opcode = __le16_to_cpu(ev->opcode);
 	*status = skb->data[sizeof(*ev)];
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [Patch net v2 2/3] bluetooth: validate HCI_EV_LE_META packet carefully
  2019-04-03 23:08 ` [Patch net v2 2/3] bluetooth: validate HCI_EV_LE_META " Cong Wang
@ 2019-04-04  8:34   ` Dan Carpenter
  2019-04-05 17:26     ` Cong Wang
  0 siblings, 1 reply; 10+ messages in thread
From: Dan Carpenter @ 2019-04-04  8:34 UTC (permalink / raw)
  To: Cong Wang
  Cc: netdev, linux-bluetooth, Marcel Holtmann, Johan Hedberg, Tomas Bortoli

On Wed, Apr 03, 2019 at 04:08:34PM -0700, Cong Wang wrote:
>  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;

The "+ 1" is a bug.  It was discussed in a different thread.  Jaganath
says he has sent a patch to fix it already.

Probably it worked in testing because the num_reports was always 1, but
now when we add this condition with the "+ 1" bug at the start of the
loop the the the num_reports == 1 case will be broken as well.

Tomas and I should get Reported-by tags for parts of this patch.

> +		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);

regards,
dan carpenter


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Patch net v2 2/3] bluetooth: validate HCI_EV_LE_META packet carefully
  2019-04-04  8:34   ` Dan Carpenter
@ 2019-04-05 17:26     ` Cong Wang
  2019-04-05 20:09       ` Dan Carpenter
  0 siblings, 1 reply; 10+ messages in thread
From: Cong Wang @ 2019-04-05 17:26 UTC (permalink / raw)
  To: Dan Carpenter
  Cc: Linux Kernel Network Developers, linux-bluetooth,
	Marcel Holtmann, Johan Hedberg, Tomas Bortoli

On Thu, Apr 4, 2019 at 1:35 AM Dan Carpenter <dan.carpenter@oracle.com> wrote:
>
> On Wed, Apr 03, 2019 at 04:08:34PM -0700, Cong Wang wrote:
> >  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;
>
> The "+ 1" is a bug.  It was discussed in a different thread.  Jaganath
> says he has sent a patch to fix it already.
>
> Probably it worked in testing because the num_reports was always 1, but
> now when we add this condition with the "+ 1" bug at the start of the
> loop the the the num_reports == 1 case will be broken as well.

It could be, at least it is not a bug introduced by my patch therefore
I have no obligation to fix it?

I am happy to rebase if that fix is merged before mine, like for any other
changes, if this is what you are trying to say.

>
> Tomas and I should get Reported-by tags for parts of this patch.


Sure, sorry for missing it, as I got reports from syzbot directly and
before you reported it. Will add it in v3.

Thanks.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Patch net v2 2/3] bluetooth: validate HCI_EV_LE_META packet carefully
  2019-04-05 17:26     ` Cong Wang
@ 2019-04-05 20:09       ` Dan Carpenter
  0 siblings, 0 replies; 10+ messages in thread
From: Dan Carpenter @ 2019-04-05 20:09 UTC (permalink / raw)
  To: Cong Wang
  Cc: Linux Kernel Network Developers, linux-bluetooth,
	Marcel Holtmann, Johan Hedberg, Tomas Bortoli


As I explained in my email, the original code is buggy if
num_reports > 1 (probably uncommon), but your code is buggy for
num_reports >= 1 (everything).

regards,
dan carpenter


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Patch net v2 1/3] bluetooth: validate HCI_EVENT_PKT packet carefully
  2019-04-03 23:08 ` [Patch net v2 1/3] bluetooth: validate HCI_EVENT_PKT packet carefully Cong Wang
@ 2019-04-23 19:42   ` Marcel Holtmann
  2019-04-24  1:36     ` Cong Wang
  0 siblings, 1 reply; 10+ messages in thread
From: Marcel Holtmann @ 2019-04-23 19:42 UTC (permalink / raw)
  To: Cong Wang
  Cc: netdev, linux-bluetooth, syzbot+cec7a50c412a2c03f8f5,
	syzbot+660883c56e2fa65d4497, Johan Hedberg, Dan Carpenter,
	Tomas Bortoli

Hi Cong,

> hci_event_packet() blindly assumes all packets are sane, at least
> for packets allocated via vhci_get_user() path this is not true.
> We have to check if we access skb data out-of-bound with
> pskb_may_pull() before each skb->data dereference on RX path.
> 
> Reported-and-tested-by: syzbot+cec7a50c412a2c03f8f5@syzkaller.appspotmail.com
> Reported-and-tested-by: syzbot+660883c56e2fa65d4497@syzkaller.appspotmail.com
> Cc: Marcel Holtmann <marcel@holtmann.org>
> Cc: Johan Hedberg <johan.hedberg@gmail.com>
> Cc: Dan Carpenter <dan.carpenter@oracle.com>
> Reviewed-by: Tomas Bortoli <tomasbortoli@gmail.com>
> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
> ---
> net/bluetooth/hci_event.c | 262 +++++++++++++++++++++++++++++++-------
> 1 file changed, 218 insertions(+), 44 deletions(-)
> 
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> index 609fd6871c5a..2fef70c0bffe 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -2331,10 +2331,13 @@ static void hci_cs_switch_role(struct hci_dev *hdev, u8 status)
> 
> static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
> {
> -	__u8 status = *((__u8 *) skb->data);
> 	struct discovery_state *discov = &hdev->discovery;
> 	struct inquiry_entry *e;
> +	__u8 status;
> 
> +	if (unlikely(!pskb_may_pull(skb, 1)))
> +		return;
> +	status = *((__u8 *)skb->data);
> 	BT_DBG("%s status 0x%2.2x", hdev->name, status);
> 
> 	hci_conn_check_pending(hdev);
> @@ -2391,14 +2394,21 @@ static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
> static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
> {
> 	struct inquiry_data data;
> -	struct inquiry_info *info = (void *) (skb->data + 1);
> -	int num_rsp = *((__u8 *) skb->data);
> +	struct inquiry_info *info;
> +	int num_rsp;
> 
> 	BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
> 
> +	if (unlikely(!pskb_may_pull(skb, 1)))
> +		return;
> +	num_rsp = *((__u8 *)skb->data);
> 	if (!num_rsp)
> 		return;
> 
> +	if (unlikely(!pskb_may_pull(skb, 1 + num_rsp * sizeof(*info))))
> +		return;
> +	info = (void *)(skb->data + 1);
> +
> 	if (hci_dev_test_flag(hdev, HCI_PERIODIC_INQ))
> 		return;

this really looks like we better create a macro for this. It is repetitive code that can be turned into just a macro usage.

Regards

Marcel


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Patch net v2 1/3] bluetooth: validate HCI_EVENT_PKT packet carefully
  2019-04-23 19:42   ` Marcel Holtmann
@ 2019-04-24  1:36     ` Cong Wang
  0 siblings, 0 replies; 10+ messages in thread
From: Cong Wang @ 2019-04-24  1:36 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: Linux Kernel Network Developers, linux-bluetooth, syzbot, syzbot,
	Johan Hedberg, Dan Carpenter, Tomas Bortoli

On Tue, Apr 23, 2019 at 12:42 PM Marcel Holtmann <marcel@holtmann.org> wrote:
>
> Hi Cong,
>
> > hci_event_packet() blindly assumes all packets are sane, at least
> > for packets allocated via vhci_get_user() path this is not true.
> > We have to check if we access skb data out-of-bound with
> > pskb_may_pull() before each skb->data dereference on RX path.
> >
> > Reported-and-tested-by: syzbot+cec7a50c412a2c03f8f5@syzkaller.appspotmail.com
> > Reported-and-tested-by: syzbot+660883c56e2fa65d4497@syzkaller.appspotmail.com
> > Cc: Marcel Holtmann <marcel@holtmann.org>
> > Cc: Johan Hedberg <johan.hedberg@gmail.com>
> > Cc: Dan Carpenter <dan.carpenter@oracle.com>
> > Reviewed-by: Tomas Bortoli <tomasbortoli@gmail.com>
> > Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
> > ---
> > net/bluetooth/hci_event.c | 262 +++++++++++++++++++++++++++++++-------
> > 1 file changed, 218 insertions(+), 44 deletions(-)
> >
> > diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> > index 609fd6871c5a..2fef70c0bffe 100644
> > --- a/net/bluetooth/hci_event.c
> > +++ b/net/bluetooth/hci_event.c
> > @@ -2331,10 +2331,13 @@ static void hci_cs_switch_role(struct hci_dev *hdev, u8 status)
> >
> > static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
> > {
> > -     __u8 status = *((__u8 *) skb->data);
> >       struct discovery_state *discov = &hdev->discovery;
> >       struct inquiry_entry *e;
> > +     __u8 status;
> >
> > +     if (unlikely(!pskb_may_pull(skb, 1)))
> > +             return;
> > +     status = *((__u8 *)skb->data);
> >       BT_DBG("%s status 0x%2.2x", hdev->name, status);
> >
> >       hci_conn_check_pending(hdev);
> > @@ -2391,14 +2394,21 @@ static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
> > static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
> > {
> >       struct inquiry_data data;
> > -     struct inquiry_info *info = (void *) (skb->data + 1);
> > -     int num_rsp = *((__u8 *) skb->data);
> > +     struct inquiry_info *info;
> > +     int num_rsp;
> >
> >       BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
> >
> > +     if (unlikely(!pskb_may_pull(skb, 1)))
> > +             return;
> > +     num_rsp = *((__u8 *)skb->data);
> >       if (!num_rsp)
> >               return;
> >
> > +     if (unlikely(!pskb_may_pull(skb, 1 + num_rsp * sizeof(*info))))
> > +             return;
> > +     info = (void *)(skb->data + 1);
> > +
> >       if (hci_dev_test_flag(hdev, HCI_PERIODIC_INQ))
> >               return;
>
> this really looks like we better create a macro for this. It is repetitive code that can be turned into just a macro usage.

Hmm, I have no idea on how to make a macro for this, any hints?

By the way, we use the similar pattern in networking code, I am not
aware of any macro there.

Thanks.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Patch net v2 2/3] bluetooth: validate HCI_EV_LE_META packet carefully
  2019-03-21  6:12 [Patch net v2 0/3] bluetooth: validate packet boundary carefully Cong Wang
@ 2019-03-21  6:12 ` Cong Wang
  0 siblings, 0 replies; 10+ messages in thread
From: Cong Wang @ 2019-03-21  6:12 UTC (permalink / raw)
  To: netdev; +Cc: Cong Wang, Marcel Holtmann, Johan Hedberg

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@holtmann.org>
Cc: Johan Hedberg <johan.hedberg@gmail.com>
Signed-off-by: Cong Wang <xiyou.wangcong@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


^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2019-04-24  1:36 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-03 23:08 [Patch net v2 0/3] bluetooth: validate packet boundary carefully Cong Wang
2019-04-03 23:08 ` [Patch net v2 1/3] bluetooth: validate HCI_EVENT_PKT packet carefully Cong Wang
2019-04-23 19:42   ` Marcel Holtmann
2019-04-24  1:36     ` Cong Wang
2019-04-03 23:08 ` [Patch net v2 2/3] bluetooth: validate HCI_EV_LE_META " Cong Wang
2019-04-04  8:34   ` Dan Carpenter
2019-04-05 17:26     ` Cong Wang
2019-04-05 20:09       ` Dan Carpenter
2019-04-03 23:08 ` [Patch net v2 3/3] bluetooth: validate HCI_EV_CMD_COMPLETE " Cong Wang
  -- strict thread matches above, loose matches on Subject: below --
2019-03-21  6:12 [Patch net v2 0/3] bluetooth: validate packet boundary carefully Cong Wang
2019-03-21  6:12 ` [Patch net v2 2/3] bluetooth: validate HCI_EV_LE_META packet carefully Cong Wang

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.