Re: [PATCH] Input: uinput - fix use-after-free of FF requests in ioctl handlers
From: Chad Aldreda
Date: Mon Nov 09 2026 - 10:36:34 EST
On Tue, 13 Oct 2026, Cen Zhang (Microsoft) wrote:
> An easy-to-hit case: two processes sharing a uinput fd and both issuing
> UI_END_FF_UPLOAD for the same request id crash a KASAN kernel within
> seconds.
Tested on mainline d48723711bae (v7.4-rc1-672), where this still
applies, in QEMU with KASAN, lockdep and kmemleak. A test program
creates a uinput device with FF_RUMBLE, uploads and erases effects
through its evdev node, and answers the requests through /dev/uinput.
Without the patch, a variant of the case above reproduces at once: a
handler process answering each request while two other processes sharing
the uinput fd issue UI_END_FF_UPLOAD and UI_END_FF_ERASE for every id
gives "BUG: spinlock wrong CPU" from UI_END_FF_UPLOAD, then a NULL
pointer dereference in ttwu_queue_wakelist() under complete() from
UI_END_FF_ERASE, and the guest locks up. The BEGIN side fails too: two
processes issuing UI_BEGIN_FF_UPLOAD while the handler answers give a
general protection fault in uinput_ioctl_handler() within seconds.
With the patch there are no KASAN, lockdep, oops or kmemleak reports.
Each race ran for 20 s, and both together for another 20 s. Over a
million requests were answered. Duplicate BEGIN and END calls either
succeeded, while the request was still in its slot, or got -EINVAL once
it had been released. KASAN does not see stack use-after-return, so
without the patch it caught only what followed the corruption; "clean"
here means no crash or corruption.
Normal use still works: an upload and an erase complete, a negative
retval from the handler (-ENOSPC) comes back from EVIOCSFF, BEGIN on an
idle slot and END on an out-of-range id return -EINVAL, and an
unanswered upload times out with -ETIMEDOUT after 30 s, after which
answering it returns -EINVAL. The timeout case behaves the same without
the patch.
I also ran 300 rounds of UI_DEV_DESTROY while one process uploaded
effects in a loop and another ended every slot. That was clean with the
patch, but also clean without it, so it does not show the flush window
either way.
Not tested: KCSAN. The double-END runs did reach the window the
automated review describes for request->retval (about 540k ENDs
succeeded on a request already answered but not yet released), but every
answer used retval 0, so a wrong value would not have shown. Also not
tested: the compat ioctls, UI_BEGIN_FF_ERASE racing, an END landing
between a timeout and the slot release, real force-feedback hardware or
applications, and module unload (uinput was built in). Only x86_64 with
4 vCPUs.
The harness and this report were produced with an AI assistant (Claude
Opus 5.5), which also did the earlier runs, including the unpatched
comparison. I ran the final version on the patched kernel myself and got
the same results. The harness is available on request.
Tested-by: Chad Aldreda <ca@xxxxxxxxxxxxxx>