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:
Linus Torvalds 2022-12-12 19:20:05 -08:00
commit e1212e9b6f
16 changed files with 150 additions and 198 deletions

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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));
}
/**

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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);