[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <aSBPJPOlZdUfgzgg@pathway.suse.cz>
Date: Fri, 21 Nov 2025 12:38:12 +0100
From: Petr Mladek <pmladek@...e.com>
To: Chris Down <chris@...isdown.name>
Cc: linux-kernel@...r.kernel.org,
Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
Sergey Senozhatsky <senozhatsky@...omium.org>,
Steven Rostedt <rostedt@...dmis.org>,
John Ogness <john.ogness@...utronix.de>,
Geert Uytterhoeven <geert@...ux-m68k.org>,
Tony Lindgren <tony.lindgren@...ux.intel.com>, kernel-team@...com
Subject: Re: [PATCH v7 07/13] printk: console: Introduce sysfs interface for
per-console loglevels
On Wed 2025-11-19 03:07:27, Chris Down wrote:
> A sysfs interface under /sys/class/console/ is created that permits
> viewing and configuring per-console attributes. This is the main
> interface with which we expect users to interact with and configure
> per-console loglevels.
I made the following test:
1. Enable some debugging (CONFIG_DEBUG_KOBJECT=y, CONFIG_DEBUG_DRIVER=y)
2. Compile ttynull driver as a module (CONFIG_NULL_TTY=m)
3. Add "console=null" on the command line
4. Load the module "modprobe ttynull"
5. Remove the module "rmmod ttynull"
And I got the following warning when the module was removed:
[ 382.299081] printk: legacy console [ttynull0] disabled
[ 382.301829] device: 'ttynull0': device_unregister
[ 382.302057] kobject: 'ttynull0' (000000006a6b229d): kobject_uevent_env
[ 382.302088] kobject: 'ttynull0' (000000006a6b229d): fill_kobj_path: path = '/devices/virtual/console/ttynull0'
[ 382.302250] kobject: 'ttynull0' (000000006a6b229d): kobject_cleanup, parent 0000000000000000
[ 382.302261] kobject: 'ttynull0' (000000006a6b229d): calling ktype release
[ 382.302272] kobject: 'ttynull0': free name
[ 382.302281] ------------[ cut here ]------------
[ 382.302289] refcount_t: underflow; use-after-free.
[ 382.302319] WARNING: CPU: 4 PID: 1857 at lib/refcount.c:28 refcount_warn_saturate+0xbe/0x110
[ 382.302335] Modules linked in: ttynull(E-)
[ 382.302366] CPU: 4 UID: 0 PID: 1857 Comm: rmmod Tainted: G E 6.18.0-rc6-default+ #448 PREEMPT(full) b65a5eeebb0a78c479429a4b06dbf6320bbcd33d
[ 382.302379] Tainted: [E]=UNSIGNED_MODULE
[ 382.302388] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.3-2-gc13ff2cd-prebuilt.qemu.org 04/01/2014
[ 382.302396] RIP: 0010:refcount_warn_saturate+0xbe/0x110
[ 382.302407] Code: 01 01 e8 05 11 60 ff 0f 0b e9 29 2f 3b ff 80 3d cb 17 b0 01 00 75 85 48 c7 c7 28 d8 00 9d c6 05 bb 17 b0 01 01 e8 e2 10 60 ff <0f> 0b e9 06 2f 3b ff 80 3d a9 17 b0 01 00 0f 85 5e ff ff ff 48 c7
[ 382.302417] RSP: 0018:ffffcbd70189fe60 EFLAGS: 00010282
[ 382.302433] RAX: 0000000000000000 RBX: ffffffffc0459040 RCX: 0000000000000002
[ 382.302441] RDX: ffff8b32f57dff48 RSI: 0000000000000001 RDI: 00000000ffffffff
[ 382.302450] RBP: ffff8b328b4f7000 R08: 00000000fff7ffff R09: ffff8b32fe3fdfa8
[ 382.302458] R10: 0000000000000004 R11: 00000000fff80000 R12: ffffcbd70189ff58
[ 382.302467] R13: 00000000000000b0 R14: 0000000000000000 R15: 0000000000000000
[ 382.302479] FS: 00007f2e97442740(0000) GS:ffff8b3357178000(0000) knlGS:0000000000000000
[ 382.302488] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 382.302497] CR2: 00007fa3088176f8 CR3: 0000000105373000 CR4: 0000000000750ef0
[ 382.302524] PKRU: 55555554
[ 382.302532] Call Trace:
[ 382.302542] <TASK>
[ 382.302551] unregister_console_locked.cold+0x28e/0x2cd
[ 382.302582] unregister_console+0x1f/0x40
[ 382.302599] ttynull_exit+0x10/0xed0 [ttynull 4b641f8e4981ec0e180c1229c097d2bddb0fbe2a]
[ 382.302613] __do_sys_delete_module.isra.0+0x19b/0x270
[ 382.302648] ? srso_alias_return_thunk+0x5/0xfbef5
[ 382.302665] do_syscall_64+0x7a/0x360
[ 382.302692] entry_SYSCALL_64_after_hwframe+0x76/0x7e
[ 382.302703] RIP: 0033:0x7f2e95d18437
[ 382.302715] Code: 73 01 c3 48 8b 0d 59 0a 2d 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 b8 b0 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 29 0a 2d 00 f7 d8 64 89 01 48
[ 382.302725] RSP: 002b:00007fff591d8468 EFLAGS: 00000206 ORIG_RAX: 00000000000000b0
[ 382.302740] RAX: ffffffffffffffda RBX: 00007fff591d84c8 RCX: 00007f2e95d18437
[ 382.302748] RDX: 000000000000000a RSI: 0000000000000800 RDI: 000055fe1453b5e8
[ 382.302757] RBP: 000055fe1453b580 R08: 00007fff591d73e1 R09: 0000000000000000
[ 382.302765] R10: 00007f2e95d9d660 R11: 0000000000000206 R12: 00007fff591d86a0
[ 382.302774] R13: 00007fff591da738 R14: 000055fe1453a3c0 R15: 000055fe1453b580
[ 382.302834] </TASK>
[ 382.302843] irq event stamp: 2523
[ 382.302851] hardirqs last enabled at (2529): [<ffffffff9b40932e>] __up_console_sem+0x5e/0x70
[ 382.302863] hardirqs last disabled at (2534): [<ffffffff9b409313>] __up_console_sem+0x43/0x70
[ 382.302873] softirqs last enabled at (1622): [<ffffffff9b35cb2c>] handle_softirqs+0x32c/0x400
[ 382.302885] softirqs last disabled at (1617): [<ffffffff9b35cce9>] __irq_exit_rcu+0xd9/0x150
[ 382.302896] ---[ end trace 0000000000000000 ]---
[ 382.303050] device: 'ttynull': device_unregister
[ 382.303445] PM: Removing info for No Bus:ttynull
[ 382.303454] kobject: 'ttynull' (0000000012b1dfce): kobject_uevent_env
[ 382.303459] kobject: 'ttynull' (0000000012b1dfce): fill_kobj_path: path = '/devices/virtual/tty/ttynull'
[ 382.303494] kobject: 'ttynull' (0000000012b1dfce): kobject_cleanup, parent 0000000000000000
[ 382.303498] kobject: 'ttynull' (0000000012b1dfce): calling ktype release
[ 382.303502] kobject: 'ttynull': free name
[ 382.303506] kobject: '(null)' (00000000eec627ea): kobject_cleanup, parent 0000000000000000
[ 382.303516] kobject: '(null)' (00000000eec627ea): calling ktype release
[ 382.325859] kobject: 'holders' (0000000087b71c70): kobject_cleanup, parent 0000000040844ced
[ 382.325880] kobject: 'holders' (0000000087b71c70): auto cleanup kobject_del
[ 382.325918] kobject: 'holders' (0000000087b71c70): calling ktype release
[ 382.325931] kobject: (0000000087b71c70): dynamic_kobj_release
[ 382.325943] kobject: 'holders': free name
[ 382.326895] kobject: 'ttynull' (0000000040844ced): kobject_cleanup, parent 00000000546c84c0
[ 382.326915] kobject: 'ttynull' (0000000040844ced): auto cleanup kobject_del
[ 382.326928] kobject: 'ttynull' (0000000040844ced): auto cleanup 'remove' event
[ 382.326941] kobject: 'ttynull' (0000000040844ced): kobject_uevent_env
[ 382.326959] kobject: 'ttynull' (0000000040844ced): fill_kobj_path: path = '/module/ttynull'
[ 382.327049] kobject: 'ttynull' (0000000040844ced): calling ktype release
[ 382.327148] kobject: 'ttynull': free name
> The lifecycle of this classdev looks like this on registration:
>
> register_console(con)/printk_late_init()
> console_register_device(con)
> device_initialize(con->classdev) # kref_init: refcount = 1
> device_add(con->classdev) # get_device: refcount++ (to 2)
I think that the problem is here. It is true that device_add() gets
extra refcount at the beginning but it is decremented on success,
see:
int device_add(struct device *dev)
{
[...]
dev = get_device(dev); <---- refcount++ (to 2)
[...]
done:
put_device(dev); <----- refcount-- (back to 1)
return error;
> At stable state, the refcount is two.
>
> Console unregistration looks like this:
>
> unregister_console_locked(con)
> struct device *dev = console->classdev;
> console->classdev = NULL;
> device_unregister(dev)
> device_del(dev)
> device_remove_class_symlinks(dev)
> sysfs_delete_link()
> kernfs_remove_by_name_ns()
> __kernfs_remove()
> kernfs_drain()
> kernfs_drain_open_files() # wait for close()
> kobject_del(&dev->kobj) # removes from sysfs, does NOT change refcount
> put_device(dev) # kref_put: refcount-- (from 2 to 1)
> put_device(dev) # kref_put: refcount-- (from 1 to 0)
This extra put_device() is superfluous and must not be called,
see below.
> kobject_release()
> kobject_cleanup()
> device_release()
> console_classdev_release(dev)
> kfree(dev)
> --- a/kernel/printk/printk.c
> +++ b/kernel/printk/printk.c
> @@ -4379,6 +4383,13 @@ static int unregister_console_locked(struct console *console)
> if (console->flags & CON_NBCON)
> nbcon_free(console);
>
> + if (console->classdev) {
> + struct device *dev = console->classdev;
> + console->classdev = NULL;
> + device_unregister(dev);
> + put_device(dev);
The WARNING has gone after I removed this extra put_device().
And it seems to work well. The sysfs interface gets removed...
Just for record. I tried to load/remove the "ttynull" module
several times and it worked as well.
> + }
> +
> console_sysfs_notify();
>
> if (console->exit)
Best Regards,
Petr
Powered by blists - more mailing lists