lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<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

Powered by Openwall GNU/*/Linux Powered by OpenVZ