Message ID | 20211202231123.v7.1.Ic0a40b84dee3825302890aaea690e73165c71820@changeid |
---|---|
State | New |
Headers | show |
Series | [v7,1/2] bluetooth: Handle MSFT Monitor Device Event | expand |
Hi Manish, url: https://github.com/0day-ci/linux/commits/Manish-Mandlik/bluetooth-Handle-MSFT-Monitor-Device-Event/20211203-151659 base: https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master config: x86_64-randconfig-m001-20211203 (https://download.01.org/0day-ci/archive/20211205/202112050416.RYsEcWkk-lkp@intel.com/config) compiler: gcc-9 (Debian 9.3.0-22) 9.3.0 If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> Reported-by: Dan Carpenter <dan.carpenter@oracle.com> smatch warnings: net/bluetooth/msft.c:312 msft_le_cancel_monitor_advertisement_cb() error: dereferencing freed memory 'handle_data' vim +/handle_data +312 net/bluetooth/msft.c 182ee45da083db Luiz Augusto von Dentz 2021-10-27 266 static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev, 182ee45da083db Luiz Augusto von Dentz 2021-10-27 267 u8 status, u16 opcode, 182ee45da083db Luiz Augusto von Dentz 2021-10-27 268 struct sk_buff *skb) ce81843be24e9d Manish Mandlik 2021-09-21 269 { 182ee45da083db Luiz Augusto von Dentz 2021-10-27 270 struct msft_cp_le_cancel_monitor_advertisement *cp; 182ee45da083db Luiz Augusto von Dentz 2021-10-27 271 struct msft_rp_le_cancel_monitor_advertisement *rp; 182ee45da083db Luiz Augusto von Dentz 2021-10-27 272 struct adv_monitor *monitor; 182ee45da083db Luiz Augusto von Dentz 2021-10-27 273 struct msft_monitor_advertisement_handle_data *handle_data; ce81843be24e9d Manish Mandlik 2021-09-21 274 struct msft_data *msft = hdev->msft_data; 182ee45da083db Luiz Augusto von Dentz 2021-10-27 275 int err; 182ee45da083db Luiz Augusto von Dentz 2021-10-27 276 bool pending; eb96f195e598b7 Manish Mandlik 2021-12-02 277 struct monitored_device *dev, *tmp; ce81843be24e9d Manish Mandlik 2021-09-21 278 182ee45da083db Luiz Augusto von Dentz 2021-10-27 279 if (status) 182ee45da083db Luiz Augusto von Dentz 2021-10-27 280 goto done; 182ee45da083db Luiz Augusto von Dentz 2021-10-27 281 182ee45da083db Luiz Augusto von Dentz 2021-10-27 282 rp = (struct msft_rp_le_cancel_monitor_advertisement *)skb->data; 182ee45da083db Luiz Augusto von Dentz 2021-10-27 283 if (skb->len < sizeof(*rp)) { 182ee45da083db Luiz Augusto von Dentz 2021-10-27 284 status = HCI_ERROR_UNSPECIFIED; 182ee45da083db Luiz Augusto von Dentz 2021-10-27 285 goto done; 182ee45da083db Luiz Augusto von Dentz 2021-10-27 286 } 182ee45da083db Luiz Augusto von Dentz 2021-10-27 287 182ee45da083db Luiz Augusto von Dentz 2021-10-27 288 hci_dev_lock(hdev); 182ee45da083db Luiz Augusto von Dentz 2021-10-27 289 182ee45da083db Luiz Augusto von Dentz 2021-10-27 290 cp = hci_sent_cmd_data(hdev, hdev->msft_opcode); 182ee45da083db Luiz Augusto von Dentz 2021-10-27 291 handle_data = msft_find_handle_data(hdev, cp->handle, false); 182ee45da083db Luiz Augusto von Dentz 2021-10-27 292 182ee45da083db Luiz Augusto von Dentz 2021-10-27 293 if (handle_data) { 182ee45da083db Luiz Augusto von Dentz 2021-10-27 294 monitor = idr_find(&hdev->adv_monitors_idr, 182ee45da083db Luiz Augusto von Dentz 2021-10-27 295 handle_data->mgmt_handle); 182ee45da083db Luiz Augusto von Dentz 2021-10-27 296 182ee45da083db Luiz Augusto von Dentz 2021-10-27 297 if (monitor && monitor->state == ADV_MONITOR_STATE_OFFLOADED) 182ee45da083db Luiz Augusto von Dentz 2021-10-27 298 monitor->state = ADV_MONITOR_STATE_REGISTERED; 182ee45da083db Luiz Augusto von Dentz 2021-10-27 299 182ee45da083db Luiz Augusto von Dentz 2021-10-27 300 /* Do not free the monitor if it is being removed due to 182ee45da083db Luiz Augusto von Dentz 2021-10-27 301 * suspend. It will be re-monitored on resume. 182ee45da083db Luiz Augusto von Dentz 2021-10-27 302 */ 182ee45da083db Luiz Augusto von Dentz 2021-10-27 303 if (monitor && !msft->suspending) 182ee45da083db Luiz Augusto von Dentz 2021-10-27 304 hci_free_adv_monitor(hdev, monitor); 182ee45da083db Luiz Augusto von Dentz 2021-10-27 305 182ee45da083db Luiz Augusto von Dentz 2021-10-27 306 list_del(&handle_data->list); 182ee45da083db Luiz Augusto von Dentz 2021-10-27 307 kfree(handle_data); ^^^^^^^^^^^^^^^^^^ Free eb96f195e598b7 Manish Mandlik 2021-12-02 308 eb96f195e598b7 Manish Mandlik 2021-12-02 309 /* Clear any monitored devices by this Adv Monitor */ eb96f195e598b7 Manish Mandlik 2021-12-02 310 list_for_each_entry_safe(dev, tmp, &hdev->monitored_devices, eb96f195e598b7 Manish Mandlik 2021-12-02 311 list) { eb96f195e598b7 Manish Mandlik 2021-12-02 @312 if (dev->handle == handle_data->mgmt_handle) { ^^^^^^^^^^^^^^^^^^^^^^^^ Use after free. eb96f195e598b7 Manish Mandlik 2021-12-02 313 list_del(&dev->list); eb96f195e598b7 Manish Mandlik 2021-12-02 314 kfree(dev); eb96f195e598b7 Manish Mandlik 2021-12-02 315 } eb96f195e598b7 Manish Mandlik 2021-12-02 316 } 182ee45da083db Luiz Augusto von Dentz 2021-10-27 317 } 182ee45da083db Luiz Augusto von Dentz 2021-10-27 318 182ee45da083db Luiz Augusto von Dentz 2021-10-27 319 /* If remove all monitors is required, we need to continue the process 182ee45da083db Luiz Augusto von Dentz 2021-10-27 320 * here because the earlier it was paused when waiting for the 182ee45da083db Luiz Augusto von Dentz 2021-10-27 321 * response from controller. 182ee45da083db Luiz Augusto von Dentz 2021-10-27 322 */ 182ee45da083db Luiz Augusto von Dentz 2021-10-27 323 if (msft->pending_remove_handle == 0) { 182ee45da083db Luiz Augusto von Dentz 2021-10-27 324 pending = hci_remove_all_adv_monitor(hdev, &err); 182ee45da083db Luiz Augusto von Dentz 2021-10-27 325 if (pending) { 182ee45da083db Luiz Augusto von Dentz 2021-10-27 326 hci_dev_unlock(hdev); ce81843be24e9d Manish Mandlik 2021-09-21 327 return; 182ee45da083db Luiz Augusto von Dentz 2021-10-27 328 } 182ee45da083db Luiz Augusto von Dentz 2021-10-27 329 182ee45da083db Luiz Augusto von Dentz 2021-10-27 330 if (err) 182ee45da083db Luiz Augusto von Dentz 2021-10-27 331 status = HCI_ERROR_UNSPECIFIED; 182ee45da083db Luiz Augusto von Dentz 2021-10-27 332 } 182ee45da083db Luiz Augusto von Dentz 2021-10-27 333 182ee45da083db Luiz Augusto von Dentz 2021-10-27 334 hci_dev_unlock(hdev); 182ee45da083db Luiz Augusto von Dentz 2021-10-27 335 182ee45da083db Luiz Augusto von Dentz 2021-10-27 336 done: 182ee45da083db Luiz Augusto von Dentz 2021-10-27 337 if (!msft->suspending) 182ee45da083db Luiz Augusto von Dentz 2021-10-27 338 hci_remove_adv_monitor_complete(hdev, status); 182ee45da083db Luiz Augusto von Dentz 2021-10-27 339 } --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 7bae8376fd6f..5ccd19dec77c 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -258,6 +258,15 @@ struct adv_info { #define HCI_ADV_TX_POWER_NO_PREFERENCE 0x7F +struct monitored_device { + struct list_head list; + + bdaddr_t bdaddr; + __u8 addr_type; + __u16 handle; + bool notified; +}; + struct adv_pattern { struct list_head list; __u8 ad_type; @@ -589,6 +598,8 @@ struct hci_dev { struct delayed_work interleave_scan; + struct list_head monitored_devices; + #if IS_ENABLED(CONFIG_BT_LEDS) struct led_trigger *power_led; #endif diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index fdc0dcf8ee36..d4bcd511530a 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2503,6 +2503,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv) INIT_LIST_HEAD(&hdev->conn_hash.list); INIT_LIST_HEAD(&hdev->adv_instances); INIT_LIST_HEAD(&hdev->blocked_keys); + INIT_LIST_HEAD(&hdev->monitored_devices); INIT_LIST_HEAD(&hdev->local_codecs); INIT_WORK(&hdev->rx_work, hci_rx_work); diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c index 1122097e1e49..aadabe78baf6 100644 --- a/net/bluetooth/msft.c +++ b/net/bluetooth/msft.c @@ -80,6 +80,14 @@ struct msft_rp_le_set_advertisement_filter_enable { __u8 sub_opcode; } __packed; +#define MSFT_EV_LE_MONITOR_DEVICE 0x02 +struct msft_ev_le_monitor_device { + __u8 addr_type; + bdaddr_t bdaddr; + __u8 monitor_handle; + __u8 monitor_state; +} __packed; + struct msft_monitor_advertisement_handle_data { __u8 msft_handle; __u16 mgmt_handle; @@ -266,6 +274,7 @@ static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev, struct msft_data *msft = hdev->msft_data; int err; bool pending; + struct monitored_device *dev, *tmp; if (status) goto done; @@ -296,6 +305,15 @@ static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev, list_del(&handle_data->list); kfree(handle_data); + + /* Clear any monitored devices by this Adv Monitor */ + list_for_each_entry_safe(dev, tmp, &hdev->monitored_devices, + list) { + if (dev->handle == handle_data->mgmt_handle) { + list_del(&dev->list); + kfree(dev); + } + } } /* If remove all monitors is required, we need to continue the process @@ -538,6 +556,7 @@ void msft_do_close(struct hci_dev *hdev) struct msft_data *msft = hdev->msft_data; struct msft_monitor_advertisement_handle_data *handle_data, *tmp; struct adv_monitor *monitor; + struct monitored_device *dev, *tmp_dev; if (!msft) return; @@ -557,6 +576,16 @@ void msft_do_close(struct hci_dev *hdev) list_del(&handle_data->list); kfree(handle_data); } + + hci_dev_lock(hdev); + + /* Clear any devices that are being monitored */ + list_for_each_entry_safe(dev, tmp_dev, &hdev->monitored_devices, list) { + list_del(&dev->list); + kfree(dev); + } + + hci_dev_unlock(hdev); } void msft_register(struct hci_dev *hdev) @@ -590,6 +619,90 @@ void msft_unregister(struct hci_dev *hdev) kfree(msft); } +/* This function requires the caller holds hdev->lock */ +static void msft_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, + __u8 addr_type, __u16 mgmt_handle) +{ + struct monitored_device *dev; + + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + bt_dev_err(hdev, "MSFT vendor event %u: no memory", + MSFT_EV_LE_MONITOR_DEVICE); + return; + } + + bacpy(&dev->bdaddr, bdaddr); + dev->addr_type = addr_type; + dev->handle = mgmt_handle; + dev->notified = false; + + INIT_LIST_HEAD(&dev->list); + list_add(&dev->list, &hdev->monitored_devices); +} + +/* This function requires the caller holds hdev->lock */ +static void msft_device_lost(struct hci_dev *hdev, bdaddr_t *bdaddr, + __u8 addr_type, __u16 mgmt_handle) +{ + struct monitored_device *dev, *tmp; + + list_for_each_entry_safe(dev, tmp, &hdev->monitored_devices, list) { + if (dev->handle == mgmt_handle) { + list_del(&dev->list); + kfree(dev); + + break; + } + } +} + +/* This function requires the caller holds hdev->lock */ +static void msft_monitor_device_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct msft_ev_le_monitor_device *ev = (void *)skb->data; + struct msft_monitor_advertisement_handle_data *handle_data; + u8 addr_type; + + if (skb->len < sizeof(*ev)) { + bt_dev_err(hdev, + "MSFT vendor event %u: insufficient data (len: %u)", + MSFT_EV_LE_MONITOR_DEVICE, skb->len); + return; + } + skb_pull(skb, sizeof(*ev)); + + bt_dev_dbg(hdev, + "MSFT vendor event %u: handle 0x%04x state %d addr %pMR", + MSFT_EV_LE_MONITOR_DEVICE, ev->monitor_handle, + ev->monitor_state, &ev->bdaddr); + + handle_data = msft_find_handle_data(hdev, ev->monitor_handle, false); + + switch (ev->addr_type) { + case ADDR_LE_DEV_PUBLIC: + addr_type = BDADDR_LE_PUBLIC; + break; + + case ADDR_LE_DEV_RANDOM: + addr_type = BDADDR_LE_RANDOM; + break; + + default: + bt_dev_err(hdev, + "MSFT vendor event %u: unknown addr type 0x%02x", + MSFT_EV_LE_MONITOR_DEVICE, ev->addr_type); + return; + } + + if (ev->monitor_state) + msft_device_found(hdev, &ev->bdaddr, addr_type, + handle_data->mgmt_handle); + else + msft_device_lost(hdev, &ev->bdaddr, addr_type, + handle_data->mgmt_handle); +} + void msft_vendor_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct msft_data *msft = hdev->msft_data; @@ -617,10 +730,22 @@ void msft_vendor_evt(struct hci_dev *hdev, struct sk_buff *skb) if (skb->len < 1) return; + hci_dev_lock(hdev); + event = *skb->data; skb_pull(skb, 1); - bt_dev_dbg(hdev, "MSFT vendor event %u", event); + switch (event) { + case MSFT_EV_LE_MONITOR_DEVICE: + msft_monitor_device_evt(hdev, skb); + break; + + default: + bt_dev_dbg(hdev, "MSFT vendor event %u", event); + break; + } + + hci_dev_unlock(hdev); } __u64 msft_get_features(struct hci_dev *hdev)