From: Ingo Molnar <mingo@kernel.org>
To: Borislav Petkov <bp@alien8.de>
Cc: "Linus Torvalds" <torvalds@linux-foundation.org>,
"Steven Rostedt" <rostedt@goodmis.org>,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
"Peter Zijlstra" <peterz@infradead.org>,
"Andrew Morton" <akpm@linux-foundation.org>,
"Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>,
"Franck Bui" <fbui@suse.com>, LKML <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH -v2 2/2] printk: Add kernel parameter to control writes to /dev/kmsg
Date: Fri, 1 Jul 2016 11:04:13 +0200 [thread overview]
Message-ID: <20160701090413.GB27709@gmail.com> (raw)
In-Reply-To: <1467194161-1472-3-git-send-email-bp@alien8.de>
* Borislav Petkov <bp@alien8.de> wrote:
> +printk_kmsg:
> +
> +Control the logging to /dev/kmsg from userspace:
> +
> +0: default, ratelimited
> +1: unlimited logging to /dev/kmsg from userspace
> +2: logging to /dev/kmsg disabled
> +
> +The kernel command line parameter printk.kmsg= overrides this and is a
> +one-time setting for the duration of the system lifetime: once set, it
> +cannot be changed by this sysctl interface anymore.
Nit:
s/
is a one-time setting for the duration of the system lifetime: once set, it ...
/
is a one-time setting until the next reboot: once set, it ...
As I really hope this bit is not burned permanently into the system hardware! ;-)
> +++ b/include/linux/printk.h
> @@ -171,6 +171,12 @@ extern bool printk_timed_ratelimit(unsigned long *caller_jiffies,
> extern int printk_delay_msec;
> extern int dmesg_restrict;
> extern int kptr_restrict;
> +extern unsigned int devkmsg_log;
> +
> +struct ctl_table;
> +
> +int devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write,
> + void __user *buffer, size_t *lenp, loff_t *ppos);
>
> extern void wake_up_klogd(void);
Nit: I'd make devkmsg_sysctl_set_loglvl() extern as well, to stay consistent with
the surrounding prototypes.
> --- a/kernel/printk/printk.c
> +++ b/kernel/printk/printk.c
> @@ -86,6 +86,48 @@ static struct lockdep_map console_lock_dep_map = {
> };
> #endif
>
> +#define DEVKMSG_LOG_RATELIMIT 0
> +#define DEVKMSG_LOG_ON 1
> +#define DEVKMSG_LOG_OFF 2
> +#define DEVKMSG_LOCK (1 << 8)
> +#define DEVKMSG_LOG_MASK (DEVKMSG_LOCK - 1)
> +#define DEVKMSG_LOCKED_MASK ~DEVKMSG_LOG_MASK
Hm, so the state definitions and names here look a bit confusing to me, got a
headache trying to sort through them!
So from a UI point of view, what we want to have is 5 levels:
permanent-off
off
ratelimit
on
permanent-on
Right?
You implemented the 'permanent' bit via an independent LOCK bit in the flags
state. This leaves us:
off
ratelimit
on
... which you implemented via giving two independent bits to 'off' and 'on', and
if neither is set that means 'ratelimit', right?
So the most robust way to define such bitfields is via a pattern like this:
enum devkmsg_log_bits {
__DEVKMSG_LOG_BIT_ON,
__DEVKMSG_LOG_BIT_OFF,
__DEVKMSG_LOG_BIT_LOCK,
};
enum devkmsg_log_masks {
DEVKMSG_LOG_MASK_ON = BIT(__DEVKMSG_LOG_BIT_ON),
DEVKMSG_LOG_MASK_OFF = BIT(__DEVKMSG_LOG_BIT_OFF),
DEVKMSG_LOG_MASK_LOCK = BIT(__DEVKMSG_LOG_BIT_LOCK),
};
/* Keep both the 'on' and 'off' bits clear, i.e. ratelimit by default: */
#define DEVKMSG_LOG_MASK_DEFAULT 0
The double underscore prefixes are there to make sure we never use the bit numbers
directly.
And then all the code becomes pretty self-explanatory IMHO:
> +/* DEVKMSG_LOG_RATELIMIT by default */
> +unsigned int __read_mostly devkmsg_log;
unsigned int __read_mostly devkmsg_log = DEVKMSG_LOG_MASK_DEFAULT;
Note that this initialization would survive any future change of the default.
> +static int __init control_devkmsg(char *str)
> +{
> + if (!str)
> + return -EINVAL;
> +
> + if (!strncmp(str, "on", 2))
> + devkmsg_log = DEVKMSG_LOG_ON;
> + else if (!strncmp(str, "off", 3))
> + devkmsg_log = DEVKMSG_LOG_OFF;
> + else if (!strncmp(str, "ratelimit", 9))
> + devkmsg_log = DEVKMSG_LOG_RATELIMIT;
> + else
> + return -EINVAL;
> +
> + /* Sysctl cannot change it anymore. */
> + devkmsg_log |= DEVKMSG_LOCK;
> +
> + return 0;
> +}
> +__setup("printk.kmsg=", control_devkmsg);
This would become something like:
if (!strncmp(str, "on", 2))
devkmsg_log = DEVKMSG_LOG_MASK_ON;
else if (!strncmp(str, "off", 3))
devkmsg_log = DEVKMSG_LOG_MASK_OFF;
else if (!strncmp(str, "ratelimit", 9))
devkmsg_log = 0;
else
return -EINVAL;
/* Sysctl cannot change it anymore: */
devkmsg_log |= DEVKMSG_LOG_MASK_LOCK;
> +
> +int devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write,
> + void __user *buffer, size_t *lenp, loff_t *ppos)
> +{
> + if (devkmsg_log & DEVKMSG_LOCKED_MASK) {
> + if (write)
> + return -EINVAL;
> + }
> +
> + return proc_dointvec_minmax(table, write, buffer, lenp, ppos);
> +}
This could be written as:
if (devkmsg_log & DEVKMSG_LOG_MASK_LOCK) {
> + /* Ignore when user logging is disabled. */
> + if ((devkmsg_log & DEVKMSG_LOG_MASK) == DEVKMSG_LOG_OFF)
> + return len;
This could be written more clearly as:
if (devkmsg_log & DEVKMSG_LOG_MASK_OFF)
return len;
... note how we don't have to be careful about masking out the locked bit: we just
query the 'off' state bit.
> + /* Ratelimit when not explicitly enabled or when we're not booting. */
> + if ((system_state != SYSTEM_BOOTING) &&
> + ((devkmsg_log & DEVKMSG_LOG_MASK) != DEVKMSG_LOG_ON)) {
> + if (!___ratelimit(&user->rs, current->comm))
> + return ret;
> + }
... and this could be written as:
if ((system_state != SYSTEM_BOOTING) &&
(!(devkmsg_log & DEVKMSG_LOG_MASK_ON)) {
which too is a bit more robust: we already know that user logging is not disabled,
now we check whether it's always-on or ratelimited.
> + .procname = "printk_kmsg",
> + .data = &devkmsg_log,
So I liked the 'devkmsg_log' name, because it clearly tells us that this is about
/dev/kmsg logging state. So I think the visible UI name should be similar:
.procname = "printk_devkmsg",
.data = &devkmsg_log,
... this way people who know the 'devkmsg' string would know what to grep for in
the kernel source - or what flag to search for in /proc/sys/kernel/.
Thanks,
Ingo
next prev parent reply other threads:[~2016-07-01 9:10 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-06-29 9:55 [PATCH -v2 0/2] printk.kmsg: Ratelimit it by default Borislav Petkov
2016-06-29 9:56 ` [PATCH -v2 1/2] ratelimit: Extend to print suppressed messages on release Borislav Petkov
2016-06-29 10:24 ` Joe Perches
2016-06-29 14:25 ` Borislav Petkov
2016-07-01 8:22 ` Ingo Molnar
2016-07-01 9:07 ` Borislav Petkov
2016-07-01 10:17 ` Ingo Molnar
2016-07-01 10:29 ` Borislav Petkov
2016-07-01 10:38 ` Ingo Molnar
2016-06-29 9:56 ` [PATCH -v2 2/2] printk: Add kernel parameter to control writes to /dev/kmsg Borislav Petkov
2016-07-01 9:04 ` Ingo Molnar [this message]
2016-07-01 9:17 ` Borislav Petkov
2016-07-01 10:20 ` Ingo Molnar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20160701090413.GB27709@gmail.com \
--to=mingo@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=bp@alien8.de \
--cc=fbui@suse.com \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=peterz@infradead.org \
--cc=rostedt@goodmis.org \
--cc=torvalds@linux-foundation.org \
--cc=u.kleine-koenig@pengutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox