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: <662c8dbd954f8a52a099805299da93d4c5473a97.1764272407.git.chris@chrisdown.name>
Date: Fri, 28 Nov 2025 03:43:36 +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 v8 07/21] printk: Introduce per-console loglevel support

Implement the logic to determine which loglevel should be used for
message filtering on each console.

The effective loglevel for a console is determined by a hierarchy of
controls:

1. ignore_loglevel (highest priority), which prints all messages regardless
   of level, overriding both global and per-console settings.

2. The per-console loglevel. If set to a valid value (> 0), the console
   uses this level instead of the global console_loglevel.

3. Global console_loglevel (fallback). This is used when per-console
   loglevel is not set (LOGLEVEL_DEFAULT, i.e. -1).

Reviewed-by: Petr Mladek <pmladek@...e.com>
Signed-off-by: Chris Down <chris@...isdown.name>
---
 kernel/printk/internal.h | 10 +++++
 kernel/printk/nbcon.c    | 10 +++--
 kernel/printk/printk.c   | 86 +++++++++++++++++++++++++++++++++++++++-
 3 files changed, 101 insertions(+), 5 deletions(-)

diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 1ed86577896c..f2ebaa2a6aa2 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -15,6 +15,16 @@ int devkmsg_sysctl_set_loglvl(const struct ctl_table *table, int write,
 #define printk_sysctl_init() do { } while (0)
 #endif
 
+enum loglevel_source {
+	LLS_GLOBAL,
+	LLS_LOCAL,
+	LLS_IGNORE_LOGLEVEL,
+};
+
+enum loglevel_source
+console_effective_loglevel_source(int con_level);
+int console_effective_loglevel(int con_level);
+
 #define con_printk(lvl, con, fmt, ...)				\
 	printk(lvl pr_fmt("%s%sconsole [%s%d] " fmt),		\
 		(con->flags & CON_NBCON) ? "" : "legacy ",	\
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 493c9e8b2dd5..a61a607a5159 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -961,6 +961,7 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt, bool use_a
 	struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
 	struct console *con = ctxt->console;
 	bool is_extended = console_srcu_read_flags(con) & CON_EXTENDED;
+	int con_level = console_srcu_read_loglevel(con);
 	struct printk_message pmsg = {
 		.pbufs = ctxt->pbufs,
 	};
@@ -993,7 +994,8 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt, bool use_a
 	if (!nbcon_context_enter_unsafe(ctxt))
 		return false;
 
-	ctxt->backlog = printk_get_next_message(&pmsg, ctxt->seq, is_extended, console_loglevel);
+	ctxt->backlog = printk_get_next_message(&pmsg, ctxt->seq, is_extended,
+						console_effective_loglevel(con_level));
 	if (!ctxt->backlog)
 		return nbcon_context_exit_unsafe(ctxt);
 
@@ -1509,9 +1511,9 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq,
 
 	/*
 	 * Match the console_srcu_read_lock()/unlock expectation embedded in
-	 * console_srcu_read_flags(), which is called from nbcon_emit_next_record().
-	 * Without this, unregister_console() cannot synchronise against the
-	 * atomic flusher.
+	 * console_srcu_read_loglevel()/console_srcu_read_flags(), both of which
+	 * are called from nbcon_emit_next_record(). Without this,
+	 * unregister_console() cannot synchronise against the atomic flusher.
 	 */
 	cookie = console_srcu_read_lock();
 
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index c6b56f4d8072..d9c1bc4a32c4 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1280,6 +1280,89 @@ module_param(ignore_loglevel, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(ignore_loglevel,
 		 "ignore loglevel setting (prints all kernel messages to the console)");
 
+/**
+ * is_valid_per_console_loglevel - Check if a loglevel is valid for per-console
+ *
+ * @con_level: The loglevel to check
+ *
+ * Per-console loglevels must be strictly positive (> 0). Level 0 (KERN_EMERG)
+ * is reserved for emergency messages that should go to all consoles (and so is
+ * disallowed), and -1 (LOGLEVEL_DEFAULT) means use the global console_loglevel.
+ *
+ * Return: true if con_level is a valid per-console loglevel (> 0), false
+ * otherwise
+ */
+static bool is_valid_per_console_loglevel(int con_level)
+{
+	return (con_level > 0);
+}
+
+/**
+ * console_effective_loglevel_source - Determine the source of effective loglevel
+ *
+ * @con_level: The console's per-console loglevel value
+ *
+ * This function determines which loglevel authority is in effect for a console,
+ * based on the hierarchy of controls:
+ *
+ * 1. ignore_loglevel (overrides everything - prints all messages)
+ * 2. per-console loglevel (if set and not ignored)
+ * 3. global console_loglevel (fallback)
+ *
+ * Return: The loglevel source (LLS_IGNORE_LOGLEVEL, LLS_LOCAL, or LLS_GLOBAL)
+ */
+enum loglevel_source
+console_effective_loglevel_source(int con_level)
+{
+	if (ignore_loglevel)
+		return LLS_IGNORE_LOGLEVEL;
+
+	if (is_valid_per_console_loglevel(con_level))
+		return LLS_LOCAL;
+
+	return LLS_GLOBAL;
+}
+
+/**
+ * console_effective_loglevel - Get the effective loglevel for a console
+ *
+ * @con_level: The console's per-console loglevel value
+ *
+ * This function returns the actual loglevel value that should be used for
+ * message filtering for a console, taking into account all loglevel controls
+ * (global, per-console, and ignore_loglevel).
+ *
+ * The effective loglevel is used to determine which messages get printed to
+ * the console. Messages with priority less than the effective level are printed.
+ *
+ * Return: The effective loglevel value to use for filtering
+ */
+int console_effective_loglevel(int con_level)
+{
+	enum loglevel_source source;
+	int level;
+
+	source = console_effective_loglevel_source(con_level);
+
+	switch (source) {
+	case LLS_IGNORE_LOGLEVEL:
+		level = CONSOLE_LOGLEVEL_MOTORMOUTH;
+		break;
+	case LLS_LOCAL:
+		level = con_level;
+		break;
+	case LLS_GLOBAL:
+		level = console_loglevel;
+		break;
+	default:
+		pr_warn("Unhandled console loglevel source: %d", source);
+		level = console_loglevel;
+		break;
+	}
+
+	return level;
+}
+
 static bool suppress_message_printing(int level, int con_eff_level)
 {
 	return (level >= con_eff_level && !ignore_loglevel);
@@ -3090,6 +3173,7 @@ struct printk_buffers printk_shared_pbufs;
 static bool console_emit_next_record(struct console *con, bool *handover, int cookie)
 {
 	bool is_extended = console_srcu_read_flags(con) & CON_EXTENDED;
+	int con_level = console_srcu_read_loglevel(con);
 	char *outbuf = &printk_shared_pbufs.outbuf[0];
 	struct printk_message pmsg = {
 		.pbufs = &printk_shared_pbufs,
@@ -3099,7 +3183,7 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co
 	*handover = false;
 
 	if (!printk_get_next_message(&pmsg, con->seq, is_extended,
-				     console_loglevel))
+				     console_effective_loglevel(con_level)))
 		return false;
 
 	con->dropped += pmsg.dropped;
-- 
2.51.2


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