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

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'input-for-v7.0-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

Pull input fixes from Dmitry Torokhov:
"Two fixes for force feedback handling in uinput driver:

- fix circular locking dependency in uinput

- fix potential corruption of uinput event queue"

* tag 'input-for-v7.0-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
Input: uinput - take event lock when submitting FF request "event"
Input: uinput - fix circular locking dependency with ff-core

+28 -7
+28 -7
drivers/input/misc/uinput.c
··· 25 25 #include <linux/module.h> 26 26 #include <linux/init.h> 27 27 #include <linux/fs.h> 28 + #include <linux/lockdep.h> 28 29 #include <linux/miscdevice.h> 29 30 #include <linux/overflow.h> 31 + #include <linux/spinlock.h> 30 32 #include <linux/input/mt.h> 31 33 #include "../input-compat.h" 32 34 ··· 59 57 struct input_dev *dev; 60 58 struct mutex mutex; 61 59 enum uinput_state state; 60 + spinlock_t state_lock; 62 61 wait_queue_head_t waitq; 63 62 unsigned char ready; 64 63 unsigned char head; ··· 77 74 { 78 75 struct uinput_device *udev = input_get_drvdata(dev); 79 76 struct timespec64 ts; 77 + 78 + lockdep_assert_held(&dev->event_lock); 80 79 81 80 ktime_get_ts64(&ts); 82 81 ··· 151 146 static int uinput_request_send(struct uinput_device *udev, 152 147 struct uinput_request *request) 153 148 { 154 - int retval; 149 + unsigned long flags; 150 + int retval = 0; 155 151 156 - retval = mutex_lock_interruptible(&udev->mutex); 157 - if (retval) 158 - return retval; 152 + spin_lock(&udev->state_lock); 159 153 160 154 if (udev->state != UIST_CREATED) { 161 155 retval = -ENODEV; 162 156 goto out; 163 157 } 164 158 165 - init_completion(&request->done); 166 - 167 159 /* 168 160 * Tell our userspace application about this new request 169 161 * by queueing an input event. 170 162 */ 163 + spin_lock_irqsave(&udev->dev->event_lock, flags); 171 164 uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id); 165 + spin_unlock_irqrestore(&udev->dev->event_lock, flags); 172 166 173 167 out: 174 - mutex_unlock(&udev->mutex); 168 + spin_unlock(&udev->state_lock); 175 169 return retval; 176 170 } 177 171 ··· 178 174 struct uinput_request *request) 179 175 { 180 176 int retval; 177 + 178 + /* 179 + * Initialize completion before allocating the request slot. 180 + * Once the slot is allocated, uinput_flush_requests() may 181 + * complete it at any time, so it must be initialized first. 182 + */ 183 + init_completion(&request->done); 181 184 182 185 retval = uinput_request_reserve_slot(udev, request); 183 186 if (retval) ··· 300 289 struct input_dev *dev = udev->dev; 301 290 enum uinput_state old_state = udev->state; 302 291 292 + /* 293 + * Update state under state_lock so that concurrent 294 + * uinput_request_send() sees the state change before we 295 + * flush pending requests and tear down the device. 296 + */ 297 + spin_lock(&udev->state_lock); 303 298 udev->state = UIST_NEW_DEVICE; 299 + spin_unlock(&udev->state_lock); 304 300 305 301 if (dev) { 306 302 name = dev->name; ··· 384 366 if (error) 385 367 goto fail2; 386 368 369 + spin_lock(&udev->state_lock); 387 370 udev->state = UIST_CREATED; 371 + spin_unlock(&udev->state_lock); 388 372 389 373 return 0; 390 374 ··· 404 384 return -ENOMEM; 405 385 406 386 mutex_init(&newdev->mutex); 387 + spin_lock_init(&newdev->state_lock); 407 388 spin_lock_init(&newdev->requests_lock); 408 389 init_waitqueue_head(&newdev->requests_waitq); 409 390 init_waitqueue_head(&newdev->waitq);