diff options
Diffstat (limited to 'drivers/input/joydev.c')
| -rw-r--r-- | drivers/input/joydev.c | 106 | 
1 files changed, 74 insertions, 32 deletions
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 9a1d55b74d7..901b2525993 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -452,6 +452,76 @@ static unsigned int joydev_poll(struct file *file, poll_table *wait)  		(joydev->exist ?  0 : (POLLHUP | POLLERR));  } +static int joydev_handle_JSIOCSAXMAP(struct joydev *joydev, +				     void __user *argp, size_t len) +{ +	__u8 *abspam; +	int i; +	int retval = 0; + +	len = min(len, sizeof(joydev->abspam)); + +	/* Validate the map. */ +	abspam = kmalloc(len, GFP_KERNEL); +	if (!abspam) +		return -ENOMEM; + +	if (copy_from_user(abspam, argp, len)) { +		retval = -EFAULT; +		goto out; +	} + +	for (i = 0; i < joydev->nabs; i++) { +		if (abspam[i] > ABS_MAX) { +			retval = -EINVAL; +			goto out; +		} +	} + +	memcpy(joydev->abspam, abspam, len); + + out: +	kfree(abspam); +	return retval; +} + +static int joydev_handle_JSIOCSBTNMAP(struct joydev *joydev, +				      void __user *argp, size_t len) +{ +	__u16 *keypam; +	int i; +	int retval = 0; + +	len = min(len, sizeof(joydev->keypam)); + +	/* Validate the map. */ +	keypam = kmalloc(len, GFP_KERNEL); +	if (!keypam) +		return -ENOMEM; + +	if (copy_from_user(keypam, argp, len)) { +		retval = -EFAULT; +		goto out; +	} + +	for (i = 0; i < joydev->nkey; i++) { +		if (keypam[i] > KEY_MAX || keypam[i] < BTN_MISC) { +			retval = -EINVAL; +			goto out; +		} +	} + +	memcpy(joydev->keypam, keypam, len); + +	for (i = 0; i < joydev->nkey; i++) +		joydev->keymap[keypam[i] - BTN_MISC] = i; + + out: +	kfree(keypam); +	return retval; +} + +  static int joydev_ioctl_common(struct joydev *joydev,  				unsigned int cmd, void __user *argp)  { @@ -512,46 +582,18 @@ static int joydev_ioctl_common(struct joydev *joydev,  	switch (cmd & ~IOCSIZE_MASK) {  	case (JSIOCSAXMAP & ~IOCSIZE_MASK): -		len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->abspam)); -		/* -		 * FIXME: we should not copy into our axis map before -		 * validating the data. -		 */ -		if (copy_from_user(joydev->abspam, argp, len)) -			return -EFAULT; - -		for (i = 0; i < joydev->nabs; i++) { -			if (joydev->abspam[i] > ABS_MAX) -				return -EINVAL; -			joydev->absmap[joydev->abspam[i]] = i; -		} -		return 0; +		return joydev_handle_JSIOCSAXMAP(joydev, argp, _IOC_SIZE(cmd));  	case (JSIOCGAXMAP & ~IOCSIZE_MASK):  		len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->abspam)); -		return copy_to_user(argp, joydev->abspam, len) ? -EFAULT : 0; +		return copy_to_user(argp, joydev->abspam, len) ? -EFAULT : len;  	case (JSIOCSBTNMAP & ~IOCSIZE_MASK): -		len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->keypam)); -		/* -		 * FIXME: we should not copy into our keymap before -		 * validating the data. -		 */ -		if (copy_from_user(joydev->keypam, argp, len)) -			return -EFAULT; - -		for (i = 0; i < joydev->nkey; i++) { -			if (joydev->keypam[i] > KEY_MAX || -			    joydev->keypam[i] < BTN_MISC) -				return -EINVAL; -			joydev->keymap[joydev->keypam[i] - BTN_MISC] = i; -		} - -		return 0; +		return joydev_handle_JSIOCSBTNMAP(joydev, argp, _IOC_SIZE(cmd));  	case (JSIOCGBTNMAP & ~IOCSIZE_MASK):  		len = min_t(size_t, _IOC_SIZE(cmd), sizeof(joydev->keypam)); -		return copy_to_user(argp, joydev->keypam, len) ? -EFAULT : 0; +		return copy_to_user(argp, joydev->keypam, len) ? -EFAULT : len;  	case JSIOCGNAME(0):  		name = dev->name;  |