printk.devkmsg: Ratelimit it by default
Subsystems (4)
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
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.
--- include/linux/ratelimit.h | 38 +++++++++++++++++++++++++++++++++----- lib/ratelimit.c | 10 ++++++---- 2 files changed, 39 insertions(+), 9 deletions(-)
include/linux/ratelimit.h +33 -5
@@ -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
@@ -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
PATCH 2/2 printk: Add kernel parameter to control writes to /dev/kmsg
In reply to Borislav PetkovFrom: 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.
--- 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
@@ -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
@@ -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
@@ -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
@@ -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