wcnss: fix the race condition issue during cal data extraction

The wcnss platform driver update the wlan calibration data
by the user space wlan daemon. The wlan user space daemon store
the updated wlan calibration data reported by wlan firmware in
user space and write it back to the wcnss platform calibration
data buffer for the calibration data download and update.

During the wlan calibration data extraction there are some potential
race condition which leads to memory leak and buffer overflow during
the context switch. Fix the above issue by adding protection code.

CRs-Fixed: 2015791
Change-Id: I231807f6b2d8094d7138b95c659ed6272897ba2d
Signed-off-by: Sarada Prasanna Garnayak <sgarna@codeaurora.org>
This commit is contained in:
Sarada Prasanna Garnayak 2017-04-17 14:48:16 +05:30 committed by Gerrit - the friendly Code Review server
parent 6cf6835d96
commit bf00f32974

View file

@ -2045,21 +2045,23 @@ void extract_cal_data(int len)
return;
}
mutex_lock(&penv->dev_lock);
rc = smd_read(penv->smd_ch, (unsigned char *)&calhdr,
sizeof(struct cal_data_params));
if (rc < sizeof(struct cal_data_params)) {
pr_err("wcnss: incomplete cal header read from smd\n");
mutex_unlock(&penv->dev_lock);
return;
}
if (penv->fw_cal_exp_frag != calhdr.frag_number) {
pr_err("wcnss: Invalid frgament");
goto exit;
goto unlock_exit;
}
if (calhdr.frag_size > WCNSS_MAX_FRAME_SIZE) {
pr_err("wcnss: Invalid fragment size");
goto exit;
goto unlock_exit;
}
if (penv->fw_cal_available) {
@ -2068,8 +2070,9 @@ void extract_cal_data(int len)
penv->fw_cal_exp_frag++;
if (calhdr.msg_flags & LAST_FRAGMENT) {
penv->fw_cal_exp_frag = 0;
goto exit;
goto unlock_exit;
}
mutex_unlock(&penv->dev_lock);
return;
}
@ -2077,7 +2080,7 @@ void extract_cal_data(int len)
if (calhdr.total_size > MAX_CALIBRATED_DATA_SIZE) {
pr_err("wcnss: Invalid cal data size %d",
calhdr.total_size);
goto exit;
goto unlock_exit;
}
kfree(penv->fw_cal_data);
penv->fw_cal_rcvd = 0;
@ -2085,11 +2088,10 @@ void extract_cal_data(int len)
GFP_KERNEL);
if (penv->fw_cal_data == NULL) {
smd_read(penv->smd_ch, NULL, calhdr.frag_size);
goto exit;
goto unlock_exit;
}
}
mutex_lock(&penv->dev_lock);
if (penv->fw_cal_rcvd + calhdr.frag_size >
MAX_CALIBRATED_DATA_SIZE) {
pr_err("calibrated data size is more than expected %d",
@ -2124,13 +2126,10 @@ void extract_cal_data(int len)
unlock_exit:
mutex_unlock(&penv->dev_lock);
exit:
wcnss_send_cal_rsp(fw_status);
return;
}
static void wcnssctrl_rx_handler(struct work_struct *worker)
{
int len = 0;