| From 72262330f7b3ad2130e800cecf02adcce3c32c77 Mon Sep 17 00:00:00 2001 |
| From: Ian Abbott <abbotti@mev.co.uk> |
| Date: Thu, 23 Oct 2025 13:31:41 +0100 |
| Subject: comedi: c6xdigio: Fix invalid PNP driver unregistration |
| |
| From: Ian Abbott <abbotti@mev.co.uk> |
| |
| commit 72262330f7b3ad2130e800cecf02adcce3c32c77 upstream. |
| |
| The Comedi low-level driver "c6xdigio" seems to be for a parallel port |
| connected device. When the Comedi core calls the driver's Comedi |
| "attach" handler `c6xdigio_attach()` to configure a Comedi to use this |
| driver, it tries to enable the parallel port PNP resources by |
| registering a PNP driver with `pnp_register_driver()`, but ignores the |
| return value. (The `struct pnp_driver` it uses has only the `name` and |
| `id_table` members filled in.) The driver's Comedi "detach" handler |
| `c6xdigio_detach()` unconditionally unregisters the PNP driver with |
| `pnp_unregister_driver()`. |
| |
| It is possible for `c6xdigio_attach()` to return an error before it |
| calls `pnp_register_driver()` and it is possible for the call to |
| `pnp_register_driver()` to return an error (that is ignored). In both |
| cases, the driver should not be calling `pnp_unregister_driver()` as it |
| does in `c6xdigio_detach()`. (Note that `c6xdigio_detach()` will be |
| called by the Comedi core if `c6xdigio_attach()` returns an error, or if |
| the Comedi core decides to detach the Comedi device from the driver for |
| some other reason.) |
| |
| The unconditional call to `pnp_unregister_driver()` without a previous |
| successful call to `pnp_register_driver()` will cause |
| `driver_unregister()` to issue a warning "Unexpected driver |
| unregister!". This was detected by Syzbot [1]. |
| |
| Also, the PNP driver registration and unregistration should be done at |
| module init and exit time, respectively, not when attaching or detaching |
| Comedi devices to the driver. (There might be more than one Comedi |
| device being attached to the driver, although that is unlikely.) |
| |
| Change the driver to do the PNP driver registration at module init time, |
| and the unregistration at module exit time. Since `c6xdigio_detach()` |
| now only calls `comedi_legacy_detach()`, remove the function and change |
| the Comedi driver "detach" handler to `comedi_legacy_detach`. |
| |
| ------------------------------------------- |
| [1] Syzbot sample crash report: |
| Unexpected driver unregister! |
| WARNING: CPU: 0 PID: 5970 at drivers/base/driver.c:273 driver_unregister drivers/base/driver.c:273 [inline] |
| WARNING: CPU: 0 PID: 5970 at drivers/base/driver.c:273 driver_unregister+0x90/0xb0 drivers/base/driver.c:270 |
| Modules linked in: |
| CPU: 0 UID: 0 PID: 5970 Comm: syz.0.17 Not tainted syzkaller #0 PREEMPT(full) |
| Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/02/2025 |
| RIP: 0010:driver_unregister drivers/base/driver.c:273 [inline] |
| RIP: 0010:driver_unregister+0x90/0xb0 drivers/base/driver.c:270 |
| Code: 48 89 ef e8 c2 e6 82 fc 48 89 df e8 3a 93 ff ff 5b 5d e9 c3 6d d9 fb e8 be 6d d9 fb 90 48 c7 c7 e0 f8 1f 8c e8 51 a2 97 fb 90 <0f> 0b 90 90 5b 5d e9 a5 6d d9 fb e8 e0 f4 41 fc eb 94 e8 d9 f4 41 |
| RSP: 0018:ffffc9000373f9a0 EFLAGS: 00010282 |
| RAX: 0000000000000000 RBX: ffffffff8ff24720 RCX: ffffffff817b6ee8 |
| RDX: ffff88807c932480 RSI: ffffffff817b6ef5 RDI: 0000000000000001 |
| RBP: 0000000000000000 R08: 0000000000000001 R09: 0000000000000000 |
| R10: 0000000000000001 R11: 0000000000000001 R12: ffffffff8ff24660 |
| R13: dffffc0000000000 R14: 0000000000000000 R15: ffff88814cca0000 |
| FS: 000055556dab1500(0000) GS:ffff8881249d9000(0000) knlGS:0000000000000000 |
| CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 |
| CR2: 000055f77f285cd0 CR3: 000000007d871000 CR4: 00000000003526f0 |
| Call Trace: |
| <TASK> |
| comedi_device_detach_locked+0x12f/0xa50 drivers/comedi/drivers.c:207 |
| comedi_device_detach+0x67/0xb0 drivers/comedi/drivers.c:215 |
| comedi_device_attach+0x43d/0x900 drivers/comedi/drivers.c:1011 |
| do_devconfig_ioctl+0x1b1/0x710 drivers/comedi/comedi_fops.c:872 |
| comedi_unlocked_ioctl+0x165d/0x2f00 drivers/comedi/comedi_fops.c:2178 |
| vfs_ioctl fs/ioctl.c:51 [inline] |
| __do_sys_ioctl fs/ioctl.c:597 [inline] |
| __se_sys_ioctl fs/ioctl.c:583 [inline] |
| __x64_sys_ioctl+0x18e/0x210 fs/ioctl.c:583 |
| do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] |
| do_syscall_64+0xcd/0xfa0 arch/x86/entry/syscall_64.c:94 |
| entry_SYSCALL_64_after_hwframe+0x77/0x7f |
| RIP: 0033:0x7fc05798eec9 |
| Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48 |
| RSP: 002b:00007ffcf8184238 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 |
| RAX: ffffffffffffffda RBX: 00007fc057be5fa0 RCX: 00007fc05798eec9 |
| RDX: 0000200000000080 RSI: 0000000040946400 RDI: 0000000000000003 |
| RBP: 00007fc057a11f91 R08: 0000000000000000 R09: 0000000000000000 |
| R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 |
| R13: 00007fc057be5fa0 R14: 00007fc057be5fa0 R15: 0000000000000003 |
| </TASK> |
| ------------------------------------------- |
| |
| Reported-by: syzbot+6616bba359cec7a1def1@syzkaller.appspotmail.com |
| Closes: https://syzkaller.appspot.com/bug?extid=6616bba359cec7a1def1 |
| Fixes: 2c89e159cd2f ("Staging: comedi: add c6xdigio driver") |
| Cc: stable <stable@kernel.org> |
| Signed-off-by: Ian Abbott <abbotti@mev.co.uk> |
| Link: https://patch.msgid.link/20251023123141.6537-1-abbotti@mev.co.uk |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/comedi/drivers/c6xdigio.c | 46 ++++++++++++++++++++++++++++---------- |
| 1 file changed, 35 insertions(+), 11 deletions(-) |
| |
| --- a/drivers/comedi/drivers/c6xdigio.c |
| +++ b/drivers/comedi/drivers/c6xdigio.c |
| @@ -250,9 +250,6 @@ static int c6xdigio_attach(struct comedi |
| if (ret) |
| return ret; |
| |
| - /* Make sure that PnP ports get activated */ |
| - pnp_register_driver(&c6xdigio_pnp_driver); |
| - |
| s = &dev->subdevices[0]; |
| /* pwm output subdevice */ |
| s->type = COMEDI_SUBD_PWM; |
| @@ -279,19 +276,46 @@ static int c6xdigio_attach(struct comedi |
| return 0; |
| } |
| |
| -static void c6xdigio_detach(struct comedi_device *dev) |
| -{ |
| - comedi_legacy_detach(dev); |
| - pnp_unregister_driver(&c6xdigio_pnp_driver); |
| -} |
| - |
| static struct comedi_driver c6xdigio_driver = { |
| .driver_name = "c6xdigio", |
| .module = THIS_MODULE, |
| .attach = c6xdigio_attach, |
| - .detach = c6xdigio_detach, |
| + .detach = comedi_legacy_detach, |
| }; |
| -module_comedi_driver(c6xdigio_driver); |
| + |
| +static bool c6xdigio_pnp_registered = false; |
| + |
| +static int __init c6xdigio_module_init(void) |
| +{ |
| + int ret; |
| + |
| + ret = comedi_driver_register(&c6xdigio_driver); |
| + if (ret) |
| + return ret; |
| + |
| + if (IS_ENABLED(CONFIG_PNP)) { |
| + /* Try to activate the PnP ports */ |
| + ret = pnp_register_driver(&c6xdigio_pnp_driver); |
| + if (ret) { |
| + pr_warn("failed to register pnp driver - err %d\n", |
| + ret); |
| + ret = 0; /* ignore the error. */ |
| + } else { |
| + c6xdigio_pnp_registered = true; |
| + } |
| + } |
| + |
| + return 0; |
| +} |
| +module_init(c6xdigio_module_init); |
| + |
| +static void __exit c6xdigio_module_exit(void) |
| +{ |
| + if (c6xdigio_pnp_registered) |
| + pnp_unregister_driver(&c6xdigio_pnp_driver); |
| + comedi_driver_unregister(&c6xdigio_driver); |
| +} |
| +module_exit(c6xdigio_module_exit); |
| |
| MODULE_AUTHOR("Comedi https://www.comedi.org"); |
| MODULE_DESCRIPTION("Comedi driver for the C6x_DIGIO DSP daughter card"); |