Linux Documentation
 help / color / mirror / Atom feed
From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
To: "Jiri Kosina" <jikos@kernel.org>,
	"Benjamin Tissoires" <bentiss@kernel.org>,
	"Jonathan Corbet" <corbet@lwn.net>,
	"Shuah Khan" <skhan@linuxfoundation.org>,
	"Julia Lawall" <Julia.Lawall@inria.fr>,
	"Nicolas Palix" <nicolas.palix@imag.fr>,
	"Filipe Laíns" <lains@riseup.net>,
	"Bastien Nocera" <hadess@hadess.net>
Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org,
	 linux-doc@vger.kernel.org, cocci@inria.fr
Subject: [PATCH 02/21] HID: add documentation and Coccinelle script for FF registration race
Date: Mon, 03 Aug 2026 11:46:27 -0700	[thread overview]
Message-ID: <20260803-hid-ff-input-configured-v1-2-1dc9bbacd88c@gmail.com> (raw)
In-Reply-To: <20260803-hid-ff-input-configured-v1-0-1dc9bbacd88c@gmail.com>

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 <dmitry.torokhov@gmail.com>
---
 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


  parent reply	other threads:[~2026-08-03 18:46 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-03 18:46 [PATCH 00/21] HID: fix racy force feedback initialization via .input_configured() Dmitry Torokhov
2026-08-03 18:46 ` [PATCH 01/21] HID: core: automatically initialize generic FF if no other FF is present Dmitry Torokhov
2026-08-03 18:46 ` Dmitry Torokhov [this message]
2026-08-03 18:46 ` [PATCH 03/21] HID: axff: move FF initialization to .input_configured() Dmitry Torokhov
2026-08-03 18:46 ` [PATCH 04/21] HID: betop: " Dmitry Torokhov
2026-08-03 18:46 ` [PATCH 05/21] HID: bigben: " Dmitry Torokhov
2026-08-03 18:46 ` [PATCH 06/21] HID: dragonrise: " Dmitry Torokhov
2026-08-03 18:46 ` [PATCH 07/21] HID: emsff: " Dmitry Torokhov
2026-08-03 18:46 ` [PATCH 08/21] HID: gaff: " Dmitry Torokhov
2026-08-03 18:46 ` [PATCH 09/21] HID: stadia: use open/close to manage workqueue lifecycle Dmitry Torokhov
2026-08-03 18:46 ` [PATCH 10/21] HID: stadia: move FF initialization to .input_configured() Dmitry Torokhov
2026-08-03 18:46 ` [PATCH 11/21] HID: holtek: " Dmitry Torokhov
2026-08-03 18:46 ` [PATCH 12/21] HID: move generic FF initialization into hidinput_connect() Dmitry Torokhov
2026-08-03 18:46 ` [PATCH 13/21] HID: microsoft: move FF initialization to .input_configured() Dmitry Torokhov
2026-08-03 18:46 ` [PATCH 14/21] HID: pantherlord: " Dmitry Torokhov
2026-08-03 18:46 ` [PATCH 15/21] HID: thrustmaster: " Dmitry Torokhov
2026-08-03 18:46 ` [PATCH 16/21] HID: zeroplus: " Dmitry Torokhov
2026-08-03 18:46 ` [PATCH 17/21] HID: mayflash: " Dmitry Torokhov
2026-08-03 18:46 ` [PATCH 18/21] HID: smartjoyplus: " Dmitry Torokhov
2026-08-03 18:46 ` [PATCH 19/21] HID: megaworld: " Dmitry Torokhov
2026-08-03 18:46 ` [PATCH 20/21] HID: logitech-hidpp: " Dmitry Torokhov
2026-08-03 18:46 ` [PATCH 21/21] HID: haptic: move FF initialization into .input_configured() Dmitry Torokhov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260803-hid-ff-input-configured-v1-2-1dc9bbacd88c@gmail.com \
    --to=dmitry.torokhov@gmail.com \
    --cc=Julia.Lawall@inria.fr \
    --cc=bentiss@kernel.org \
    --cc=cocci@inria.fr \
    --cc=corbet@lwn.net \
    --cc=hadess@hadess.net \
    --cc=jikos@kernel.org \
    --cc=lains@riseup.net \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nicolas.palix@imag.fr \
    --cc=skhan@linuxfoundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox