qcacmn: Fix use after free for vdev in tdls

When disconnect happens, TDLS_NOTIFY_STA_DISCONNECTION will be
send to scheduler_thread, in bad case, it is processed after
3s later, and the vdev passed in notify msg has been freed in
the period, invalid vdev causes invalid memory access.

change as below:
 1.1 Get vdev ref before send msg
 1.2 register callback for release ref
 1.3 send msg to scheduler_thread
 1.4 process tdls notify msg and call callback function.

Change-Id: I2b03db8b30db623796f2e8299f14ee31e28efb91
CRs-Fixed: 2275019
This commit is contained in:
Jingxiang Ge
2018-07-13 15:16:03 +08:00
committed by nshrivas
parent dad6b5beb3
commit 2b64e4d5ff
6 changed files with 109 additions and 50 deletions

View File

@@ -128,20 +128,55 @@ void hdd_notify_tdls_reset_adapter(struct wlan_objmgr_vdev *vdev)
ucfg_tdls_notify_reset_adapter(vdev);
}
static void hdd_notify_sta_connect_callback(struct wlan_objmgr_vdev *vdev)
{
if (!vdev) {
cfg80211_err("vdev is NULL");
return;
}
wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
}
void
hdd_notify_sta_connect(uint8_t session_id,
bool tdls_chan_swit_prohibited,
bool tdls_prohibited,
struct wlan_objmgr_vdev *vdev)
{
struct tdls_sta_notify_params notify_info;
struct tdls_sta_notify_params notify_info = {0};
QDF_STATUS status;
if (!vdev) {
cfg80211_err("vdev is NULL");
return;
}
status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID);
if (QDF_IS_STATUS_ERROR(status)) {
cfg80211_err("can't get vdev");
return;
}
notify_info.session_id = session_id;
notify_info.vdev = vdev;
notify_info.tdls_chan_swit_prohibited = tdls_chan_swit_prohibited;
notify_info.tdls_prohibited = tdls_prohibited;
ucfg_tdls_notify_sta_connect(&notify_info);
notify_info.callback = hdd_notify_sta_connect_callback;
status = ucfg_tdls_notify_sta_connect(&notify_info);
if (QDF_IS_STATUS_ERROR(status)) {
cfg80211_err("ucfg_tdls_notify_sta_connect failed");
wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
}
}
static void hdd_notify_sta_disconnect_callback(struct wlan_objmgr_vdev *vdev)
{
if (!vdev) {
cfg80211_err("vdev is NULL");
return;
}
wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
}
void hdd_notify_sta_disconnect(uint8_t session_id,
@@ -149,14 +184,32 @@ void hdd_notify_sta_disconnect(uint8_t session_id,
bool user_disconnect,
struct wlan_objmgr_vdev *vdev)
{
struct tdls_sta_notify_params notify_info;
struct tdls_sta_notify_params notify_info = {0};
QDF_STATUS status;
if (!vdev) {
cfg80211_err("vdev is NULL");
return;
}
status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID);
if (QDF_IS_STATUS_ERROR(status)) {
cfg80211_err("can't get vdev");
return;
}
notify_info.session_id = session_id;
notify_info.lfr_roam = lfr_roam;
notify_info.tdls_chan_swit_prohibited = false;
notify_info.tdls_prohibited = false;
notify_info.vdev = vdev;
notify_info.user_disconnect = user_disconnect;
ucfg_tdls_notify_sta_disconnect(&notify_info);
notify_info.callback = hdd_notify_sta_disconnect_callback;
status = ucfg_tdls_notify_sta_disconnect(&notify_info);
if (QDF_IS_STATUS_ERROR(status)) {
cfg80211_err("ucfg_tdls_notify_sta_disconnect failed");
wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
}
}
int wlan_cfg80211_tdls_add_peer(struct wlan_objmgr_pdev *pdev,
struct net_device *dev, const uint8_t *mac)