[PATCH] media: rc: ati_remote: fix NULL input_dev on rc device open
From: YuanZhe Liu
Date: Sat Oct 17 2026 - 07:10:03 EST
ati_remote_probe() registers the rc device before it allocates and
assigns the mouse input device:
rc_register_device(ati_remote->rdev);
...
ati_remote->idev = input_dev;
The rc device can be opened as soon as it is registered, either through
its evdev node or through /dev/lirc0; both call ati_remote_open(), which
submits the interrupt URB. The completion handler ati_remote_irq_in()
reports the events it receives through ati_remote->idev, so a report
that arrives before the assignment above is passed to input_report_rel()
and input_event() as a NULL device:
BUG: kernel NULL pointer dereference, address: 0000000000000028
#PF: supervisor read access in kernel mode
...
RIP: 0010:input_event+0x41/0xa0 drivers/input/input.c:394
...
Call Trace:
<IRQ>
input_report_rel include/linux/input.h:450 [inline]
ati_remote_input_report drivers/media/rc/ati_remote.c:634 [inline]
ati_remote_irq_in+0xf45/0x1420 drivers/media/rc/ati_remote.c:657
__usb_hcd_giveback_urb+0x238/0x550 drivers/usb/core/hcd.c:1657
input_event() dereferences the device it is given and the faulting
address 0x28 is the offset of evbit in struct input_dev. ati_remote is
zeroed when it is allocated and ati_remote->idev is never written back,
so the pointer is NULL because it has not been assigned yet, not
because an input device was freed.
Allocate and initialize the mouse input device before the rc device is
registered, so that ati_remote->idev is valid before any path that
submits the interrupt URB exists. input_register_device() keeps its
place: input_event() is documented to be safe before registration, the
events are then simply not delivered to any input handler.
Fixes: c34516e599d9 ("[media] ati_remote: migrate to the rc subsystem")
Cc: stable@xxxxxxxxxxxxxxx
Co-developed-by: Bin Yu <byu@xxxxxxxxxxxxx>
Signed-off-by: Bin Yu <byu@xxxxxxxxxxxxx>
Co-developed-by: Cheng Wen <wencheng@xxxxxxxxxxxxx>
Signed-off-by: Cheng Wen <wencheng@xxxxxxxxxxxxx>
Signed-off-by: YuanZhe Liu <25031212351@xxxxxxxxxxxxxxxxx>
---
drivers/media/rc/ati_remote.c | 30 ++++++++++++++++++++----------
1 file changed, 20 insertions(+), 10 deletions(-)
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index 51d85de24fae..393717fbecc7 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -813,7 +813,7 @@ static int ati_remote_probe(struct usb_interface *interface,
struct usb_endpoint_descriptor *endpoint_in, *endpoint_out;
struct ati_receiver_type *type = (struct ati_receiver_type *)id->driver_info;
struct ati_remote *ati_remote;
- struct input_dev *input_dev;
+ struct input_dev *input_dev = NULL;
struct device *device = &interface->dev;
struct rc_dev *rc_dev;
int err = -ENOMEM;
@@ -893,23 +893,34 @@ static int ati_remote_probe(struct usb_interface *interface,
if (err)
goto exit_kill_urbs;
- /* Set up and register rc device */
- err = rc_register_device(ati_remote->rdev);
- if (err)
- goto exit_kill_urbs;
-
- /* Set up and register mouse input device */
+ /*
+ * Set up the mouse input device before registering the rc device:
+ * opening the rc device submits the interrupt URB, and its
+ * completion handler reports mouse events through
+ * ati_remote->idev, so that pointer has to be valid before the rc
+ * device can be opened. input_event() may be called before
+ * input_register_device(); such events are then simply not
+ * delivered to any input handler.
+ */
if (mouse) {
input_dev = input_allocate_device();
if (!input_dev) {
err = -ENOMEM;
- goto exit_unregister_device;
+ goto exit_kill_urbs;
}
ati_remote->idev = input_dev;
ati_remote_input_init(ati_remote);
- err = input_register_device(input_dev);
+ }
+ /* Set up and register rc device */
+ err = rc_register_device(ati_remote->rdev);
+ if (err)
+ goto exit_free_input_device;
+
+ /* Register the mouse input device */
+ if (mouse) {
+ err = input_register_device(input_dev);
if (err)
goto exit_free_input_device;
}
@@ -919,7 +930,6 @@ static int ati_remote_probe(struct usb_interface *interface,
exit_free_input_device:
input_free_device(input_dev);
- exit_unregister_device:
rc_unregister_device(rc_dev);
exit_kill_urbs:
usb_kill_urb(ati_remote->irq_urb);
--
2.34.1