From: Carsten Haitzler carsten.haitzler@arm.com
DRM makes copies of ioctl payload data to/from userspace and some of this can also have pointers to other memory (or capabilities for morello) and thus it needs to assume the worst and copy while retaining capabilities. Also don't use stack as the kernel side buffer (optimization for smaller payloads) doesn't work.
Signed-off-by: Carsten Haitzler Carsten.Haitzler@arm.com --- drivers/gpu/drm/drm_file.c | 2 +- drivers/gpu/drm/drm_ioctl.c | 20 ++++++++------------ 2 files changed, 9 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index 446458aca8e9..76e3616158f3 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -651,7 +651,7 @@ ssize_t drm_read(struct file *filp, char __user *buffer, break; }
- if (copy_to_user(buffer + ret, e->event, length)) { + if (copy_to_user_with_ptr(buffer + ret, e->event, length)) { if (ret == 0) ret = -EFAULT; goto put_back_event; diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index f2cda382f8ed..950a83828cc9 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -469,9 +469,9 @@ EXPORT_SYMBOL(drm_invalid_op); /* * Copy and IOCTL return string to user space */ -static int drm_copy_field(char __user *buf, size_t *buf_len, const char *value) +static int drm_copy_field(char __user *buf, size_t __user *buf_len, const char *value) { - size_t len; + size_t len, len_orig;
/* don't attempt to copy a NULL pointer */ if (WARN_ONCE(!value, "BUG: the value to copy was not set!")) { @@ -480,13 +480,13 @@ static int drm_copy_field(char __user *buf, size_t *buf_len, const char *value) }
/* don't overflow userbuf */ - len = strlen(value); + len = len_orig = strlen(value); if (len > *buf_len) len = *buf_len;
/* let userspace know exact length of driver value (which could be * larger than the userspace-supplied buffer) */ - *buf_len = strlen(value); + *buf_len = len_orig;
/* finally, try filling in the userbuf */ if (len && buf) @@ -821,7 +821,6 @@ long drm_ioctl(struct file *filp, drm_ioctl_t *func; unsigned int nr = DRM_IOCTL_NR(cmd); int retcode = -EINVAL; - char stack_kdata[128]; char *kdata = NULL; unsigned int in_size, out_size, drv_size, ksize; bool is_driver_ioctl; @@ -874,9 +873,7 @@ long drm_ioctl(struct file *filp, goto err_i1; }
- if (ksize <= sizeof(stack_kdata)) { - kdata = stack_kdata; - } else { + if (ksize > 0) { kdata = kmalloc(ksize, GFP_KERNEL); if (!kdata) { retcode = -ENOMEM; @@ -884,16 +881,15 @@ long drm_ioctl(struct file *filp, } }
- if (copy_from_user(kdata, (void __user *)arg, in_size) != 0) { + if (copy_from_user_with_ptr(kdata, (void __user *)arg, in_size) != 0) { retcode = -EFAULT; goto err_i1; } - if (ksize > in_size) memset(kdata + in_size, 0, ksize - in_size);
retcode = drm_ioctl_kernel(filp, func, kdata, ioctl->flags); - if (copy_to_user((void __user *)arg, kdata, out_size) != 0) + if (copy_to_user_with_ptr((void __user *)arg, kdata, out_size) != 0) retcode = -EFAULT;
err_i1: @@ -904,7 +900,7 @@ long drm_ioctl(struct file *filp, (long)old_encode_dev(file_priv->minor->kdev->devt), file_priv->authenticated, cmd, nr);
- if (kdata != stack_kdata) + if (kdata != NULL) kfree(kdata); if (retcode) drm_dbg_core(dev, "comm="%s", pid=%d, ret=%d\n",