Commit b9154df5 authored by Johan Hovold's avatar Johan Hovold Committed by Greg Kroah-Hartman

greybus: sdio: fix work-queue leak and use-after-free

A single global work-queue pointer was used for the per-connection
workqueue, something which would lead to memory leaks and all sorts of
bad things if there are ever more than one SDIO connection in a system.

Also add the missing error handling when allocating the queue.
Signed-off-by: default avatarJohan Hovold <johan@hovoldconsulting.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
parent e5265266
...@@ -25,6 +25,7 @@ struct gb_sdio_host { ...@@ -25,6 +25,7 @@ struct gb_sdio_host {
void *xfer_buffer; void *xfer_buffer;
spinlock_t xfer; /* lock to cancel ongoing transfer */ spinlock_t xfer; /* lock to cancel ongoing transfer */
bool xfer_stop; bool xfer_stop;
struct workqueue_struct *mrq_workqueue;
struct work_struct mrqwork; struct work_struct mrqwork;
u8 queued_events; u8 queued_events;
bool removed; bool removed;
...@@ -32,7 +33,6 @@ struct gb_sdio_host { ...@@ -32,7 +33,6 @@ struct gb_sdio_host {
bool read_only; bool read_only;
}; };
static struct workqueue_struct *gb_sdio_mrq_workqueue;
#define GB_SDIO_RSP_R1_R5_R6_R7 (GB_SDIO_RSP_PRESENT | GB_SDIO_RSP_CRC | \ #define GB_SDIO_RSP_R1_R5_R6_R7 (GB_SDIO_RSP_PRESENT | GB_SDIO_RSP_CRC | \
GB_SDIO_RSP_OPCODE) GB_SDIO_RSP_OPCODE)
...@@ -497,7 +497,7 @@ static void gb_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) ...@@ -497,7 +497,7 @@ static void gb_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
goto out; goto out;
} }
queue_work(gb_sdio_mrq_workqueue, &host->mrqwork); queue_work(host->mrq_workqueue, &host->mrqwork);
mutex_unlock(&host->lock); mutex_unlock(&host->lock);
return; return;
...@@ -710,7 +710,12 @@ static int gb_sdio_connection_init(struct gb_connection *connection) ...@@ -710,7 +710,12 @@ static int gb_sdio_connection_init(struct gb_connection *connection)
} }
mutex_init(&host->lock); mutex_init(&host->lock);
spin_lock_init(&host->xfer); spin_lock_init(&host->xfer);
gb_sdio_mrq_workqueue = alloc_workqueue("gb_sdio_mrq", 0, 1); host->mrq_workqueue = alloc_workqueue("mmc-%s", 0, 1,
dev_name(&connection->dev));
if (!host->mrq_workqueue) {
ret = -ENOMEM;
goto free_buffer;
}
INIT_WORK(&host->mrqwork, gb_sdio_mrq_work); INIT_WORK(&host->mrqwork, gb_sdio_mrq_work);
ret = mmc_add_host(mmc); ret = mmc_add_host(mmc);
...@@ -723,9 +728,9 @@ static int gb_sdio_connection_init(struct gb_connection *connection) ...@@ -723,9 +728,9 @@ static int gb_sdio_connection_init(struct gb_connection *connection)
return ret; return ret;
free_work: free_work:
destroy_workqueue(gb_sdio_mrq_workqueue); destroy_workqueue(host->mrq_workqueue);
free_buffer:
kfree(host->xfer_buffer); kfree(host->xfer_buffer);
free_mmc: free_mmc:
connection->private = NULL; connection->private = NULL;
mmc_free_host(mmc); mmc_free_host(mmc);
...@@ -747,8 +752,8 @@ static void gb_sdio_connection_exit(struct gb_connection *connection) ...@@ -747,8 +752,8 @@ static void gb_sdio_connection_exit(struct gb_connection *connection)
connection->private = NULL; connection->private = NULL;
mutex_unlock(&host->lock); mutex_unlock(&host->lock);
flush_workqueue(gb_sdio_mrq_workqueue); flush_workqueue(host->mrq_workqueue);
destroy_workqueue(gb_sdio_mrq_workqueue); destroy_workqueue(host->mrq_workqueue);
mmc_remove_host(mmc); mmc_remove_host(mmc);
kfree(host->xfer_buffer); kfree(host->xfer_buffer);
mmc_free_host(mmc); mmc_free_host(mmc);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment