[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <9ffc0801a64e5f7d0685c263c1908a34cf89d1a5.1763492585.git.chris@chrisdown.name>
Date: Wed, 19 Nov 2025 03:07:17 +0800
From: Chris Down <chris@...isdown.name>
To: Petr Mladek <pmladek@...e.com>
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: [PATCH v7 05/13] printk: Add synchronisation for concurrent console
state changes
The syslog actions SYSLOG_ACTION_CONSOLE_OFF and
SYSLOG_ACTION_CONSOLE_ON currently run without any locking. This creates
a race condition if two processes attempt to toggle the console state
simultaneously.
While this race has existed for donkey's years, it was previously
somewhat tolerable because it involved only a single integer variable
(saved_console_loglevel). However, upcoming changes will introduce a
second piece of state (saved_ignore_per_console_loglevel) to be saved
and restored. With two variables, this can result in saved state getting
lost.
Here is a demonstration:
CPU 0 (SYSLOG_ACTION_CONSOLE_OFF) CPU 1 (SYSLOG_ACTION_CONSOLE_ON)
--------------------------------- --------------------------------
// saved_console_loglevel is DEFAULT
if (saved == DEFAULT) (True)
saved = console_loglevel (7)
// Race triggers here
if (saved != DEFAULT) (True)
loglevel = saved (7)
saved = DEFAULT
// CPU 0 continues, unaware saved
// was just reset by CPU 1
loglevel = minimum_console_loglevel (1)
The result is that the console is now set to the minimum loglevel, but
saved_console_loglevel is LOGLEVEL_DEFAULT. A subsequent CONSOLE_ON call
will see saved == LOGLEVEL_DEFAULT and thus refuse to restore the
original loglevel. The console is effectively stuck in quiet mode until
manually reset via sysctl. Oh dear.
The callers of do_syslog are syscalls (so user context) or procfs write
handlers. These contexts are allowed to sleep, so acquiring a mutex is
safe. We also already make use of syslog_lock in
SYSLOG_ACTION_SIZE_UNREAD and SYSLOG_ACTION_READ, so this is consistent.
Signed-off-by: Chris Down <chris@...isdown.name>
---
kernel/printk/printk.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 928d77c56c77..b8679b0da42f 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1903,16 +1903,20 @@ int do_syslog(int type, char __user *buf, int len, int source)
break;
/* Disable logging to console */
case SYSLOG_ACTION_CONSOLE_OFF:
+ mutex_lock(&syslog_lock);
if (saved_console_loglevel == LOGLEVEL_DEFAULT)
saved_console_loglevel = console_loglevel;
console_loglevel = minimum_console_loglevel;
+ mutex_unlock(&syslog_lock);
break;
/* Enable logging to console */
case SYSLOG_ACTION_CONSOLE_ON:
+ mutex_lock(&syslog_lock);
if (saved_console_loglevel != LOGLEVEL_DEFAULT) {
console_loglevel = saved_console_loglevel;
saved_console_loglevel = LOGLEVEL_DEFAULT;
}
+ mutex_unlock(&syslog_lock);
break;
/* Set level of messages printed to console */
case SYSLOG_ACTION_CONSOLE_LEVEL:
--
2.51.2
Powered by blists - more mailing lists