From: Borislav Petkov <[email protected]>

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

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

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

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

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

Signed-off-by: Borislav Petkov <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Steven Rostedt <[email protected]>
---
 Documentation/kernel-parameters.txt |  6 ++++
 kernel/printk/printk.c              | 57 +++++++++++++++++++++++++++++++------
 2 files changed, 55 insertions(+), 8 deletions(-)

diff --git a/Documentation/kernel-parameters.txt 
b/Documentation/kernel-parameters.txt
index 82b42c958d1c..4799c88b7258 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -3150,6 +3150,12 @@ bytes respectively. Such letter suffixes can also be 
entirely omitted.
                        Format: <bool>  (1/Y/y=enable, 0/N/n=disable)
                        default: disabled
 
+       printk.kmsg={on,off}
+                       Control writing to /dev/kmsg.
+                       on - unlimited logging to /dev/kmsg from userspace
+                       off - logging to /dev/kmsg disabled
+                       Default: ratelimited logging.
+
        printk.time=    Show timing data prefixed to each printk message line
                        Format: <bool>  (1/Y/y=enable, 0/N/n=disable)
 
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 60cdf6386763..33701a166f26 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -86,6 +86,29 @@ static struct lockdep_map console_lock_dep_map = {
 };
 #endif
 
+#define DEVKMSG_LOG_RATELIMIT  0
+#define DEVKMSG_LOG_ON         1
+#define DEVKMSG_LOG_OFF                2
+
+/* DEVKMSG_LOG_RATELIMIT by default */
+static unsigned int __read_mostly devkmsg_log;
+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
+               return -EINVAL;
+
+       return 0;
+}
+__setup("printk.kmsg=", control_devkmsg);
+
+
 /*
  * Number of registered extended console drivers.
  *
@@ -614,6 +637,7 @@ struct devkmsg_user {
        u64 seq;
        u32 idx;
        enum log_flags prev;
+       struct ratelimit_state rs;
        struct mutex lock;
        char buf[CONSOLE_EXT_LOG_MAX];
 };
@@ -623,11 +647,24 @@ static ssize_t devkmsg_write(struct kiocb *iocb, struct 
iov_iter *from)
        char *buf, *line;
        int level = default_message_loglevel;
        int facility = 1;       /* LOG_USER */
+       struct file *file = iocb->ki_filp;
+       struct devkmsg_user *user = file->private_data;
        size_t len = iov_iter_count(from);
        ssize_t ret = len;
 
-       if (len > LOG_LINE_MAX)
+       if (!user || len > LOG_LINE_MAX)
                return -EINVAL;
+
+       /* Ignore when user logging is disabled. */
+       if (devkmsg_log == 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 (!___ratelimit(&user->rs, current->comm))
+                       return ret;
+       }
+
        buf = kmalloc(len+1, GFP_KERNEL);
        if (buf == NULL)
                return -ENOMEM;
@@ -801,18 +838,20 @@ static int devkmsg_open(struct inode *inode, struct file 
*file)
        int err;
 
        /* write-only does not need any file context */
-       if ((file->f_flags & O_ACCMODE) == O_WRONLY)
-               return 0;
-
-       err = check_syslog_permissions(SYSLOG_ACTION_READ_ALL,
-                                      SYSLOG_FROM_READER);
-       if (err)
-               return err;
+       if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
+               err = check_syslog_permissions(SYSLOG_ACTION_READ_ALL,
+                                              SYSLOG_FROM_READER);
+               if (err)
+                       return err;
+       }
 
        user = kmalloc(sizeof(struct devkmsg_user), GFP_KERNEL);
        if (!user)
                return -ENOMEM;
 
+       ratelimit_default_init(&user->rs);
+       ratelimit_set_flags(&user->rs, RATELIMIT_MSG_ON_RELEASE);
+
        mutex_init(&user->lock);
 
        raw_spin_lock_irq(&logbuf_lock);
@@ -831,6 +870,8 @@ static int devkmsg_release(struct inode *inode, struct file 
*file)
        if (!user)
                return 0;
 
+       ratelimit_state_exit(&user->rs);
+
        mutex_destroy(&user->lock);
        kfree(user);
        return 0;
-- 
2.7.3

Reply via email to