Am 12.07.2016 um 16:59 schrieb Chris Wilson:
> Currently, we completely ignore the user when it comes to the in/out
> direction of the ioctl argument, as we simply cannot trust userspace.
> (For example, they might request a copy of the modified ioctl argument
> when the driver is not expecting such and so leak kernel stack.)
> However, blindly copying over the target address may also lead to a
> spurious EFAULT, and a failure after the ioctl was completed
> successfully. This is important in order to avoid an ABI break when
> extending an ioctl from IOR to IORW. Similar to how we only copy the
> intersection of the kernel arg size and the user arg size, we only want
> to copy back the kernel arg data iff both the kernel and userspace
> request the copy.
>
> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

Seems to make a lot of sense to me, patch is Reviewed-by: Christian 
König <christian.koenig at amd.com>

Regards,
Christian.

> ---
>   drivers/gpu/drm/drm_ioctl.c | 50 
> ++++++++++++++++++++-------------------------
>   1 file changed, 22 insertions(+), 28 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
> index 2c87c1df0910..33af4a5ddca1 100644
> --- a/drivers/gpu/drm/drm_ioctl.c
> +++ b/drivers/gpu/drm/drm_ioctl.c
> @@ -648,7 +648,7 @@ long drm_ioctl(struct file *filp,
>       int retcode = -EINVAL;
>       char stack_kdata[128];
>       char *kdata = NULL;
> -     unsigned int usize, asize, drv_size;
> +     unsigned int in_size, out_size, drv_size, ksize;
>       bool is_driver_ioctl;
>   
>       dev = file_priv->minor->dev;
> @@ -671,9 +671,12 @@ long drm_ioctl(struct file *filp,
>       }
>   
>       drv_size = _IOC_SIZE(ioctl->cmd);
> -     usize = _IOC_SIZE(cmd);
> -     asize = max(usize, drv_size);
> -     cmd = ioctl->cmd;
> +     out_size = in_size = _IOC_SIZE(cmd);
> +     if ((cmd & ioctl->cmd & IOC_IN) == 0)
> +             in_size = 0;
> +     if ((cmd & ioctl->cmd & IOC_OUT) == 0)
> +             out_size = 0;
> +     ksize = max(max(in_size, out_size), drv_size);
>   
>       DRM_DEBUG("pid=%d, dev=0x%lx, auth=%d, %s\n",
>                 task_pid_nr(current),
> @@ -693,30 +696,24 @@ long drm_ioctl(struct file *filp,
>       if (unlikely(retcode))
>               goto err_i1;
>   
> -     if (cmd & (IOC_IN | IOC_OUT)) {
> -             if (asize <= sizeof(stack_kdata)) {
> -                     kdata = stack_kdata;
> -             } else {
> -                     kdata = kmalloc(asize, GFP_KERNEL);
> -                     if (!kdata) {
> -                             retcode = -ENOMEM;
> -                             goto err_i1;
> -                     }
> +     if (ksize <= sizeof(stack_kdata)) {
> +             kdata = stack_kdata;
> +     } else {
> +             kdata = kmalloc(ksize, GFP_KERNEL);
> +             if (!kdata) {
> +                     retcode = -ENOMEM;
> +                     goto err_i1;
>               }
> -             if (asize > usize)
> -                     memset(kdata + usize, 0, asize - usize);
>       }
>   
> -     if (cmd & IOC_IN) {
> -             if (copy_from_user(kdata, (void __user *)arg,
> -                                usize) != 0) {
> -                     retcode = -EFAULT;
> -                     goto err_i1;
> -             }
> -     } else if (cmd & IOC_OUT) {
> -             memset(kdata, 0, usize);
> +     if (copy_from_user(kdata, (void __user *)arg, in_size) != 0) {
> +             retcode = -EFAULT;
> +             goto err_i1;
>       }
>   
> +     if (ksize > in_size)
> +             memset(kdata + in_size, 0, ksize - in_size);
> +
>       /* Enforce sane locking for kms driver ioctls. Core ioctls are
>        * too messy still. */
>       if ((drm_core_check_feature(dev, DRIVER_MODESET) && is_driver_ioctl) ||
> @@ -728,11 +725,8 @@ long drm_ioctl(struct file *filp,
>               mutex_unlock(&drm_global_mutex);
>       }
>   
> -     if (cmd & IOC_OUT) {
> -             if (copy_to_user((void __user *)arg, kdata,
> -                              usize) != 0)
> -                     retcode = -EFAULT;
> -     }
> +     if (copy_to_user((void __user *)arg, kdata, out_size) != 0)
> +             retcode = -EFAULT;
>   
>         err_i1:
>       if (!ioctl)

Reply via email to