[PATCH 02/21] HID: add documentation and Coccinelle script for FF registration race
Dmitry Torokhov <[email protected]> Mon, 03 Aug 2026 11:46:27 -0700
| Newsgroups | org.kernel.vger.linux-doc,org.kernel.vger.linux-input,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
HID drivers that rely on the HID core to register input devices must ensure that all private data and capabilities (like force-feedback) are fully initialized before registration. When hid_hw_start() is called with HID_CONNECT_HIDINPUT, the input device is registered immediately. This is racy if the driver attempts to augment the input device in probe() after starting the hardware. The correct way to handle this is to use the .input_configured() callback. Add documentation and a Coccinelle script to detect and prevent this anti-pattern. Assisted-by: Gemini:gemini-3.1-pro Signed-off-by: Dmitry Torokhov <[email protected]> --- Documentation/hid/hidintro.rst | 50 ++++++++++++++++++++++++++++++++++++ scripts/coccinelle/hid/ff_race.cocci | 34 ++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/Documentation/hid/hidintro.rst b/Documentation/hid/hidintro.rst index 73523e315ebd..5d367dfca0b8 100644 --- a/Documentation/hid/hidintro.rst +++ b/Documentation/hid/hidintro.rst @@ -522,3 +522,53 @@ This should really be your last resort. vendor: 0x093a product: 0x2510 ... + +Input Device Registration and Lifecycle +======================================== + +HID drivers that rely on the HID core to register input devices (by using the +``HID_CONNECT_HIDINPUT`` flag, which is part of ``HID_CONNECT_DEFAULT``) +must be aware of the registration timing. + +When ``hid_hw_start(hdev, flags)`` is called with ``HID_CONNECT_HIDINPUT``, +the HID core immediately parses the report descriptor, allocates ``input_dev`` +structures, and calls ``input_register_device()`` for each of them. + +This means the input device becomes **live and visible to userspace** before +``hid_hw_start()`` returns. + +If a driver needs to perform additional configuration on the input device (such +as adding force-feedback support, setting extra bits in ``evbit``, or +assigning custom event handlers), doing so in the ``probe`` function after +``hid_hw_start()`` is **incorrect and racy**. Userspace may trigger +callbacks (like ``play_effect``) via ioctls immediately after registration, +leading to potential NULL pointer dereferences if the driver hasn't finished +initializing its private data. + +The correct way to augment an input device before it is registered is to use the +``.input_configured`` callback in ``struct hid_driver``. This hook is +called by the HID core after the ``input_dev`` is fully formed but **before** +``input_register_device()`` is invoked. + +Example: + +.. code-block:: c + + static int my_input_configured(struct hid_device *hdev, struct hid_input *hidinput) + { + struct input_dev *input = hidinput->input; + + /* Initialize private data and capabilities here */ + set_bit(EV_FF, input->evbit); + return input_ff_create_memless(input, NULL, my_play_effect); + } + + static struct hid_driver my_driver = { + .name = "my_driver", + .probe = my_probe, + .input_configured = my_input_configured, + }; + +Drivers that require even more control over the lifecycle should mask out +``HID_CONNECT_HIDINPUT`` and call ``input_register_device()`` manually +when they are ready. diff --git a/scripts/coccinelle/hid/ff_race.cocci b/scripts/coccinelle/hid/ff_race.cocci new file mode 100644 index 000000000000..479f5d1e3184 --- /dev/null +++ b/scripts/coccinelle/hid/ff_race.cocci @@ -0,0 +1,34 @@ +/// Detect HID drivers that initialize force-feedback after hid_hw_start() +/// when HID_CONNECT_HIDINPUT is used. This is a lifecycle violation as +/// the input device is already registered. +// +// Confidence: High +// Copyright: (C) 2026 Gemini. GPLv2. + +virtual report + +@r@ +identifier probe_fn; +expression hdev, flags; +position p1, p2; +@@ + +probe_fn(struct hid_device *hdev, ...) { + <... + hid_hw_start@p1(hdev, flags) + ... + \(input_ff_create\|input_ff_create_memless\)@p2(...) + ...> +} + +@script:python depends on report@ +p1 << r.p1; +p2 << r.p2; +flags << r.flags; +@@ + +# Check if flags include HID_CONNECT_HIDINPUT (0x01) or HID_CONNECT_DEFAULT (0x0f) +# Note: HID_CONNECT_DEFAULT is 0x0f, HID_CONNECT_HIDINPUT is 0x01 +if "HID_CONNECT_HIDINPUT" in flags or "HID_CONNECT_DEFAULT" in flags: + msg = "WARNING: force-feedback initialized after hid_hw_start() with HID_CONNECT_HIDINPUT. Input device is already registered at this point. Use .input_configured() instead." + coccilib.report.print_report(p2[0], msg) -- 2.55.0.629.g250fe7f194-goog