mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
userns: Replace the hard to write inode_userns with inode_capable.
This represents a change in strategy of how to handle user namespaces. Instead of tagging everything explicitly with a user namespace and bulking up all of the comparisons of uids and gids in the kernel, all uids and gids in use will have a mapping to a flat kuid and kgid spaces respectively. This allows much more of the existing logic to be preserved and in general allows for faster code. In this new and improved world we allow someone to utiliize capabilities over an inode if the inodes owner mapps into the capabilities holders user namespace and the user has capabilities in their user namespace. Which is simple and efficient. Moving the fs uid comparisons to be comparisons in a flat kuid space follows in later patches, something that is only significant if you are using user namespaces. Acked-by: Serge Hallyn <serge.hallyn@canonical.com> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
This commit is contained in:
parent
973c591426
commit
1a48e2ac03
5 changed files with 28 additions and 23 deletions
|
@ -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;
|
||||
}
|
||||
|
|
18
fs/namei.c
18
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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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... */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue