Commit d3cd67d6 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'fs.idmapped.fixes.v6.0-rc3' of...

Merge tag 'fs.idmapped.fixes.v6.0-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/idmapping

Pull idmapping fixes from Christian Brauner:

 - Since Seth joined as co-maintainer for idmapped mounts we decided to
   use a shared git tree. Konstantin suggested we use vfs/idmapping.git
   on kernel.org under the vfs/ namespace. So this updates the tree in
   the maintainers file.

 - Ensure that POSIX ACLs checking, getting, and setting works correctly
   for filesystems mountable with a filesystem idmapping that want to
   support idmapped mounts.

   Since no filesystems mountable with an fs_idmapping do yet support
   idmapped mounts there is no problem. But this could change in the
   future, so add a check to refuse to create idmapped mounts when the
   mounter is not privileged over the mount's idmapping.

 - Check that caller is privileged over the idmapping that will be
   attached to a mount.

   Currently no FS_USERNS_MOUNT filesystems support idmapped mounts,
   thus this is not a problem as only CAP_SYS_ADMIN in init_user_ns is
   allowed to set up idmapped mounts. But this could change in the
   future, so add a check to refuse to create idmapped mounts when the
   mounter is not privileged over the mount's idmapping.

 - Fix POSIX ACLs for ntfs3. While looking at our current POSIX ACL
   handling in the context of some overlayfs work I went through a range
   of other filesystems checking how they handle them currently and
   encountered a few bugs in ntfs3.

   I've sent this some time ago and the fixes haven't been picked up
   even though the pull request for other ntfs3 fixes got sent after.
   This should really be fixed as right now POSIX ACLs are broken in
   certain circumstances for ntfs3.

* tag 'fs.idmapped.fixes.v6.0-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/idmapping:
  ntfs: fix acl handling
  fs: require CAP_SYS_ADMIN in target namespace for idmapped mounts
  MAINTAINERS: update idmapping tree
  acl: handle idmapped mounts for idmapped filesystems
