Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: mousedev - fix race when creating mixed device

We should not be using static variable mousedev_mix in methods that can be
called before that singleton gets assigned. While at it let's add open and
close methods to mousedev structure so that we do not need to test if we
are dealing with multiplexor or normal device and simply call appropriate
method directly.

This fixes: https://bugzilla.kernel.org/show_bug.cgi?id=71551

Reported-by: GiulioDP <depasquale.giulio@gmail.com>
Tested-by: GiulioDP <depasquale.giulio@gmail.com>
Cc: stable@vger.kernel.org
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

+42 -31
+42 -31
drivers/input/mousedev.c
··· 67 67 struct device dev; 68 68 struct cdev cdev; 69 69 bool exist; 70 - bool is_mixdev; 71 70 72 71 struct list_head mixdev_node; 73 72 bool opened_by_mixdev; ··· 76 77 int old_x[4], old_y[4]; 77 78 int frac_dx, frac_dy; 78 79 unsigned long touch; 80 + 81 + int (*open_device)(struct mousedev *mousedev); 82 + void (*close_device)(struct mousedev *mousedev); 79 83 }; 80 84 81 85 enum mousedev_emul { ··· 117 115 118 116 static struct mousedev *mousedev_mix; 119 117 static LIST_HEAD(mousedev_mix_list); 120 - 121 - static void mixdev_open_devices(void); 122 - static void mixdev_close_devices(void); 123 118 124 119 #define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03]) 125 120 #define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03]) ··· 427 428 if (retval) 428 429 return retval; 429 430 430 - if (mousedev->is_mixdev) 431 - mixdev_open_devices(); 432 - else if (!mousedev->exist) 431 + if (!mousedev->exist) 433 432 retval = -ENODEV; 434 433 else if (!mousedev->open++) { 435 434 retval = input_open_device(&mousedev->handle); ··· 443 446 { 444 447 mutex_lock(&mousedev->mutex); 445 448 446 - if (mousedev->is_mixdev) 447 - mixdev_close_devices(); 448 - else if (mousedev->exist && !--mousedev->open) 449 + if (mousedev->exist && !--mousedev->open) 449 450 input_close_device(&mousedev->handle); 450 451 451 452 mutex_unlock(&mousedev->mutex); ··· 454 459 * stream. Note that this function is called with mousedev_mix->mutex 455 460 * held. 456 461 */ 457 - static void mixdev_open_devices(void) 462 + static int mixdev_open_devices(struct mousedev *mixdev) 458 463 { 459 - struct mousedev *mousedev; 464 + int error; 460 465 461 - if (mousedev_mix->open++) 462 - return; 466 + error = mutex_lock_interruptible(&mixdev->mutex); 467 + if (error) 468 + return error; 463 469 464 - list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { 465 - if (!mousedev->opened_by_mixdev) { 466 - if (mousedev_open_device(mousedev)) 467 - continue; 470 + if (!mixdev->open++) { 471 + struct mousedev *mousedev; 468 472 469 - mousedev->opened_by_mixdev = true; 473 + list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { 474 + if (!mousedev->opened_by_mixdev) { 475 + if (mousedev_open_device(mousedev)) 476 + continue; 477 + 478 + mousedev->opened_by_mixdev = true; 479 + } 470 480 } 471 481 } 482 + 483 + mutex_unlock(&mixdev->mutex); 484 + return 0; 472 485 } 473 486 474 487 /* ··· 484 481 * device. Note that this function is called with mousedev_mix->mutex 485 482 * held. 486 483 */ 487 - static void mixdev_close_devices(void) 484 + static void mixdev_close_devices(struct mousedev *mixdev) 488 485 { 489 - struct mousedev *mousedev; 486 + mutex_lock(&mixdev->mutex); 490 487 491 - if (--mousedev_mix->open) 492 - return; 488 + if (!--mixdev->open) { 489 + struct mousedev *mousedev; 493 490 494 - list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { 495 - if (mousedev->opened_by_mixdev) { 496 - mousedev->opened_by_mixdev = false; 497 - mousedev_close_device(mousedev); 491 + list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { 492 + if (mousedev->opened_by_mixdev) { 493 + mousedev->opened_by_mixdev = false; 494 + mousedev_close_device(mousedev); 495 + } 498 496 } 499 497 } 498 + 499 + mutex_unlock(&mixdev->mutex); 500 500 } 501 501 502 502 ··· 528 522 mousedev_detach_client(mousedev, client); 529 523 kfree(client); 530 524 531 - mousedev_close_device(mousedev); 525 + mousedev->close_device(mousedev); 532 526 533 527 return 0; 534 528 } ··· 556 550 client->mousedev = mousedev; 557 551 mousedev_attach_client(mousedev, client); 558 552 559 - error = mousedev_open_device(mousedev); 553 + error = mousedev->open_device(mousedev); 560 554 if (error) 561 555 goto err_free_client; 562 556 ··· 867 861 868 862 if (mixdev) { 869 863 dev_set_name(&mousedev->dev, "mice"); 864 + 865 + mousedev->open_device = mixdev_open_devices; 866 + mousedev->close_device = mixdev_close_devices; 870 867 } else { 871 868 int dev_no = minor; 872 869 /* Normalize device number if it falls into legacy range */ 873 870 if (dev_no < MOUSEDEV_MINOR_BASE + MOUSEDEV_MINORS) 874 871 dev_no -= MOUSEDEV_MINOR_BASE; 875 872 dev_set_name(&mousedev->dev, "mouse%d", dev_no); 873 + 874 + mousedev->open_device = mousedev_open_device; 875 + mousedev->close_device = mousedev_close_device; 876 876 } 877 877 878 878 mousedev->exist = true; 879 - mousedev->is_mixdev = mixdev; 880 879 mousedev->handle.dev = input_get_device(dev); 881 880 mousedev->handle.name = dev_name(&mousedev->dev); 882 881 mousedev->handle.handler = handler; ··· 930 919 device_del(&mousedev->dev); 931 920 mousedev_cleanup(mousedev); 932 921 input_free_minor(MINOR(mousedev->dev.devt)); 933 - if (!mousedev->is_mixdev) 922 + if (mousedev != mousedev_mix) 934 923 input_unregister_handle(&mousedev->handle); 935 924 put_device(&mousedev->dev); 936 925 }