fs.vfsuid.conversion.v6.2
-----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCY5bspgAKCRCRxhvAZXjc opEWAQDpF5rnZn1vv4/uOTij9ztcA4yLxu/Q19CdqBaoHlWZ9AD/d3eecee3bh5h iPHtlUK5/VspfD9LPpdc5ZbPCdZ2pA4= =t6NN -----END PGP SIGNATURE----- Merge tag 'fs.vfsuid.conversion.v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/idmapping Pull vfsuid updates from Christian Brauner: "Last cycle we introduced the vfs{g,u}id_t types and associated helpers to gain type safety when dealing with idmapped mounts. That initial work already converted a lot of places over but there were still some left, This converts all remaining places that still make use of non-type safe idmapping helpers to rely on the new type safe vfs{g,u}id based helpers. Afterwards it removes all the old non-type safe helpers" * tag 'fs.vfsuid.conversion.v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/idmapping: fs: remove unused idmapping helpers ovl: port to vfs{g,u}id_t and associated helpers fuse: port to vfs{g,u}id_t and associated helpers ima: use type safe idmapping helpers apparmor: use type safe idmapping helpers caps: use type safe idmapping helpers fs: use type safe idmapping helpers mnt_idmapping: add missing helpers
This commit is contained in:
Коммит
e1212e9b6f
|
@ -720,8 +720,8 @@ void do_coredump(const kernel_siginfo_t *siginfo)
|
|||
* filesystem.
|
||||
*/
|
||||
mnt_userns = file_mnt_user_ns(cprm.file);
|
||||
if (!uid_eq(i_uid_into_mnt(mnt_userns, inode),
|
||||
current_fsuid())) {
|
||||
if (!vfsuid_eq_kuid(i_uid_into_vfsuid(mnt_userns, inode),
|
||||
current_fsuid())) {
|
||||
pr_info_ratelimited("Core dump to %s aborted: cannot preserve file owner\n",
|
||||
cn.corename);
|
||||
goto close_fail;
|
||||
|
|
16
fs/exec.c
16
fs/exec.c
|
@ -1599,8 +1599,8 @@ static void bprm_fill_uid(struct linux_binprm *bprm, struct file *file)
|
|||
struct user_namespace *mnt_userns;
|
||||
struct inode *inode = file_inode(file);
|
||||
unsigned int mode;
|
||||
kuid_t uid;
|
||||
kgid_t gid;
|
||||
vfsuid_t vfsuid;
|
||||
vfsgid_t vfsgid;
|
||||
|
||||
if (!mnt_may_suid(file->f_path.mnt))
|
||||
return;
|
||||
|
@ -1619,23 +1619,23 @@ static void bprm_fill_uid(struct linux_binprm *bprm, struct file *file)
|
|||
|
||||
/* reload atomically mode/uid/gid now that lock held */
|
||||
mode = inode->i_mode;
|
||||
uid = i_uid_into_mnt(mnt_userns, inode);
|
||||
gid = i_gid_into_mnt(mnt_userns, inode);
|
||||
vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
|
||||
vfsgid = i_gid_into_vfsgid(mnt_userns, inode);
|
||||
inode_unlock(inode);
|
||||
|
||||
/* We ignore suid/sgid if there are no mappings for them in the ns */
|
||||
if (!kuid_has_mapping(bprm->cred->user_ns, uid) ||
|
||||
!kgid_has_mapping(bprm->cred->user_ns, gid))
|
||||
if (!vfsuid_has_mapping(bprm->cred->user_ns, vfsuid) ||
|
||||
!vfsgid_has_mapping(bprm->cred->user_ns, vfsgid))
|
||||
return;
|
||||
|
||||
if (mode & S_ISUID) {
|
||||
bprm->per_clear |= PER_CLEAR_ON_SETID;
|
||||
bprm->cred->euid = uid;
|
||||
bprm->cred->euid = vfsuid_into_kuid(vfsuid);
|
||||
}
|
||||
|
||||
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
|
||||
bprm->per_clear |= PER_CLEAR_ON_SETID;
|
||||
bprm->cred->egid = gid;
|
||||
bprm->cred->egid = vfsgid_into_kgid(vfsgid);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ int fuse_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (!in_group_p(i_gid_into_mnt(&init_user_ns, inode)) &&
|
||||
if (!vfsgid_in_group_p(i_gid_into_vfsgid(&init_user_ns, inode)) &&
|
||||
!capable_wrt_inode_uidgid(&init_user_ns, inode, CAP_FSETID))
|
||||
extra_flags |= FUSE_SETXATTR_ACL_KILL_SGID;
|
||||
|
||||
|
|
|
@ -2323,15 +2323,15 @@ EXPORT_SYMBOL(inode_init_owner);
|
|||
bool inode_owner_or_capable(struct user_namespace *mnt_userns,
|
||||
const struct inode *inode)
|
||||
{
|
||||
kuid_t i_uid;
|
||||
vfsuid_t vfsuid;
|
||||
struct user_namespace *ns;
|
||||
|
||||
i_uid = i_uid_into_mnt(mnt_userns, inode);
|
||||
if (uid_eq(current_fsuid(), i_uid))
|
||||
vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
|
||||
if (vfsuid_eq_kuid(vfsuid, current_fsuid()))
|
||||
return true;
|
||||
|
||||
ns = current_user_ns();
|
||||
if (kuid_has_mapping(ns, i_uid) && ns_capable(ns, CAP_FOWNER))
|
||||
if (vfsuid_has_mapping(ns, vfsuid) && ns_capable(ns, CAP_FOWNER))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
|
40
fs/namei.c
40
fs/namei.c
|
@ -336,11 +336,11 @@ static int acl_permission_check(struct user_namespace *mnt_userns,
|
|||
struct inode *inode, int mask)
|
||||
{
|
||||
unsigned int mode = inode->i_mode;
|
||||
kuid_t i_uid;
|
||||
vfsuid_t vfsuid;
|
||||
|
||||
/* Are we the owner? If so, ACL's don't matter */
|
||||
i_uid = i_uid_into_mnt(mnt_userns, inode);
|
||||
if (likely(uid_eq(current_fsuid(), i_uid))) {
|
||||
vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
|
||||
if (likely(vfsuid_eq_kuid(vfsuid, current_fsuid()))) {
|
||||
mask &= 7;
|
||||
mode >>= 6;
|
||||
return (mask & ~mode) ? -EACCES : 0;
|
||||
|
@ -362,8 +362,8 @@ static int acl_permission_check(struct user_namespace *mnt_userns,
|
|||
* about? Need to check group ownership if so.
|
||||
*/
|
||||
if (mask & (mode ^ (mode >> 3))) {
|
||||
kgid_t kgid = i_gid_into_mnt(mnt_userns, inode);
|
||||
if (in_group_p(kgid))
|
||||
vfsgid_t vfsgid = i_gid_into_vfsgid(mnt_userns, inode);
|
||||
if (vfsgid_in_group_p(vfsgid))
|
||||
mode >>= 3;
|
||||
}
|
||||
|
||||
|
@ -581,7 +581,7 @@ struct nameidata {
|
|||
struct nameidata *saved;
|
||||
unsigned root_seq;
|
||||
int dfd;
|
||||
kuid_t dir_uid;
|
||||
vfsuid_t dir_vfsuid;
|
||||
umode_t dir_mode;
|
||||
} __randomize_layout;
|
||||
|
||||
|
@ -1095,15 +1095,15 @@ fs_initcall(init_fs_namei_sysctls);
|
|||
static inline int may_follow_link(struct nameidata *nd, const struct inode *inode)
|
||||
{
|
||||
struct user_namespace *mnt_userns;
|
||||
kuid_t i_uid;
|
||||
vfsuid_t vfsuid;
|
||||
|
||||
if (!sysctl_protected_symlinks)
|
||||
return 0;
|
||||
|
||||
mnt_userns = mnt_user_ns(nd->path.mnt);
|
||||
i_uid = i_uid_into_mnt(mnt_userns, inode);
|
||||
vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
|
||||
/* Allowed if owner and follower match. */
|
||||
if (uid_eq(current_cred()->fsuid, i_uid))
|
||||
if (vfsuid_eq_kuid(vfsuid, current_fsuid()))
|
||||
return 0;
|
||||
|
||||
/* Allowed if parent directory not sticky and world-writable. */
|
||||
|
@ -1111,7 +1111,7 @@ static inline int may_follow_link(struct nameidata *nd, const struct inode *inod
|
|||
return 0;
|
||||
|
||||
/* Allowed if parent directory and link owner match. */
|
||||
if (uid_valid(nd->dir_uid) && uid_eq(nd->dir_uid, i_uid))
|
||||
if (vfsuid_valid(nd->dir_vfsuid) && vfsuid_eq(nd->dir_vfsuid, vfsuid))
|
||||
return 0;
|
||||
|
||||
if (nd->flags & LOOKUP_RCU)
|
||||
|
@ -1183,8 +1183,8 @@ int may_linkat(struct user_namespace *mnt_userns, const struct path *link)
|
|||
struct inode *inode = link->dentry->d_inode;
|
||||
|
||||
/* Inode writeback is not safe when the uid or gid are invalid. */
|
||||
if (!uid_valid(i_uid_into_mnt(mnt_userns, inode)) ||
|
||||
!gid_valid(i_gid_into_mnt(mnt_userns, inode)))
|
||||
if (!vfsuid_valid(i_uid_into_vfsuid(mnt_userns, inode)) ||
|
||||
!vfsgid_valid(i_gid_into_vfsgid(mnt_userns, inode)))
|
||||
return -EOVERFLOW;
|
||||
|
||||
if (!sysctl_protected_hardlinks)
|
||||
|
@ -1232,13 +1232,13 @@ static int may_create_in_sticky(struct user_namespace *mnt_userns,
|
|||
struct nameidata *nd, struct inode *const inode)
|
||||
{
|
||||
umode_t dir_mode = nd->dir_mode;
|
||||
kuid_t dir_uid = nd->dir_uid;
|
||||
vfsuid_t dir_vfsuid = nd->dir_vfsuid;
|
||||
|
||||
if ((!sysctl_protected_fifos && S_ISFIFO(inode->i_mode)) ||
|
||||
(!sysctl_protected_regular && S_ISREG(inode->i_mode)) ||
|
||||
likely(!(dir_mode & S_ISVTX)) ||
|
||||
uid_eq(i_uid_into_mnt(mnt_userns, inode), dir_uid) ||
|
||||
uid_eq(current_fsuid(), i_uid_into_mnt(mnt_userns, inode)))
|
||||
vfsuid_eq(i_uid_into_vfsuid(mnt_userns, inode), dir_vfsuid) ||
|
||||
vfsuid_eq_kuid(i_uid_into_vfsuid(mnt_userns, inode), current_fsuid()))
|
||||
return 0;
|
||||
|
||||
if (likely(dir_mode & 0002) ||
|
||||
|
@ -2307,7 +2307,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
|
|||
OK:
|
||||
/* pathname or trailing symlink, done */
|
||||
if (!depth) {
|
||||
nd->dir_uid = i_uid_into_mnt(mnt_userns, nd->inode);
|
||||
nd->dir_vfsuid = i_uid_into_vfsuid(mnt_userns, nd->inode);
|
||||
nd->dir_mode = nd->inode->i_mode;
|
||||
nd->flags &= ~LOOKUP_PARENT;
|
||||
return 0;
|
||||
|
@ -2885,9 +2885,9 @@ int __check_sticky(struct user_namespace *mnt_userns, struct inode *dir,
|
|||
{
|
||||
kuid_t fsuid = current_fsuid();
|
||||
|
||||
if (uid_eq(i_uid_into_mnt(mnt_userns, inode), fsuid))
|
||||
if (vfsuid_eq_kuid(i_uid_into_vfsuid(mnt_userns, inode), fsuid))
|
||||
return 0;
|
||||
if (uid_eq(i_uid_into_mnt(mnt_userns, dir), fsuid))
|
||||
if (vfsuid_eq_kuid(i_uid_into_vfsuid(mnt_userns, dir), fsuid))
|
||||
return 0;
|
||||
return !capable_wrt_inode_uidgid(mnt_userns, inode, CAP_FOWNER);
|
||||
}
|
||||
|
@ -2926,8 +2926,8 @@ static int may_delete(struct user_namespace *mnt_userns, struct inode *dir,
|
|||
BUG_ON(victim->d_parent->d_inode != dir);
|
||||
|
||||
/* Inode writeback is not safe when the uid or gid are invalid. */
|
||||
if (!uid_valid(i_uid_into_mnt(mnt_userns, inode)) ||
|
||||
!gid_valid(i_gid_into_mnt(mnt_userns, inode)))
|
||||
if (!vfsuid_valid(i_uid_into_vfsuid(mnt_userns, inode)) ||
|
||||
!vfsgid_valid(i_gid_into_vfsgid(mnt_userns, inode)))
|
||||
return -EOVERFLOW;
|
||||
|
||||
audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);
|
||||
|
|
|
@ -1104,13 +1104,18 @@ void ovl_copyattr(struct inode *inode)
|
|||
struct path realpath;
|
||||
struct inode *realinode;
|
||||
struct user_namespace *real_mnt_userns;
|
||||
vfsuid_t vfsuid;
|
||||
vfsgid_t vfsgid;
|
||||
|
||||
ovl_i_path_real(inode, &realpath);
|
||||
realinode = d_inode(realpath.dentry);
|
||||
real_mnt_userns = mnt_user_ns(realpath.mnt);
|
||||
|
||||
inode->i_uid = i_uid_into_mnt(real_mnt_userns, realinode);
|
||||
inode->i_gid = i_gid_into_mnt(real_mnt_userns, realinode);
|
||||
vfsuid = i_uid_into_vfsuid(real_mnt_userns, realinode);
|
||||
vfsgid = i_gid_into_vfsgid(real_mnt_userns, realinode);
|
||||
|
||||
inode->i_uid = vfsuid_into_kuid(vfsuid);
|
||||
inode->i_gid = vfsgid_into_kgid(vfsgid);
|
||||
inode->i_mode = realinode->i_mode;
|
||||
inode->i_atime = realinode->i_atime;
|
||||
inode->i_mtime = realinode->i_mtime;
|
||||
|
|
|
@ -429,7 +429,7 @@ static bool allow_file_dedupe(struct file *file)
|
|||
return true;
|
||||
if (file->f_mode & FMODE_WRITE)
|
||||
return true;
|
||||
if (uid_eq(current_fsuid(), i_uid_into_mnt(mnt_userns, inode)))
|
||||
if (vfsuid_eq_kuid(i_uid_into_vfsuid(mnt_userns, inode), current_fsuid()))
|
||||
return true;
|
||||
if (!inode_permission(mnt_userns, inode, MAY_WRITE))
|
||||
return true;
|
||||
|
|
|
@ -44,12 +44,15 @@
|
|||
void generic_fillattr(struct user_namespace *mnt_userns, struct inode *inode,
|
||||
struct kstat *stat)
|
||||
{
|
||||
vfsuid_t vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
|
||||
vfsgid_t vfsgid = i_gid_into_vfsgid(mnt_userns, inode);
|
||||
|
||||
stat->dev = inode->i_sb->s_dev;
|
||||
stat->ino = inode->i_ino;
|
||||
stat->mode = inode->i_mode;
|
||||
stat->nlink = inode->i_nlink;
|
||||
stat->uid = i_uid_into_mnt(mnt_userns, inode);
|
||||
stat->gid = i_gid_into_mnt(mnt_userns, inode);
|
||||
stat->uid = vfsuid_into_kuid(vfsuid);
|
||||
stat->gid = vfsgid_into_kgid(vfsgid);
|
||||
stat->rdev = inode->i_rdev;
|
||||
stat->size = i_size_read(inode);
|
||||
stat->atime = inode->i_atime;
|
||||
|
|
|
@ -1631,23 +1631,6 @@ static inline void i_gid_write(struct inode *inode, gid_t gid)
|
|||
inode->i_gid = make_kgid(i_user_ns(inode), gid);
|
||||
}
|
||||
|
||||
/**
|
||||
* i_uid_into_mnt - map an inode's i_uid down into a mnt_userns
|
||||
* @mnt_userns: user namespace of the mount the inode was found from
|
||||
* @inode: inode to map
|
||||
*
|
||||
* Note, this will eventually be removed completely in favor of the type-safe
|
||||
* i_uid_into_vfsuid().
|
||||
*
|
||||
* Return: the inode's i_uid mapped down according to @mnt_userns.
|
||||
* If the inode's i_uid has no mapping INVALID_UID is returned.
|
||||
*/
|
||||
static inline kuid_t i_uid_into_mnt(struct user_namespace *mnt_userns,
|
||||
const struct inode *inode)
|
||||
{
|
||||
return AS_KUIDT(make_vfsuid(mnt_userns, i_user_ns(inode), inode->i_uid));
|
||||
}
|
||||
|
||||
/**
|
||||
* i_uid_into_vfsuid - map an inode's i_uid down into a mnt_userns
|
||||
* @mnt_userns: user namespace of the mount the inode was found from
|
||||
|
@ -1700,23 +1683,6 @@ static inline void i_uid_update(struct user_namespace *mnt_userns,
|
|||
attr->ia_vfsuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* i_gid_into_mnt - map an inode's i_gid down into a mnt_userns
|
||||
* @mnt_userns: user namespace of the mount the inode was found from
|
||||
* @inode: inode to map
|
||||
*
|
||||
* Note, this will eventually be removed completely in favor of the type-safe
|
||||
* i_gid_into_vfsgid().
|
||||
*
|
||||
* Return: the inode's i_gid mapped down according to @mnt_userns.
|
||||
* If the inode's i_gid has no mapping INVALID_GID is returned.
|
||||
*/
|
||||
static inline kgid_t i_gid_into_mnt(struct user_namespace *mnt_userns,
|
||||
const struct inode *inode)
|
||||
{
|
||||
return AS_KGIDT(make_vfsgid(mnt_userns, i_user_ns(inode), inode->i_gid));
|
||||
}
|
||||
|
||||
/**
|
||||
* i_gid_into_vfsgid - map an inode's i_gid down into a mnt_userns
|
||||
* @mnt_userns: user namespace of the mount the inode was found from
|
||||
|
|
|
@ -98,6 +98,26 @@ static inline bool vfsgid_eq_kgid(vfsgid_t vfsgid, kgid_t kgid)
|
|||
return vfsgid_valid(vfsgid) && __vfsgid_val(vfsgid) == __kgid_val(kgid);
|
||||
}
|
||||
|
||||
static inline bool vfsuid_gt_kuid(vfsuid_t vfsuid, kuid_t kuid)
|
||||
{
|
||||
return __vfsuid_val(vfsuid) > __kuid_val(kuid);
|
||||
}
|
||||
|
||||
static inline bool vfsgid_gt_kgid(vfsgid_t vfsgid, kgid_t kgid)
|
||||
{
|
||||
return __vfsgid_val(vfsgid) > __kgid_val(kgid);
|
||||
}
|
||||
|
||||
static inline bool vfsuid_lt_kuid(vfsuid_t vfsuid, kuid_t kuid)
|
||||
{
|
||||
return __vfsuid_val(vfsuid) < __kuid_val(kuid);
|
||||
}
|
||||
|
||||
static inline bool vfsgid_lt_kgid(vfsgid_t vfsgid, kgid_t kgid)
|
||||
{
|
||||
return __vfsgid_val(vfsgid) < __kgid_val(kgid);
|
||||
}
|
||||
|
||||
/*
|
||||
* vfs{g,u}ids are created from k{g,u}ids.
|
||||
* We don't allow them to be created from regular {u,g}id.
|
||||
|
@ -208,13 +228,6 @@ static inline vfsuid_t make_vfsuid(struct user_namespace *mnt_userns,
|
|||
return VFSUIDT_INIT(make_kuid(mnt_userns, uid));
|
||||
}
|
||||
|
||||
static inline kuid_t mapped_kuid_fs(struct user_namespace *mnt_userns,
|
||||
struct user_namespace *fs_userns,
|
||||
kuid_t kuid)
|
||||
{
|
||||
return AS_KUIDT(make_vfsuid(mnt_userns, fs_userns, kuid));
|
||||
}
|
||||
|
||||
/**
|
||||
* make_vfsgid - map a filesystem kgid into a mnt_userns
|
||||
* @mnt_userns: the mount's idmapping
|
||||
|
@ -253,13 +266,6 @@ static inline vfsgid_t make_vfsgid(struct user_namespace *mnt_userns,
|
|||
return VFSGIDT_INIT(make_kgid(mnt_userns, gid));
|
||||
}
|
||||
|
||||
static inline kgid_t mapped_kgid_fs(struct user_namespace *mnt_userns,
|
||||
struct user_namespace *fs_userns,
|
||||
kgid_t kgid)
|
||||
{
|
||||
return AS_KGIDT(make_vfsgid(mnt_userns, fs_userns, kgid));
|
||||
}
|
||||
|
||||
/**
|
||||
* from_vfsuid - map a vfsuid into the filesystem idmapping
|
||||
* @mnt_userns: the mount's idmapping
|
||||
|
@ -287,33 +293,6 @@ static inline kuid_t from_vfsuid(struct user_namespace *mnt_userns,
|
|||
return make_kuid(fs_userns, uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* mapped_kuid_user - map a user kuid into a mnt_userns
|
||||
* @mnt_userns: the mount's idmapping
|
||||
* @fs_userns: the filesystem's idmapping
|
||||
* @kuid : kuid to be mapped
|
||||
*
|
||||
* Use the idmapping of @mnt_userns to remap a @kuid into @fs_userns. Use this
|
||||
* function when preparing a @kuid to be written to disk or inode.
|
||||
*
|
||||
* If no_idmapping() determines that this is not an idmapped mount we can
|
||||
* simply return @kuid unchanged.
|
||||
* If initial_idmapping() tells us that the filesystem is not mounted with an
|
||||
* idmapping we know the value of @kuid won't change when calling
|
||||
* make_kuid() so we can simply retrieve the value via KUIDT_INIT()
|
||||
* directly.
|
||||
*
|
||||
* Return: @kuid mapped according to @mnt_userns.
|
||||
* If @kuid has no mapping in either @mnt_userns or @fs_userns INVALID_UID is
|
||||
* returned.
|
||||
*/
|
||||
static inline kuid_t mapped_kuid_user(struct user_namespace *mnt_userns,
|
||||
struct user_namespace *fs_userns,
|
||||
kuid_t kuid)
|
||||
{
|
||||
return from_vfsuid(mnt_userns, fs_userns, VFSUIDT_INIT(kuid));
|
||||
}
|
||||
|
||||
/**
|
||||
* vfsuid_has_fsmapping - check whether a vfsuid maps into the filesystem
|
||||
* @mnt_userns: the mount's idmapping
|
||||
|
@ -333,6 +312,12 @@ static inline bool vfsuid_has_fsmapping(struct user_namespace *mnt_userns,
|
|||
return uid_valid(from_vfsuid(mnt_userns, fs_userns, vfsuid));
|
||||
}
|
||||
|
||||
static inline bool vfsuid_has_mapping(struct user_namespace *userns,
|
||||
vfsuid_t vfsuid)
|
||||
{
|
||||
return from_kuid(userns, AS_KUIDT(vfsuid)) != (uid_t)-1;
|
||||
}
|
||||
|
||||
/**
|
||||
* vfsuid_into_kuid - convert vfsuid into kuid
|
||||
* @vfsuid: the vfsuid to convert
|
||||
|
@ -373,33 +358,6 @@ static inline kgid_t from_vfsgid(struct user_namespace *mnt_userns,
|
|||
return make_kgid(fs_userns, gid);
|
||||
}
|
||||
|
||||
/**
|
||||
* mapped_kgid_user - map a user kgid into a mnt_userns
|
||||
* @mnt_userns: the mount's idmapping
|
||||
* @fs_userns: the filesystem's idmapping
|
||||
* @kgid : kgid to be mapped
|
||||
*
|
||||
* Use the idmapping of @mnt_userns to remap a @kgid into @fs_userns. Use this
|
||||
* function when preparing a @kgid to be written to disk or inode.
|
||||
*
|
||||
* If no_idmapping() determines that this is not an idmapped mount we can
|
||||
* simply return @kgid unchanged.
|
||||
* If initial_idmapping() tells us that the filesystem is not mounted with an
|
||||
* idmapping we know the value of @kgid won't change when calling
|
||||
* make_kgid() so we can simply retrieve the value via KGIDT_INIT()
|
||||
* directly.
|
||||
*
|
||||
* Return: @kgid mapped according to @mnt_userns.
|
||||
* If @kgid has no mapping in either @mnt_userns or @fs_userns INVALID_GID is
|
||||
* returned.
|
||||
*/
|
||||
static inline kgid_t mapped_kgid_user(struct user_namespace *mnt_userns,
|
||||
struct user_namespace *fs_userns,
|
||||
kgid_t kgid)
|
||||
{
|
||||
return from_vfsgid(mnt_userns, fs_userns, VFSGIDT_INIT(kgid));
|
||||
}
|
||||
|
||||
/**
|
||||
* vfsgid_has_fsmapping - check whether a vfsgid maps into the filesystem
|
||||
* @mnt_userns: the mount's idmapping
|
||||
|
@ -419,6 +377,12 @@ static inline bool vfsgid_has_fsmapping(struct user_namespace *mnt_userns,
|
|||
return gid_valid(from_vfsgid(mnt_userns, fs_userns, vfsgid));
|
||||
}
|
||||
|
||||
static inline bool vfsgid_has_mapping(struct user_namespace *userns,
|
||||
vfsgid_t vfsgid)
|
||||
{
|
||||
return from_kgid(userns, AS_KGIDT(vfsgid)) != (gid_t)-1;
|
||||
}
|
||||
|
||||
/**
|
||||
* vfsgid_into_kgid - convert vfsgid into kgid
|
||||
* @vfsgid: the vfsgid to convert
|
||||
|
|
|
@ -489,8 +489,8 @@ bool privileged_wrt_inode_uidgid(struct user_namespace *ns,
|
|||
struct user_namespace *mnt_userns,
|
||||
const struct inode *inode)
|
||||
{
|
||||
return kuid_has_mapping(ns, i_uid_into_mnt(mnt_userns, inode)) &&
|
||||
kgid_has_mapping(ns, i_gid_into_mnt(mnt_userns, inode));
|
||||
return vfsuid_has_mapping(ns, i_uid_into_vfsuid(mnt_userns, inode)) &&
|
||||
vfsgid_has_mapping(ns, i_gid_into_vfsgid(mnt_userns, inode));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -859,10 +859,10 @@ int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm)
|
|||
const char *info = NULL;
|
||||
int error = 0;
|
||||
bool unsafe = false;
|
||||
kuid_t i_uid = i_uid_into_mnt(file_mnt_user_ns(bprm->file),
|
||||
file_inode(bprm->file));
|
||||
vfsuid_t vfsuid = i_uid_into_vfsuid(file_mnt_user_ns(bprm->file),
|
||||
file_inode(bprm->file));
|
||||
struct path_cond cond = {
|
||||
i_uid,
|
||||
vfsuid_into_kuid(vfsuid),
|
||||
file_inode(bprm->file)->i_mode
|
||||
};
|
||||
|
||||
|
@ -970,7 +970,7 @@ audit:
|
|||
error = fn_for_each(label, profile,
|
||||
aa_audit_file(profile, &nullperms, OP_EXEC, MAY_EXEC,
|
||||
bprm->filename, NULL, new,
|
||||
i_uid, info, error));
|
||||
vfsuid_into_kuid(vfsuid), info, error));
|
||||
aa_put_label(new);
|
||||
goto done;
|
||||
}
|
||||
|
|
|
@ -510,8 +510,10 @@ static int __file_path_perm(const char *op, struct aa_label *label,
|
|||
{
|
||||
struct aa_profile *profile;
|
||||
struct aa_perms perms = {};
|
||||
vfsuid_t vfsuid = i_uid_into_vfsuid(file_mnt_user_ns(file),
|
||||
file_inode(file));
|
||||
struct path_cond cond = {
|
||||
.uid = i_uid_into_mnt(file_mnt_user_ns(file), file_inode(file)),
|
||||
.uid = vfsuid_into_kuid(vfsuid),
|
||||
.mode = file_inode(file)->i_mode
|
||||
};
|
||||
char *buffer;
|
||||
|
|
|
@ -225,8 +225,10 @@ static int common_perm(const char *op, const struct path *path, u32 mask,
|
|||
static int common_perm_cond(const char *op, const struct path *path, u32 mask)
|
||||
{
|
||||
struct user_namespace *mnt_userns = mnt_user_ns(path->mnt);
|
||||
vfsuid_t vfsuid = i_uid_into_vfsuid(mnt_userns,
|
||||
d_backing_inode(path->dentry));
|
||||
struct path_cond cond = {
|
||||
i_uid_into_mnt(mnt_userns, d_backing_inode(path->dentry)),
|
||||
vfsuid_into_kuid(vfsuid),
|
||||
d_backing_inode(path->dentry)->i_mode
|
||||
};
|
||||
|
||||
|
@ -270,11 +272,13 @@ static int common_perm_rm(const char *op, const struct path *dir,
|
|||
struct inode *inode = d_backing_inode(dentry);
|
||||
struct user_namespace *mnt_userns = mnt_user_ns(dir->mnt);
|
||||
struct path_cond cond = { };
|
||||
vfsuid_t vfsuid;
|
||||
|
||||
if (!inode || !path_mediated_fs(dentry))
|
||||
return 0;
|
||||
|
||||
cond.uid = i_uid_into_mnt(mnt_userns, inode);
|
||||
vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
|
||||
cond.uid = vfsuid_into_kuid(vfsuid);
|
||||
cond.mode = inode->i_mode;
|
||||
|
||||
return common_perm_dir_dentry(op, dir, dentry, mask, &cond);
|
||||
|
@ -368,20 +372,23 @@ static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_d
|
|||
label = begin_current_label_crit_section();
|
||||
if (!unconfined(label)) {
|
||||
struct user_namespace *mnt_userns = mnt_user_ns(old_dir->mnt);
|
||||
vfsuid_t vfsuid;
|
||||
struct path old_path = { .mnt = old_dir->mnt,
|
||||
.dentry = old_dentry };
|
||||
struct path new_path = { .mnt = new_dir->mnt,
|
||||
.dentry = new_dentry };
|
||||
struct path_cond cond = {
|
||||
i_uid_into_mnt(mnt_userns, d_backing_inode(old_dentry)),
|
||||
d_backing_inode(old_dentry)->i_mode
|
||||
.mode = d_backing_inode(old_dentry)->i_mode
|
||||
};
|
||||
vfsuid = i_uid_into_vfsuid(mnt_userns, d_backing_inode(old_dentry));
|
||||
cond.uid = vfsuid_into_kuid(vfsuid);
|
||||
|
||||
if (flags & RENAME_EXCHANGE) {
|
||||
struct path_cond cond_exchange = {
|
||||
i_uid_into_mnt(mnt_userns, d_backing_inode(new_dentry)),
|
||||
d_backing_inode(new_dentry)->i_mode
|
||||
.mode = d_backing_inode(new_dentry)->i_mode,
|
||||
};
|
||||
vfsuid = i_uid_into_vfsuid(mnt_userns, d_backing_inode(old_dentry));
|
||||
cond_exchange.uid = vfsuid_into_kuid(vfsuid);
|
||||
|
||||
error = aa_path_perm(OP_RENAME_SRC, label, &new_path, 0,
|
||||
MAY_READ | AA_MAY_GETATTR | MAY_WRITE |
|
||||
|
@ -447,10 +454,12 @@ static int apparmor_file_open(struct file *file)
|
|||
if (!unconfined(label)) {
|
||||
struct user_namespace *mnt_userns = file_mnt_user_ns(file);
|
||||
struct inode *inode = file_inode(file);
|
||||
vfsuid_t vfsuid;
|
||||
struct path_cond cond = {
|
||||
i_uid_into_mnt(mnt_userns, inode),
|
||||
inode->i_mode
|
||||
.mode = inode->i_mode,
|
||||
};
|
||||
vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
|
||||
cond.uid = vfsuid_into_kuid(vfsuid);
|
||||
|
||||
error = aa_path_perm(OP_OPEN, label, &file->f_path, 0,
|
||||
aa_map_file_to_perms(file), &cond);
|
||||
|
|
|
@ -328,14 +328,16 @@ int cap_inode_killpriv(struct user_namespace *mnt_userns, struct dentry *dentry)
|
|||
return error;
|
||||
}
|
||||
|
||||
static bool rootid_owns_currentns(kuid_t kroot)
|
||||
static bool rootid_owns_currentns(vfsuid_t rootvfsuid)
|
||||
{
|
||||
struct user_namespace *ns;
|
||||
kuid_t kroot;
|
||||
|
||||
if (!uid_valid(kroot))
|
||||
if (!vfsuid_valid(rootvfsuid))
|
||||
return false;
|
||||
|
||||
for (ns = current_user_ns(); ; ns = ns->parent) {
|
||||
kroot = vfsuid_into_kuid(rootvfsuid);
|
||||
for (ns = current_user_ns();; ns = ns->parent) {
|
||||
if (from_kuid(ns, kroot) == 0)
|
||||
return true;
|
||||
if (ns == &init_user_ns)
|
||||
|
@ -381,6 +383,7 @@ int cap_inode_getsecurity(struct user_namespace *mnt_userns,
|
|||
{
|
||||
int size, ret;
|
||||
kuid_t kroot;
|
||||
vfsuid_t vfsroot;
|
||||
u32 nsmagic, magic;
|
||||
uid_t root, mappedroot;
|
||||
char *tmpbuf = NULL;
|
||||
|
@ -421,11 +424,11 @@ int cap_inode_getsecurity(struct user_namespace *mnt_userns,
|
|||
kroot = make_kuid(fs_ns, root);
|
||||
|
||||
/* If this is an idmapped mount shift the kuid. */
|
||||
kroot = mapped_kuid_fs(mnt_userns, fs_ns, kroot);
|
||||
vfsroot = make_vfsuid(mnt_userns, fs_ns, kroot);
|
||||
|
||||
/* If the root kuid maps to a valid uid in current ns, then return
|
||||
* this as a nscap. */
|
||||
mappedroot = from_kuid(current_user_ns(), kroot);
|
||||
mappedroot = from_kuid(current_user_ns(), vfsuid_into_kuid(vfsroot));
|
||||
if (mappedroot != (uid_t)-1 && mappedroot != (uid_t)0) {
|
||||
size = sizeof(struct vfs_ns_cap_data);
|
||||
if (alloc) {
|
||||
|
@ -452,7 +455,7 @@ int cap_inode_getsecurity(struct user_namespace *mnt_userns,
|
|||
goto out_free;
|
||||
}
|
||||
|
||||
if (!rootid_owns_currentns(kroot)) {
|
||||
if (!rootid_owns_currentns(vfsroot)) {
|
||||
size = -EOVERFLOW;
|
||||
goto out_free;
|
||||
}
|
||||
|
@ -490,29 +493,17 @@ out_free:
|
|||
* @value: vfs caps value which may be modified by this function
|
||||
* @size: size of @ivalue
|
||||
* @task_ns: user namespace of the caller
|
||||
* @mnt_userns: user namespace of the mount the inode was found from
|
||||
* @fs_userns: user namespace of the filesystem
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
static kuid_t rootid_from_xattr(const void *value, size_t size,
|
||||
struct user_namespace *task_ns,
|
||||
struct user_namespace *mnt_userns,
|
||||
struct user_namespace *fs_userns)
|
||||
static vfsuid_t rootid_from_xattr(const void *value, size_t size,
|
||||
struct user_namespace *task_ns)
|
||||
{
|
||||
const struct vfs_ns_cap_data *nscap = value;
|
||||
kuid_t rootkid;
|
||||
uid_t rootid = 0;
|
||||
|
||||
if (size == XATTR_CAPS_SZ_3)
|
||||
rootid = le32_to_cpu(nscap->rootid);
|
||||
|
||||
rootkid = make_kuid(task_ns, rootid);
|
||||
return mapped_kuid_user(mnt_userns, fs_userns, rootkid);
|
||||
return VFSUIDT_INIT(make_kuid(task_ns, rootid));
|
||||
}
|
||||
|
||||
static bool validheader(size_t size, const struct vfs_cap_data *cap)
|
||||
|
@ -550,6 +541,7 @@ int cap_convert_nscap(struct user_namespace *mnt_userns, struct dentry *dentry,
|
|||
struct user_namespace *task_ns = current_user_ns(),
|
||||
*fs_ns = inode->i_sb->s_user_ns;
|
||||
kuid_t rootid;
|
||||
vfsuid_t vfsrootid;
|
||||
size_t newsize;
|
||||
|
||||
if (!*ivalue)
|
||||
|
@ -563,7 +555,11 @@ int cap_convert_nscap(struct user_namespace *mnt_userns, struct dentry *dentry,
|
|||
/* user is privileged, just write the v2 */
|
||||
return size;
|
||||
|
||||
rootid = rootid_from_xattr(*ivalue, size, task_ns, mnt_userns, fs_ns);
|
||||
vfsrootid = rootid_from_xattr(*ivalue, size, task_ns);
|
||||
if (!vfsuid_valid(vfsrootid))
|
||||
return -EINVAL;
|
||||
|
||||
rootid = from_vfsuid(mnt_userns, fs_ns, vfsrootid);
|
||||
if (!uid_valid(rootid))
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -657,6 +653,7 @@ int get_vfs_caps_from_disk(struct user_namespace *mnt_userns,
|
|||
struct vfs_ns_cap_data data, *nscaps = &data;
|
||||
struct vfs_cap_data *caps = (struct vfs_cap_data *) &data;
|
||||
kuid_t rootkuid;
|
||||
vfsuid_t rootvfsuid;
|
||||
struct user_namespace *fs_ns;
|
||||
|
||||
memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data));
|
||||
|
@ -701,11 +698,15 @@ int get_vfs_caps_from_disk(struct user_namespace *mnt_userns,
|
|||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rootvfsuid = make_vfsuid(mnt_userns, fs_ns, rootkuid);
|
||||
if (!vfsuid_valid(rootvfsuid))
|
||||
return -ENODATA;
|
||||
|
||||
/* Limit the caps to the mounter of the filesystem
|
||||
* or the more limited uid specified in the xattr.
|
||||
*/
|
||||
rootkuid = mapped_kuid_fs(mnt_userns, fs_ns, rootkuid);
|
||||
if (!rootid_owns_currentns(rootkuid))
|
||||
if (!rootid_owns_currentns(rootvfsuid))
|
||||
return -ENODATA;
|
||||
|
||||
CAP_FOR_EACH_U32(i) {
|
||||
|
@ -718,7 +719,7 @@ int get_vfs_caps_from_disk(struct user_namespace *mnt_userns,
|
|||
cpu_caps->permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
|
||||
cpu_caps->inheritable.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
|
||||
|
||||
cpu_caps->rootid = rootkuid;
|
||||
cpu_caps->rootid = vfsuid_into_kuid(rootvfsuid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -85,8 +85,8 @@ struct ima_rule_entry {
|
|||
kgid_t fgroup;
|
||||
bool (*uid_op)(kuid_t cred_uid, kuid_t rule_uid); /* Handlers for operators */
|
||||
bool (*gid_op)(kgid_t cred_gid, kgid_t rule_gid);
|
||||
bool (*fowner_op)(kuid_t cred_uid, kuid_t rule_uid); /* uid_eq(), uid_gt(), uid_lt() */
|
||||
bool (*fgroup_op)(kgid_t cred_gid, kgid_t rule_gid); /* gid_eq(), gid_gt(), gid_lt() */
|
||||
bool (*fowner_op)(vfsuid_t vfsuid, kuid_t rule_uid); /* vfsuid_eq_kuid(), vfsuid_gt_kuid(), vfsuid_lt_kuid() */
|
||||
bool (*fgroup_op)(vfsgid_t vfsgid, kgid_t rule_gid); /* vfsgid_eq_kgid(), vfsgid_gt_kgid(), vfsgid_lt_kgid() */
|
||||
int pcr;
|
||||
unsigned int allowed_algos; /* bitfield of allowed hash algorithms */
|
||||
struct {
|
||||
|
@ -186,11 +186,11 @@ static struct ima_rule_entry default_appraise_rules[] __ro_after_init = {
|
|||
.flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
|
||||
#endif
|
||||
#ifndef CONFIG_IMA_APPRAISE_SIGNED_INIT
|
||||
{.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &uid_eq,
|
||||
{.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &vfsuid_eq_kuid,
|
||||
.flags = IMA_FOWNER},
|
||||
#else
|
||||
/* force signature */
|
||||
{.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &uid_eq,
|
||||
{.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &vfsuid_eq_kuid,
|
||||
.flags = IMA_FOWNER | IMA_DIGSIG_REQUIRED},
|
||||
#endif
|
||||
};
|
||||
|
@ -601,10 +601,12 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
|
|||
return false;
|
||||
}
|
||||
if ((rule->flags & IMA_FOWNER) &&
|
||||
!rule->fowner_op(i_uid_into_mnt(mnt_userns, inode), rule->fowner))
|
||||
!rule->fowner_op(i_uid_into_vfsuid(mnt_userns, inode),
|
||||
rule->fowner))
|
||||
return false;
|
||||
if ((rule->flags & IMA_FGROUP) &&
|
||||
!rule->fgroup_op(i_gid_into_mnt(mnt_userns, inode), rule->fgroup))
|
||||
!rule->fgroup_op(i_gid_into_vfsgid(mnt_userns, inode),
|
||||
rule->fgroup))
|
||||
return false;
|
||||
for (i = 0; i < MAX_LSM_RULES; i++) {
|
||||
int rc = 0;
|
||||
|
@ -1371,8 +1373,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
|||
entry->fgroup = INVALID_GID;
|
||||
entry->uid_op = &uid_eq;
|
||||
entry->gid_op = &gid_eq;
|
||||
entry->fowner_op = &uid_eq;
|
||||
entry->fgroup_op = &gid_eq;
|
||||
entry->fowner_op = &vfsuid_eq_kuid;
|
||||
entry->fgroup_op = &vfsgid_eq_kgid;
|
||||
entry->action = UNKNOWN;
|
||||
while ((p = strsep(&rule, " \t")) != NULL) {
|
||||
substring_t args[MAX_OPT_ARGS];
|
||||
|
@ -1650,11 +1652,11 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
|||
}
|
||||
break;
|
||||
case Opt_fowner_gt:
|
||||
entry->fowner_op = &uid_gt;
|
||||
entry->fowner_op = &vfsuid_gt_kuid;
|
||||
fallthrough;
|
||||
case Opt_fowner_lt:
|
||||
if (token == Opt_fowner_lt)
|
||||
entry->fowner_op = &uid_lt;
|
||||
entry->fowner_op = &vfsuid_lt_kuid;
|
||||
fallthrough;
|
||||
case Opt_fowner_eq:
|
||||
ima_log_string_op(ab, "fowner", args[0].from, token);
|
||||
|
@ -1676,11 +1678,11 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
|
|||
}
|
||||
break;
|
||||
case Opt_fgroup_gt:
|
||||
entry->fgroup_op = &gid_gt;
|
||||
entry->fgroup_op = &vfsgid_gt_kgid;
|
||||
fallthrough;
|
||||
case Opt_fgroup_lt:
|
||||
if (token == Opt_fgroup_lt)
|
||||
entry->fgroup_op = &gid_lt;
|
||||
entry->fgroup_op = &vfsgid_lt_kgid;
|
||||
fallthrough;
|
||||
case Opt_fgroup_eq:
|
||||
ima_log_string_op(ab, "fgroup", args[0].from, token);
|
||||
|
@ -2151,9 +2153,9 @@ int ima_policy_show(struct seq_file *m, void *v)
|
|||
|
||||
if (entry->flags & IMA_FOWNER) {
|
||||
snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->fowner));
|
||||
if (entry->fowner_op == &uid_gt)
|
||||
if (entry->fowner_op == &vfsuid_gt_kuid)
|
||||
seq_printf(m, pt(Opt_fowner_gt), tbuf);
|
||||
else if (entry->fowner_op == &uid_lt)
|
||||
else if (entry->fowner_op == &vfsuid_lt_kuid)
|
||||
seq_printf(m, pt(Opt_fowner_lt), tbuf);
|
||||
else
|
||||
seq_printf(m, pt(Opt_fowner_eq), tbuf);
|
||||
|
@ -2162,9 +2164,9 @@ int ima_policy_show(struct seq_file *m, void *v)
|
|||
|
||||
if (entry->flags & IMA_FGROUP) {
|
||||
snprintf(tbuf, sizeof(tbuf), "%d", __kgid_val(entry->fgroup));
|
||||
if (entry->fgroup_op == &gid_gt)
|
||||
if (entry->fgroup_op == &vfsgid_gt_kgid)
|
||||
seq_printf(m, pt(Opt_fgroup_gt), tbuf);
|
||||
else if (entry->fgroup_op == &gid_lt)
|
||||
else if (entry->fgroup_op == &vfsgid_lt_kgid)
|
||||
seq_printf(m, pt(Opt_fgroup_lt), tbuf);
|
||||
else
|
||||
seq_printf(m, pt(Opt_fgroup_eq), tbuf);
|
||||
|
|
Загрузка…
Ссылка в новой задаче