Message ID | eea3b0bd-6091-f005-7189-b5b7868abdb6@omp.ru (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | mmc: core: block: fix sloppy typing in mmc_blk_ioctl_multi_cmd() | expand |
On Wed, 30 Mar 2022 at 23:09, Sergey Shtylyov <s.shtylyov@omp.ru> wrote: > > Despite mmc_ioc_multi_cmd::num_of_cmds is a 64-bit field, its maximum > value is limited to MMC_IOC_MAX_CMDS (only 255); using a 64-bit local > variable to hold a copy of that field leads to gcc generating ineffective > loop code: despite the source code using an *int* variable for the loop > counters, the 32-bit object code uses 64-bit unsigned counters. Also, > gcc has to drop the most significant word of that 64-bit variable when > calling kcalloc() and assigning to mmc_queue_req::ioc_count anyway. > Using the *unsigned int* variable instead results in a better code. > > Found by Linux Verification Center (linuxtesting.org) with the SVACE static > analysis tool. > > Signed-off-by: Sergey Shtylyov <s.shtylyov@omp.ru> Applied for next, thanks! Kind regards Uffe > > --- > This patch is against the 'next' branch of Ulf Hansson's 'mmc.git' repo. > > drivers/mmc/core/block.c | 16 +++++++++------- > 1 file changed, 9 insertions(+), 7 deletions(-) > > Index: mmc/drivers/mmc/core/block.c > =================================================================== > --- mmc.orig/drivers/mmc/core/block.c > +++ mmc/drivers/mmc/core/block.c > @@ -676,8 +676,9 @@ static int mmc_blk_ioctl_multi_cmd(struc > struct mmc_ioc_cmd __user *cmds = user->cmds; > struct mmc_card *card; > struct mmc_queue *mq; > - int i, err = 0, ioc_err = 0; > + int err = 0, ioc_err = 0; > __u64 num_of_cmds; > + unsigned int i, n; > struct request *req; > > if (copy_from_user(&num_of_cmds, &user->num_of_cmds, > @@ -690,15 +691,16 @@ static int mmc_blk_ioctl_multi_cmd(struc > if (num_of_cmds > MMC_IOC_MAX_CMDS) > return -EINVAL; > > - idata = kcalloc(num_of_cmds, sizeof(*idata), GFP_KERNEL); > + n = num_of_cmds; > + idata = kcalloc(n, sizeof(*idata), GFP_KERNEL); > if (!idata) > return -ENOMEM; > > - for (i = 0; i < num_of_cmds; i++) { > + for (i = 0; i < n; i++) { > idata[i] = mmc_blk_ioctl_copy_from_user(&cmds[i]); > if (IS_ERR(idata[i])) { > err = PTR_ERR(idata[i]); > - num_of_cmds = i; > + n = i; > goto cmd_err; > } > /* This will be NULL on non-RPMB ioctl():s */ > @@ -725,18 +727,18 @@ static int mmc_blk_ioctl_multi_cmd(struc > req_to_mmc_queue_req(req)->drv_op = > rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL; > req_to_mmc_queue_req(req)->drv_op_data = idata; > - req_to_mmc_queue_req(req)->ioc_count = num_of_cmds; > + req_to_mmc_queue_req(req)->ioc_count = n; > blk_execute_rq(req, false); > ioc_err = req_to_mmc_queue_req(req)->drv_op_result; > > /* copy to user if data and response */ > - for (i = 0; i < num_of_cmds && !err; i++) > + for (i = 0; i < n && !err; i++) > err = mmc_blk_ioctl_copy_to_user(&cmds[i], idata[i]); > > blk_mq_free_request(req); > > cmd_err: > - for (i = 0; i < num_of_cmds; i++) { > + for (i = 0; i < n; i++) { > kfree(idata[i]->buf); > kfree(idata[i]); > }
Index: mmc/drivers/mmc/core/block.c =================================================================== --- mmc.orig/drivers/mmc/core/block.c +++ mmc/drivers/mmc/core/block.c @@ -676,8 +676,9 @@ static int mmc_blk_ioctl_multi_cmd(struc struct mmc_ioc_cmd __user *cmds = user->cmds; struct mmc_card *card; struct mmc_queue *mq; - int i, err = 0, ioc_err = 0; + int err = 0, ioc_err = 0; __u64 num_of_cmds; + unsigned int i, n; struct request *req; if (copy_from_user(&num_of_cmds, &user->num_of_cmds, @@ -690,15 +691,16 @@ static int mmc_blk_ioctl_multi_cmd(struc if (num_of_cmds > MMC_IOC_MAX_CMDS) return -EINVAL; - idata = kcalloc(num_of_cmds, sizeof(*idata), GFP_KERNEL); + n = num_of_cmds; + idata = kcalloc(n, sizeof(*idata), GFP_KERNEL); if (!idata) return -ENOMEM; - for (i = 0; i < num_of_cmds; i++) { + for (i = 0; i < n; i++) { idata[i] = mmc_blk_ioctl_copy_from_user(&cmds[i]); if (IS_ERR(idata[i])) { err = PTR_ERR(idata[i]); - num_of_cmds = i; + n = i; goto cmd_err; } /* This will be NULL on non-RPMB ioctl():s */ @@ -725,18 +727,18 @@ static int mmc_blk_ioctl_multi_cmd(struc req_to_mmc_queue_req(req)->drv_op = rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL; req_to_mmc_queue_req(req)->drv_op_data = idata; - req_to_mmc_queue_req(req)->ioc_count = num_of_cmds; + req_to_mmc_queue_req(req)->ioc_count = n; blk_execute_rq(req, false); ioc_err = req_to_mmc_queue_req(req)->drv_op_result; /* copy to user if data and response */ - for (i = 0; i < num_of_cmds && !err; i++) + for (i = 0; i < n && !err; i++) err = mmc_blk_ioctl_copy_to_user(&cmds[i], idata[i]); blk_mq_free_request(req); cmd_err: - for (i = 0; i < num_of_cmds; i++) { + for (i = 0; i < n; i++) { kfree(idata[i]->buf); kfree(idata[i]); }
Despite mmc_ioc_multi_cmd::num_of_cmds is a 64-bit field, its maximum value is limited to MMC_IOC_MAX_CMDS (only 255); using a 64-bit local variable to hold a copy of that field leads to gcc generating ineffective loop code: despite the source code using an *int* variable for the loop counters, the 32-bit object code uses 64-bit unsigned counters. Also, gcc has to drop the most significant word of that 64-bit variable when calling kcalloc() and assigning to mmc_queue_req::ioc_count anyway. Using the *unsigned int* variable instead results in a better code. Found by Linux Verification Center (linuxtesting.org) with the SVACE static analysis tool. Signed-off-by: Sergey Shtylyov <s.shtylyov@omp.ru> --- This patch is against the 'next' branch of Ulf Hansson's 'mmc.git' repo. drivers/mmc/core/block.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-)