msm: camera: reqmgr: Fix pagefault in workqueue get task

Protect taskpool memory free operation with workqueue lock to prevent
use after free issues.

CRs-Fixed: 3019429
Change-Id: I0282e01e093f80578c5058a41823036370f5a88a
Signed-off-by: Anand Ravi <ananravi@codeaurora.org>
This commit is contained in:
Anand Ravi
2021-08-23 12:42:46 -07:00
committed by Gerrit - the friendly Code Review server
parent bb15434c6d
commit 22097757a8

View File

@@ -153,21 +153,17 @@ int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task,
if (!task) {
CAM_WARN(CAM_CRM, "NULL task pointer can not schedule");
rc = -EINVAL;
goto end;
return -EINVAL;
}
workq = (struct cam_req_mgr_core_workq *)task->parent;
if (!workq) {
CAM_DBG(CAM_CRM, "NULL workq pointer suspect mem corruption");
rc = -EINVAL;
goto end;
return -EINVAL;
}
if (task->cancel == 1 || atomic_read(&workq->flush)) {
cam_req_mgr_workq_put_task(task);
CAM_INFO(CAM_CRM, "task aborted and queued back to pool");
rc = 0;
goto end;
goto abort;
}
task->priv = priv;
task->priority =
@@ -175,11 +171,11 @@ int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task,
? prio : CRM_TASK_PRIORITY_0;
WORKQ_ACQUIRE_LOCK(workq, flags);
if (!workq->job) {
rc = -EINVAL;
WORKQ_RELEASE_LOCK(workq, flags);
goto end;
}
if (!workq->job) {
rc = -EINVAL;
WORKQ_RELEASE_LOCK(workq, flags);
goto abort;
}
list_add_tail(&task->entry,
&workq->task.process_head[task->priority]);
@@ -191,7 +187,11 @@ int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task,
workq->workq_scheduled_ts = ktime_get();
queue_work(workq->job, &workq->work);
WORKQ_RELEASE_LOCK(workq, flags);
end:
return rc;
abort:
cam_req_mgr_workq_put_task(task);
CAM_INFO(CAM_CRM, "task aborted and queued back to pool");
return rc;
}
@@ -271,24 +271,32 @@ void cam_req_mgr_workq_destroy(struct cam_req_mgr_core_workq **crm_workq)
{
unsigned long flags = 0;
struct workqueue_struct *job;
struct cam_req_mgr_core_workq *workq;
int i;
CAM_DBG(CAM_CRM, "destroy workque %pK", crm_workq);
if (*crm_workq) {
WORKQ_ACQUIRE_LOCK(*crm_workq, flags);
if ((*crm_workq)->job) {
job = (*crm_workq)->job;
(*crm_workq)->job = NULL;
WORKQ_RELEASE_LOCK(*crm_workq, flags);
if (crm_workq && *crm_workq) {
workq = *crm_workq;
CAM_DBG(CAM_CRM, "destroy workque %s", workq->workq_name);
WORKQ_ACQUIRE_LOCK(workq, flags);
/* prevent any processing of callbacks */
atomic_set(&workq->flush, 1);
if (workq->job) {
job = workq->job;
workq->job = NULL;
WORKQ_RELEASE_LOCK(workq, flags);
destroy_workqueue(job);
} else {
WORKQ_RELEASE_LOCK(*crm_workq, flags);
WORKQ_ACQUIRE_LOCK(workq, flags);
}
/* Destroy workq payload data */
kfree((*crm_workq)->task.pool[0].payload);
(*crm_workq)->task.pool[0].payload = NULL;
kfree((*crm_workq)->task.pool);
kfree(*crm_workq);
kfree(workq->task.pool[0].payload);
kfree(workq->task.pool);
/* Leave lists in stable state after freeing pool */
INIT_LIST_HEAD(&workq->task.empty_head);
for (i = 0; i < CRM_TASK_PRIORITY_MAX; i++)
INIT_LIST_HEAD(&workq->task.process_head[i]);
*crm_workq = NULL;
WORKQ_RELEASE_LOCK(workq, flags);
kfree(workq);
}
}