aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@gmail.com>2015-10-25 05:34:13 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2015-12-18 20:48:51 -0500
commitfbae10db094046dba1d59e1c2ee5140835045f14 (patch)
treef9129de6b266dada624d4bbce5457ed87fb42630
parent052876f8e5aec887d22c4d06e54aa5531ffcec75 (diff)
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. Userspace can initialize the device and afterwards set absinfo just fine. Signed-off-by: David Herrmann <dh.herrmann@gmail.com> Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Tested-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r--drivers/input/misc/uinput.c89
-rw-r--r--include/uapi/linux/uinput.h29
2 files changed, 58 insertions, 60 deletions
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index a16fc4a4bb1f..782df415e4d5 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -256,13 +256,22 @@ static void uinput_destroy_device(struct uinput_device *udev)
256static int uinput_create_device(struct uinput_device *udev) 256static int uinput_create_device(struct uinput_device *udev)
257{ 257{
258 struct input_dev *dev = udev->dev; 258 struct input_dev *dev = udev->dev;
259 int error; 259 int error, nslot;
260 260
261 if (udev->state != UIST_SETUP_COMPLETE) { 261 if (udev->state != UIST_SETUP_COMPLETE) {
262 printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME); 262 printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME);
263 return -EINVAL; 263 return -EINVAL;
264 } 264 }
265 265
266 if (test_bit(ABS_MT_SLOT, dev->absbit)) {
267 nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
268 error = input_mt_init_slots(dev, nslot, 0);
269 if (error)
270 goto fail1;
271 } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
272 input_set_events_per_packet(dev, 60);
273 }
274
266 if (udev->ff_effects_max) { 275 if (udev->ff_effects_max) {
267 error = input_ff_create(dev, udev->ff_effects_max); 276 error = input_ff_create(dev, udev->ff_effects_max);
268 if (error) 277 if (error)
@@ -308,10 +317,35 @@ static int uinput_open(struct inode *inode, struct file *file)
308 return 0; 317 return 0;
309} 318}
310 319
320static int uinput_validate_absinfo(struct input_dev *dev, unsigned int code,
321 const struct input_absinfo *abs)
322{
323 int min, max;
324
325 min = abs->minimum;
326 max = abs->maximum;
327
328 if ((min != 0 || max != 0) && max <= min) {
329 printk(KERN_DEBUG
330 "%s: invalid abs[%02x] min:%d max:%d\n",
331 UINPUT_NAME, code, min, max);
332 return -EINVAL;
333 }
334
335 if (abs->flat > max - min) {
336 printk(KERN_DEBUG
337 "%s: abs_flat #%02x out of range: %d (min:%d/max:%d)\n",
338 UINPUT_NAME, code, abs->flat, min, max);
339 return -EINVAL;
340 }
341
342 return 0;
343}
344
311static int uinput_validate_absbits(struct input_dev *dev) 345static int uinput_validate_absbits(struct input_dev *dev)
312{ 346{
313 unsigned int cnt; 347 unsigned int cnt;
314 int nslot; 348 int error;
315 349
316 if (!test_bit(EV_ABS, dev->evbit)) 350 if (!test_bit(EV_ABS, dev->evbit))
317 return 0; 351 return 0;
@@ -321,38 +355,12 @@ static int uinput_validate_absbits(struct input_dev *dev)
321 */ 355 */
322 356
323 for_each_set_bit(cnt, dev->absbit, ABS_CNT) { 357 for_each_set_bit(cnt, dev->absbit, ABS_CNT) {
324 int min, max; 358 if (!dev->absinfo)
325
326 min = input_abs_get_min(dev, cnt);
327 max = input_abs_get_max(dev, cnt);
328
329 if ((min != 0 || max != 0) && max <= min) {
330 printk(KERN_DEBUG
331 "%s: invalid abs[%02x] min:%d max:%d\n",
332 UINPUT_NAME, cnt,
333 input_abs_get_min(dev, cnt),
334 input_abs_get_max(dev, cnt));
335 return -EINVAL; 359 return -EINVAL;
336 }
337
338 if (input_abs_get_flat(dev, cnt) >
339 input_abs_get_max(dev, cnt) - input_abs_get_min(dev, cnt)) {
340 printk(KERN_DEBUG
341 "%s: abs_flat #%02x out of range: %d "
342 "(min:%d/max:%d)\n",
343 UINPUT_NAME, cnt,
344 input_abs_get_flat(dev, cnt),
345 input_abs_get_min(dev, cnt),
346 input_abs_get_max(dev, cnt));
347 return -EINVAL;
348 }
349 }
350 360
351 if (test_bit(ABS_MT_SLOT, dev->absbit)) { 361 error = uinput_validate_absinfo(dev, cnt, &dev->absinfo[cnt]);
352 nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1; 362 if (error)
353 input_mt_init_slots(dev, nslot, 0); 363 return error;
354 } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
355 input_set_events_per_packet(dev, 60);
356 } 364 }
357 365
358 return 0; 366 return 0;
@@ -375,7 +383,6 @@ static int uinput_dev_setup(struct uinput_device *udev,
375{ 383{
376 struct uinput_setup setup; 384 struct uinput_setup setup;
377 struct input_dev *dev; 385 struct input_dev *dev;
378 int retval;
379 386
380 if (udev->state == UIST_CREATED) 387 if (udev->state == UIST_CREATED)
381 return -EINVAL; 388 return -EINVAL;
@@ -395,10 +402,6 @@ static int uinput_dev_setup(struct uinput_device *udev,
395 if (!dev->name) 402 if (!dev->name)
396 return -ENOMEM; 403 return -ENOMEM;
397 404
398 retval = uinput_validate_absbits(dev);
399 if (retval < 0)
400 return retval;
401
402 udev->state = UIST_SETUP_COMPLETE; 405 udev->state = UIST_SETUP_COMPLETE;
403 return 0; 406 return 0;
404} 407}
@@ -408,6 +411,7 @@ static int uinput_abs_setup(struct uinput_device *udev,
408{ 411{
409 struct uinput_abs_setup setup = {}; 412 struct uinput_abs_setup setup = {};
410 struct input_dev *dev; 413 struct input_dev *dev;
414 int error;
411 415
412 if (size > sizeof(setup)) 416 if (size > sizeof(setup))
413 return -E2BIG; 417 return -E2BIG;
@@ -423,19 +427,16 @@ static int uinput_abs_setup(struct uinput_device *udev,
423 427
424 dev = udev->dev; 428 dev = udev->dev;
425 429
430 error = uinput_validate_absinfo(dev, setup.code, &setup.absinfo);
431 if (error)
432 return error;
433
426 input_alloc_absinfo(dev); 434 input_alloc_absinfo(dev);
427 if (!dev->absinfo) 435 if (!dev->absinfo)
428 return -ENOMEM; 436 return -ENOMEM;
429 437
430 set_bit(setup.code, dev->absbit); 438 set_bit(setup.code, dev->absbit);
431 dev->absinfo[setup.code] = setup.absinfo; 439 dev->absinfo[setup.code] = setup.absinfo;
432
433 /*
434 * We restore the state to UIST_NEW_DEVICE because the user has to call
435 * UI_DEV_SETUP in the last place before UI_DEV_CREATE to check the
436 * validity of the absbits.
437 */
438 udev->state = UIST_NEW_DEVICE;
439 return 0; 440 return 0;
440} 441}
441 442
diff --git a/include/uapi/linux/uinput.h b/include/uapi/linux/uinput.h
index 77b8cf73a178..dc652e224b67 100644
--- a/include/uapi/linux/uinput.h
+++ b/include/uapi/linux/uinput.h
@@ -72,13 +72,12 @@ struct uinput_setup {
72/** 72/**
73 * UI_DEV_SETUP - Set device parameters for setup 73 * UI_DEV_SETUP - Set device parameters for setup
74 * 74 *
75 * This ioctl sets parameters for the input device to be created. It must be 75 * This ioctl sets parameters for the input device to be created. It
76 * issued *before* calling UI_DEV_CREATE or it will fail. This ioctl supersedes 76 * supersedes the old "struct uinput_user_dev" method, which wrote this data
77 * the old "struct uinput_user_dev" method, which wrote this data via write(). 77 * via write(). To actually set the absolute axes UI_ABS_SETUP should be
78 * To actually set the absolute axes, you also need to call the ioctl 78 * used.
79 * UI_ABS_SETUP *before* calling this ioctl.
80 * 79 *
81 * This ioctl takes a "struct uinput_setup" object as argument. The fields of 80 * The ioctl takes a "struct uinput_setup" object as argument. The fields of
82 * this object are as follows: 81 * this object are as follows:
83 * id: See the description of "struct input_id". This field is 82 * id: See the description of "struct input_id". This field is
84 * copied unchanged into the new device. 83 * copied unchanged into the new device.
@@ -87,9 +86,9 @@ struct uinput_setup {
87 * See below for a description of FF with uinput. 86 * See below for a description of FF with uinput.
88 * 87 *
89 * This ioctl can be called multiple times and will overwrite previous values. 88 * This ioctl can be called multiple times and will overwrite previous values.
90 * If this ioctl fails with -EINVAL, you're recommended to use the old 89 * If this ioctl fails with -EINVAL, it is recommended to use the old
91 * "uinput_user_dev" method via write() as fallback, in case you run on an old 90 * "uinput_user_dev" method via write() as a fallback, in case you run on an
92 * kernel that does not support this ioctl. 91 * old kernel that does not support this ioctl.
93 * 92 *
94 * This ioctl may fail with -EINVAL if it is not supported or if you passed 93 * This ioctl may fail with -EINVAL if it is not supported or if you passed
95 * incorrect values, -ENOMEM if the kernel runs out of memory or -EFAULT if the 94 * incorrect values, -ENOMEM if the kernel runs out of memory or -EFAULT if the
@@ -109,12 +108,10 @@ struct uinput_abs_setup {
109 * UI_ABS_SETUP - Set absolute axis information for the device to setup 108 * UI_ABS_SETUP - Set absolute axis information for the device to setup
110 * 109 *
111 * This ioctl sets one absolute axis information for the input device to be 110 * This ioctl sets one absolute axis information for the input device to be
112 * created. It must be issued *before* calling UI_DEV_SETUP and UI_DEV_CREATE 111 * created. It supersedes the old "struct uinput_user_dev" method, which wrote
113 * for every absolute axis the device exports.
114 * This ioctl supersedes the old "struct uinput_user_dev" method, which wrote
115 * part of this data and the content of UI_DEV_SETUP via write(). 112 * part of this data and the content of UI_DEV_SETUP via write().
116 * 113 *
117 * This ioctl takes a "struct uinput_abs_setup" object as argument. The fields 114 * The ioctl takes a "struct uinput_abs_setup" object as argument. The fields
118 * of this object are as follows: 115 * of this object are as follows:
119 * code: The corresponding input code associated with this axis 116 * code: The corresponding input code associated with this axis
120 * (ABS_X, ABS_Y, etc...) 117 * (ABS_X, ABS_Y, etc...)
@@ -124,9 +121,9 @@ struct uinput_abs_setup {
124 * UI_SET_ABSBIT, this ioctl will enable it. 121 * UI_SET_ABSBIT, this ioctl will enable it.
125 * 122 *
126 * This ioctl can be called multiple times and will overwrite previous values. 123 * This ioctl can be called multiple times and will overwrite previous values.
127 * If this ioctl fails with -EINVAL, you're recommended to use the old 124 * If this ioctl fails with -EINVAL, it is recommended to use the old
128 * "uinput_user_dev" method via write() as fallback, in case you run on an old 125 * "uinput_user_dev" method via write() as a fallback, in case you run on an
129 * kernel that does not support this ioctl. 126 * old kernel that does not support this ioctl.
130 * 127 *
131 * This ioctl may fail with -EINVAL if it is not supported or if you passed 128 * This ioctl may fail with -EINVAL if it is not supported or if you passed
132 * incorrect values, -ENOMEM if the kernel runs out of memory or -EFAULT if the 129 * incorrect values, -ENOMEM if the kernel runs out of memory or -EFAULT if the