Skip to contentSkip to conversation

printk.devkmsg: Ratelimit it by default

PATCH Applied Borislav Petkov 1 participant 3 messages Jul 16, 2016

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

cover printk.devkmsg: Ratelimit it by default

From: Borislav Petkov <[email protected]>

Hi guys,

here's v5 with Andrew's review comments addressed (I hope all).

I've unified the setting names for both sysctl(2) and the kernel cmdline to "on", "off" and "ratelimit" so that there's no confusion anymore as to which sysctl number corresponds to what string. This should make dealing with that option straight-forward.

Also, requested textual expansion regarding the reasoning for the current design has been added in comments and commit messages.

Thanks.

Changelog:
----------

v4:

sorry for spamming so quickly again and not waiting for a week before resubmitting but I believe the stuff is ready for 4.8.

So here's v4 with all the minor review comments addressed.

v3:

here's v3 integrating Ingo's comments. The thing is called printk.devkmsg= or printk_devkmsg now, depending on cmdline option or sysctl.

v2:

here's v2 with the requested sysctl option kernel.printk_kmsg and locking of the setting when printk.kmsg= is supplied on the command line.

Patch 1 is unchanged.

Patch 2 has grown the sysctl addition.

v1:

Rostedt is busy so I took Linus' old patch and Steven's last v2 and split and extended them with the comments people had on the last thread:

https://lkml.kernel.org/r/[email protected]

I hope, at least.

So it is ratelimiting by default, with "on" and "off" cmdline options. I called the option somewhat a bit shorter too: "printk.kmsg"

The current use cases of this and of which I'm aware are:

* debug the kernel and thus shut up all interfering input from userspace, i.e. boot with "printk.kmsg=off"

* debug userspace (and by that I mean systemd) by booting with "printk.kmsg=on" so that the ratelimiting is disabled and the kernel log gets all the spew.

Thoughts?

Please queue,
thanks.

Borislav Petkov (2):
ratelimit: Extend to print suppressed messages on release
printk: Add kernel parameter to control writes to /dev/kmsg

 Documentation/kernel-parameters.txt |   7 ++
 Documentation/sysctl/kernel.txt     |  14 ++++
 include/linux/printk.h              |   9 +++
 include/linux/ratelimit.h           |  38 ++++++++--
 kernel/printk/printk.c              | 143 ++++++++++++++++++++++++++++++++++--
 kernel/sysctl.c                     |   7 ++
 lib/ratelimit.c                     |  10 ++-
 7 files changed, 211 insertions(+), 17 deletions(-)
Signature · 1 line
2.8.4
#1 lore raw

PATCH 1/2 ratelimit: Extend to print suppressed messages on release

From: Borislav Petkov <[email protected]>

Extend the ratelimiting facility to print the amount of suppressed lines when it is being released.

This use case is aimed at short-termed, burst-like users for which we want to output the suppressed lines stats only once, after it has been disposed of. For an example, see /dev/kmsg usage in a follow-on patch.

Also, change the printk() line we issue on release to not use "callbacks" as it is misleading: we're not suppressing callbacks but printk() calls.

This has been separated from a previous patch by Linus.

Cc Andrew Morton <[email protected]>
Cc Dave Young <[email protected]>
Cc Franck Bui <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Steven Rostedt <[email protected]>
Cc Uwe Kleine-König <[email protected]>
---
 include/linux/ratelimit.h | 38 +++++++++++++++++++++++++++++++++-----
 lib/ratelimit.c           | 10 ++++++----
 2 files changed, 39 insertions(+), 9 deletions(-)
include/linux/ratelimit.h +33 -5
index 18102529254e..57c9e0622a38 100644
@@ -2,11 +2,15 @@
 #define _LINUX_RATELIMIT_H
 
 #include <linux/param.h>
+#include <linux/sched.h>
 #include <linux/spinlock.h>
 
 #define DEFAULT_RATELIMIT_INTERVAL	(5 * HZ)
 #define DEFAULT_RATELIMIT_BURST		10
 
