[Devel] [PATCH] cred: add ve_capable to check capabilities relative to the current VE (v2)
Andrew Vagin
avagin at openvz.org
Tue Sep 1 05:59:59 PDT 2015
We want to allow a few operations in VE. Currently we use nsown_capable,
but it's wrong, because in this case we allow these operations in any
user namespace.
v2: take ve0->cred if the currect ve isn't running
Signed-off-by: Andrew Vagin <avagin at openvz.org>
---
fs/autofs4/root.c | 6 ++----
fs/ioprio.c | 2 +-
fs/namei.c | 2 +-
include/linux/capability.h | 1 +
kernel/capability.c | 20 ++++++++++++++++++++
kernel/printk.c | 5 ++---
net/ipv6/sit.c | 2 +-
net/netfilter/nf_sockopt.c | 2 +-
security/commoncap.c | 4 ++--
security/device_cgroup.c | 4 ++--
10 files changed, 33 insertions(+), 15 deletions(-)
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 68e3edb..1462d8b 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -588,8 +588,7 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry)
struct autofs_info *p_ino;
/* This allows root to remove symlinks */
- if (!autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) &&
- !capable(CAP_VE_SYS_ADMIN))
+ if (!autofs4_oz_mode(sbi) && !ve_capable(CAP_SYS_ADMIN))
return -EPERM;
if (atomic_dec_and_test(&ino->count)) {
@@ -837,8 +836,7 @@ static int autofs4_root_ioctl_unlocked(struct inode *inode, struct file *filp,
_IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT)
return -ENOTTY;
- if (!autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) &&
- !capable(CAP_VE_SYS_ADMIN))
+ if (!autofs4_oz_mode(sbi) && !ve_capable(CAP_SYS_ADMIN))
return -EPERM;
switch(cmd) {
diff --git a/fs/ioprio.c b/fs/ioprio.c
index c876fad..f9d9187 100644
--- a/fs/ioprio.c
+++ b/fs/ioprio.c
@@ -75,7 +75,7 @@ SYSCALL_DEFINE3(ioprio_set, int, which, int, who, int, ioprio)
switch (class) {
case IOPRIO_CLASS_RT:
- if (!capable(CAP_VE_ADMIN))
+ if (!ve_capable(CAP_SYS_ADMIN))
return -EPERM;
class = IOPRIO_CLASS_BE;
data = 0;
diff --git a/fs/namei.c b/fs/namei.c
index 8e29a44..e7d9f54 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3397,7 +3397,7 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
if (error)
return error;
- if ((S_ISCHR(mode) || S_ISBLK(mode)) && !nsown_capable(CAP_MKNOD))
+ if ((S_ISCHR(mode) || S_ISBLK(mode)) && !ve_capable(CAP_MKNOD))
return -EPERM;
if (!dir->i_op->mknod)
diff --git a/include/linux/capability.h b/include/linux/capability.h
index 2b77384..b1131e3 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -217,6 +217,7 @@ extern bool has_ns_capability_noaudit(struct task_struct *t,
extern bool capable(int cap);
extern bool ns_capable(struct user_namespace *ns, int cap);
extern bool nsown_capable(int cap);
+extern bool ve_capable(int cap);
extern bool inode_capable(const struct inode *inode, int cap);
extern bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap);
diff --git a/kernel/capability.c b/kernel/capability.c
index 0a843d5..4a73381 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -16,6 +16,7 @@
#include <linux/pid_namespace.h>
#include <linux/user_namespace.h>
#include <asm/uaccess.h>
+#include <linux/ve.h>
/*
* Leveraged for setting/resetting capabilities
@@ -396,6 +397,25 @@ bool ns_capable(struct user_namespace *ns, int cap)
}
EXPORT_SYMBOL(ns_capable);
+#if CONFIG_VE
+bool ve_capable(int cap)
+{
+ struct cred *cred = get_exec_env()->init_cred;
+
+ if (cred == NULL) /* ve isn't running */
+ cred = ve0.init_cred;
+
+ return ns_capable(cred->user_ns, cap);
+}
+#else
+bool ve_capable(int cap)
+{
+ return capable(cap);
+}
+#endif
+
+EXPORT_SYMBOL_GPL(ve_capable);
+
/**
* file_ns_capable - Determine if the file's opener had a capability in effect
* @file: The file we want to check
diff --git a/kernel/printk.c b/kernel/printk.c
index 44b3783..91766fc 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -468,14 +468,13 @@ static int check_syslog_permissions(int type, bool from_file)
return 0;
if (syslog_action_restricted(type)) {
- if (nsown_capable(CAP_SYSLOG))
+ if (ve_capable(CAP_SYSLOG))
return 0;
/*
* For historical reasons, accept CAP_SYS_ADMIN too, with
* a warning.
*/
- if (nsown_capable(CAP_SYS_ADMIN) ||
- nsown_capable(CAP_VE_ADMIN)) {
+ if (ve_capable(CAP_SYS_ADMIN)) {
pr_warn_once("%s (%d): Attempt to access syslog with "
"CAP_SYS_ADMIN but no CAP_SYSLOG "
"(deprecated).\n",
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 8f4c52d..0cbb2b2 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -309,7 +309,7 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t,
/* For simple GET or for root users,
* we try harder to allocate.
*/
- kp = (cmax <= 1 || capable(CAP_NET_ADMIN) || capable(CAP_VE_NET_ADMIN)) ?
+ kp = (cmax <= 1 || ve_capable(CAP_NET_ADMIN)) ?
kcalloc(cmax, sizeof(*kp), GFP_KERNEL) :
NULL;
diff --git a/net/netfilter/nf_sockopt.c b/net/netfilter/nf_sockopt.c
index 84dfd09..951a11b 100644
--- a/net/netfilter/nf_sockopt.c
+++ b/net/netfilter/nf_sockopt.c
@@ -115,7 +115,7 @@ static int ve0_load_sockopt_module(struct net *net, u8 pf, int val, int get)
const char *name;
int ret = -EPERM;
- if (!capable(CAP_VE_NET_ADMIN))
+ if (!ve_capable(CAP_NET_ADMIN))
goto out;
if (sockopt_module_fits(pf, val, get, PF_INET,
diff --git a/security/commoncap.c b/security/commoncap.c
index 59ff538..9d0a2b6 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -654,7 +654,7 @@ int cap_inode_setxattr(struct dentry *dentry, const char *name,
if (!strncmp(name, XATTR_SECURITY_PREFIX,
sizeof(XATTR_SECURITY_PREFIX) - 1) &&
- !capable(CAP_SYS_ADMIN) && !capable(CAP_VE_ADMIN))
+ !ve_capable(CAP_SYS_ADMIN))
return -EPERM;
return 0;
}
@@ -680,7 +680,7 @@ int cap_inode_removexattr(struct dentry *dentry, const char *name)
if (!strncmp(name, XATTR_SECURITY_PREFIX,
sizeof(XATTR_SECURITY_PREFIX) - 1) &&
- !capable(CAP_SYS_ADMIN) && !capable(CAP_VE_ADMIN))
+ !ve_capable(CAP_SYS_ADMIN))
return -EPERM;
return 0;
}
diff --git a/security/device_cgroup.c b/security/device_cgroup.c
index 375711e..531e40c 100644
--- a/security/device_cgroup.c
+++ b/security/device_cgroup.c
@@ -83,7 +83,7 @@ static int devcgroup_can_attach(struct cgroup *new_cgrp,
{
struct task_struct *task = cgroup_taskset_first(set);
- if (current != task && !capable(CAP_SYS_ADMIN) && !capable(CAP_VE_SYS_ADMIN))
+ if (current != task && !ve_capable(CAP_SYS_ADMIN))
return -EPERM;
return 0;
}
@@ -673,7 +673,7 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
struct cgroup *p = devcgroup->css.cgroup;
struct dev_cgroup *parent = NULL;
- if (!capable(CAP_SYS_ADMIN) && !capable(CAP_VE_SYS_ADMIN))
+ if (!ve_capable(CAP_SYS_ADMIN))
return -EPERM;
if (p->parent)
--
1.7.1
More information about the Devel
mailing list