diff --git a/MAINTAINERS b/MAINTAINERS index d7798fdde245..b2eaee98852f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22436,6 +22436,7 @@ M: Petr Mladek M: John Ogness R: Steven Rostedt R: Sergey Senozhatsky +L: printk@lists.linux.dev S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux.git F: Documentation/core-api/printk-basics.rst @@ -22444,6 +22445,7 @@ F: kernel/printk/ PRINTK INDEXING R: Chris Down +L: printk@lists.linux.dev S: Maintained F: Documentation/core-api/printk-index.rst F: kernel/printk/index.c @@ -30062,6 +30064,7 @@ M: Steven Rostedt R: Andy Shevchenko R: Rasmus Villemoes R: Sergey Senozhatsky +L: printk@lists.linux.dev S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux.git F: Documentation/core-api/printk-formats.rst diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 9a205f94bfac..5dbcf8a9909b 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -3792,6 +3792,13 @@ static struct syscore printk_syscore = { * If appropriate, start nbcon kthreads and set @printk_kthreads_running. * If any kthreads fail to start, those consoles are unregistered. * + * Called after consoles are registered or unregistered. + * + * This MUST NOT be called within an hlist_for_each_entry_safe(console_list) + * loop because it can unregister multiple consoles if any kthreads fail to + * start. That would lead to use-after-free scenarios within the + * hlist_for_each_entry_safe(console_list) loop of the caller. + * * Must be called under console_list_lock(). */ static void printk_kthreads_check_locked(void) @@ -4230,7 +4237,20 @@ void register_console(struct console *newcon) } EXPORT_SYMBOL(register_console); -/* Must be called under console_list_lock(). */ +/* + * Unregister the specified console. + * + * This can be called safely from within an + * hlist_for_each_entry_safe(console_list) loop because it unregisters + * _only_ the specified console. + * + * Afterwards the caller should call printk_kthreads_check_locked() since + * unregistering a console may require printer threads to start/stop. Note + * that printk_kthreads_check_locked() cannot be called safely from within + * an hlist_for_each_entry_safe(console_list) loop. + * + * Must be called under console_list_lock(). + */ static int unregister_console_locked(struct console *console) { bool use_device_lock = (console->flags & CON_NBCON) && console->write_atomic; @@ -4322,9 +4342,6 @@ static int unregister_console_locked(struct console *console) if (console->exit) res = console->exit(console); - /* Changed console list, may require printer threads to start/stop. */ - printk_kthreads_check_locked(); - return res; } @@ -4333,7 +4350,12 @@ int unregister_console(struct console *console) int res; console_list_lock(); + res = unregister_console_locked(console); + + /* Changed console list, may require printer threads to start/stop. */ + printk_kthreads_check_locked(); + console_list_unlock(); return res; } @@ -4472,6 +4494,10 @@ static int __init printk_late_init(void) unregister_console_locked(con); } + + /* Changed console list, may require printer threads to start/stop. */ + printk_kthreads_check_locked(); + console_list_unlock(); ret = cpuhp_setup_state_nocalls(CPUHP_PRINTK_DEAD, "printk:dead", NULL, diff --git a/kernel/printk/printk_ringbuffer.c b/kernel/printk/printk_ringbuffer.c index d38e7c2f6887..46a79ec0940a 100644 --- a/kernel/printk/printk_ringbuffer.c +++ b/kernel/printk/printk_ringbuffer.c @@ -1237,11 +1237,9 @@ static unsigned int space_used(struct prb_data_ring *data_ring, if (BLK_DATALESS(blk_lpos)) return 0; - if (!is_blk_wrapped(data_ring, blk_lpos->begin, blk_lpos->next)) { - /* Data block does not wrap. */ - return (DATA_INDEX(data_ring, blk_lpos->next) - - DATA_INDEX(data_ring, blk_lpos->begin)); - } + /* Data block does not wrap. */ + if (!is_blk_wrapped(data_ring, blk_lpos->begin, blk_lpos->next)) + return blk_lpos->next - blk_lpos->begin; /* * For wrapping data blocks, the trailing (wasted) space is