+/* issue num suppressed message on exit */
+#define RATELIMIT_MSG_ON_RELEASE	BIT(0)
+
 struct ratelimit_state {
 	raw_spinlock_t	lock;		/* protect the state */
 
@@ -15,6 +19,7 @@ struct ratelimit_state {
 	int		printed;
 	int		missed;
 	unsigned long	begin;
+	unsigned long	flags;
 };
 
 #define RATELIMIT_STATE_INIT(name, interval_init, burst_init) {		\
@@ -34,12 +39,35 @@ struct ratelimit_state {
 static inline void ratelimit_state_init(struct ratelimit_state *rs,
 					int interval, int burst)
 {
+	memset(rs, 0, sizeof(*rs));
+
 	raw_spin_lock_init(&rs->lock);
-	rs->interval = interval;
-	rs->burst = burst;
-	rs->printed = 0;
-	rs->missed = 0;
-	rs->begin = 0;
+	rs->interval	= interval;
+	rs->burst	= burst;
+}
+
+static inline void ratelimit_default_init(struct ratelimit_state *rs)
+{
+	return ratelimit_state_init(rs, DEFAULT_RATELIMIT_INTERVAL,
+					DEFAULT_RATELIMIT_BURST);
+}
+
+static inline void ratelimit_state_exit(struct ratelimit_state *rs)
+{
+	if (!(rs->flags & RATELIMIT_MSG_ON_RELEASE))
+		return;
+
+	if (rs->missed) {
+		pr_warn("%s: %d output lines suppressed due to ratelimiting\n",
+			current->comm, rs->missed);
+		rs->missed = 0;
+	}
+}
+
+static inline void
+ratelimit_set_flags(struct ratelimit_state *rs, unsigned long flags)
+{
+	rs->flags = flags;
 }
 
 extern struct ratelimit_state printk_ratelimit_state;
lib/ratelimit.c +6 -4
index 2c5de86460c5..08f8043cac61 100644
@@ -46,12 +46,14 @@ int ___ratelimit(struct ratelimit_state *rs, const char *func)
 		rs->begin = jiffies;
 
 	if (time_is_before_jiffies(rs->begin + rs->interval)) {
-		if (rs->missed)
-			printk(KERN_WARNING "%s: %d callbacks suppressed\n",
-				func, rs->missed);
+		if (rs->missed) {
+			if (!(rs->flags & RATELIMIT_MSG_ON_RELEASE)) {
+				pr_warn("%s: %d callbacks suppressed\n", func, rs->missed);
+				rs->missed = 0;
+			}
+		}
 		rs->begin   = jiffies;
 		rs->printed = 0;
-		rs->missed  = 0;
 	}
 	if (rs->burst && rs->burst > rs->printed) {
 		rs->printed++;
Signature · 1 line
2.8.4
#2 lore raw

PATCH 2/2 printk: Add kernel parameter to control writes to /dev/kmsg

In reply to Borislav Petkov

From: Borislav Petkov <[email protected]>

Add a "printk.devkmsg" kernel command line parameter which controls how userspace writes into /dev/kmsg. It has three options:

* ratelimit - ratelimit logging from userspace.
* on - unlimited logging from userspace
* off - logging from userspace gets ignored

The default setting is to ratelimit the messages written to it.

This changes the kernel default setting of "on" to "ratelimit" and we do that because we want to keep userspace spamming /dev/kmsg to sane levels. This is especially moot when a small kernel log buffer wraps around and messages get lost. So the ratelimiting setting should be a sane setting where kernel messages should have a bit higher chance of survival from all the spamming.

It additionally does not limit logging to /dev/kmsg while the system is booting if we haven't disabled it on the command line.

Furthermore, we can control the logging from a lower priority sysctl interface - kernel.printk_devkmsg.

That interface will succeed only if printk.devkmsg *hasn't* been supplied on the command line. If it has, then printk.devkmsg is a one-time setting which remains for the duration of the system lifetime. This "locking" of the setting is to prevent userspace from changing the logging on us through sysctl(2).

This patch is based on previous patches from Linus and Steven.

Cc Andrew Morton <[email protected]>
Cc Dave Young <[email protected]>
Cc Franck Bui <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc Linus Torvalds <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Steven Rostedt <[email protected]>
Cc Uwe Kleine-König <[email protected]>
---
 Documentation/kernel-parameters.txt |   7 ++
 Documentation/sysctl/kernel.txt     |  14 ++++
 include/linux/printk.h              |   9 +++
 kernel/printk/printk.c              | 143 ++++++++++++++++++++++++++++++++++--
 kernel/sysctl.c                     |   7 ++
 5 files changed, 172 insertions(+), 8 deletions(-)
Documentation/kernel-parameters.txt +7 -0
index 82b42c958d1c..a8e9f0bd7801 100644
@@ -3150,6 +3150,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 			Format: <bool>  (1/Y/y=enable, 0/N/n=disable)
 			default: disabled
 
+	printk.devkmsg={on,off,ratelimit}
+			Control writing to /dev/kmsg.
+			on - unlimited logging to /dev/kmsg from userspace
+			off - logging to /dev/kmsg disabled
+			ratelimit - ratelimit the logging
+			Default: ratelimit
+
 	printk.time=	Show timing data prefixed to each printk message line
 			Format: <bool>  (1/Y/y=enable, 0/N/n=disable)
 
Documentation/sysctl/kernel.txt +14 -0
index a3683ce2a2f3..378421d423fa 100644
@@ -752,6 +752,20 @@ send before ratelimiting kicks in.
 
 ==============================================================
 
+printk_devkmsg:
+
+Control the logging to /dev/kmsg from userspace:
+
+ratelimit: default, ratelimited
+on: unlimited logging to /dev/kmsg from userspace
+off: logging to /dev/kmsg disabled
+
+The kernel command line parameter printk.devkmsg= overrides this and is
+a one-time setting until next reboot: once set, it cannot be changed by
+this sysctl interface anymore.
+
+==============================================================
+
 randomize_va_space:
 
 This option can be used to select the type of process address
include/linux/printk.h +9 -0
index f4da695fd615..9c21535e5714 100644
@@ -61,6 +61,11 @@ static inline void console_verbose(void)
 		console_loglevel = CONSOLE_LOGLEVEL_MOTORMOUTH;
 }
 
+/* strlen("ratelimit") + 1 */
+#define DEVKMSG_STR_MAX_SIZE 10
+extern char devkmsg_log_str[];
+struct ctl_table;
+
 struct va_format {
 	const char *fmt;
 	va_list *va;
@@ -172,6 +177,10 @@ extern int printk_delay_msec;
 extern int dmesg_restrict;
 extern int kptr_restrict;
 
+extern int
+devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write, void __user *buf,
+			  size_t *lenp, loff_t *ppos);
+
 extern void wake_up_klogd(void);
 
 char *log_buf_addr_get(void);
kernel/printk/printk.c +135 -8

183 lines not on this page · raw message

kernel/sysctl.c +7 -0
index 87b2fc38398b..0d9fe53682bb 100644
@@ -814,6 +814,13 @@ static struct ctl_table kern_table[] = {
 		.extra2		= &ten_thousand,
 	},
 	{
+		.procname	= "printk_devkmsg",
+		.data		= devkmsg_log_str,
+		.maxlen		= DEVKMSG_STR_MAX_SIZE,
+		.mode		= 0644,
+		.proc_handler	= devkmsg_sysctl_set_loglvl,
+	},
+	{
 		.procname	= "dmesg_restrict",
 		.data		= &dmesg_restrict,
 		.maxlen		= sizeof(int),
Signature · 1 line
2.8.4