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
Este commit está contenido en:
@@ -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(¬ify_info);
|
||||
notify_info.callback = hdd_notify_sta_connect_callback;
|
||||
status = ucfg_tdls_notify_sta_connect(¬ify_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(¬ify_info);
|
||||
|
||||
notify_info.callback = hdd_notify_sta_disconnect_callback;
|
||||
status = ucfg_tdls_notify_sta_disconnect(¬ify_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)
|
||||
|
@@ -901,19 +901,16 @@ QDF_STATUS tdls_notify_sta_connect(struct tdls_sta_notify_params *notify)
|
||||
{
|
||||
QDF_STATUS status;
|
||||
|
||||
if (!notify || !notify->vdev)
|
||||
return QDF_STATUS_E_INVAL;
|
||||
|
||||
if (QDF_STATUS_SUCCESS != wlan_objmgr_vdev_try_get_ref(notify->vdev,
|
||||
WLAN_TDLS_NB_ID)) {
|
||||
qdf_mem_free(notify);
|
||||
if (!notify || !notify->vdev) {
|
||||
tdls_err("invalid param");
|
||||
return QDF_STATUS_E_INVAL;
|
||||
}
|
||||
|
||||
status = tdls_process_sta_connect(notify);
|
||||
|
||||
wlan_objmgr_vdev_release_ref(notify->vdev,
|
||||
WLAN_TDLS_NB_ID);
|
||||
if (notify->callback)
|
||||
notify->callback(notify->vdev);
|
||||
|
||||
qdf_mem_free(notify);
|
||||
return status;
|
||||
}
|
||||
@@ -993,19 +990,15 @@ QDF_STATUS tdls_notify_sta_disconnect(struct tdls_sta_notify_params *notify)
|
||||
{
|
||||
QDF_STATUS status;
|
||||
|
||||
if (!notify || !notify->vdev)
|
||||
return QDF_STATUS_E_INVAL;
|
||||
|
||||
if (QDF_STATUS_SUCCESS != wlan_objmgr_vdev_try_get_ref(notify->vdev,
|
||||
WLAN_TDLS_NB_ID)) {
|
||||
qdf_mem_free(notify);
|
||||
if (!notify || !notify->vdev) {
|
||||
tdls_err("invalid param");
|
||||
return QDF_STATUS_E_INVAL;
|
||||
}
|
||||
|
||||
status = tdls_process_sta_disconnect(notify);
|
||||
|
||||
wlan_objmgr_vdev_release_ref(notify->vdev,
|
||||
WLAN_TDLS_NB_ID);
|
||||
if (notify->callback)
|
||||
notify->callback(notify->vdev);
|
||||
|
||||
qdf_mem_free(notify);
|
||||
return status;
|
||||
@@ -1127,8 +1120,8 @@ void tdls_notify_reset_adapter(struct wlan_objmgr_vdev *vdev)
|
||||
wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID);
|
||||
}
|
||||
|
||||
void tdls_peers_deleted_notification(struct wlan_objmgr_vdev *vdev,
|
||||
uint32_t session_id)
|
||||
QDF_STATUS tdls_peers_deleted_notification(
|
||||
struct tdls_sta_notify_params *notify_info)
|
||||
{
|
||||
struct scheduler_msg msg = {0, };
|
||||
struct tdls_sta_notify_params *notify;
|
||||
@@ -1137,15 +1130,10 @@ void tdls_peers_deleted_notification(struct wlan_objmgr_vdev *vdev,
|
||||
notify = qdf_mem_malloc(sizeof(*notify));
|
||||
if (!notify) {
|
||||
tdls_err("memory allocation failed !!!");
|
||||
return;
|
||||
return QDF_STATUS_E_NULL_VALUE;
|
||||
}
|
||||
|
||||
notify->lfr_roam = true;
|
||||
notify->tdls_chan_swit_prohibited = false;
|
||||
notify->tdls_prohibited = false;
|
||||
notify->session_id = session_id;
|
||||
notify->vdev = vdev;
|
||||
notify->user_disconnect = false;
|
||||
*notify = *notify_info;
|
||||
|
||||
msg.bodyptr = notify;
|
||||
msg.callback = tdls_process_cmd;
|
||||
@@ -1155,7 +1143,10 @@ void tdls_peers_deleted_notification(struct wlan_objmgr_vdev *vdev,
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
qdf_mem_free(notify);
|
||||
tdls_alert("message post failed ");
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
}
|
||||
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -584,17 +584,16 @@ void tdls_notify_reset_adapter(struct wlan_objmgr_vdev *vdev);
|
||||
|
||||
/**
|
||||
* tdls_peers_deleted_notification() - peer delete notification
|
||||
* @vdev: vdev object
|
||||
* @session_id: session id
|
||||
* @notify_info: peer info
|
||||
*
|
||||
* Legacy lim layer will delete tdls peers for roaming and heart beat failures
|
||||
* and notify the component about the delete event to update the tdls.
|
||||
* state.
|
||||
*
|
||||
* Return: None
|
||||
* Return: QDF_STATUS
|
||||
*/
|
||||
void tdls_peers_deleted_notification(struct wlan_objmgr_vdev *vdev,
|
||||
uint32_t session_id);
|
||||
QDF_STATUS tdls_peers_deleted_notification(
|
||||
struct tdls_sta_notify_params *notify_info);
|
||||
|
||||
/**
|
||||
* tdls_notify_decrement_session() - Notify the session decrement
|
||||
|
@@ -563,6 +563,9 @@ typedef QDF_STATUS
|
||||
uint32_t vdev_param,
|
||||
bool is_link_up);
|
||||
|
||||
/* This callback is to release vdev ref for tdls sta notify msg */
|
||||
typedef void (*tdls_sta_notify_callback)(struct wlan_objmgr_vdev *vdev);
|
||||
|
||||
/**
|
||||
* struct tdls_start_params - tdls start params
|
||||
* @config: tdls user config
|
||||
@@ -1041,6 +1044,7 @@ struct tdls_sta_notify_params {
|
||||
bool lfr_roam;
|
||||
bool user_disconnect;
|
||||
uint8_t session_id;
|
||||
tdls_sta_notify_callback callback;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -329,10 +329,23 @@ release_nbuf:
|
||||
return status;
|
||||
}
|
||||
|
||||
static void tgt_tdls_peers_deleted_notification_callback(
|
||||
struct wlan_objmgr_vdev *vdev)
|
||||
{
|
||||
if (!vdev) {
|
||||
tdls_err("vdev is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID);
|
||||
}
|
||||
|
||||
void tgt_tdls_peers_deleted_notification(struct wlan_objmgr_psoc *psoc,
|
||||
uint32_t session_id)
|
||||
{
|
||||
struct wlan_objmgr_vdev *vdev;
|
||||
struct tdls_sta_notify_params notify_info;
|
||||
QDF_STATUS status;
|
||||
|
||||
vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
|
||||
session_id,
|
||||
@@ -344,9 +357,17 @@ void tgt_tdls_peers_deleted_notification(struct wlan_objmgr_psoc *psoc,
|
||||
return;
|
||||
}
|
||||
|
||||
tdls_peers_deleted_notification(vdev, session_id);
|
||||
|
||||
wlan_objmgr_vdev_release_ref(vdev,
|
||||
WLAN_TDLS_SB_ID);
|
||||
notify_info.lfr_roam = true;
|
||||
notify_info.tdls_chan_swit_prohibited = false;
|
||||
notify_info.tdls_prohibited = false;
|
||||
notify_info.session_id = session_id;
|
||||
notify_info.vdev = vdev;
|
||||
notify_info.user_disconnect = false;
|
||||
notify_info.callback = tgt_tdls_peers_deleted_notification_callback;
|
||||
status = tdls_peers_deleted_notification(¬ify_info);
|
||||
if (QDF_IS_STATUS_ERROR(status)) {
|
||||
tdls_err("tdls_peers_deleted_notification failed");
|
||||
wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -627,11 +627,7 @@ QDF_STATUS ucfg_tdls_notify_sta_connect(
|
||||
if (!notify)
|
||||
return QDF_STATUS_E_NULL_VALUE;
|
||||
|
||||
notify->session_id = notify_info->session_id;
|
||||
notify->tdls_chan_swit_prohibited =
|
||||
notify_info->tdls_chan_swit_prohibited;
|
||||
notify->tdls_prohibited = notify_info->tdls_prohibited;
|
||||
notify->vdev = notify_info->vdev;
|
||||
*notify = *notify_info;
|
||||
|
||||
msg.bodyptr = notify;
|
||||
msg.callback = tdls_process_cmd;
|
||||
@@ -659,12 +655,7 @@ QDF_STATUS ucfg_tdls_notify_sta_disconnect(
|
||||
if (!notify)
|
||||
return QDF_STATUS_E_NULL_VALUE;
|
||||
|
||||
notify->session_id = notify_info->session_id;
|
||||
notify->tdls_chan_swit_prohibited = false;
|
||||
notify->tdls_prohibited = false;
|
||||
notify->vdev = notify_info->vdev;
|
||||
notify->lfr_roam = notify_info->lfr_roam;
|
||||
notify->user_disconnect = notify_info->user_disconnect;
|
||||
*notify = *notify_info;
|
||||
|
||||
msg.bodyptr = notify;
|
||||
msg.callback = tdls_process_cmd;
|
||||
|
Referencia en una nueva incidencia
Block a user