parents b20ee481 0c3bc789
...@@ -9781,7 +9781,7 @@ M: Christian Brauner <brauner@kernel.org> ...@@ -9781,7 +9781,7 @@ M: Christian Brauner <brauner@kernel.org>
M: Seth Forshee <sforshee@kernel.org> M: Seth Forshee <sforshee@kernel.org>
L: linux-fsdevel@vger.kernel.org L: linux-fsdevel@vger.kernel.org
S: Maintained S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux.git T: git://git.kernel.org/pub/scm/linux/kernel/git/vfs/idmapping.git
F: Documentation/filesystems/idmappings.rst F: Documentation/filesystems/idmappings.rst
F: tools/testing/selftests/mount_setattr/ F: tools/testing/selftests/mount_setattr/
F: include/linux/mnt_idmapping.h F: include/linux/mnt_idmapping.h
......
...@@ -4238,6 +4238,13 @@ static int build_mount_idmapped(const struct mount_attr *attr, size_t usize, ...@@ -4238,6 +4238,13 @@ static int build_mount_idmapped(const struct mount_attr *attr, size_t usize,
err = -EPERM; err = -EPERM;
goto out_fput; goto out_fput;
} }
/* We're not controlling the target namespace. */
if (!ns_capable(mnt_userns, CAP_SYS_ADMIN)) {
err = -EPERM;
goto out_fput;
}
kattr->mnt_userns = get_user_ns(mnt_userns); kattr->mnt_userns = get_user_ns(mnt_userns);
out_fput: out_fput:
......
...@@ -483,8 +483,7 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name, ...@@ -483,8 +483,7 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
} }
#ifdef CONFIG_NTFS3_FS_POSIX_ACL #ifdef CONFIG_NTFS3_FS_POSIX_ACL
static struct posix_acl *ntfs_get_acl_ex(struct user_namespace *mnt_userns, static struct posix_acl *ntfs_get_acl_ex(struct inode *inode, int type,
struct inode *inode, int type,
int locked) int locked)
{ {
struct ntfs_inode *ni = ntfs_i(inode); struct ntfs_inode *ni = ntfs_i(inode);
...@@ -519,7 +518,7 @@ static struct posix_acl *ntfs_get_acl_ex(struct user_namespace *mnt_userns, ...@@ -519,7 +518,7 @@ static struct posix_acl *ntfs_get_acl_ex(struct user_namespace *mnt_userns,
/* Translate extended attribute to acl. */ /* Translate extended attribute to acl. */
if (err >= 0) { if (err >= 0) {
acl = posix_acl_from_xattr(mnt_userns, buf, err); acl = posix_acl_from_xattr(&init_user_ns, buf, err);
} else if (err == -ENODATA) { } else if (err == -ENODATA) {
acl = NULL; acl = NULL;
} else { } else {
...@@ -542,8 +541,7 @@ struct posix_acl *ntfs_get_acl(struct inode *inode, int type, bool rcu) ...@@ -542,8 +541,7 @@ struct posix_acl *ntfs_get_acl(struct inode *inode, int type, bool rcu)
if (rcu) if (rcu)
return ERR_PTR(-ECHILD); return ERR_PTR(-ECHILD);
/* TODO: init_user_ns? */ return ntfs_get_acl_ex(inode, type, 0);
return ntfs_get_acl_ex(&init_user_ns, inode, type, 0);
} }
static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns, static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
...@@ -595,7 +593,7 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns, ...@@ -595,7 +593,7 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
value = kmalloc(size, GFP_NOFS); value = kmalloc(size, GFP_NOFS);
if (!value) if (!value)
return -ENOMEM; return -ENOMEM;
err = posix_acl_to_xattr(mnt_userns, acl, value, size); err = posix_acl_to_xattr(&init_user_ns, acl, value, size);
if (err < 0) if (err < 0)
goto out; goto out;
flags = 0; flags = 0;
...@@ -646,7 +644,7 @@ static int ntfs_xattr_get_acl(struct user_namespace *mnt_userns, ...@@ -646,7 +644,7 @@ static int ntfs_xattr_get_acl(struct user_namespace *mnt_userns,
if (!acl) if (!acl)
return -ENODATA; return -ENODATA;
err = posix_acl_to_xattr(mnt_userns, acl, buffer, size); err = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
posix_acl_release(acl); posix_acl_release(acl);
return err; return err;
...@@ -670,12 +668,12 @@ static int ntfs_xattr_set_acl(struct user_namespace *mnt_userns, ...@@ -670,12 +668,12 @@ static int ntfs_xattr_set_acl(struct user_namespace *mnt_userns,
if (!value) { if (!value) {
acl = NULL; acl = NULL;
} else { } else {
acl = posix_acl_from_xattr(mnt_userns, value, size); acl = posix_acl_from_xattr(&init_user_ns, value, size);
if (IS_ERR(acl)) if (IS_ERR(acl))
return PTR_ERR(acl); return PTR_ERR(acl);
if (acl) { if (acl) {
err = posix_acl_valid(mnt_userns, acl); err = posix_acl_valid(&init_user_ns, acl);
if (err) if (err)
goto release_and_out; goto release_and_out;
} }
......
...@@ -460,9 +460,12 @@ ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size) ...@@ -460,9 +460,12 @@ ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
* of the POSIX ACLs retrieved from the lower layer to this function to not * of the POSIX ACLs retrieved from the lower layer to this function to not
* alter the POSIX ACLs for the underlying filesystem. * alter the POSIX ACLs for the underlying filesystem.
*/ */
static void ovl_idmap_posix_acl(struct user_namespace *mnt_userns, static void ovl_idmap_posix_acl(struct inode *realinode,
struct user_namespace *mnt_userns,
struct posix_acl *acl) struct posix_acl *acl)
{ {
struct user_namespace *fs_userns = i_user_ns(realinode);
for (unsigned int i = 0; i < acl->a_count; i++) { for (unsigned int i = 0; i < acl->a_count; i++) {
vfsuid_t vfsuid; vfsuid_t vfsuid;
vfsgid_t vfsgid; vfsgid_t vfsgid;
...@@ -470,11 +473,11 @@ static void ovl_idmap_posix_acl(struct user_namespace *mnt_userns, ...@@ -470,11 +473,11 @@ static void ovl_idmap_posix_acl(struct user_namespace *mnt_userns,
struct posix_acl_entry *e = &acl->a_entries[i]; struct posix_acl_entry *e = &acl->a_entries[i];
switch (e->e_tag) { switch (e->e_tag) {
case ACL_USER: case ACL_USER:
vfsuid = make_vfsuid(mnt_userns, &init_user_ns, e->e_uid); vfsuid = make_vfsuid(mnt_userns, fs_userns, e->e_uid);
e->e_uid = vfsuid_into_kuid(vfsuid); e->e_uid = vfsuid_into_kuid(vfsuid);
break; break;
case ACL_GROUP: case ACL_GROUP:
vfsgid = make_vfsgid(mnt_userns, &init_user_ns, e->e_gid); vfsgid = make_vfsgid(mnt_userns, fs_userns, e->e_gid);
e->e_gid = vfsgid_into_kgid(vfsgid); e->e_gid = vfsgid_into_kgid(vfsgid);
break; break;
} }
...@@ -536,7 +539,7 @@ struct posix_acl *ovl_get_acl(struct inode *inode, int type, bool rcu) ...@@ -536,7 +539,7 @@ struct posix_acl *ovl_get_acl(struct inode *inode, int type, bool rcu)
if (!clone) if (!clone)
clone = ERR_PTR(-ENOMEM); clone = ERR_PTR(-ENOMEM);
else else
ovl_idmap_posix_acl(mnt_user_ns(realpath.mnt), clone); ovl_idmap_posix_acl(realinode, mnt_user_ns(realpath.mnt), clone);
/* /*
* Since we're not in RCU path walk we always need to release the * Since we're not in RCU path walk we always need to release the
* original ACLs. * original ACLs.
......
...@@ -361,6 +361,7 @@ posix_acl_permission(struct user_namespace *mnt_userns, struct inode *inode, ...@@ -361,6 +361,7 @@ posix_acl_permission(struct user_namespace *mnt_userns, struct inode *inode,
const struct posix_acl *acl, int want) const struct posix_acl *acl, int want)
{ {
const struct posix_acl_entry *pa, *pe, *mask_obj; const struct posix_acl_entry *pa, *pe, *mask_obj;
struct user_namespace *fs_userns = i_user_ns(inode);
int found = 0; int found = 0;
vfsuid_t vfsuid; vfsuid_t vfsuid;
vfsgid_t vfsgid; vfsgid_t vfsgid;
...@@ -376,7 +377,7 @@ posix_acl_permission(struct user_namespace *mnt_userns, struct inode *inode, ...@@ -376,7 +377,7 @@ posix_acl_permission(struct user_namespace *mnt_userns, struct inode *inode,
goto check_perm; goto check_perm;
break; break;
case ACL_USER: case ACL_USER:
vfsuid = make_vfsuid(mnt_userns, &init_user_ns, vfsuid = make_vfsuid(mnt_userns, fs_userns,
pa->e_uid); pa->e_uid);
if (vfsuid_eq_kuid(vfsuid, current_fsuid())) if (vfsuid_eq_kuid(vfsuid, current_fsuid()))
goto mask; goto mask;
...@@ -390,7 +391,7 @@ posix_acl_permission(struct user_namespace *mnt_userns, struct inode *inode, ...@@ -390,7 +391,7 @@ posix_acl_permission(struct user_namespace *mnt_userns, struct inode *inode,
} }
break; break;
case ACL_GROUP: case ACL_GROUP:
vfsgid = make_vfsgid(mnt_userns, &init_user_ns, vfsgid = make_vfsgid(mnt_userns, fs_userns,
pa->e_gid); pa->e_gid);
if (vfsgid_in_group_p(vfsgid)) { if (vfsgid_in_group_p(vfsgid)) {
found = 1; found = 1;
...@@ -736,6 +737,7 @@ void posix_acl_getxattr_idmapped_mnt(struct user_namespace *mnt_userns, ...@@ -736,6 +737,7 @@ void posix_acl_getxattr_idmapped_mnt(struct user_namespace *mnt_userns,
{ {
struct posix_acl_xattr_header *header = value; struct posix_acl_xattr_header *header = value;
struct posix_acl_xattr_entry *entry = (void *)(header + 1), *end; struct posix_acl_xattr_entry *entry = (void *)(header + 1), *end;
struct user_namespace *fs_userns = i_user_ns(inode);
int count; int count;
vfsuid_t vfsuid; vfsuid_t vfsuid;
vfsgid_t vfsgid; vfsgid_t vfsgid;
...@@ -753,13 +755,13 @@ void posix_acl_getxattr_idmapped_mnt(struct user_namespace *mnt_userns, ...@@ -753,13 +755,13 @@ void posix_acl_getxattr_idmapped_mnt(struct user_namespace *mnt_userns,
switch (le16_to_cpu(entry->e_tag)) { switch (le16_to_cpu(entry->e_tag)) {
case ACL_USER: case ACL_USER:
uid = make_kuid(&init_user_ns, le32_to_cpu(entry->e_id)); uid = make_kuid(&init_user_ns, le32_to_cpu(entry->e_id));
vfsuid = make_vfsuid(mnt_userns, &init_user_ns, uid); vfsuid = make_vfsuid(mnt_userns, fs_userns, uid);
entry->e_id = cpu_to_le32(from_kuid(&init_user_ns, entry->e_id = cpu_to_le32(from_kuid(&init_user_ns,
vfsuid_into_kuid(vfsuid))); vfsuid_into_kuid(vfsuid)));
break; break;
case ACL_GROUP: case ACL_GROUP:
gid = make_kgid(&init_user_ns, le32_to_cpu(entry->e_id)); gid = make_kgid(&init_user_ns, le32_to_cpu(entry->e_id));
vfsgid = make_vfsgid(mnt_userns, &init_user_ns, gid); vfsgid = make_vfsgid(mnt_userns, fs_userns, gid);
entry->e_id = cpu_to_le32(from_kgid(&init_user_ns, entry->e_id = cpu_to_le32(from_kgid(&init_user_ns,
vfsgid_into_kgid(vfsgid))); vfsgid_into_kgid(vfsgid)));
break; break;
...@@ -775,6 +777,7 @@ void posix_acl_setxattr_idmapped_mnt(struct user_namespace *mnt_userns, ...@@ -775,6 +777,7 @@ void posix_acl_setxattr_idmapped_mnt(struct user_namespace *mnt_userns,
{ {
struct posix_acl_xattr_header *header = value; struct posix_acl_xattr_header *header = value;
struct posix_acl_xattr_entry *entry = (void *)(header + 1), *end; struct posix_acl_xattr_entry *entry = (void *)(header + 1), *end;
struct user_namespace *fs_userns = i_user_ns(inode);
int count; int count;
vfsuid_t vfsuid; vfsuid_t vfsuid;
vfsgid_t vfsgid; vfsgid_t vfsgid;
...@@ -793,13 +796,13 @@ void posix_acl_setxattr_idmapped_mnt(struct user_namespace *mnt_userns, ...@@ -793,13 +796,13 @@ void posix_acl_setxattr_idmapped_mnt(struct user_namespace *mnt_userns,
case ACL_USER: case ACL_USER:
uid = make_kuid(&init_user_ns, le32_to_cpu(entry->e_id)); uid = make_kuid(&init_user_ns, le32_to_cpu(entry->e_id));
vfsuid = VFSUIDT_INIT(uid); vfsuid = VFSUIDT_INIT(uid);
uid = from_vfsuid(mnt_userns, &init_user_ns, vfsuid); uid = from_vfsuid(mnt_userns, fs_userns, vfsuid);
entry->e_id = cpu_to_le32(from_kuid(&init_user_ns, uid)); entry->e_id = cpu_to_le32(from_kuid(&init_user_ns, uid));
break; break;
case ACL_GROUP: case ACL_GROUP:
gid = make_kgid(&init_user_ns, le32_to_cpu(entry->e_id)); gid = make_kgid(&init_user_ns, le32_to_cpu(entry->e_id));
vfsgid = VFSGIDT_INIT(gid); vfsgid = VFSGIDT_INIT(gid);
gid = from_vfsgid(mnt_userns, &init_user_ns, vfsgid); gid = from_vfsgid(mnt_userns, fs_userns, vfsgid);
entry->e_id = cpu_to_le32(from_kgid(&init_user_ns, gid)); entry->e_id = cpu_to_le32(from_kgid(&init_user_ns, gid));
break; break;
default: default:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment