From 50eb4e04528a88776571c1fb76ea34da39b863c2 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 14 Nov 2011 16:24:06 -0800 Subject: [PATCH] --- yaml --- r: 305989 b: refs/heads/master c: 1a48e2ac034d47ed843081c4523b63c46b46888b h: refs/heads/master i: 305987: 83aa86402c322737e4ccb4de12d8e777040e6930 v: v3 --- [refs] | 2 +- trunk/fs/inode.c | 6 ++---- trunk/fs/namei.c | 18 +++++------------- trunk/include/linux/capability.h | 2 ++ trunk/include/linux/fs.h | 6 ------ trunk/kernel/capability.c | 19 +++++++++++++++++++ 6 files changed, 29 insertions(+), 24 deletions(-) diff --git a/[refs] b/[refs] index a40a04a490da..a5eb1df20e6e 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 973c5914260d75292f71a4729753086b9e863d57 +refs/heads/master: 1a48e2ac034d47ed843081c4523b63c46b46888b diff --git a/trunk/fs/inode.c b/trunk/fs/inode.c index 9f4f5fecc096..f0c4ace408e4 100644 --- a/trunk/fs/inode.c +++ b/trunk/fs/inode.c @@ -1732,11 +1732,9 @@ EXPORT_SYMBOL(inode_init_owner); */ bool inode_owner_or_capable(const struct inode *inode) { - struct user_namespace *ns = inode_userns(inode); - - if (current_user_ns() == ns && current_fsuid() == inode->i_uid) + if (current_fsuid() == inode->i_uid) return true; - if (ns_capable(ns, CAP_FOWNER)) + if (inode_capable(inode, CAP_FOWNER)) return true; return false; } diff --git a/trunk/fs/namei.c b/trunk/fs/namei.c index 701954d68ac7..941c4362e298 100644 --- a/trunk/fs/namei.c +++ b/trunk/fs/namei.c @@ -228,9 +228,6 @@ static int acl_permission_check(struct inode *inode, int mask) { unsigned int mode = inode->i_mode; - if (current_user_ns() != inode_userns(inode)) - goto other_perms; - if (likely(current_fsuid() == inode->i_uid)) mode >>= 6; else { @@ -244,7 +241,6 @@ static int acl_permission_check(struct inode *inode, int mask) mode >>= 3; } -other_perms: /* * If the DACs are ok we don't need any capability check. */ @@ -280,10 +276,10 @@ int generic_permission(struct inode *inode, int mask) if (S_ISDIR(inode->i_mode)) { /* DACs are overridable for directories */ - if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE)) + if (inode_capable(inode, CAP_DAC_OVERRIDE)) return 0; if (!(mask & MAY_WRITE)) - if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH)) + if (inode_capable(inode, CAP_DAC_READ_SEARCH)) return 0; return -EACCES; } @@ -293,7 +289,7 @@ int generic_permission(struct inode *inode, int mask) * at least one exec bit set. */ if (!(mask & MAY_EXEC) || (inode->i_mode & S_IXUGO)) - if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE)) + if (inode_capable(inode, CAP_DAC_OVERRIDE)) return 0; /* @@ -301,7 +297,7 @@ int generic_permission(struct inode *inode, int mask) */ mask &= MAY_READ | MAY_WRITE | MAY_EXEC; if (mask == MAY_READ) - if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH)) + if (inode_capable(inode, CAP_DAC_READ_SEARCH)) return 0; return -EACCES; @@ -1964,15 +1960,11 @@ static inline int check_sticky(struct inode *dir, struct inode *inode) if (!(dir->i_mode & S_ISVTX)) return 0; - if (current_user_ns() != inode_userns(inode)) - goto other_userns; if (inode->i_uid == fsuid) return 0; if (dir->i_uid == fsuid) return 0; - -other_userns: - return !ns_capable(inode_userns(inode), CAP_FOWNER); + return !inode_capable(inode, CAP_FOWNER); } /* diff --git a/trunk/include/linux/capability.h b/trunk/include/linux/capability.h index 12d52dedb229..a76eca907470 100644 --- a/trunk/include/linux/capability.h +++ b/trunk/include/linux/capability.h @@ -374,6 +374,7 @@ struct cpu_vfs_cap_data { #ifdef __KERNEL__ +struct inode; struct dentry; struct user_namespace; @@ -548,6 +549,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 inode_capable(const struct inode *inode, int cap); /* audit system wants to get cap info from files as well */ extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps); diff --git a/trunk/include/linux/fs.h b/trunk/include/linux/fs.h index 135693e79f2b..a6c5efbee0d7 100644 --- a/trunk/include/linux/fs.h +++ b/trunk/include/linux/fs.h @@ -1522,12 +1522,6 @@ enum { #define vfs_check_frozen(sb, level) \ wait_event((sb)->s_wait_unfrozen, ((sb)->s_frozen < (level))) -/* - * until VFS tracks user namespaces for inodes, just make all files - * belong to init_user_ns - */ -extern struct user_namespace init_user_ns; -#define inode_userns(inode) (&init_user_ns) extern bool inode_owner_or_capable(const struct inode *inode); /* not quite ready to be deprecated, but... */ diff --git a/trunk/kernel/capability.c b/trunk/kernel/capability.c index 3f1adb6c6470..cc5f0718215d 100644 --- a/trunk/kernel/capability.c +++ b/trunk/kernel/capability.c @@ -419,3 +419,22 @@ bool nsown_capable(int cap) { return ns_capable(current_user_ns(), cap); } + +/** + * inode_capable - Check superior capability over inode + * @inode: The inode in question + * @cap: The capability in question + * + * Return true if the current task has the given superior capability + * targeted at it's own user namespace and that the given inode is owned + * by the current user namespace or a child namespace. + * + * Currently inodes can only be owned by the initial user namespace. + * + */ +bool inode_capable(const struct inode *inode, int cap) +{ + struct user_namespace *ns = current_user_ns(); + + return ns_capable(ns, cap) && (ns == &init_user_ns); +}