qcacmn: Protect pktlog under mutex to avoid possible race conditions

Protect pktlog funcitonality under given mutex to avoid possible
race condition between pktlog_release/pktlog_open and pktlogmod_exit.
Also call pktlogmod_exit before calling wdi_event_detach to avoid
accessing freed memory in pktlog release.

Change-Id: I5ca4b304d0f4dc1af289daa167958d5b773d9a6e
CRs-Fixed: 2578623
This commit is contained in:
Alok Kumar
2019-12-03 14:43:20 +05:30
committed by nshrivas
parent 19ba060714
commit a316b315d8
3 changed files with 77 additions and 30 deletions

View File

@@ -132,6 +132,9 @@ void pktlog_callback(void *pdev, enum WDI_EVENT event, void *log_data,
void pktlog_init(struct hif_opaque_softc *scn);
int pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state,
bool, uint8_t, uint32_t);
int __pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state,
bool ini_triggered, uint8_t user_triggered,
uint32_t is_iwpriv_command);
int pktlog_setsize(struct hif_opaque_softc *scn, int32_t log_state);
int pktlog_clearbuff(struct hif_opaque_softc *scn, bool clear_buff);
int pktlog_disable(struct hif_opaque_softc *scn);
@@ -171,6 +174,14 @@ static inline int pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state,
return 0;
}
static inline
int __pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state,
bool ini_triggered, uint8_t user_triggered,
uint32_t is_iwpriv_command)
{
return 0;
}
static inline int pktlog_setsize(struct hif_opaque_softc *scn,
int32_t log_state)
{

View File

@@ -506,6 +506,12 @@ static void pktlog_detach(struct hif_opaque_softc *scn)
}
pl_info = pl_dev->pl_info;
if (!pl_info) {
qdf_print("%s: Invalid pktlog handle", __func__);
ASSERT(0);
return;
}
mutex_lock(&pl_info->pktlog_mutex);
remove_proc_entry(WLANDEV_BASENAME, g_pktlog_pde);
pktlog_sysctl_unregister(pl_dev);
@@ -516,6 +522,7 @@ static void pktlog_detach(struct hif_opaque_softc *scn)
pl_dev->tgt_pktlog_alloced = false;
}
qdf_spin_unlock_bh(&pl_info->log_lock);
mutex_unlock(&pl_info->pktlog_mutex);
pktlog_cleanup(pl_info);
if (pl_dev) {
@@ -529,25 +536,12 @@ static int __pktlog_open(struct inode *i, struct file *f)
struct hif_opaque_softc *scn;
struct pktlog_dev_t *pl_dev;
struct ath_pktlog_info *pl_info;
struct ath_pktlog_info_lnx *pl_info_lnx;
int ret = 0;
PKTLOG_MOD_INC_USE_COUNT;
pl_info = PDE_DATA(f->f_path.dentry->d_inode);
if (!pl_info) {
qdf_nofl_err("%s: pl_info NULL", __func__);
return -EINVAL;
}
if (pl_info->curr_pkt_state != PKTLOG_OPR_NOT_IN_PROGRESS) {
qdf_nofl_info("%s: plinfo state (%d) != PKTLOG_OPR_NOT_IN_PROGRESS",
__func__, pl_info->curr_pkt_state);
return -EBUSY;
}
pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS_READ_START;
scn = cds_get_context(QDF_MODULE_ID_HIF);
if (!scn) {
pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
qdf_print("%s: Invalid scn context", __func__);
ASSERT(0);
return -EINVAL;
@@ -556,12 +550,38 @@ static int __pktlog_open(struct inode *i, struct file *f)
pl_dev = get_pktlog_handle();
if (!pl_dev) {
pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
qdf_print("%s: Invalid pktlog handle", __func__);
ASSERT(0);
return -ENODEV;
}
pl_info = pl_dev->pl_info;
if (!pl_info) {
qdf_nofl_err("%s: pl_info NULL", __func__);
return -EINVAL;
}
mutex_lock(&pl_info->pktlog_mutex);
pl_info_lnx = (pl_dev) ? PL_INFO_LNX(pl_dev->pl_info) :
PL_INFO_LNX(g_pktlog_info);
if (!pl_info_lnx->sysctl_header) {
mutex_unlock(&pl_info->pktlog_mutex);
qdf_print("%s: pktlog sysctl is unergistered.", __func__);
ASSERT(0);
return -EINVAL;
}
if (pl_info->curr_pkt_state != PKTLOG_OPR_NOT_IN_PROGRESS) {
mutex_unlock(&pl_info->pktlog_mutex);
qdf_print("%s: plinfo state (%d) != PKTLOG_OPR_NOT_IN_PROGRESS",
__func__, pl_info->curr_pkt_state);
return -EBUSY;
}
pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS_READ_START;
pl_info->init_saved_state = pl_info->log_state;
if (!pl_info->log_state) {
/* Pktlog is already disabled.
@@ -569,6 +589,7 @@ static int __pktlog_open(struct inode *i, struct file *f)
*/
pl_info->curr_pkt_state =
PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED;
mutex_unlock(&pl_info->pktlog_mutex);
return ret;
}
/* Disbable the pktlog internally. */
@@ -576,6 +597,7 @@ static int __pktlog_open(struct inode *i, struct file *f)
pl_info->log_state = 0;
pl_info->curr_pkt_state =
PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED;
mutex_unlock(&pl_info->pktlog_mutex);
return ret;
}
@@ -600,17 +622,12 @@ static int __pktlog_release(struct inode *i, struct file *f)
struct hif_opaque_softc *scn;
struct pktlog_dev_t *pl_dev;
struct ath_pktlog_info *pl_info;
struct ath_pktlog_info_lnx *pl_info_lnx;
int ret = 0;
PKTLOG_MOD_DEC_USE_COUNT;
pl_info = PDE_DATA(f->f_path.dentry->d_inode);
if (!pl_info)
return -EINVAL;
scn = cds_get_context(QDF_MODULE_ID_HIF);
if (!scn) {
pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
qdf_print("%s: Invalid scn context", __func__);
ASSERT(0);
return -EINVAL;
@@ -619,12 +636,30 @@ static int __pktlog_release(struct inode *i, struct file *f)
pl_dev = get_pktlog_handle();
if (!pl_dev) {
pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
qdf_print("%s: Invalid pktlog handle", __func__);
ASSERT(0);
return -ENODEV;
}
pl_info = pl_dev->pl_info;
if (!pl_info) {
qdf_print("%s: Invalid pktlog info", __func__);
ASSERT(0);
return -EINVAL;
}
mutex_lock(&pl_info->pktlog_mutex);
pl_info_lnx = (pl_dev) ? PL_INFO_LNX(pl_dev->pl_info) :
PL_INFO_LNX(g_pktlog_info);
if (!pl_info_lnx->sysctl_header) {
pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
mutex_unlock(&pl_info->pktlog_mutex);
qdf_print("%s: pktlog sysctl is unergistered.", __func__);
ASSERT(0);
return -EINVAL;
}
pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS_READ_COMPLETE;
/*clear pktlog buffer.*/
pktlog_clearbuff(scn, true);
@@ -632,15 +667,16 @@ static int __pktlog_release(struct inode *i, struct file *f)
pl_info->init_saved_state = 0;
/*Enable pktlog again*/
ret = pl_dev->pl_funcs->pktlog_enable(
ret = __pktlog_enable(
(struct hif_opaque_softc *)scn, pl_info->log_state,
cds_is_packet_log_enabled(), 0, 1);
pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
mutex_unlock(&pl_info->pktlog_mutex);
if (ret != 0)
qdf_nofl_warn("%s: pktlog cannot be enabled. ret value %d",
qdf_print("%s: pktlog cannot be enabled. ret value %d",
__func__, ret);
pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS;
return ret;
}

View File

@@ -625,7 +625,7 @@ void pktlog_init(struct hif_opaque_softc *scn)
pktlog_callback_registration(pl_dev->callback_type);
}
static int __pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state,
int __pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state,
bool ini_triggered, uint8_t user_triggered,
uint32_t is_iwpriv_command)
{