Skip to content

Commit 4cda78d

Browse files
NTMandtor
authored andcommitted
Input: uinput - fix circular locking dependency with ff-core
A lockdep circular locking dependency warning can be triggered reproducibly when using a force-feedback gamepad with uinput (for example, playing ELDEN RING under Wine with a Flydigi Vader 5 controller): ff->mutex -> udev->mutex -> input_mutex -> dev->mutex -> ff->mutex The cycle is caused by four lock acquisition paths: 1. ff upload: input_ff_upload() holds ff->mutex and calls uinput_dev_upload_effect() -> uinput_request_submit() -> uinput_request_send(), which acquires udev->mutex. 2. device create: uinput_ioctl_handler() holds udev->mutex and calls uinput_create_device() -> input_register_device(), which acquires input_mutex. 3. device register: input_register_device() holds input_mutex and calls kbd_connect() -> input_register_handle(), which acquires dev->mutex. 4. evdev release: evdev_release() calls input_flush_device() under dev->mutex, which calls input_ff_flush() acquiring ff->mutex. Fix this by introducing a new state_lock spinlock to protect udev->state and udev->dev access in uinput_request_send() instead of acquiring udev->mutex. The function only needs to atomically check device state and queue an input event into the ring buffer via uinput_dev_event() -- both operations are safe under a spinlock (ktime_get_ts64() and wake_up_interruptible() do not sleep). This breaks the ff->mutex -> udev->mutex link since a spinlock is a leaf in the lock ordering and cannot form cycles with mutexes. To keep state transitions visible to uinput_request_send(), protect writes to udev->state in uinput_create_device() and uinput_destroy_device() with the same state_lock spinlock. Additionally, move init_completion(&request->done) from uinput_request_send() to uinput_request_submit() before uinput_request_reserve_slot(). Once the slot is allocated, uinput_flush_requests() may call complete() on it at any time from the destroy path, so the completion must be initialised before the request becomes visible. Lock ordering after the fix: ff->mutex -> state_lock (spinlock, leaf) udev->mutex -> state_lock (spinlock, leaf) udev->mutex -> input_mutex -> dev->mutex -> ff->mutex (no back-edge) Fixes: ff46255 ("Input: uinput - switch to the new FF interface") Cc: [email protected] Link: https://lore.kernel.org/all/CABXGCsMoxag+kEwHhb7KqhuyxfmGGd0P=tHZyb1uKE0pLr8Hkg@mail.gmail.com/ Signed-off-by: Mikhail Gavrilov <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Dmitry Torokhov <[email protected]>
1 parent 0d9363a commit 4cda78d

1 file changed

Lines changed: 21 additions & 7 deletions

File tree

drivers/input/misc/uinput.c

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct uinput_device {
5757
struct input_dev *dev;
5858
struct mutex mutex;
5959
enum uinput_state state;
60+
spinlock_t state_lock;
6061
wait_queue_head_t waitq;
6162
unsigned char ready;
6263
unsigned char head;
@@ -146,27 +147,23 @@ static void uinput_request_release_slot(struct uinput_device *udev,
146147
static int uinput_request_send(struct uinput_device *udev,
147148
struct uinput_request *request)
148149
{
149-
int retval;
150+
int retval = 0;
150151

151-
retval = mutex_lock_interruptible(&udev->mutex);
152-
if (retval)
153-
return retval;
152+
spin_lock(&udev->state_lock);
154153

155154
if (udev->state != UIST_CREATED) {
156155
retval = -ENODEV;
157156
goto out;
158157
}
159158

160-
init_completion(&request->done);
161-
162159
/*
163160
* Tell our userspace application about this new request
164161
* by queueing an input event.
165162
*/
166163
uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
167164

168165
out:
169-
mutex_unlock(&udev->mutex);
166+
spin_unlock(&udev->state_lock);
170167
return retval;
171168
}
172169

@@ -175,6 +172,13 @@ static int uinput_request_submit(struct uinput_device *udev,
175172
{
176173
int retval;
177174

175+
/*
176+
* Initialize completion before allocating the request slot.
177+
* Once the slot is allocated, uinput_flush_requests() may
178+
* complete it at any time, so it must be initialized first.
179+
*/
180+
init_completion(&request->done);
181+
178182
retval = uinput_request_reserve_slot(udev, request);
179183
if (retval)
180184
return retval;
@@ -289,7 +293,14 @@ static void uinput_destroy_device(struct uinput_device *udev)
289293
struct input_dev *dev = udev->dev;
290294
enum uinput_state old_state = udev->state;
291295

296+
/*
297+
* Update state under state_lock so that concurrent
298+
* uinput_request_send() sees the state change before we
299+
* flush pending requests and tear down the device.
300+
*/
301+
spin_lock(&udev->state_lock);
292302
udev->state = UIST_NEW_DEVICE;
303+
spin_unlock(&udev->state_lock);
293304

294305
if (dev) {
295306
name = dev->name;
@@ -366,7 +377,9 @@ static int uinput_create_device(struct uinput_device *udev)
366377
if (error)
367378
goto fail2;
368379

380+
spin_lock(&udev->state_lock);
369381
udev->state = UIST_CREATED;
382+
spin_unlock(&udev->state_lock);
370383

371384
return 0;
372385

@@ -384,6 +397,7 @@ static int uinput_open(struct inode *inode, struct file *file)
384397
return -ENOMEM;
385398

386399
mutex_init(&newdev->mutex);
400+
spin_lock_init(&newdev->state_lock);
387401
spin_lock_init(&newdev->requests_lock);
388402
init_waitqueue_head(&newdev->requests_waitq);
389403
init_waitqueue_head(&newdev->waitq);

0 commit comments

Comments
 (0)