Re: [PATCH v3] Input: uinput - add new UINPUT_DEV_SETUP and UI_ABS_SETUP ioctl

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

On Oct 25 2015 or thereabouts, David Herrmann wrote:
> Hi
> 
> On Sun, Oct 25, 2015 at 12:53 AM, Dmitry Torokhov
> <dmitry.torokhov@xxxxxxxxx> wrote:
> > Hi Benjamin,
> >
> > On Tue, Aug 25, 2015 at 11:12:59AM -0400, Benjamin Tissoires wrote:
> >> +static int uinput_abs_setup(struct uinput_device *udev,
> >> +                         struct uinput_setup __user *arg, size_t size)
> >> +{
> >> +     struct uinput_abs_setup setup = {};
> >> +     struct input_dev *dev;
> >> +
> >> +     if (size > sizeof(setup))
> >> +             return -E2BIG;
> >> +     if (udev->state == UIST_CREATED)
> >> +             return -EINVAL;
> >> +     if (copy_from_user(&setup, arg, size))
> >> +             return -EFAULT;
> >> +     if (setup.code > ABS_MAX)
> >> +             return -ERANGE;
> >> +
> >> +     dev = udev->dev;
> >> +
> >> +     input_alloc_absinfo(dev);
> >> +     if (!dev->absinfo)
> >> +             return -ENOMEM;
> >> +
> >> +     set_bit(setup.code, dev->absbit);
> >> +     dev->absinfo[setup.code] = setup.absinfo;
> >> +
> >> +     /*
> >> +      * We restore the state to UIST_NEW_DEVICE because the user has to call
> >> +      * UI_DEV_SETUP in the last place before UI_DEV_CREATE to check the
> >> +      * validity of the absbits.
> >> +      */
> >
> > Do we have to be this strict? It seems to me that with the new IOCTLs
> > you naturally want to use the new ioctl to setup the device, then adjust
> > various axes and bits and then validate everything.
> 
> Indeed, we now force the order to be abs-setup first, then
> device-setup as last step. Appended is a follow-up patch to cleanup
> ABS handling in uinput. It is untested. Benjamin, care to give it a
> spin?
> 

Sorry it took so long for the tests/review.

So the test part is fine. It works as expected. (Tested-by: BT
<benjamin.tissoires@xxxxxxxxxx>)

For the review part, everything looks good except that now the doc for
UI_ABS_SETUP in uapi/linux/uinput.h should be changed to reflect the
fact that UI_DEV_SETUP is not a pre-requirement before calling
UI_ABS_SETUP.

With the doc change, the patch is also Reviewed-by: me.

Cheers,
Benjamin

> Thanks
> David
> 
> ----
> From 2568f83bcc5c4b8aeb149be2c5fc5a743812f0fe Mon Sep 17 00:00:00 2001
> From: David Herrmann <dh.herrmann@xxxxxxxxx>
> Date: Sun, 25 Oct 2015 10:34:13 +0100
> Subject: [PATCH] Input: uinput - rework ABS validation
> 
> Rework the uinput ABS validation to check passed absinfo data
> immediately, but do ABS initialization as last step in UI_DEV_CREATE. The
> behavior observed by user-space is not changed, as ABS initialization was
> never checked for errors.
> 
> With this in place, the order of device-initialization and
> abs-configuration is no longer fixed. User-space can initialize the
> device and afterwards set absinfo just fine.
> 
> Signed-off-by: David Herrmann <dh.herrmann@xxxxxxxxx>
> ---
>  drivers/input/misc/uinput.c | 89 +++++++++++++++++++++++----------------------
>  1 file changed, 45 insertions(+), 44 deletions(-)
> 
> diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
> index baac903..1d93037 100644
> --- a/drivers/input/misc/uinput.c
> +++ b/drivers/input/misc/uinput.c
> @@ -256,13 +256,22 @@ static void uinput_destroy_device(...)
>  static int uinput_create_device(struct uinput_device *udev)
>  {
>   struct input_dev *dev = udev->dev;
> - int error;
> + int error, nslot;
> 
>   if (udev->state != UIST_SETUP_COMPLETE) {
>   printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME);
>   return -EINVAL;
>   }
> 
> + if (test_bit(ABS_MT_SLOT, dev->absbit)) {
> + nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
> + error = input_mt_init_slots(dev, nslot, 0);
> + if (error)
> + goto fail1;
> + } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
> + input_set_events_per_packet(dev, 60);
> + }
> +
>   if (udev->ff_effects_max) {
>   error = input_ff_create(dev, udev->ff_effects_max);
>   if (error)
> @@ -308,10 +317,35 @@ static int uinput_open(...)
>   return 0;
>  }
> 
> +static int uinput_validate_absinfo(struct input_dev *dev, unsigned int code,
> +   const struct input_absinfo *abs)
> +{
> + int min, max;
> +
> + min = abs->minimum;
> + max = abs->maximum;
> +
> + if ((min != 0 || max != 0) && max <= min) {
> + printk(KERN_DEBUG
> +       "%s: invalid abs[%02x] min:%d max:%d\n",
> +       UINPUT_NAME, code, min, max);
> + return -EINVAL;
> + }
> +
> + if (abs->flat > max - min) {
> + printk(KERN_DEBUG
> +       "%s: abs_flat #%02x out of range: %d (min:%d/max:%d)\n",
> +       UINPUT_NAME, code, abs->flat, min, max);
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
>  static int uinput_validate_absbits(struct input_dev *dev)
>  {
>   unsigned int cnt;
> - int nslot;
> + int error;
> 
>   if (!test_bit(EV_ABS, dev->evbit))
>   return 0;
> @@ -321,38 +355,12 @@ static int uinput_validate_absbits(struct input_dev *dev)
>   */
> 
>   for_each_set_bit(cnt, dev->absbit, ABS_CNT) {
> - int min, max;
> -
> - min = input_abs_get_min(dev, cnt);
> - max = input_abs_get_max(dev, cnt);
> -
> - if ((min != 0 || max != 0) && max <= min) {
> - printk(KERN_DEBUG
> - "%s: invalid abs[%02x] min:%d max:%d\n",
> - UINPUT_NAME, cnt,
> - input_abs_get_min(dev, cnt),
> - input_abs_get_max(dev, cnt));
> + if (!dev->absinfo)
>   return -EINVAL;
> - }
> -
> - if (input_abs_get_flat(dev, cnt) >
> -    input_abs_get_max(dev, cnt) - input_abs_get_min(dev, cnt)) {
> - printk(KERN_DEBUG
> - "%s: abs_flat #%02x out of range: %d "
> - "(min:%d/max:%d)\n",
> - UINPUT_NAME, cnt,
> - input_abs_get_flat(dev, cnt),
> - input_abs_get_min(dev, cnt),
> - input_abs_get_max(dev, cnt));
> - return -EINVAL;
> - }
> - }
> 
> - if (test_bit(ABS_MT_SLOT, dev->absbit)) {
> - nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
> - input_mt_init_slots(dev, nslot, 0);
> - } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
> - input_set_events_per_packet(dev, 60);
> + error = uinput_validate_absinfo(dev, cnt, &dev->absinfo[cnt]);
> + if (error)
> + return error;
>   }
> 
>   return 0;
> @@ -375,7 +383,6 @@ static int uinput_dev_setup(struct uinput_device *udev,
>  {
>   struct uinput_setup setup;
>   struct input_dev *dev;
> - int retval;
> 
>   if (udev->state == UIST_CREATED)
>   return -EINVAL;
> @@ -393,10 +400,6 @@ static int uinput_dev_setup(struct uinput_device *udev,
>   if (!dev->name)
>   return -ENOMEM;
> 
> - retval = uinput_validate_absbits(dev);
> - if (retval < 0)
> - return retval;
> -
>   udev->state = UIST_SETUP_COMPLETE;
>   return 0;
>  }
> @@ -406,6 +409,7 @@ static int uinput_abs_setup(struct uinput_device *udev,
>  {
>   struct uinput_abs_setup setup = {};
>   struct input_dev *dev;
> + int error;
> 
>   if (size > sizeof(setup))
>   return -E2BIG;
> @@ -418,19 +422,16 @@ static int uinput_abs_setup(struct uinput_device *udev,
> 
>   dev = udev->dev;
> 
> + error = uinput_validate_absinfo(dev, setup.code, &setup.absinfo);
> + if (error)
> + return error;
> +
>   input_alloc_absinfo(dev);
>   if (!dev->absinfo)
>   return -ENOMEM;
> 
>   set_bit(setup.code, dev->absbit);
>   dev->absinfo[setup.code] = setup.absinfo;
> -
> - /*
> - * We restore the state to UIST_NEW_DEVICE because the user has to call
> - * UI_DEV_SETUP in the last place before UI_DEV_CREATE to check the
> - * validity of the absbits.
> - */
> - udev->state = UIST_NEW_DEVICE;
>   return 0;
>  }
> 
> -- 
> 2.6.1

> From 2568f83bcc5c4b8aeb149be2c5fc5a743812f0fe Mon Sep 17 00:00:00 2001
> From: David Herrmann <dh.herrmann@xxxxxxxxx>
> Date: Sun, 25 Oct 2015 10:34:13 +0100
> Subject: [PATCH] Input: uinput - rework ABS validation
> 
> Rework the uinput ABS validation to check passed absinfo data
> immediately, but do ABS initialization as last step in UI_DEV_CREATE. The
> behavior observed by user-space is not changed, as ABS initialization was
> never checked for errors.
> 
> With this in place, the order of device-initialization and
> abs-configuration is no longer fixed. User-space can initialize the
> device and afterwards set absinfo just fine.
> 
> Signed-off-by: David Herrmann <dh.herrmann@xxxxxxxxx>
> ---
>  drivers/input/misc/uinput.c | 89 +++++++++++++++++++++++----------------------
>  1 file changed, 45 insertions(+), 44 deletions(-)
> 
> diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
> index baac903..1d93037 100644
> --- a/drivers/input/misc/uinput.c
> +++ b/drivers/input/misc/uinput.c
> @@ -256,13 +256,22 @@ static void uinput_destroy_device(...)
>  static int uinput_create_device(struct uinput_device *udev)
>  {
>  	struct input_dev *dev = udev->dev;
> -	int error;
> +	int error, nslot;
>  
>  	if (udev->state != UIST_SETUP_COMPLETE) {
>  		printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME);
>  		return -EINVAL;
>  	}
>  
> +	if (test_bit(ABS_MT_SLOT, dev->absbit)) {
> +		nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
> +		error = input_mt_init_slots(dev, nslot, 0);
> +		if (error)
> +			goto fail1;
> +	} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
> +		input_set_events_per_packet(dev, 60);
> +	}
> +
>  	if (udev->ff_effects_max) {
>  		error = input_ff_create(dev, udev->ff_effects_max);
>  		if (error)
> @@ -308,10 +317,35 @@ static int uinput_open(...)
>  	return 0;
>  }
>  
> +static int uinput_validate_absinfo(struct input_dev *dev, unsigned int code,
> +				   const struct input_absinfo *abs)
> +{
> +	int min, max;
> +
> +	min = abs->minimum;
> +	max = abs->maximum;
> +
> +	if ((min != 0 || max != 0) && max <= min) {
> +		printk(KERN_DEBUG
> +		       "%s: invalid abs[%02x] min:%d max:%d\n",
> +		       UINPUT_NAME, code, min, max);
> +		return -EINVAL;
> +	}
> +
> +	if (abs->flat > max - min) {
> +		printk(KERN_DEBUG
> +		       "%s: abs_flat #%02x out of range: %d (min:%d/max:%d)\n",
> +		       UINPUT_NAME, code, abs->flat, min, max);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
>  static int uinput_validate_absbits(struct input_dev *dev)
>  {
>  	unsigned int cnt;
> -	int nslot;
> +	int error;
>  
>  	if (!test_bit(EV_ABS, dev->evbit))
>  		return 0;
> @@ -321,38 +355,12 @@ static int uinput_validate_absbits(struct input_dev *dev)
>  	 */
>  
>  	for_each_set_bit(cnt, dev->absbit, ABS_CNT) {
> -		int min, max;
> -
> -		min = input_abs_get_min(dev, cnt);
> -		max = input_abs_get_max(dev, cnt);
> -
> -		if ((min != 0 || max != 0) && max <= min) {
> -			printk(KERN_DEBUG
> -				"%s: invalid abs[%02x] min:%d max:%d\n",
> -				UINPUT_NAME, cnt,
> -				input_abs_get_min(dev, cnt),
> -				input_abs_get_max(dev, cnt));
> +		if (!dev->absinfo)
>  			return -EINVAL;
> -		}
> -
> -		if (input_abs_get_flat(dev, cnt) >
> -		    input_abs_get_max(dev, cnt) - input_abs_get_min(dev, cnt)) {
> -			printk(KERN_DEBUG
> -				"%s: abs_flat #%02x out of range: %d "
> -				"(min:%d/max:%d)\n",
> -				UINPUT_NAME, cnt,
> -				input_abs_get_flat(dev, cnt),
> -				input_abs_get_min(dev, cnt),
> -				input_abs_get_max(dev, cnt));
> -			return -EINVAL;
> -		}
> -	}
>  
> -	if (test_bit(ABS_MT_SLOT, dev->absbit)) {
> -		nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
> -		input_mt_init_slots(dev, nslot, 0);
> -	} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
> -		input_set_events_per_packet(dev, 60);
> +		error = uinput_validate_absinfo(dev, cnt, &dev->absinfo[cnt]);
> +		if (error)
> +			return error;
>  	}
>  
>  	return 0;
> @@ -375,7 +383,6 @@ static int uinput_dev_setup(struct uinput_device *udev,
>  {
>  	struct uinput_setup setup;
>  	struct input_dev *dev;
> -	int retval;
>  
>  	if (udev->state == UIST_CREATED)
>  		return -EINVAL;
> @@ -393,10 +400,6 @@ static int uinput_dev_setup(struct uinput_device *udev,
>  	if (!dev->name)
>  		return -ENOMEM;
>  
> -	retval = uinput_validate_absbits(dev);
> -	if (retval < 0)
> -		return retval;
> -
>  	udev->state = UIST_SETUP_COMPLETE;
>  	return 0;
>  }
> @@ -406,6 +409,7 @@ static int uinput_abs_setup(struct uinput_device *udev,
>  {
>  	struct uinput_abs_setup setup = {};
>  	struct input_dev *dev;
> +	int error;
>  
>  	if (size > sizeof(setup))
>  		return -E2BIG;
> @@ -418,19 +422,16 @@ static int uinput_abs_setup(struct uinput_device *udev,
>  
>  	dev = udev->dev;
>  
> +	error = uinput_validate_absinfo(dev, setup.code, &setup.absinfo);
> +	if (error)
> +		return error;
> +
>  	input_alloc_absinfo(dev);
>  	if (!dev->absinfo)
>  		return -ENOMEM;
>  
>  	set_bit(setup.code, dev->absbit);
>  	dev->absinfo[setup.code] = setup.absinfo;
> -
> -	/*
> -	 * We restore the state to UIST_NEW_DEVICE because the user has to call
> -	 * UI_DEV_SETUP in the last place before UI_DEV_CREATE to check the
> -	 * validity of the absbits.
> -	 */
> -	udev->state = UIST_NEW_DEVICE;
>  	return 0;
>  }
>  
> -- 
> 2.6.1
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux