diff options
Diffstat (limited to 'drivers/gpu/drm/drm_drv.c')
| -rw-r--r-- | drivers/gpu/drm/drm_drv.c | 25 | 
1 files changed, 19 insertions, 6 deletions
| diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 90288ec7c28..84da748555b 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -55,6 +55,9 @@  static int drm_version(struct drm_device *dev, void *data,  		       struct drm_file *file_priv); +#define DRM_IOCTL_DEF(ioctl, _func, _flags) \ +	[DRM_IOCTL_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, .cmd_drv = 0} +  /** Ioctl table */  static struct drm_ioctl_desc drm_ioctls[] = {  	DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, 0), @@ -421,6 +424,7 @@ long drm_ioctl(struct file *filp,  	int retcode = -EINVAL;  	char stack_kdata[128];  	char *kdata = NULL; +	unsigned int usize, asize;  	dev = file_priv->minor->dev;  	atomic_inc(&dev->ioctl_count); @@ -436,11 +440,18 @@ long drm_ioctl(struct file *filp,  	    ((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END)))  		goto err_i1;  	if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) && -	    (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) +	    (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) { +		u32 drv_size;  		ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE]; +		drv_size = _IOC_SIZE(ioctl->cmd_drv); +		usize = asize = _IOC_SIZE(cmd); +		if (drv_size > asize) +			asize = drv_size; +	}  	else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE)) {  		ioctl = &drm_ioctls[nr];  		cmd = ioctl->cmd; +		usize = asize = _IOC_SIZE(cmd);  	} else  		goto err_i1; @@ -460,10 +471,10 @@ long drm_ioctl(struct file *filp,  		retcode = -EACCES;  	} else {  		if (cmd & (IOC_IN | IOC_OUT)) { -			if (_IOC_SIZE(cmd) <= sizeof(stack_kdata)) { +			if (asize <= sizeof(stack_kdata)) {  				kdata = stack_kdata;  			} else { -				kdata = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL); +				kdata = kmalloc(asize, GFP_KERNEL);  				if (!kdata) {  					retcode = -ENOMEM;  					goto err_i1; @@ -473,11 +484,13 @@ long drm_ioctl(struct file *filp,  		if (cmd & IOC_IN) {  			if (copy_from_user(kdata, (void __user *)arg, -					   _IOC_SIZE(cmd)) != 0) { +					   usize) != 0) {  				retcode = -EFAULT;  				goto err_i1;  			} -		} +		} else +			memset(kdata, 0, usize); +  		if (ioctl->flags & DRM_UNLOCKED)  			retcode = func(dev, kdata, file_priv);  		else { @@ -488,7 +501,7 @@ long drm_ioctl(struct file *filp,  		if (cmd & IOC_OUT) {  			if (copy_to_user((void __user *)arg, kdata, -					 _IOC_SIZE(cmd)) != 0) +					 usize) != 0)  				retcode = -EFAULT;  		}  	} | 
