PT-2026-35019 · Linux · Linux

Published

2026-04-24

·

Updated

2026-04-24

·

CVE-2026-31667

None

No severity ratings or metrics are available. When they are, we'll update the corresponding info on the page.
In the Linux kernel, the following vulnerability has been resolved:
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)

Related Identifiers

CVE-2026-31667

Affected Products

Linux