[Devel] [PATCH rh7] ploop: avoid costly user-controllable kmalloc() calls
Maxim Patlasov
mpatlasov at virtuozzo.com
Thu May 19 14:24:50 PDT 2016
Acked-by: Maxim Patlasov <mpatlasov at virtuozzo.com>
On 05/19/2016 04:40 AM, Andrey Ryabinin wrote:
> Certain ploop's ioctls copy large arrays from user space into
> kernel memory allocated via kmalloc() call.
> User-controllable kmalloc() is bad as it could taint the kernel
> (if size > MAX_ORDER). Also allocation of large physically contiguous
> memory is slow and not reliable in low-memory situations.
>
> So instead of preallocating memory and coping big chunk of user memory
> into the kernel, we copy only one element that we need at the moment.
> Such approach is much more reliable, may save us several MBs of kernel
> memory, and might be even faster.
>
> https://jira.sw.ru/browse/PSBM-47303
>
> Signed-off-by: Andrey Ryabinin <aryabinin at virtuozzo.com>
> ---
> drivers/block/ploop/dev.c | 73 +++++++++++++++++++++--------------------------
> 1 file changed, 32 insertions(+), 41 deletions(-)
>
> diff --git a/drivers/block/ploop/dev.c b/drivers/block/ploop/dev.c
> index f3bb092..c4f81df 100644
> --- a/drivers/block/ploop/dev.c
> +++ b/drivers/block/ploop/dev.c
> @@ -4167,7 +4167,7 @@ static int ploop_freeblks_ioc(struct ploop_device *plo, unsigned long arg)
> {
> struct ploop_delta *delta;
> struct ploop_freeblks_ctl ctl;
> - struct ploop_freeblks_ctl_extent *extents;
> + struct ploop_freeblks_ctl_extent __user *extents;
> struct ploop_freeblks_desc *fbd;
> int i;
> int rc = 0;
> @@ -4184,34 +4184,35 @@ static int ploop_freeblks_ioc(struct ploop_device *plo, unsigned long arg)
> if (copy_from_user(&ctl, (void*)arg, sizeof(ctl)))
> return -EFAULT;
>
> - extents = kzalloc(sizeof(*extents) * ctl.n_extents, GFP_KERNEL);
> - if (!extents)
> - return -ENOMEM;
> -
> delta = ploop_top_delta(plo);
> if (delta->level != ctl.level) {
> rc = -EINVAL;
> - goto free_extents;
> - }
> -
> - if (copy_from_user(extents, (u8*)arg + sizeof(ctl),
> - sizeof(*extents) * ctl.n_extents)) {
> - rc = -EINVAL;
> - goto free_extents;
> + goto exit;
> }
>
> fbd = ploop_fb_init(plo);
> if (!fbd) {
> rc = -ENOMEM;
> - goto free_extents;
> + goto exit;
> }
>
> + extents = (void __user *)(arg + sizeof(ctl));
> +
> for (i = 0; i < ctl.n_extents; i++) {
> - rc = ploop_fb_add_free_extent(fbd, extents[i].clu,
> - extents[i].iblk, extents[i].len);
> + struct ploop_freeblks_ctl_extent extent;
> +
> + if (copy_from_user(&extent, &extents[i],
> + sizeof(extent))) {
> + rc = -EFAULT;
> + ploop_fb_fini(fbd, rc);
> + goto exit;
> + }
> +
> + rc = ploop_fb_add_free_extent(fbd, extent.clu,
> + extent.iblk, extent.len);
> if (rc) {
> ploop_fb_fini(fbd, rc);
> - goto free_extents;
> + goto exit;
> }
> }
>
> @@ -4232,8 +4233,7 @@ static int ploop_freeblks_ioc(struct ploop_device *plo, unsigned long arg)
> }
>
> ploop_relax(plo);
> -free_extents:
> - kfree(extents);
> +exit:
> return rc;
> }
>
> @@ -4324,13 +4324,8 @@ static void ploop_relocblks_process(struct ploop_device *plo)
> spin_unlock_irq(&plo->lock);
> }
>
> -static int release_fbd(struct ploop_device *plo,
> - struct ploop_relocblks_ctl_extent *e,
> - int err)
> +static int release_fbd(struct ploop_device *plo, int err)
> {
> - if (e)
> - kfree(e);
> -
> clear_bit(PLOOP_S_DISCARD, &plo->state);
>
> ploop_quiesce(plo);
> @@ -4378,7 +4373,6 @@ static int ploop_relocblks_ioc(struct ploop_device *plo, unsigned long arg)
> {
> struct ploop_delta *delta = ploop_top_delta(plo);
> struct ploop_relocblks_ctl ctl;
> - struct ploop_relocblks_ctl_extent *extents = NULL;
> struct ploop_freeblks_desc *fbd = plo->fbd;
> int i;
> int err = 0;
> @@ -4406,26 +4400,23 @@ static int ploop_relocblks_ioc(struct ploop_device *plo, unsigned long arg)
> goto already;
>
> if (ctl.n_extents) {
> - extents = kzalloc(sizeof(*extents) * ctl.n_extents,
> - GFP_KERNEL);
> - if (!extents)
> - return release_fbd(plo, extents, -ENOMEM);
> + struct ploop_relocblks_ctl_extent __user *extents;
>
> - if (copy_from_user(extents, (u8*)arg + sizeof(ctl),
> - sizeof(*extents) * ctl.n_extents))
> - return release_fbd(plo, extents, -EINVAL);
> + extents = (void __user *)(arg + sizeof(ctl));
>
> for (i = 0; i < ctl.n_extents; i++) {
> - err = ploop_fb_add_reloc_extent(fbd, extents[i].clu,
> - extents[i].iblk,
> - extents[i].len,
> - extents[i].free);
> + struct ploop_relocblks_ctl_extent extent;
> +
> + if (copy_from_user(&extent, &extents[i],
> + sizeof(extent)))
> + return release_fbd(plo, -EFAULT);
> +
> + /* this extent is also present in freemap */
> + err = ploop_fb_add_reloc_extent(fbd, extent.clu,
> + extent.iblk, extent.len, extent.free);
> if (err)
> - return release_fbd(plo, extents, err);
> + return release_fbd(plo, err);
> }
> -
> - kfree(extents);
> - extents = NULL;
> }
>
> ploop_quiesce(plo);
> @@ -4472,7 +4463,7 @@ already:
> }
>
> if (ploop_fb_get_n_relocated(fbd) != ploop_fb_get_n_relocating(fbd))
> - return release_fbd(plo, extents, -EIO);
> + return release_fbd(plo, -EIO);
>
> /* time to truncate */
> ploop_quiesce(plo);
More information about the Devel
mailing list