From e449244e9f772eab8a31be3bacfc036029f13c94 Mon Sep 17 00:00:00 2001 From: Pragaspathi Thilagaraj Date: Wed, 16 May 2018 18:51:32 +0530 Subject: [PATCH 1/4] qcacmn: Fix possible buffer overflow in send_stats_ext_req_cmd_tlv In the function __wlan_hdd_cfg80211_stats_ext_request, data_len is recieved from vendor command and is passed ultimately to send_stats_ext_req_cmd_tlv. In send_stats_ext_req_cmd_tlv, len is calculated as sum of sizeof(*cmd), WMI_TLV_HDR_SIZE, preq->request_data_len.The len is of type uint16_t and adding sizeof(*cmd) + WMI_TLV_HDR_SIZE will cause a buffer overflow. Changed the datatype of len to size_t so that it doesn't overflow. Change-Id: I6618042e3c60bbdb1ff5d833188f4bdb4832da7a CRs-Fixed: 2243169 --- wmi/src/wmi_unified_tlv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wmi/src/wmi_unified_tlv.c b/wmi/src/wmi_unified_tlv.c index 4397b32d4f..864850ce0d 100644 --- a/wmi/src/wmi_unified_tlv.c +++ b/wmi/src/wmi_unified_tlv.c @@ -9294,7 +9294,7 @@ static QDF_STATUS send_stats_ext_req_cmd_tlv(wmi_unified_t wmi_handle, QDF_STATUS ret; wmi_req_stats_ext_cmd_fixed_param *cmd; wmi_buf_t buf; - uint16_t len; + size_t len; uint8_t *buf_ptr; len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + preq->request_data_len; From 3bdf380c03c06018010418abea29e7f1b1521ce7 Mon Sep 17 00:00:00 2001 From: Krunal Soni Date: Wed, 20 Jun 2018 16:45:03 -0700 Subject: [PATCH 2/4] qcacmn: Don't process scan command when vdev delete is in process When driver performs vdev delete operation, it changes vdev state to logically deleted or physically deleted only after receiving vdev delete command's response from FW. In between (sending vdev del req and receiving vdev del rsp) if thread gets pre-empted and other thread start posting command (like scan command) to process then it could lead to use after free scenario. Notify scan component when vdev delete is intiated and let scan component record that in to vdev's scan private object as one of the flags. check this flag before processing the scan command. CRs-Fixed: 2261704 Change-Id: Id884d6c42cd8766e70835808863632e096158487 --- umac/scan/core/src/wlan_scan_main.h | 2 + umac/scan/core/src/wlan_scan_manager.c | 39 +++++++++++++------ umac/scan/dispatcher/inc/wlan_scan_ucfg_api.h | 15 +++++++ umac/scan/dispatcher/src/wlan_scan_ucfg_api.c | 32 +++++++++++++++ 4 files changed, 76 insertions(+), 12 deletions(-) diff --git a/umac/scan/core/src/wlan_scan_main.h b/umac/scan/core/src/wlan_scan_main.h index caa38c6de7..2da8cdad83 100644 --- a/umac/scan/core/src/wlan_scan_main.h +++ b/umac/scan/core/src/wlan_scan_main.h @@ -219,10 +219,12 @@ struct pdev_scan_info { * struct scan_vdev_obj - scan vdev obj * @pno_match_evt_received: pno match received * @pno_in_progress: pno in progress + * @is_vdev_delete_in_progress: flag to indicate if vdev del is in progress */ struct scan_vdev_obj { bool pno_match_evt_received; bool pno_in_progress; + bool is_vdev_delete_in_progress; }; /** diff --git a/umac/scan/core/src/wlan_scan_manager.c b/umac/scan/core/src/wlan_scan_manager.c index 3bbe50564d..5dbe64cf4e 100644 --- a/umac/scan/core/src/wlan_scan_manager.c +++ b/umac/scan/core/src/wlan_scan_manager.c @@ -369,8 +369,9 @@ scm_scan_start_req(struct scheduler_msg *msg) { struct wlan_serialization_command cmd = {0, }; enum wlan_serialization_status ser_cmd_status; - struct scan_start_request *req; + struct scan_start_request *req = NULL; struct wlan_scan_obj *scan_obj; + struct scan_vdev_obj *scan_vdev_priv_obj; QDF_STATUS status = QDF_STATUS_SUCCESS; if (!msg) { @@ -388,7 +389,8 @@ scm_scan_start_req(struct scheduler_msg *msg) scan_obj = wlan_vdev_get_scan_obj(req->vdev); if (!scan_obj) { scm_debug("Couldn't find scan object"); - return QDF_STATUS_E_NULL_VALUE; + status = QDF_STATUS_E_NULL_VALUE; + goto err; } cmd.cmd_type = WLAN_SER_CMD_SCAN; @@ -409,6 +411,18 @@ scm_scan_start_req(struct scheduler_msg *msg) req, req->scan_req.scan_req_id, req->scan_req.scan_id, req->scan_req.vdev_id); + scan_vdev_priv_obj = wlan_get_vdev_scan_obj(req->vdev); + if (!scan_vdev_priv_obj) { + scm_debug("Couldn't find scan priv object"); + status = QDF_STATUS_E_NULL_VALUE; + goto err; + } + if (scan_vdev_priv_obj->is_vdev_delete_in_progress) { + scm_err("Can't allow scan on vdev_id:%d", + wlan_vdev_get_id(req->vdev)); + status = QDF_STATUS_E_NULL_VALUE; + goto err; + } ser_cmd_status = wlan_serialization_request(&cmd); scm_info("wlan_serialization_request status:%d", ser_cmd_status); @@ -427,21 +441,22 @@ scm_scan_start_req(struct scheduler_msg *msg) */ scm_post_internal_scan_complete_event(req, SCAN_REASON_INTERNAL_FAILURE); - /* cmd can't be serviced. - * release vdev reference and free scan_start_request memory - */ - wlan_objmgr_vdev_release_ref(req->vdev, WLAN_SCAN_ID); - scm_scan_free_scan_request_mem(req); - break; + goto err; default: QDF_ASSERT(0); status = QDF_STATUS_E_INVAL; - /* cmd can't be serviced. - * release vdev reference and free scan_start_request memory - */ + goto err; + } + + return status; +err: + /* + * cmd can't be serviced. + * release vdev reference and free scan_start_request memory + */ + if (req) { wlan_objmgr_vdev_release_ref(req->vdev, WLAN_SCAN_ID); scm_scan_free_scan_request_mem(req); - break; } return status; diff --git a/umac/scan/dispatcher/inc/wlan_scan_ucfg_api.h b/umac/scan/dispatcher/inc/wlan_scan_ucfg_api.h index 5eb8f371f3..e9b9bb50c4 100644 --- a/umac/scan/dispatcher/inc/wlan_scan_ucfg_api.h +++ b/umac/scan/dispatcher/inc/wlan_scan_ucfg_api.h @@ -590,4 +590,19 @@ void ucfg_scan_set_bt_activity(struct wlan_objmgr_psoc *psoc, * Return: true if enabled else false. */ bool ucfg_scan_get_bt_activity(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_scan_set_vdev_del_in_progress() - API to mark vdev delete in progress + * @vdev: pointer to vdev object + * + * Return: none + */ +void ucfg_scan_set_vdev_del_in_progress(struct wlan_objmgr_vdev *vdev); +/** + * ucfg_scan_clear_vdev_del_in_progress() - API to reset vdev delete in progress + * @vdev: pointer to vdev object + * + * Return: none + */ +void ucfg_scan_clear_vdev_del_in_progress(struct wlan_objmgr_vdev *vdev); #endif diff --git a/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c b/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c index 556f4147f9..0cbfba94e1 100644 --- a/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c +++ b/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c @@ -2178,6 +2178,38 @@ bool ucfg_scan_get_bt_activity(struct wlan_objmgr_psoc *psoc) return scan_obj->bt_a2dp_enabled; } +void ucfg_scan_set_vdev_del_in_progress(struct wlan_objmgr_vdev *vdev) +{ + struct scan_vdev_obj *scan_vdev_obj; + + if (!vdev) { + scm_err("invalid vdev"); + return; + } + scan_vdev_obj = wlan_get_vdev_scan_obj(vdev); + if (!scan_vdev_obj) { + scm_err("null scan_vdev_obj"); + return; + } + scan_vdev_obj->is_vdev_delete_in_progress = true; +} + +void ucfg_scan_clear_vdev_del_in_progress(struct wlan_objmgr_vdev *vdev) +{ + struct scan_vdev_obj *scan_vdev_obj; + + if (!vdev) { + scm_err("invalid vdev"); + return; + } + scan_vdev_obj = wlan_get_vdev_scan_obj(vdev); + if (!scan_vdev_obj) { + scm_err("null scan_vdev_obj"); + return; + } + scan_vdev_obj->is_vdev_delete_in_progress = false; +} + QDF_STATUS ucfg_scan_set_global_config(struct wlan_objmgr_psoc *psoc, enum scan_config config, uint32_t val) From 942f939848a43f3822f7829016c1edede488e8e9 Mon Sep 17 00:00:00 2001 From: Dustin Brown Date: Mon, 25 Jun 2018 14:34:45 -0700 Subject: [PATCH 3/4] qcacmn: Conditionally unmap nbuf in htc_issue_packets htc_issue_packets currently unmaps all nbufs during error handling. However, htc_issue_packets only maps nbufs under some situations. Make the criteria for unmapping match the criteria for mapping. Change-Id: Ia77cffb30edbdb4d1378af38368f860c6f8c0b18 CRs-Fixed: 2266437 --- htc/htc_send.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/htc/htc_send.c b/htc/htc_send.c index c58b37c109..f10b1c9073 100644 --- a/htc/htc_send.c +++ b/htc/htc_send.c @@ -633,9 +633,13 @@ static QDF_STATUS htc_issue_packets(HTC_TARGET *target, ("hif_send Failed status:%d\n", status)); } - qdf_nbuf_unmap(target->osdev, - GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket), - QDF_DMA_TO_DEVICE); + + /* only unmap if we mapped in this function */ + if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) + qdf_nbuf_unmap(target->osdev, + GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket), + QDF_DMA_TO_DEVICE); + if (!pEndpoint->async_update) { LOCK_HTC_TX(target); } From a8eefc87b9c12341e1a768b5293731f7461e32df Mon Sep 17 00:00:00 2001 From: Dustin Brown Date: Mon, 18 Jun 2018 14:01:25 -0700 Subject: [PATCH 4/4] qcacmn: Add objmgr check for pdev leaks API During objmgr psoc teardown, it would be useful to assert that there are no longer any pdevs attached. Add an API that logs a list of all pdevs attached to a given psoc, and panics if any are found. Change-Id: Ia171ae1f443c91808c1f465c2570f6d9cb2237bc CRs-Fixed: 2267143 --- .../obj_mgr/inc/wlan_objmgr_psoc_obj.h | 8 +++ .../obj_mgr/src/wlan_objmgr_psoc_obj.c | 49 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/umac/cmn_services/obj_mgr/inc/wlan_objmgr_psoc_obj.h b/umac/cmn_services/obj_mgr/inc/wlan_objmgr_psoc_obj.h index 50cfb8e6a9..242f857cbf 100644 --- a/umac/cmn_services/obj_mgr/inc/wlan_objmgr_psoc_obj.h +++ b/umac/cmn_services/obj_mgr/inc/wlan_objmgr_psoc_obj.h @@ -1436,6 +1436,14 @@ QDF_STATUS wlan_objmgr_print_ref_all_objects_per_psoc( QDF_STATUS wlan_objmgr_psoc_set_user_config(struct wlan_objmgr_psoc *psoc, struct wlan_objmgr_psoc_user_config *user_config_data); +/** + * wlan_objmgr_psoc_check_for_pdev_leaks() - Assert no pdevs attached to @psoc + * @psoc: The psoc to check + * + * Return: None + */ +void wlan_objmgr_psoc_check_for_pdev_leaks(struct wlan_objmgr_psoc *psoc); + /** * wlan_objmgr_psoc_check_for_vdev_leaks() - Assert no vdevs attached to @psoc * @psoc: The psoc to check diff --git a/umac/cmn_services/obj_mgr/src/wlan_objmgr_psoc_obj.c b/umac/cmn_services/obj_mgr/src/wlan_objmgr_psoc_obj.c index cc5cf350b1..31e29874bd 100644 --- a/umac/cmn_services/obj_mgr/src/wlan_objmgr_psoc_obj.c +++ b/umac/cmn_services/obj_mgr/src/wlan_objmgr_psoc_obj.c @@ -2005,6 +2005,55 @@ QDF_STATUS wlan_objmgr_psoc_set_user_config(struct wlan_objmgr_psoc *psoc, return QDF_STATUS_SUCCESS; } +void wlan_objmgr_psoc_check_for_pdev_leaks(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_objmgr_psoc_objmgr *_psoc; + int pdev_id; + int ref_id; + + QDF_BUG(psoc); + if (!psoc) + return; + + wlan_psoc_obj_lock(psoc); + _psoc = &psoc->soc_objmgr; + if (!_psoc->wlan_pdev_count) { + wlan_psoc_obj_unlock(psoc); + return; + } + + obj_mgr_err("objmgr pdev leaks detected for psoc %u!", _psoc->psoc_id); + obj_mgr_err("--------------------------------------------------------"); + obj_mgr_err("Pdev Id Refs Module"); + obj_mgr_err("--------------------------------------------------------"); + + for (pdev_id = 0; pdev_id < WLAN_UMAC_MAX_PDEVS; pdev_id++) { + struct wlan_objmgr_pdev *pdev = _psoc->wlan_pdev_list[pdev_id]; + qdf_atomic_t *ref_id_dbg; + + if (!pdev) + continue; + + wlan_pdev_obj_lock(pdev); + ref_id_dbg = pdev->pdev_objmgr.ref_id_dbg; + for (ref_id = 0; ref_id < WLAN_REF_ID_MAX; ref_id++) { + int32_t refs = qdf_atomic_read(&ref_id_dbg[ref_id]); + + if (refs <= 0) + continue; + + obj_mgr_err("%7u %4u x %s", + pdev_id, refs, string_from_dbgid(ref_id)); + } + wlan_pdev_obj_unlock(pdev); + } + + wlan_psoc_obj_unlock(psoc); + + QDF_DEBUG_PANIC(); +} +qdf_export_symbol(wlan_objmgr_psoc_check_for_pdev_leaks); + void wlan_objmgr_psoc_check_for_vdev_leaks(struct wlan_objmgr_psoc *psoc) { struct wlan_objmgr_psoc_objmgr *_psoc;