mirror of
https://gitee.com/bianbu-linux/linux-6.6
synced 2025-04-26 14:17:26 -04:00
inode: make init and permission helpers idmapped mount aware
The inode_owner_or_capable() helper determines whether the caller is the owner of the inode or is capable with respect to that inode. Allow it to handle idmapped mounts. If the inode is accessed through an idmapped mount it according to the mount's user namespace. Afterwards the checks are identical to non-idmapped mounts. If the initial user namespace is passed nothing changes so non-idmapped mounts will see identical behavior as before. Similarly, allow the inode_init_owner() helper to handle idmapped mounts. It initializes a new inode on idmapped mounts by mapping the fsuid and fsgid of the caller from the mount's user namespace. If the initial user namespace is passed nothing changes so non-idmapped mounts will see identical behavior as before. Link: https://lore.kernel.org/r/20210121131959.646623-7-christian.brauner@ubuntu.com Cc: Christoph Hellwig <hch@lst.de> Cc: David Howells <dhowells@redhat.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: linux-fsdevel@vger.kernel.org Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: James Morris <jamorris@linux.microsoft.com> Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
This commit is contained in:
parent
47291baa8d
commit
21cb47be6f
54 changed files with 112 additions and 91 deletions
36
fs/inode.c
36
fs/inode.c
|
@ -2130,14 +2130,21 @@ EXPORT_SYMBOL(init_special_inode);
|
|||
|
||||
/**
|
||||
* inode_init_owner - Init uid,gid,mode for new inode according to posix standards
|
||||
* @mnt_userns: User namespace of the mount the inode was created from
|
||||
* @inode: New inode
|
||||
* @dir: Directory inode
|
||||
* @mode: mode of the new inode
|
||||
*
|
||||
* If the inode has been created through an idmapped mount the user namespace of
|
||||
* the vfsmount must be passed through @mnt_userns. This function will then take
|
||||
* care to map the inode according to @mnt_userns before checking permissions
|
||||
* and initializing i_uid and i_gid. On non-idmapped mounts or if permission
|
||||
* checking is to be performed on the raw inode simply passs init_user_ns.
|
||||
*/
|
||||
void inode_init_owner(struct inode *inode, const struct inode *dir,
|
||||
umode_t mode)
|
||||
void inode_init_owner(struct user_namespace *mnt_userns, struct inode *inode,
|
||||
const struct inode *dir, umode_t mode)
|
||||
{
|
||||
inode->i_uid = current_fsuid();
|
||||
inode->i_uid = fsuid_into_mnt(mnt_userns);
|
||||
if (dir && dir->i_mode & S_ISGID) {
|
||||
inode->i_gid = dir->i_gid;
|
||||
|
||||
|
@ -2145,32 +2152,41 @@ void inode_init_owner(struct inode *inode, const struct inode *dir,
|
|||
if (S_ISDIR(mode))
|
||||
mode |= S_ISGID;
|
||||
else if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP) &&
|
||||
!in_group_p(inode->i_gid) &&
|
||||
!capable_wrt_inode_uidgid(&init_user_ns, dir,
|
||||
CAP_FSETID))
|
||||
!in_group_p(i_gid_into_mnt(mnt_userns, dir)) &&
|
||||
!capable_wrt_inode_uidgid(mnt_userns, dir, CAP_FSETID))
|
||||
mode &= ~S_ISGID;
|
||||
} else
|
||||
inode->i_gid = current_fsgid();
|
||||
inode->i_gid = fsgid_into_mnt(mnt_userns);
|
||||
inode->i_mode = mode;
|
||||
}
|
||||
EXPORT_SYMBOL(inode_init_owner);
|
||||
|
||||
/**
|
||||
* inode_owner_or_capable - check current task permissions to inode
|
||||
* @mnt_userns: user namespace of the mount the inode was found from
|
||||
* @inode: inode being checked
|
||||
*
|
||||
* Return true if current either has CAP_FOWNER in a namespace with the
|
||||
* inode owner uid mapped, or owns the file.
|
||||
*
|
||||
* If the inode has been found through an idmapped mount the user namespace of
|
||||
* the vfsmount must be passed through @mnt_userns. This function will then take
|
||||
* care to map the inode according to @mnt_userns before checking permissions.
|
||||
* On non-idmapped mounts or if permission checking is to be performed on the
|
||||
* raw inode simply passs init_user_ns.
|
||||
*/
|
||||
bool inode_owner_or_capable(const struct inode *inode)
|
||||
bool inode_owner_or_capable(struct user_namespace *mnt_userns,
|
||||
const struct inode *inode)
|
||||
{
|
||||
kuid_t i_uid;
|
||||
struct user_namespace *ns;
|
||||
|
||||
if (uid_eq(current_fsuid(), inode->i_uid))
|
||||
i_uid = i_uid_into_mnt(mnt_userns, inode);
|
||||
if (uid_eq(current_fsuid(), i_uid))
|
||||
return true;
|
||||
|
||||
ns = current_user_ns();
|
||||
if (kuid_has_mapping(ns, inode->i_uid) && ns_capable(ns, CAP_FOWNER))
|
||||
if (kuid_has_mapping(ns, i_uid) && ns_capable(ns, CAP_FOWNER))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue