Skip to content

Commit

Permalink
mmc: mxcmmc: fix race conditions for host->req and host->data access
Browse files Browse the repository at this point in the history
mxcmci_dma_callback() is invoked by DMA drivers in soft-irq
context and can be interrupted by the mxcmci_irq() interrupt
which can finish the mmc request or data transfer and set
host->req or host->data pointers to NULL. Then mxcmci_data_done()
crashes with a null pointer dereferences. Protect all accesses
to host->req and host->data by spin locks.

Also check host->data pointer in mxcmci_watchdog() before
dereferencing it.

Signed-off-by: Anatolij Gustschin <[email protected]>
Acked-by: Sascha Hauer <[email protected]>
Signed-off-by: Chris Ball <[email protected]>
  • Loading branch information
vdsao authored and cjb committed Apr 12, 2013
1 parent 7ff747c commit 70aa610
Showing 1 changed file with 24 additions and 7 deletions.
31 changes: 24 additions & 7 deletions drivers/mmc/host/mxcmmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -623,24 +623,40 @@ static void mxcmci_datawork(struct work_struct *work)

static void mxcmci_data_done(struct mxcmci_host *host, unsigned int stat)
{
struct mmc_data *data = host->data;
struct mmc_request *req;
int data_error;
unsigned long flags;

spin_lock_irqsave(&host->lock, flags);

if (!data)
if (!host->data) {
spin_unlock_irqrestore(&host->lock, flags);
return;
}

if (!host->req) {
spin_unlock_irqrestore(&host->lock, flags);
return;
}

req = host->req;
if (!req->stop)
host->req = NULL; /* we will handle finish req below */

data_error = mxcmci_finish_data(host, stat);

spin_unlock_irqrestore(&host->lock, flags);

mxcmci_read_response(host, stat);
host->cmd = NULL;

if (host->req->stop) {
if (mxcmci_start_cmd(host, host->req->stop, 0)) {
mxcmci_finish_request(host, host->req);
if (req->stop) {
if (mxcmci_start_cmd(host, req->stop, 0)) {
mxcmci_finish_request(host, req);
return;
}
} else {
mxcmci_finish_request(host, host->req);
mxcmci_finish_request(host, req);
}
}

Expand Down Expand Up @@ -931,7 +947,8 @@ static void mxcmci_watchdog(unsigned long data)

/* Mark transfer as erroneus and inform the upper layers */

host->data->error = -ETIMEDOUT;
if (host->data)
host->data->error = -ETIMEDOUT;
host->req = NULL;
host->cmd = NULL;
host->data = NULL;
Expand Down

0 comments on commit 70aa610

Please sign in to comment.