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:

committed by
Gerrit - the friendly Code Review server

parent
bb15434c6d
commit
22097757a8
@@ -153,21 +153,17 @@ int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task,
|
|||||||
|
|
||||||
if (!task) {
|
if (!task) {
|
||||||
CAM_WARN(CAM_CRM, "NULL task pointer can not schedule");
|
CAM_WARN(CAM_CRM, "NULL task pointer can not schedule");
|
||||||
rc = -EINVAL;
|
return -EINVAL;
|
||||||
goto end;
|
|
||||||
}
|
}
|
||||||
workq = (struct cam_req_mgr_core_workq *)task->parent;
|
workq = (struct cam_req_mgr_core_workq *)task->parent;
|
||||||
if (!workq) {
|
if (!workq) {
|
||||||
CAM_DBG(CAM_CRM, "NULL workq pointer suspect mem corruption");
|
CAM_DBG(CAM_CRM, "NULL workq pointer suspect mem corruption");
|
||||||
rc = -EINVAL;
|
return -EINVAL;
|
||||||
goto end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (task->cancel == 1 || atomic_read(&workq->flush)) {
|
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;
|
rc = 0;
|
||||||
goto end;
|
goto abort;
|
||||||
}
|
}
|
||||||
task->priv = priv;
|
task->priv = priv;
|
||||||
task->priority =
|
task->priority =
|
||||||
@@ -175,11 +171,11 @@ int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task,
|
|||||||
? prio : CRM_TASK_PRIORITY_0;
|
? prio : CRM_TASK_PRIORITY_0;
|
||||||
|
|
||||||
WORKQ_ACQUIRE_LOCK(workq, flags);
|
WORKQ_ACQUIRE_LOCK(workq, flags);
|
||||||
if (!workq->job) {
|
if (!workq->job) {
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
WORKQ_RELEASE_LOCK(workq, flags);
|
WORKQ_RELEASE_LOCK(workq, flags);
|
||||||
goto end;
|
goto abort;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_add_tail(&task->entry,
|
list_add_tail(&task->entry,
|
||||||
&workq->task.process_head[task->priority]);
|
&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();
|
workq->workq_scheduled_ts = ktime_get();
|
||||||
queue_work(workq->job, &workq->work);
|
queue_work(workq->job, &workq->work);
|
||||||
WORKQ_RELEASE_LOCK(workq, flags);
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,24 +271,32 @@ void cam_req_mgr_workq_destroy(struct cam_req_mgr_core_workq **crm_workq)
|
|||||||
{
|
{
|
||||||
unsigned long flags = 0;
|
unsigned long flags = 0;
|
||||||
struct workqueue_struct *job;
|
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 && *crm_workq) {
|
||||||
if (*crm_workq) {
|
workq = *crm_workq;
|
||||||
WORKQ_ACQUIRE_LOCK(*crm_workq, flags);
|
CAM_DBG(CAM_CRM, "destroy workque %s", workq->workq_name);
|
||||||
if ((*crm_workq)->job) {
|
WORKQ_ACQUIRE_LOCK(workq, flags);
|
||||||
job = (*crm_workq)->job;
|
/* prevent any processing of callbacks */
|
||||||
(*crm_workq)->job = NULL;
|
atomic_set(&workq->flush, 1);
|
||||||
WORKQ_RELEASE_LOCK(*crm_workq, flags);
|
if (workq->job) {
|
||||||
|
job = workq->job;
|
||||||
|
workq->job = NULL;
|
||||||
|
WORKQ_RELEASE_LOCK(workq, flags);
|
||||||
destroy_workqueue(job);
|
destroy_workqueue(job);
|
||||||
} else {
|
WORKQ_ACQUIRE_LOCK(workq, flags);
|
||||||
WORKQ_RELEASE_LOCK(*crm_workq, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Destroy workq payload data */
|
/* Destroy workq payload data */
|
||||||
kfree((*crm_workq)->task.pool[0].payload);
|
kfree(workq->task.pool[0].payload);
|
||||||
(*crm_workq)->task.pool[0].payload = NULL;
|
kfree(workq->task.pool);
|
||||||
kfree((*crm_workq)->task.pool);
|
|
||||||
kfree(*crm_workq);
|
/* 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;
|
*crm_workq = NULL;
|
||||||
|
WORKQ_RELEASE_LOCK(workq, flags);
|
||||||
|
kfree(workq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user