[Devel] [PATCH rh6] syslog: distinguish between /proc/kmsg and syscalls
Vasily Averin
vvs at odin.com
Wed May 6 07:11:36 PDT 2015
This patch fixes "100% CPU on Ubuntu 13.04 when using rsyslog" issue.
rsyslogd inside Ubuntu containers drops privileges after opening /proc/kmsg.
Old rsyslogd ignores error on access to this file, cycles and consumes 100% CPU.
New "fixed" rsyslogd detects openVZ container and disables kernel logger.
To fix the problem following patch was backported from mainline to RHEL6,
it allows all versions of rsyslog to work with dmesg buffer of containers.
commit 002345925e6c45861f60db6f4fc6236713fd8847
Author: Kees Cook <kees.cook at canonical.com>
Date: Wed Feb 3 15:36:43 2010 -0800
syslog: distinguish between /proc/kmsg and syscalls
This allows the LSM to distinguish between syslog functions originating
from /proc/kmsg access and direct syscalls. By default, the commoncaps
will now no longer require CAP_SYS_ADMIN to read an opened /proc/kmsg
file descriptor. For example the kernel syslog reader can now drop
privileges after opening /proc/kmsg, instead of staying privileged with
CAP_SYS_ADMIN. MAC systems that implement security_syslog have unchanged
behavior.
Signed-off-by: Kees Cook <kees.cook at canonical.com>
Acked-by: Serge Hallyn <serue at us.ibm.com>
Acked-by: John Johansen <john.johansen at canonical.com>
Signed-off-by: James Morris <jmorris at namei.org>
https://bugzilla.openvz.org/show_bug.cgi?id=2693
Signed-off-by: Vasily Averin <vvs at openvz.org>
---
fs/proc/kmsg.c | 14 +++++++-------
include/linux/security.h | 11 ++++++-----
include/linux/syslog.h | 29 +++++++++++++++++++++++++++++
kernel/printk.c | 7 ++++---
security/commoncap.c | 7 ++++++-
security/security.c | 4 ++--
security/selinux/hooks.c | 5 +++--
security/smack/smack_lsm.c | 4 ++--
8 files changed, 59 insertions(+), 22 deletions(-)
create mode 100644 include/linux/syslog.h
diff --git a/fs/proc/kmsg.c b/fs/proc/kmsg.c
index 618f8e1..c0dc5b0 100644
--- a/fs/proc/kmsg.c
+++ b/fs/proc/kmsg.c
@@ -12,6 +12,7 @@
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/fs.h>
+#include <linux/syslog.h>
#include <linux/veprintk.h>
#include <linux/sched.h>
#include <linux/module.h>
@@ -22,31 +23,30 @@
extern wait_queue_head_t log_wait;
-extern int do_syslog(int type, char __user *bug, int count);
-
static int kmsg_open(struct inode * inode, struct file * file)
{
- return do_syslog(1,NULL,0);
+ return do_syslog(1, NULL, 0, SYSLOG_FROM_FILE);
}
static int kmsg_release(struct inode * inode, struct file * file)
{
- (void) do_syslog(0,NULL,0);
+ (void) do_syslog(0, NULL, 0, SYSLOG_FROM_FILE);
return 0;
}
static ssize_t kmsg_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- if ((file->f_flags & O_NONBLOCK) && !do_syslog(9, NULL, 0))
+ if ((file->f_flags & O_NONBLOCK) &&
+ !do_syslog(9, NULL, 0, SYSLOG_FROM_FILE))
return -EAGAIN;
- return do_syslog(2, buf, count);
+ return do_syslog(2, buf, count, SYSLOG_FROM_FILE);
}
static unsigned int kmsg_poll(struct file *file, poll_table *wait)
{
poll_wait(file, &ve_log_wait, wait);
- if (do_syslog(9, NULL, 0))
+ if (do_syslog(9, NULL, 0, SYSLOG_FROM_FILE))
return POLLIN | POLLRDNORM;
return 0;
}
diff --git a/include/linux/security.h b/include/linux/security.h
index f4bb630..91c2dcb 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -83,7 +83,7 @@ extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
extern int cap_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp);
extern int cap_task_setioprio(struct task_struct *p, int ioprio);
extern int cap_task_setnice(struct task_struct *p, int nice);
-extern int cap_syslog(int type);
+extern int cap_syslog(int type, bool from_file);
extern int cap_vm_enough_memory(struct mm_struct *mm, long pages);
struct msghdr;
@@ -1348,6 +1348,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* logging to the console.
* See the syslog(2) manual page for an explanation of the @type values.
* @type contains the type of action.
+ * @from_file indicates the context of action (if it came from /proc).
* Return 0 if permission is granted.
* @settime:
* Check permission to change the system time.
@@ -1462,7 +1463,7 @@ struct security_operations {
int (*sysctl) (struct ctl_table *table, int op);
int (*quotactl) (int cmds, int type, int id, struct super_block *sb);
int (*quota_on) (struct dentry *dentry);
- int (*syslog) (int type);
+ int (*syslog) (int type, bool from_file);
int (*settime) (const struct timespec *ts, const struct timezone *tz);
int (*vm_enough_memory) (struct mm_struct *mm, long pages);
@@ -1761,7 +1762,7 @@ int security_acct(struct file *file);
int security_sysctl(struct ctl_table *table, int op);
int security_quotactl(int cmds, int type, int id, struct super_block *sb);
int security_quota_on(struct dentry *dentry);
-int security_syslog(int type);
+int security_syslog(int type, bool from_file);
int security_settime(const struct timespec *ts, const struct timezone *tz);
int security_vm_enough_memory(long pages);
int security_vm_enough_memory_mm(struct mm_struct *mm, long pages);
@@ -2011,9 +2012,9 @@ static inline int security_quota_on(struct dentry *dentry)
return 0;
}
-static inline int security_syslog(int type)
+static inline int security_syslog(int type, bool from_file)
{
- return cap_syslog(type);
+ return cap_syslog(type, from_file);
}
static inline int security_settime(const struct timespec *ts,
diff --git a/include/linux/syslog.h b/include/linux/syslog.h
new file mode 100644
index 0000000..5f02b18
--- /dev/null
+++ b/include/linux/syslog.h
@@ -0,0 +1,29 @@
+/* Syslog internals
+ *
+ * Copyright 2010 Canonical, Ltd.
+ * Author: Kees Cook <kees.cook at canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _LINUX_SYSLOG_H
+#define _LINUX_SYSLOG_H
+
+#define SYSLOG_FROM_CALL 0
+#define SYSLOG_FROM_FILE 1
+
+int do_syslog(int type, char __user *buf, int count, bool from_file);
+
+#endif /* _LINUX_SYSLOG_H */
diff --git a/kernel/printk.c b/kernel/printk.c
index b1409e1..1240ba5 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -34,6 +34,7 @@
#include <linux/syscalls.h>
#include <linux/kexec.h>
#include <linux/kmsg_dump.h>
+#include <linux/syslog.h>
#include <linux/veprintk.h>
#include <asm/uaccess.h>
@@ -324,7 +325,7 @@ int dmesg_restrict;
* 9 -- Return number of unread characters in the log buffer
* 10 -- Return size of the log buffer
*/
-int do_syslog(int type, char __user *buf, int len)
+int do_syslog(int type, char __user *buf, int len, bool from_file)
{
unsigned i, j, limit, count;
int do_clear = 0;
@@ -334,7 +335,7 @@ int do_syslog(int type, char __user *buf, int len)
if (!ve_is_super(get_exec_env()) && (type == 6 || type == 7))
goto out;
- error = security_syslog(type);
+ error = security_syslog(type, from_file);
if (error)
return error;
@@ -476,7 +477,7 @@ out:
SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len)
{
- return do_syslog(type, buf, len);
+ return do_syslog(type, buf, len, SYSLOG_FROM_CALL);
}
/*
diff --git a/security/commoncap.c b/security/commoncap.c
index 2f1885f..0cf98e7 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -27,6 +27,7 @@
#include <linux/sched.h>
#include <linux/prctl.h>
#include <linux/securebits.h>
+#include <linux/syslog.h>
#include <linux/personality.h>
/*
@@ -1049,16 +1050,20 @@ error:
/**
* cap_syslog - Determine whether syslog function is permitted
* @type: Function requested
+ * @from_file: Whether this request came from an open file (i.e. /proc)
*
* Determine whether the current process is permitted to use a particular
* syslog function, returning 0 if permission is granted, -ve if not.
*/
-int cap_syslog(int type)
+int cap_syslog(int type, bool from_file)
{
if (dmesg_restrict && !capable(CAP_SYS_ADMIN) &&
ve_is_super(get_exec_env()))
return -EPERM;
+ /* /proc/kmsg can open be opened by CAP_SYS_ADMIN */
+ if (type != 1 && from_file)
+ return 0;
if ((type != 3 && type != 10) &&
!capable(CAP_VE_SYS_ADMIN) && !capable(CAP_SYS_ADMIN))
return -EPERM;
diff --git a/security/security.c b/security/security.c
index 2e3c9d7..3e841e9 100644
--- a/security/security.c
+++ b/security/security.c
@@ -199,9 +199,9 @@ int security_quota_on(struct dentry *dentry)
return security_ops->quota_on(dentry);
}
-int security_syslog(int type)
+int security_syslog(int type, bool from_file)
{
- return security_ops->syslog(type);
+ return security_ops->syslog(type, from_file);
}
int security_settime(const struct timespec *ts, const struct timezone *tz)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 4aa0167..ae12000 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -77,6 +77,7 @@
#include <linux/selinux.h>
#include <linux/mutex.h>
#include <linux/posix-timers.h>
+#include <linux/syslog.h>
#include "avc.h"
#include "objsec.h"
@@ -2089,11 +2090,11 @@ static int selinux_quota_on(struct dentry *dentry)
return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON);
}
-static int selinux_syslog(int type)
+static int selinux_syslog(int type, bool from_file)
{
int rc;
- rc = cap_syslog(type);
+ rc = cap_syslog(type, from_file);
if (rc)
return rc;
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index c33b6bb..09c4912 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -157,12 +157,12 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
*
* Returns 0 on success, error code otherwise.
*/
-static int smack_syslog(int type)
+static int smack_syslog(int type, bool from_file)
{
int rc;
char *sp = current_security();
- rc = cap_syslog(type);
+ rc = cap_syslog(type, from_file);
if (rc != 0)
return rc;
--
1.9.1
More information about the Devel
mailing list