mmc: core: check for zero length ioctl data
authorJohan Rudholm <johan.rudholm@stericsson.com>
Wed, 23 Nov 2011 08:05:58 +0000 (09:05 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 1 Mar 2012 00:30:54 +0000 (16:30 -0800)
commit 4d6144de8ba263eb3691a737c547e5b2fdc45287 upstream.

If the read or write buffer size associated with the command sent
through the mmc_blk_ioctl is zero, do not prepare data buffer.

This enables a ioctl(2) call to for instance send a MMC_SWITCH to set
a byte in the ext_csd.

Signed-off-by: Johan Rudholm <johan.rudholm@stericsson.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/mmc/card/block.c

index 1e0e27c..e15e47d 100644 (file)
@@ -266,6 +266,9 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
                goto idata_err;
        }
 
+       if (!idata->buf_bytes)
+               return idata;
+
        idata->buf = kzalloc(idata->buf_bytes, GFP_KERNEL);
        if (!idata->buf) {
                err = -ENOMEM;
@@ -312,25 +315,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
        if (IS_ERR(idata))
                return PTR_ERR(idata);
 
-       cmd.opcode = idata->ic.opcode;
-       cmd.arg = idata->ic.arg;
-       cmd.flags = idata->ic.flags;
-
-       data.sg = &sg;
-       data.sg_len = 1;
-       data.blksz = idata->ic.blksz;
-       data.blocks = idata->ic.blocks;
-
-       sg_init_one(data.sg, idata->buf, idata->buf_bytes);
-
-       if (idata->ic.write_flag)
-               data.flags = MMC_DATA_WRITE;
-       else
-               data.flags = MMC_DATA_READ;
-
-       mrq.cmd = &cmd;
-       mrq.data = &data;
-
        md = mmc_blk_get(bdev->bd_disk);
        if (!md) {
                err = -EINVAL;
@@ -343,6 +327,48 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
                goto cmd_done;
        }
 
+       cmd.opcode = idata->ic.opcode;
+       cmd.arg = idata->ic.arg;
+       cmd.flags = idata->ic.flags;
+
+       if (idata->buf_bytes) {
+               data.sg = &sg;
+               data.sg_len = 1;
+               data.blksz = idata->ic.blksz;
+               data.blocks = idata->ic.blocks;
+
+               sg_init_one(data.sg, idata->buf, idata->buf_bytes);
+
+               if (idata->ic.write_flag)
+                       data.flags = MMC_DATA_WRITE;
+               else
+                       data.flags = MMC_DATA_READ;
+
+               /* data.flags must already be set before doing this. */
+               mmc_set_data_timeout(&data, card);
+
+               /* Allow overriding the timeout_ns for empirical tuning. */
+               if (idata->ic.data_timeout_ns)
+                       data.timeout_ns = idata->ic.data_timeout_ns;
+
+               if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
+                       /*
+                        * Pretend this is a data transfer and rely on the
+                        * host driver to compute timeout.  When all host
+                        * drivers support cmd.cmd_timeout for R1B, this
+                        * can be changed to:
+                        *
+                        *     mrq.data = NULL;
+                        *     cmd.cmd_timeout = idata->ic.cmd_timeout_ms;
+                        */
+                       data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000;
+               }
+
+               mrq.data = &data;
+       }
+
+       mrq.cmd = &cmd;
+
        mmc_claim_host(card->host);
 
        if (idata->ic.is_acmd) {
@@ -351,24 +377,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
                        goto cmd_rel_host;
        }
 
-       /* data.flags must already be set before doing this. */
-       mmc_set_data_timeout(&data, card);
-       /* Allow overriding the timeout_ns for empirical tuning. */
-       if (idata->ic.data_timeout_ns)
-               data.timeout_ns = idata->ic.data_timeout_ns;
-
-       if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
-               /*
-                * Pretend this is a data transfer and rely on the host driver
-                * to compute timeout.  When all host drivers support
-                * cmd.cmd_timeout for R1B, this can be changed to:
-                *
-                *     mrq.data = NULL;
-                *     cmd.cmd_timeout = idata->ic.cmd_timeout_ms;
-                */
-               data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000;
-       }
-
        mmc_wait_for_req(card->host, &mrq);
 
        if (cmd.error) {