On Wed, Jun 15, 2016 at 03:40:04PM -1000, Linus Torvalds wrote:
> Possibly we could just say that if a kernel command line option has
> been given, that is absolute.
> 
> And then a sysctl for when you do *not* explicitly set if on the
> kernel command line?

Ok, how about this ontop?

It is only lightly tested in a vm but basically I'm using the second
byte of devkmsg_log to set a bit in there and the sysctl handler looks
at it.

It is also visible in sysctl and we know it has been cmdline-disabled:

$ cat /proc/sys/kernel/printk_kmsg
256

---
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
index a3683ce2a2f3..02fe4562953f 100644
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -752,6 +752,19 @@ send before ratelimiting kicks in.
 
 ==============================================================
 
+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 setting
+and 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
diff --git a/include/linux/printk.h b/include/linux/printk.h
index f4da695fd615..bcf72e756122 100644
--- a/include/linux/printk.h
+++ 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);
 
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 33701a166f26..9f0a885c2718 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -86,12 +86,15 @@ 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_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
 
 /* DEVKMSG_LOG_RATELIMIT by default */
-static unsigned int __read_mostly devkmsg_log;
+unsigned int __read_mostly devkmsg_log;
 static int __init control_devkmsg(char *str)
 {
        if (!str)
@@ -101,14 +104,30 @@ static int __init control_devkmsg(char *str)
                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);
 
 
+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);
+}
+
 /*
  * Number of registered extended console drivers.
  *
@@ -656,11 +675,12 @@ static ssize_t devkmsg_write(struct kiocb *iocb, struct 
iov_iter *from)
                return -EINVAL;
 
        /* Ignore when user logging is disabled. */
-       if (devkmsg_log == DEVKMSG_LOG_OFF)
+       if ((devkmsg_log & DEVKMSG_LOG_MASK) == DEVKMSG_LOG_OFF)
                return len;
 
        /* Ratelimit when not explicitly enabled or when we're not booting. */
-       if ((system_state != SYSTEM_BOOTING) && (devkmsg_log != 
DEVKMSG_LOG_ON)) {
+       if ((system_state != SYSTEM_BOOTING) &&
+           ((devkmsg_log & DEVKMSG_LOG_MASK) != DEVKMSG_LOG_ON)) {
                if (!___ratelimit(&user->rs, current->comm))
                        return ret;
        }
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 87b2fc38398b..a29d6c4fa86c 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -814,6 +814,15 @@ static struct ctl_table kern_table[] = {
                .extra2         = &ten_thousand,
        },
        {
+               .procname       = "printk_kmsg",
+               .data           = &devkmsg_log,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
+               .proc_handler   = devkmsg_sysctl_set_loglvl,
+               .extra1         = &zero,
+               .extra2         = &two,
+       },
+       {
                .procname       = "dmesg_restrict",
                .data           = &dmesg_restrict,
                .maxlen         = sizeof(int),

-- 
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.

Reply via email to