icnss: Handle wait being interrupted
When event needs to be processed synchronously, event posting thread waits for the completion. After completion, result from the event work is retrieved and event buffer would be freed. But if waiting thread gets interrupted then wait_for_completion API returns failure and it also frees the buffer posted for processing. Event work queue may accesses the freed buffer and crash the system. Fix the issue by properly synchronizing event buffer free between caller and event work by checking for return value of wait_for_completion. CRs-fixed: 1057180 Change-Id: Ic3968fd4c0232da6bc9a97d94376f540f62bd2e6 Signed-off-by: Prashanth Bhatta <bhattap@codeaurora.org>
This commit is contained in:
parent
e8a0e0808d
commit
7d45313e05
1 changed files with 31 additions and 7 deletions
|
@ -217,6 +217,8 @@ module_param(quirks, ulong, 0600);
|
||||||
|
|
||||||
void *icnss_ipc_log_context;
|
void *icnss_ipc_log_context;
|
||||||
|
|
||||||
|
#define ICNSS_EVENT_PENDING 2989
|
||||||
|
|
||||||
enum icnss_driver_event_type {
|
enum icnss_driver_event_type {
|
||||||
ICNSS_DRIVER_EVENT_SERVER_ARRIVE,
|
ICNSS_DRIVER_EVENT_SERVER_ARRIVE,
|
||||||
ICNSS_DRIVER_EVENT_SERVER_EXIT,
|
ICNSS_DRIVER_EVENT_SERVER_EXIT,
|
||||||
|
@ -486,6 +488,7 @@ static int icnss_driver_event_post(enum icnss_driver_event_type type,
|
||||||
event->type = type;
|
event->type = type;
|
||||||
event->data = data;
|
event->data = data;
|
||||||
init_completion(&event->complete);
|
init_completion(&event->complete);
|
||||||
|
event->ret = ICNSS_EVENT_PENDING;
|
||||||
event->sync = sync;
|
event->sync = sync;
|
||||||
|
|
||||||
spin_lock_irqsave(&penv->event_lock, flags);
|
spin_lock_irqsave(&penv->event_lock, flags);
|
||||||
|
@ -494,12 +497,26 @@ static int icnss_driver_event_post(enum icnss_driver_event_type type,
|
||||||
|
|
||||||
penv->stats.events[type].posted++;
|
penv->stats.events[type].posted++;
|
||||||
queue_work(penv->event_wq, &penv->event_work);
|
queue_work(penv->event_wq, &penv->event_work);
|
||||||
if (sync) {
|
|
||||||
ret = wait_for_completion_interruptible(&event->complete);
|
if (!sync)
|
||||||
if (ret == 0)
|
return ret;
|
||||||
ret = event->ret;
|
|
||||||
kfree(event);
|
ret = wait_for_completion_interruptible(&event->complete);
|
||||||
|
|
||||||
|
icnss_pr_dbg("Completed event: %s(%d), state: 0x%lx, ret: %d/%d\n",
|
||||||
|
icnss_driver_event_to_str(type), type, penv->state, ret,
|
||||||
|
event->ret);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&penv->event_lock, flags);
|
||||||
|
if (ret == -ERESTARTSYS && event->ret == ICNSS_EVENT_PENDING) {
|
||||||
|
event->sync = false;
|
||||||
|
spin_unlock_irqrestore(&penv->event_lock, flags);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
spin_unlock_irqrestore(&penv->event_lock, flags);
|
||||||
|
|
||||||
|
ret = event->ret;
|
||||||
|
kfree(event);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -2071,11 +2088,15 @@ static void icnss_driver_event_work(struct work_struct *work)
|
||||||
|
|
||||||
penv->stats.events[event->type].processed++;
|
penv->stats.events[event->type].processed++;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&penv->event_lock, flags);
|
||||||
if (event->sync) {
|
if (event->sync) {
|
||||||
event->ret = ret;
|
event->ret = ret;
|
||||||
complete(&event->complete);
|
complete(&event->complete);
|
||||||
} else
|
continue;
|
||||||
kfree(event);
|
}
|
||||||
|
spin_unlock_irqrestore(&penv->event_lock, flags);
|
||||||
|
|
||||||
|
kfree(event);
|
||||||
|
|
||||||
spin_lock_irqsave(&penv->event_lock, flags);
|
spin_lock_irqsave(&penv->event_lock, flags);
|
||||||
}
|
}
|
||||||
|
@ -2372,6 +2393,9 @@ int icnss_register_driver(struct icnss_driver_ops *ops)
|
||||||
ret = icnss_driver_event_post(ICNSS_DRIVER_EVENT_REGISTER_DRIVER,
|
ret = icnss_driver_event_post(ICNSS_DRIVER_EVENT_REGISTER_DRIVER,
|
||||||
true, ops);
|
true, ops);
|
||||||
|
|
||||||
|
if (ret == -ERESTARTSYS)
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue