]> git.ipfire.org Git - people/ms/linux.git/commitdiff
acl: handle idmapped mounts
authorChristian Brauner <christian.brauner@ubuntu.com>
Thu, 21 Jan 2021 13:19:27 +0000 (14:19 +0100)
committerChristian Brauner <christian.brauner@ubuntu.com>
Sun, 24 Jan 2021 13:27:17 +0000 (14:27 +0100)
The posix acl permission checking helpers determine whether a caller is
privileged over an inode according to the acls associated with the
inode. Add helpers that make it possible to handle acls on idmapped
mounts.

The vfs and the filesystems targeted by this first iteration make use of
posix_acl_fix_xattr_from_user() and posix_acl_fix_xattr_to_user() to
translate basic posix access and default permissions such as the
ACL_USER and ACL_GROUP type according to the initial user namespace (or
the superblock's user namespace) to and from the caller's current user
namespace. Adapt these two helpers to handle idmapped mounts whereby we
either map from or into the mount's user namespace depending on in which
direction we're translating.
Similarly, cap_convert_nscap() is used by the vfs to translate user
namespace and non-user namespace aware filesystem capabilities from the
superblock's user namespace to the caller's user namespace. Enable it to
handle idmapped mounts by accounting for the mount's user namespace.

In addition the fileystems targeted in the first iteration of this patch
series make use of the posix_acl_chmod() and, posix_acl_update_mode()
helpers. Both helpers perform permission checks on the target inode. Let
them handle idmapped mounts. These two helpers are called when posix
acls are set by the respective filesystems to handle this case we extend
the ->set() method to take an additional user namespace argument to pass
the mount's user namespace down.

Link: https://lore.kernel.org/r/20210121131959.646623-9-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>
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
72 files changed:
Documentation/filesystems/locking.rst
Documentation/filesystems/porting.rst
fs/9p/acl.c
fs/9p/xattr.c
fs/afs/xattr.c
fs/btrfs/acl.c
fs/btrfs/inode.c
fs/btrfs/xattr.c
fs/ceph/acl.c
fs/ceph/inode.c
fs/ceph/xattr.c
fs/cifs/xattr.c
fs/ecryptfs/inode.c
fs/ext2/acl.c
fs/ext2/inode.c
fs/ext2/xattr_security.c
fs/ext2/xattr_trusted.c
fs/ext2/xattr_user.c
fs/ext4/acl.c
fs/ext4/inode.c
fs/ext4/xattr_hurd.c
fs/ext4/xattr_security.c
fs/ext4/xattr_trusted.c
fs/ext4/xattr_user.c
fs/f2fs/acl.c
fs/f2fs/file.c
fs/f2fs/xattr.c
fs/fuse/xattr.c
fs/gfs2/acl.c
fs/gfs2/inode.c
fs/gfs2/xattr.c
fs/hfs/attr.c
fs/hfsplus/xattr.c
fs/hfsplus/xattr_security.c
fs/hfsplus/xattr_trusted.c
fs/hfsplus/xattr_user.c
fs/jffs2/acl.c
fs/jffs2/fs.c
fs/jffs2/security.c
fs/jffs2/xattr_trusted.c
fs/jffs2/xattr_user.c
fs/jfs/acl.c
fs/jfs/file.c
fs/jfs/xattr.c
fs/kernfs/inode.c
fs/nfs/nfs4proc.c
fs/nfsd/nfs2acl.c
fs/nfsd/nfs3acl.c
fs/nfsd/nfs4acl.c
fs/ocfs2/acl.c
fs/ocfs2/xattr.c
fs/orangefs/acl.c
fs/orangefs/inode.c
fs/orangefs/xattr.c
fs/overlayfs/super.c
fs/posix_acl.c
fs/reiserfs/xattr_acl.c
fs/reiserfs/xattr_security.c
fs/reiserfs/xattr_trusted.c
fs/reiserfs/xattr_user.c
fs/ubifs/xattr.c
fs/xattr.c
fs/xfs/xfs_acl.c
fs/xfs/xfs_iops.c
fs/xfs/xfs_xattr.c
include/linux/capability.h
include/linux/posix_acl.h
include/linux/posix_acl_xattr.h
include/linux/xattr.h
mm/shmem.c
net/socket.c
security/commoncap.c

index c0f2c7586531b0a562d7d5e62f44a456989a57c2..b7dcc86c92a45f5ed47cd17cbc5a8b82855927c2 100644 (file)
@@ -126,9 +126,10 @@ prototypes::
        int (*get)(const struct xattr_handler *handler, struct dentry *dentry,
                   struct inode *inode, const char *name, void *buffer,
                   size_t size);
-       int (*set)(const struct xattr_handler *handler, struct dentry *dentry,
-                  struct inode *inode, const char *name, const void *buffer,
-                  size_t size, int flags);
+       int (*set)(const struct xattr_handler *handler,
+                   struct user_namespace *mnt_userns,
+                   struct dentry *dentry, struct inode *inode, const char *name,
+                   const void *buffer, size_t size, int flags);
 
 locking rules:
        all may block
index 867036aa90b8394cea582fdbd183e747a630488a..de1dcec3b5b81d1f9514c1cdf473bc7c2e4b6957 100644 (file)
@@ -717,6 +717,8 @@ be removed.  Switch while you still can; the old one won't stay.
 **mandatory**
 
 ->setxattr() and xattr_handler.set() get dentry and inode passed separately.
+The xattr_handler.set() gets passed the user namespace of the mount the inode
+is seen from so filesystems can idmap the i_uid and i_gid accordingly.
 dentry might be yet to be attached to inode, so do _not_ use its ->d_inode
 in the instances.  Rationale: !@#!@# security_d_instantiate() needs to be
 called before we attach dentry to inode and !@#!@##!@$!$#!@#$!@$!@$ smack
index d77b28e8d57aba6616b58adc00aa7a1d978708a6..1c14f18a6ec9d24056d8f6a9f9356989f5a92546 100644 (file)
@@ -239,6 +239,7 @@ static int v9fs_xattr_get_acl(const struct xattr_handler *handler,
 }
 
 static int v9fs_xattr_set_acl(const struct xattr_handler *handler,
+                             struct user_namespace *mnt_userns,
                              struct dentry *dentry, struct inode *inode,
                              const char *name, const void *value,
                              size_t size, int flags)
@@ -279,7 +280,8 @@ static int v9fs_xattr_set_acl(const struct xattr_handler *handler,
                        struct iattr iattr = { 0 };
                        struct posix_acl *old_acl = acl;
 
-                       retval = posix_acl_update_mode(inode, &iattr.ia_mode, &acl);
+                       retval = posix_acl_update_mode(mnt_userns, inode,
+                                                      &iattr.ia_mode, &acl);
                        if (retval)
                                goto err_out;
                        if (!acl) {
index 87217dd0433e5a0ec9b8f958bf88a7d2217d6aa6..ee331845e2c7aacbc76f0e587dba0e54dc94a92f 100644 (file)
@@ -157,6 +157,7 @@ static int v9fs_xattr_handler_get(const struct xattr_handler *handler,
 }
 
 static int v9fs_xattr_handler_set(const struct xattr_handler *handler,
+                                 struct user_namespace *mnt_userns,
                                  struct dentry *dentry, struct inode *inode,
                                  const char *name, const void *value,
                                  size_t size, int flags)
index 95c573dcda1169d24438775fb143a94dbd1706a2..c629caae500286776bd04a800aabe11ed3c3f3ed 100644 (file)
@@ -120,6 +120,7 @@ static const struct afs_operation_ops afs_store_acl_operation = {
  * Set a file's AFS3 ACL.
  */
 static int afs_xattr_set_acl(const struct xattr_handler *handler,
+                            struct user_namespace *mnt_userns,
                              struct dentry *dentry,
                              struct inode *inode, const char *name,
                              const void *buffer, size_t size, int flags)
@@ -248,6 +249,7 @@ static const struct afs_operation_ops yfs_store_opaque_acl2_operation = {
  * Set a file's YFS ACL.
  */
 static int afs_xattr_set_yfs(const struct xattr_handler *handler,
+                            struct user_namespace *mnt_userns,
                              struct dentry *dentry,
                              struct inode *inode, const char *name,
                              const void *buffer, size_t size, int flags)
index a0af1b952c4df1c996c6a92da149d818d3b3eac6..d12a5a8730a84ae6647f0d4ed19f7cc1f37298de 100644 (file)
@@ -113,7 +113,8 @@ int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
        umode_t old_mode = inode->i_mode;
 
        if (type == ACL_TYPE_ACCESS && acl) {
-               ret = posix_acl_update_mode(inode, &inode->i_mode, &acl);
+               ret = posix_acl_update_mode(&init_user_ns, inode,
+                                           &inode->i_mode, &acl);
                if (ret)
                        return ret;
        }
index 792191a8705b06eb5cf9f2d5af13883536b3654b..6c18fb1a25afc2dd7ee8bcb5d78edfa90b54d128 100644 (file)
@@ -5070,7 +5070,8 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
                err = btrfs_dirty_inode(inode);
 
                if (!err && attr->ia_valid & ATTR_MODE)
-                       err = posix_acl_chmod(inode, inode->i_mode);
+                       err = posix_acl_chmod(&init_user_ns, inode,
+                                             inode->i_mode);
        }
 
        return err;
index af6246f36a9e5c318a335c09353093f99c8f7cc8..b025102e435fdb0c7b7005119917db9017e1936b 100644 (file)
@@ -362,6 +362,7 @@ static int btrfs_xattr_handler_get(const struct xattr_handler *handler,
 }
 
 static int btrfs_xattr_handler_set(const struct xattr_handler *handler,
+                                  struct user_namespace *mnt_userns,
                                   struct dentry *unused, struct inode *inode,
                                   const char *name, const void *buffer,
                                   size_t size, int flags)
@@ -371,6 +372,7 @@ static int btrfs_xattr_handler_set(const struct xattr_handler *handler,
 }
 
 static int btrfs_xattr_handler_set_prop(const struct xattr_handler *handler,
+                                       struct user_namespace *mnt_userns,
                                        struct dentry *unused, struct inode *inode,
                                        const char *name, const void *value,
                                        size_t size, int flags)
index e0465741c591d96668c35342558f58fcf3a796da..52a01ddbc4acb81cb9727caf46e165c73ec47b19 100644 (file)
@@ -100,7 +100,8 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type)
        case ACL_TYPE_ACCESS:
                name = XATTR_NAME_POSIX_ACL_ACCESS;
                if (acl) {
-                       ret = posix_acl_update_mode(inode, &new_mode, &acl);
+                       ret = posix_acl_update_mode(&init_user_ns, inode,
+                                                   &new_mode, &acl);
                        if (ret)
                                goto out;
                }
index 285d3baca27ef4c3d29ca7b4ac6ac8fa0fc0e049..145e26a4ddbb46d97d751158b95b755e92673fd6 100644 (file)
@@ -2262,7 +2262,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
        err = __ceph_setattr(inode, attr);
 
        if (err >= 0 && (attr->ia_valid & ATTR_MODE))
-               err = posix_acl_chmod(inode, attr->ia_mode);
+               err = posix_acl_chmod(&init_user_ns, inode, attr->ia_mode);
 
        return err;
 }
index 24997982de0164cce8ea2945df25c23c83795cf0..02f59bcb4f27ad743a6bb043333764b099eec5eb 100644 (file)
@@ -1238,6 +1238,7 @@ static int ceph_get_xattr_handler(const struct xattr_handler *handler,
 }
 
 static int ceph_set_xattr_handler(const struct xattr_handler *handler,
+                                 struct user_namespace *mnt_userns,
                                  struct dentry *unused, struct inode *inode,
                                  const char *name, const void *value,
                                  size_t size, int flags)
index 6b658a1172ef00e1ec5ff7c40435346561e3e290..41a611e76bb73f468c00e6cb53a384546954f574 100644 (file)
@@ -101,6 +101,7 @@ static int cifs_creation_time_set(unsigned int xid, struct cifs_tcon *pTcon,
 }
 
 static int cifs_xattr_set(const struct xattr_handler *handler,
+                         struct user_namespace *mnt_userns,
                          struct dentry *dentry, struct inode *inode,
                          const char *name, const void *value,
                          size_t size, int flags)
index d3ea0c57b075de49b69bf6d6ea3a5da7513a5d51..ac6472a82567cda3147cd731069036d2b2f50f39 100644 (file)
@@ -1133,6 +1133,7 @@ static int ecryptfs_xattr_get(const struct xattr_handler *handler,
 }
 
 static int ecryptfs_xattr_set(const struct xattr_handler *handler,
+                             struct user_namespace *mnt_userns,
                              struct dentry *dentry, struct inode *inode,
                              const char *name, const void *value, size_t size,
                              int flags)
index cf4c77f8dd08dc8e88c90a2e255e887c4ebc2f5d..9031f7df2d48cc373bf04fdab68c2109092febb1 100644 (file)
@@ -223,7 +223,8 @@ ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
        umode_t mode = inode->i_mode;
 
        if (type == ACL_TYPE_ACCESS && acl) {
-               error = posix_acl_update_mode(inode, &mode, &acl);
+               error = posix_acl_update_mode(&init_user_ns, inode, &mode,
+                                             &acl);
                if (error)
                        return error;
                update_mode = 1;
index 06c0cf28c1a0fe4461da05dba982634ce1e3fecd..9de813635d8dcb239f97c4a0cf5cb02e5952559a 100644 (file)
@@ -1691,7 +1691,7 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
        }
        setattr_copy(&init_user_ns, inode, iattr);
        if (iattr->ia_valid & ATTR_MODE)
-               error = posix_acl_chmod(inode, inode->i_mode);
+               error = posix_acl_chmod(&init_user_ns, inode, inode->i_mode);
        mark_inode_dirty(inode);
 
        return error;
index 9a682e440acba09b663162a990d785672e2495af..ebade1f52451da7a31b9369730f7587030ee7b85 100644 (file)
@@ -19,6 +19,7 @@ ext2_xattr_security_get(const struct xattr_handler *handler,
 
 static int
 ext2_xattr_security_set(const struct xattr_handler *handler,
+                       struct user_namespace *mnt_userns,
                        struct dentry *unused, struct inode *inode,
                        const char *name, const void *value,
                        size_t size, int flags)
index 49add11078507d22edc7fe51b8948535d3a5db04..18a87d5dd1ab98dbb79cc05aa1cabb6a352647ac 100644 (file)
@@ -26,6 +26,7 @@ ext2_xattr_trusted_get(const struct xattr_handler *handler,
 
 static int
 ext2_xattr_trusted_set(const struct xattr_handler *handler,
+                      struct user_namespace *mnt_userns,
                       struct dentry *unused, struct inode *inode,
                       const char *name, const void *value,
                       size_t size, int flags)
index c243a3b4d69d55a6da2d70646c60fb245aedacc5..58092449f8ffe2279d38d3f7d96012d68463e146 100644 (file)
@@ -30,6 +30,7 @@ ext2_xattr_user_get(const struct xattr_handler *handler,
 
 static int
 ext2_xattr_user_set(const struct xattr_handler *handler,
+                   struct user_namespace *mnt_userns,
                    struct dentry *unused, struct inode *inode,
                    const char *name, const void *value,
                    size_t size, int flags)
index 68aaed48315ff242335c9ba53c459f7fa7e8239e..7b0fb66bc04dd2c51f60d7506c7bcfb6ce3557e2 100644 (file)
@@ -245,7 +245,8 @@ retry:
        ext4_fc_start_update(inode);
 
        if ((type == ACL_TYPE_ACCESS) && acl) {
-               error = posix_acl_update_mode(inode, &mode, &acl);
+               error = posix_acl_update_mode(&init_user_ns, inode, &mode,
+                                             &acl);
                if (error)
                        goto out_stop;
                if (mode != inode->i_mode)
index 8edfa3e226e660339ac04ab39a0e1040df28eddc..24ea5851e90aed9d68d0f3c1562058551f65009a 100644 (file)
@@ -5524,7 +5524,7 @@ out_mmap_sem:
                ext4_orphan_del(NULL, inode);
 
        if (!error && (ia_valid & ATTR_MODE))
-               rc = posix_acl_chmod(inode, inode->i_mode);
+               rc = posix_acl_chmod(&init_user_ns, inode, inode->i_mode);
 
 err_out:
        if  (error)
index 8cfa74a56361e594830bbf7f3ed33c3bc0a2ba17..c78df5790377d02f7d2dab6c0e30cf26cf99b18d 100644 (file)
@@ -32,6 +32,7 @@ ext4_xattr_hurd_get(const struct xattr_handler *handler,
 
 static int
 ext4_xattr_hurd_set(const struct xattr_handler *handler,
+                   struct user_namespace *mnt_userns,
                    struct dentry *unused, struct inode *inode,
                    const char *name, const void *value,
                    size_t size, int flags)
index 197a9d8a15efe6822a2d55052005b4a23d767b31..8213f66f7b2dcb8472153a7b0799622bf913e72f 100644 (file)
@@ -23,6 +23,7 @@ ext4_xattr_security_get(const struct xattr_handler *handler,
 
 static int
 ext4_xattr_security_set(const struct xattr_handler *handler,
+                       struct user_namespace *mnt_userns,
                        struct dentry *unused, struct inode *inode,
                        const char *name, const void *value,
                        size_t size, int flags)
index e9389e5d75c30f7083a04364ccc4fea2035fc408..7c21ffb26d25de418e7409b62d4f075d02121466 100644 (file)
@@ -30,6 +30,7 @@ ext4_xattr_trusted_get(const struct xattr_handler *handler,
 
 static int
 ext4_xattr_trusted_set(const struct xattr_handler *handler,
+                      struct user_namespace *mnt_userns,
                       struct dentry *unused, struct inode *inode,
                       const char *name, const void *value,
                       size_t size, int flags)
index d4546184b34b4976ab0512eed46bbeb81a146d66..2fe7ff0a479cdeda96393919c9990208e4d34bb2 100644 (file)
@@ -31,6 +31,7 @@ ext4_xattr_user_get(const struct xattr_handler *handler,
 
 static int
 ext4_xattr_user_set(const struct xattr_handler *handler,
+                   struct user_namespace *mnt_userns,
                    struct dentry *unused, struct inode *inode,
                    const char *name, const void *value,
                    size_t size, int flags)
index 1e5e9b1136ee1c37c460578e364eac49e8c8f02d..6a95bf28f60210ea00974c8f0f6ed5f09f513f01 100644 (file)
@@ -213,7 +213,8 @@ static int __f2fs_set_acl(struct inode *inode, int type,
        case ACL_TYPE_ACCESS:
                name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;
                if (acl && !ipage) {
-                       error = posix_acl_update_mode(inode, &mode, &acl);
+                       error = posix_acl_update_mode(&init_user_ns, inode,
+                                                     &mode, &acl);
                        if (error)
                                return error;
                        set_acl_inode(inode, mode);
index 90d7b89176de8945124ba1f19dea21d91e03d0e2..6ccdfe0606d9e61a57fc04c39989217cbe561b37 100644 (file)
@@ -831,8 +831,8 @@ int f2fs_getattr(const struct path *path, struct kstat *stat,
 }
 
 #ifdef CONFIG_F2FS_FS_POSIX_ACL
-static void __setattr_copy(struct user_namespace *mnt_userns, struct inode *inode,
-                          const struct iattr *attr)
+static void __setattr_copy(struct user_namespace *mnt_userns,
+                          struct inode *inode, const struct iattr *attr)
 {
        unsigned int ia_valid = attr->ia_valid;
 
@@ -950,7 +950,8 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
        __setattr_copy(&init_user_ns, inode, attr);
 
        if (attr->ia_valid & ATTR_MODE) {
-               err = posix_acl_chmod(inode, f2fs_get_inode_mode(inode));
+               err = posix_acl_chmod(&init_user_ns, inode,
+                                     f2fs_get_inode_mode(inode));
                if (err || is_inode_flag_set(inode, FI_ACL_MODE)) {
                        inode->i_mode = F2FS_I(inode)->i_acl_mode;
                        clear_inode_flag(inode, FI_ACL_MODE);
index d772bf13a8145f339c5d92001b6e15987d00044b..10081bf74324b3d9f6c89a1122f546a81eac660e 100644 (file)
@@ -64,6 +64,7 @@ static int f2fs_xattr_generic_get(const struct xattr_handler *handler,
 }
 
 static int f2fs_xattr_generic_set(const struct xattr_handler *handler,
+               struct user_namespace *mnt_userns,
                struct dentry *unused, struct inode *inode,
                const char *name, const void *value,
                size_t size, int flags)
@@ -107,6 +108,7 @@ static int f2fs_xattr_advise_get(const struct xattr_handler *handler,
 }
 
 static int f2fs_xattr_advise_set(const struct xattr_handler *handler,
+               struct user_namespace *mnt_userns,
                struct dentry *unused, struct inode *inode,
                const char *name, const void *value,
                size_t size, int flags)
index cdea18de94f7e851780f846425752f915403c618..1a7d7ace54e10e34b732c8b097a4a0862f9b54de 100644 (file)
@@ -188,6 +188,7 @@ static int fuse_xattr_get(const struct xattr_handler *handler,
 }
 
 static int fuse_xattr_set(const struct xattr_handler *handler,
+                         struct user_namespace *mnt_userns,
                          struct dentry *dentry, struct inode *inode,
                          const char *name, const void *value, size_t size,
                          int flags)
@@ -214,6 +215,7 @@ static int no_xattr_get(const struct xattr_handler *handler,
 }
 
 static int no_xattr_set(const struct xattr_handler *handler,
+                       struct user_namespace *mnt_userns,
                        struct dentry *dentry, struct inode *nodee,
                        const char *name, const void *value,
                        size_t size, int flags)
index 2e939f5fe751cde6fda5515948af6c3a4983145e..ce88ef29eef079c3ebac4bc15b94b96704de4a39 100644 (file)
@@ -130,7 +130,7 @@ int gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 
        mode = inode->i_mode;
        if (type == ACL_TYPE_ACCESS && acl) {
-               ret = posix_acl_update_mode(inode, &mode, &acl);
+               ret = posix_acl_update_mode(&init_user_ns, inode, &mode, &acl);
                if (ret)
                        goto unlock;
        }
index 59c25181d108fa049a23993b4216a9d9112f989c..728405d15a05389982f9d147d3b425a080c8a33a 100644 (file)
@@ -1993,7 +1993,8 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr)
        else {
                error = gfs2_setattr_simple(inode, attr);
                if (!error && attr->ia_valid & ATTR_MODE)
-                       error = posix_acl_chmod(inode, inode->i_mode);
+                       error = posix_acl_chmod(&init_user_ns, inode,
+                                               inode->i_mode);
        }
 
 error:
index 9d7667bc429278bc742a4511db6785542334533c..13969a813410574478015d3a9e909bc89b1163b3 100644 (file)
@@ -1214,6 +1214,7 @@ int __gfs2_xattr_set(struct inode *inode, const char *name,
 }
 
 static int gfs2_xattr_set(const struct xattr_handler *handler,
+                         struct user_namespace *mnt_userns,
                          struct dentry *unused, struct inode *inode,
                          const char *name, const void *value,
                          size_t size, int flags)
index 74fa626431363755cb311246cd4ece74c7961b88..2bd54efaf4161d69c356207d19ff573f3a3a1d6e 100644 (file)
@@ -121,6 +121,7 @@ static int hfs_xattr_get(const struct xattr_handler *handler,
 }
 
 static int hfs_xattr_set(const struct xattr_handler *handler,
+                        struct user_namespace *mnt_userns,
                         struct dentry *unused, struct inode *inode,
                         const char *name, const void *value, size_t size,
                         int flags)
index bb0b27d88e50278fb86aeb10ad6ab655f037a200..4d169c5a2673282ce40f1066d3161b62189b51bb 100644 (file)
@@ -858,6 +858,7 @@ static int hfsplus_osx_getxattr(const struct xattr_handler *handler,
 }
 
 static int hfsplus_osx_setxattr(const struct xattr_handler *handler,
+                               struct user_namespace *mnt_userns,
                                struct dentry *unused, struct inode *inode,
                                const char *name, const void *buffer,
                                size_t size, int flags)
index cfbe6a3bfb1ee2e0c4123009e53d253c9bd2a5ec..c1c7a16cbf217cc1784bbab1089353e527fb15fd 100644 (file)
@@ -23,6 +23,7 @@ static int hfsplus_security_getxattr(const struct xattr_handler *handler,
 }
 
 static int hfsplus_security_setxattr(const struct xattr_handler *handler,
+                                    struct user_namespace *mnt_userns,
                                     struct dentry *unused, struct inode *inode,
                                     const char *name, const void *buffer,
                                     size_t size, int flags)
index fbad91e1dada2248c53d39dc104407f577a0a79c..e150372ec56490db17a1a7f3c7dfcfe200704add 100644 (file)
@@ -22,6 +22,7 @@ static int hfsplus_trusted_getxattr(const struct xattr_handler *handler,
 }
 
 static int hfsplus_trusted_setxattr(const struct xattr_handler *handler,
+                                   struct user_namespace *mnt_userns,
                                    struct dentry *unused, struct inode *inode,
                                    const char *name, const void *buffer,
                                    size_t size, int flags)
index 74d19faf255e1174c65c1412b12e1f9dc53477c4..a6b60b153916f2727859d38fbb02b7baa1b6c02d 100644 (file)
@@ -22,6 +22,7 @@ static int hfsplus_user_getxattr(const struct xattr_handler *handler,
 }
 
 static int hfsplus_user_setxattr(const struct xattr_handler *handler,
+                                struct user_namespace *mnt_userns,
                                 struct dentry *unused, struct inode *inode,
                                 const char *name, const void *buffer,
                                 size_t size, int flags)
index 093ffbd823958e900fbebfafe53cba2de13c7fa0..5f27ac593479608de4bde17ecb9fa61b121249c4 100644 (file)
@@ -236,7 +236,8 @@ int jffs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
                if (acl) {
                        umode_t mode;
 
-                       rc = posix_acl_update_mode(inode, &mode, &acl);
+                       rc = posix_acl_update_mode(&init_user_ns, inode, &mode,
+                                                  &acl);
                        if (rc)
                                return rc;
                        if (inode->i_mode != mode) {
index 67993808f4dafef6aa1d4f1ac2881c657b110ec4..ee9f51bab4c6c803dbd23ebbb9eccff797c8697c 100644 (file)
@@ -201,7 +201,7 @@ int jffs2_setattr(struct dentry *dentry, struct iattr *iattr)
 
        rc = jffs2_do_setattr(inode, iattr);
        if (!rc && (iattr->ia_valid & ATTR_MODE))
-               rc = posix_acl_chmod(inode, inode->i_mode);
+               rc = posix_acl_chmod(&init_user_ns, inode, inode->i_mode);
 
        return rc;
 }
index c2332e30f218ae7f942e51a279d357ebd46fbf69..aef5522551db39c83d2123c0baa56ca87160bfc6 100644 (file)
@@ -57,6 +57,7 @@ static int jffs2_security_getxattr(const struct xattr_handler *handler,
 }
 
 static int jffs2_security_setxattr(const struct xattr_handler *handler,
+                                  struct user_namespace *mnt_userns,
                                   struct dentry *unused, struct inode *inode,
                                   const char *name, const void *buffer,
                                   size_t size, int flags)
index 5d6030826c520487dc1967a517b8002ee70e7d69..cc3f24883e7d2b28bb61acca56502ea4284c0d94 100644 (file)
@@ -25,6 +25,7 @@ static int jffs2_trusted_getxattr(const struct xattr_handler *handler,
 }
 
 static int jffs2_trusted_setxattr(const struct xattr_handler *handler,
+                                 struct user_namespace *mnt_userns,
                                  struct dentry *unused, struct inode *inode,
                                  const char *name, const void *buffer,
                                  size_t size, int flags)
index 9d027b4abcf993e7005f1a6ae66558fd8a2e099a..fb945977c013cbf68e2bd4f95ae6b807f4a211e6 100644 (file)
@@ -25,6 +25,7 @@ static int jffs2_user_getxattr(const struct xattr_handler *handler,
 }
 
 static int jffs2_user_setxattr(const struct xattr_handler *handler,
+                              struct user_namespace *mnt_userns,
                               struct dentry *unused, struct inode *inode,
                               const char *name, const void *buffer,
                               size_t size, int flags)
index 92cc0ac2d1fc12d11596ebe5b2778a100be6fa3b..cf79a34bfada70dbf09e789faaab42e9666bf2ac 100644 (file)
@@ -101,7 +101,7 @@ int jfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
        tid = txBegin(inode->i_sb, 0);
        mutex_lock(&JFS_IP(inode)->commit_mutex);
        if (type == ACL_TYPE_ACCESS && acl) {
-               rc = posix_acl_update_mode(inode, &mode, &acl);
+               rc = posix_acl_update_mode(&init_user_ns, inode, &mode, &acl);
                if (rc)
                        goto end_tx;
                if (mode != inode->i_mode)
index ff49876e9c9b263014e3ae7cb477dbc45bc5fb20..61c3b0c1fbf61c373d7269d331313613156b4d81 100644 (file)
@@ -122,7 +122,7 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr)
        mark_inode_dirty(inode);
 
        if (iattr->ia_valid & ATTR_MODE)
-               rc = posix_acl_chmod(inode, inode->i_mode);
+               rc = posix_acl_chmod(&init_user_ns, inode, inode->i_mode);
        return rc;
 }
 
index db41e7803163ec00f866ec9ce5f61d1292851f87..f9273f6901c8d843fe1c79a1e758efd8dda0efb8 100644 (file)
@@ -932,6 +932,7 @@ static int jfs_xattr_get(const struct xattr_handler *handler,
 }
 
 static int jfs_xattr_set(const struct xattr_handler *handler,
+                        struct user_namespace *mnt_userns,
                         struct dentry *unused, struct inode *inode,
                         const char *name, const void *value,
                         size_t size, int flags)
@@ -950,6 +951,7 @@ static int jfs_xattr_get_os2(const struct xattr_handler *handler,
 }
 
 static int jfs_xattr_set_os2(const struct xattr_handler *handler,
+                            struct user_namespace *mnt_userns,
                             struct dentry *unused, struct inode *inode,
                             const char *name, const void *value,
                             size_t size, int flags)
index 86bd4c593b78a0c352746f0e50fdcc9a18aaa23d..7e44052b42e16fe39a6183cd594740f117dbfe7f 100644 (file)
@@ -319,6 +319,7 @@ static int kernfs_vfs_xattr_get(const struct xattr_handler *handler,
 }
 
 static int kernfs_vfs_xattr_set(const struct xattr_handler *handler,
+                               struct user_namespace *mnt_userns,
                                struct dentry *unused, struct inode *inode,
                                const char *suffix, const void *value,
                                size_t size, int flags)
@@ -385,6 +386,7 @@ static int kernfs_vfs_user_xattr_rm(struct kernfs_node *kn,
 }
 
 static int kernfs_vfs_user_xattr_set(const struct xattr_handler *handler,
+                                    struct user_namespace *mnt_userns,
                                     struct dentry *unused, struct inode *inode,
                                     const char *suffix, const void *value,
                                     size_t size, int flags)
index 2f4679a62712a9dd8406ac73f2961ea5d69c3480..a07530cf673daa5ab50f8823d80d95c9ecbc734a 100644 (file)
@@ -7491,6 +7491,7 @@ nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_state *lsp)
 #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl"
 
 static int nfs4_xattr_set_nfs4_acl(const struct xattr_handler *handler,
+                                  struct user_namespace *mnt_userns,
                                   struct dentry *unused, struct inode *inode,
                                   const char *key, const void *buf,
                                   size_t buflen, int flags)
@@ -7513,6 +7514,7 @@ static bool nfs4_xattr_list_nfs4_acl(struct dentry *dentry)
 #ifdef CONFIG_NFS_V4_SECURITY_LABEL
 
 static int nfs4_xattr_set_nfs4_label(const struct xattr_handler *handler,
+                                    struct user_namespace *mnt_userns,
                                     struct dentry *unused, struct inode *inode,
                                     const char *key, const void *buf,
                                     size_t buflen, int flags)
@@ -7563,6 +7565,7 @@ nfs4_listxattr_nfs4_label(struct inode *inode, char *list, size_t list_len)
 
 #ifdef CONFIG_NFS_V4_2
 static int nfs4_xattr_set_nfs4_user(const struct xattr_handler *handler,
+                                   struct user_namespace *mnt_userns,
                                    struct dentry *unused, struct inode *inode,
                                    const char *key, const void *buf,
                                    size_t buflen, int flags)
index b0f66604532a5d911df578f5d9978656784fe6d6..b83f222558e3b6f5fdf4df0e943406a6404d5d87 100644 (file)
@@ -113,10 +113,12 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
 
        fh_lock(fh);
 
-       error = set_posix_acl(inode, ACL_TYPE_ACCESS, argp->acl_access);
+       error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_ACCESS,
+                             argp->acl_access);
        if (error)
                goto out_drop_lock;
-       error = set_posix_acl(inode, ACL_TYPE_DEFAULT, argp->acl_default);
+       error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_DEFAULT,
+                             argp->acl_default);
        if (error)
                goto out_drop_lock;
 
index 7c30876a31a1b67e495d1447e3b12b4c1274fd7c..f18ec7e8094d0ab13f4e678a39279572d2bfe834 100644 (file)
@@ -103,10 +103,12 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst *rqstp)
 
        fh_lock(fh);
 
-       error = set_posix_acl(inode, ACL_TYPE_ACCESS, argp->acl_access);
+       error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_ACCESS,
+                             argp->acl_access);
        if (error)
                goto out_drop_lock;
-       error = set_posix_acl(inode, ACL_TYPE_DEFAULT, argp->acl_default);
+       error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_DEFAULT,
+                             argp->acl_default);
 
 out_drop_lock:
        fh_unlock(fh);
index 71292a0d6f09226e828b327ba139a296dc76a08b..eaa3a0cf38f1453c97c08f4ed3a59c3bbfaabfe1 100644 (file)
@@ -781,12 +781,13 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
 
        fh_lock(fhp);
 
-       host_error = set_posix_acl(inode, ACL_TYPE_ACCESS, pacl);
+       host_error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_ACCESS, pacl);
        if (host_error < 0)
                goto out_drop_lock;
 
        if (S_ISDIR(inode->i_mode)) {
-               host_error = set_posix_acl(inode, ACL_TYPE_DEFAULT, dpacl);
+               host_error = set_posix_acl(&init_user_ns, inode,
+                                          ACL_TYPE_DEFAULT, dpacl);
        }
 
 out_drop_lock:
index 7b07f5df3a299aa8ffa662a15785fe574e49a1eb..990756cee4bd4444dcb0557a7693fbc4529dfa0b 100644 (file)
@@ -274,7 +274,8 @@ int ocfs2_iop_set_acl(struct inode *inode, struct posix_acl *acl, int type)
        if (type == ACL_TYPE_ACCESS && acl) {
                umode_t mode;
 
-               status = posix_acl_update_mode(inode, &mode, &acl);
+               status = posix_acl_update_mode(&init_user_ns, inode, &mode,
+                                              &acl);
                if (status)
                        goto unlock;
 
index 9ccd19d8f7b18bf41b9acedffff178c663a836d5..36ae47a4aef685933d17d50e945b914fa86c4f47 100644 (file)
@@ -7249,6 +7249,7 @@ static int ocfs2_xattr_security_get(const struct xattr_handler *handler,
 }
 
 static int ocfs2_xattr_security_set(const struct xattr_handler *handler,
+                                   struct user_namespace *mnt_userns,
                                    struct dentry *unused, struct inode *inode,
                                    const char *name, const void *value,
                                    size_t size, int flags)
@@ -7321,6 +7322,7 @@ static int ocfs2_xattr_trusted_get(const struct xattr_handler *handler,
 }
 
 static int ocfs2_xattr_trusted_set(const struct xattr_handler *handler,
+                                  struct user_namespace *mnt_userns,
                                   struct dentry *unused, struct inode *inode,
                                   const char *name, const void *value,
                                   size_t size, int flags)
@@ -7351,6 +7353,7 @@ static int ocfs2_xattr_user_get(const struct xattr_handler *handler,
 }
 
 static int ocfs2_xattr_user_set(const struct xattr_handler *handler,
+                               struct user_namespace *mnt_userns,
                                struct dentry *unused, struct inode *inode,
                                const char *name, const void *value,
                                size_t size, int flags)
index a25e6c8909752fb95c0a9592823103d61c460dd0..628921952d16637909f2cee752bccdb835da929b 100644 (file)
@@ -132,7 +132,8 @@ int orangefs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
                 * and "mode" to the new desired value. It is up to
                 * us to propagate the new mode back to the server...
                 */
-               error = posix_acl_update_mode(inode, &iattr.ia_mode, &acl);
+               error = posix_acl_update_mode(&init_user_ns, inode,
+                                             &iattr.ia_mode, &acl);
                if (error) {
                        gossip_err("%s: posix_acl_update_mode err: %d\n",
                                   __func__,
index 8ac9491ceb9a9fa3a90f74d2f93ad427e9ae825a..563fe9ab8eb2186e13a8f864b84c3fba1ccd4319 100644 (file)
@@ -861,7 +861,7 @@ again:
 
        if (iattr->ia_valid & ATTR_MODE)
                /* change mod on a file that has ACLs */
-               ret = posix_acl_chmod(inode, inode->i_mode);
+               ret = posix_acl_chmod(&init_user_ns, inode, inode->i_mode);
 
        ret = 0;
 out:
index bdc285aea3600fca8fc61d7b3ecfc6d550c66ed1..9a5b757fbd2f623ae0b932d58e83d02eddd86992 100644 (file)
@@ -526,6 +526,7 @@ out_unlock:
 }
 
 static int orangefs_xattr_set_default(const struct xattr_handler *handler,
+                                     struct user_namespace *mnt_userns,
                                      struct dentry *unused,
                                      struct inode *inode,
                                      const char *name,
index 39b2e9aa0e5ba3e953bcc27bdab39aea306007ca..e24c995c5fd4bc5f363b6284f6910e59b33763de 100644 (file)
@@ -980,6 +980,7 @@ ovl_posix_acl_xattr_get(const struct xattr_handler *handler,
 
 static int __maybe_unused
 ovl_posix_acl_xattr_set(const struct xattr_handler *handler,
+                       struct user_namespace *mnt_userns,
                        struct dentry *dentry, struct inode *inode,
                        const char *name, const void *value,
                        size_t size, int flags)
@@ -1044,6 +1045,7 @@ static int ovl_own_xattr_get(const struct xattr_handler *handler,
 }
 
 static int ovl_own_xattr_set(const struct xattr_handler *handler,
+                            struct user_namespace *mnt_userns,
                             struct dentry *dentry, struct inode *inode,
                             const char *name, const void *value,
                             size_t size, int flags)
@@ -1059,6 +1061,7 @@ static int ovl_other_xattr_get(const struct xattr_handler *handler,
 }
 
 static int ovl_other_xattr_set(const struct xattr_handler *handler,
+                              struct user_namespace *mnt_userns,
                               struct dentry *dentry, struct inode *inode,
                               const char *name, const void *value,
                               size_t size, int flags)
index 9ce8214bfdacdbff085c7f9f20080d6df8f36156..d31b60f5d40d69907fd1c9eac7ec058bd28c682d 100644 (file)
@@ -558,8 +558,22 @@ __posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode)
 }
 EXPORT_SYMBOL(__posix_acl_chmod);
 
+/**
+ * posix_acl_chmod - chmod a posix acl
+ *
+ * @mnt_userns:        user namespace of the mount @inode was found from
+ * @inode:     inode to check permissions on
+ * @mode:      the new mode of @inode
+ *
+ * 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.
+ */
 int
-posix_acl_chmod(struct inode *inode, umode_t mode)
+ posix_acl_chmod(struct user_namespace *mnt_userns, struct inode *inode,
+                   umode_t mode)
 {
        struct posix_acl *acl;
        int ret = 0;
@@ -638,9 +652,10 @@ EXPORT_SYMBOL_GPL(posix_acl_create);
 
 /**
  * posix_acl_update_mode  -  update mode in set_acl
- * @inode: target inode
- * @mode_p: mode (pointer) for update
- * @acl: acl pointer
+ * @mnt_userns:        user namespace of the mount @inode was found from
+ * @inode:     target inode
+ * @mode_p:    mode (pointer) for update
+ * @acl:       acl pointer
  *
  * Update the file mode when setting an ACL: compute the new file permission
  * bits based on the ACL.  In addition, if the ACL is equivalent to the new
@@ -649,9 +664,16 @@ EXPORT_SYMBOL_GPL(posix_acl_create);
  * As with chmod, clear the setgid bit if the caller is not in the owning group
  * or capable of CAP_FSETID (see inode_change_ok).
  *
+ * 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.
+ *
  * Called from set_acl inode operations.
  */
-int posix_acl_update_mode(struct inode *inode, umode_t *mode_p,
+int posix_acl_update_mode(struct user_namespace *mnt_userns,
+                         struct inode *inode, umode_t *mode_p,
                          struct posix_acl **acl)
 {
        umode_t mode = inode->i_mode;
@@ -662,8 +684,8 @@ int posix_acl_update_mode(struct inode *inode, umode_t *mode_p,
                return error;
        if (error == 0)
                *acl = NULL;
-       if (!in_group_p(inode->i_gid) &&
-           !capable_wrt_inode_uidgid(&init_user_ns, inode, CAP_FSETID))
+       if (!in_group_p(i_gid_into_mnt(mnt_userns, inode)) &&
+           !capable_wrt_inode_uidgid(mnt_userns, inode, CAP_FSETID))
                mode &= ~S_ISGID;
        *mode_p = mode;
        return 0;
@@ -675,7 +697,8 @@ EXPORT_SYMBOL(posix_acl_update_mode);
  */
 static void posix_acl_fix_xattr_userns(
        struct user_namespace *to, struct user_namespace *from,
-       void *value, size_t size)
+       struct user_namespace *mnt_userns,
+       void *value, size_t size, bool from_user)
 {
        struct posix_acl_xattr_header *header = value;
        struct posix_acl_xattr_entry *entry = (void *)(header + 1), *end;
@@ -700,10 +723,18 @@ static void posix_acl_fix_xattr_userns(
                switch(le16_to_cpu(entry->e_tag)) {
                case ACL_USER:
                        uid = make_kuid(from, le32_to_cpu(entry->e_id));
+                       if (from_user)
+                               uid = kuid_from_mnt(mnt_userns, uid);
+                       else
+                               uid = kuid_into_mnt(mnt_userns, uid);
                        entry->e_id = cpu_to_le32(from_kuid(to, uid));
                        break;
                case ACL_GROUP:
                        gid = make_kgid(from, le32_to_cpu(entry->e_id));
+                       if (from_user)
+                               gid = kgid_from_mnt(mnt_userns, gid);
+                       else
+                               gid = kgid_into_mnt(mnt_userns, gid);
                        entry->e_id = cpu_to_le32(from_kgid(to, gid));
                        break;
                default:
@@ -712,20 +743,24 @@ static void posix_acl_fix_xattr_userns(
        }
 }
 
-void posix_acl_fix_xattr_from_user(void *value, size_t size)
+void posix_acl_fix_xattr_from_user(struct user_namespace *mnt_userns,
+                                  void *value, size_t size)
 {
        struct user_namespace *user_ns = current_user_ns();
-       if (user_ns == &init_user_ns)
+       if ((user_ns == &init_user_ns) && (mnt_userns == &init_user_ns))
                return;
-       posix_acl_fix_xattr_userns(&init_user_ns, user_ns, value, size);
+       posix_acl_fix_xattr_userns(&init_user_ns, user_ns, mnt_userns, value,
+                                  size, true);
 }
 
-void posix_acl_fix_xattr_to_user(void *value, size_t size)
+void posix_acl_fix_xattr_to_user(struct user_namespace *mnt_userns,
+                                void *value, size_t size)
 {
        struct user_namespace *user_ns = current_user_ns();
-       if (user_ns == &init_user_ns)
+       if ((user_ns == &init_user_ns) && (mnt_userns == &init_user_ns))
                return;
-       posix_acl_fix_xattr_userns(user_ns, &init_user_ns, value, size);
+       posix_acl_fix_xattr_userns(user_ns, &init_user_ns, mnt_userns, value,
+                                  size, false);
 }
 
 /*
@@ -865,7 +900,8 @@ posix_acl_xattr_get(const struct xattr_handler *handler,
 }
 
 int
-set_posix_acl(struct inode *inode, int type, struct posix_acl *acl)
+set_posix_acl(struct user_namespace *mnt_userns, struct inode *inode,
+             int type, struct posix_acl *acl)
 {
        if (!IS_POSIXACL(inode))
                return -EOPNOTSUPP;
@@ -874,7 +910,7 @@ set_posix_acl(struct inode *inode, int type, struct posix_acl *acl)
 
        if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
                return acl ? -EACCES : 0;
-       if (!inode_owner_or_capable(&init_user_ns, inode))
+       if (!inode_owner_or_capable(mnt_userns, inode))
                return -EPERM;
 
        if (acl) {
@@ -888,9 +924,10 @@ EXPORT_SYMBOL(set_posix_acl);
 
 static int
 posix_acl_xattr_set(const struct xattr_handler *handler,
-                   struct dentry *unused, struct inode *inode,
-                   const char *name, const void *value,
-                   size_t size, int flags)
+                          struct user_namespace *mnt_userns,
+                          struct dentry *unused, struct inode *inode,
+                          const char *name, const void *value, size_t size,
+                          int flags)
 {
        struct posix_acl *acl = NULL;
        int ret;
@@ -900,7 +937,7 @@ posix_acl_xattr_set(const struct xattr_handler *handler,
                if (IS_ERR(acl))
                        return PTR_ERR(acl);
        }
-       ret = set_posix_acl(inode, handler->flags, acl);
+       ret = set_posix_acl(mnt_userns, inode, handler->flags, acl);
        posix_acl_release(acl);
        return ret;
 }
@@ -934,7 +971,7 @@ int simple_set_acl(struct inode *inode, struct posix_acl *acl, int type)
        int error;
 
        if (type == ACL_TYPE_ACCESS) {
-               error = posix_acl_update_mode(inode,
+               error = posix_acl_update_mode(&init_user_ns, inode,
                                &inode->i_mode, &acl);
                if (error)
                        return error;
index ccd40df6eb458a51bdcfcdc993865f1c71b523f6..4bf976bc7baddb66009543d20e1f052ff5e0e19f 100644 (file)
@@ -40,7 +40,8 @@ reiserfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
        reiserfs_write_unlock(inode->i_sb);
        if (error == 0) {
                if (type == ACL_TYPE_ACCESS && acl) {
-                       error = posix_acl_update_mode(inode, &mode, &acl);
+                       error = posix_acl_update_mode(&init_user_ns, inode,
+                                                     &mode, &acl);
                        if (error)
                                goto unlock;
                        update_mode = 1;
@@ -399,5 +400,5 @@ int reiserfs_acl_chmod(struct inode *inode)
            !reiserfs_posixacl(inode->i_sb))
                return 0;
 
-       return posix_acl_chmod(inode, inode->i_mode);
+       return posix_acl_chmod(&init_user_ns, inode, inode->i_mode);
 }
index 20be9a0e5870e5c8e2ee9f6bebca804e961446bf..8965c8e5e172b9836beb505af6c7715e0c42dc63 100644 (file)
@@ -21,7 +21,8 @@ security_get(const struct xattr_handler *handler, struct dentry *unused,
 }
 
 static int
-security_set(const struct xattr_handler *handler, struct dentry *unused,
+security_set(const struct xattr_handler *handler,
+            struct user_namespace *mnt_userns, struct dentry *unused,
             struct inode *inode, const char *name, const void *buffer,
             size_t size, int flags)
 {
index 5ed48da3d02b5f2f03f2facb8c4be7cc788e15f3..d853cea2afcd7cb8390a720af7232eca976303bc 100644 (file)
@@ -20,7 +20,8 @@ trusted_get(const struct xattr_handler *handler, struct dentry *unused,
 }
 
 static int
-trusted_set(const struct xattr_handler *handler, struct dentry *unused,
+trusted_set(const struct xattr_handler *handler,
+           struct user_namespace *mnt_userns, struct dentry *unused,
            struct inode *inode, const char *name, const void *buffer,
            size_t size, int flags)
 {
index a573ca45bacc7ff3443e67ad83efe6a7ce77df05..65d9cd10a5ea8067150a55285b812e70088d812c 100644 (file)
@@ -18,7 +18,8 @@ user_get(const struct xattr_handler *handler, struct dentry *unused,
 }
 
 static int
-user_set(const struct xattr_handler *handler, struct dentry *unused,
+user_set(const struct xattr_handler *handler, struct user_namespace *mnt_userns,
+        struct dentry *unused,
         struct inode *inode, const char *name, const void *buffer,
         size_t size, int flags)
 {
index a0b9b349efe65a27471b2e2cc0fe78480b056d80..8f4135c22ab6e1cf45aef9f951db2a1ff77b96e4 100644 (file)
@@ -681,6 +681,7 @@ static int xattr_get(const struct xattr_handler *handler,
 }
 
 static int xattr_set(const struct xattr_handler *handler,
+                          struct user_namespace *mnt_userns,
                           struct dentry *dentry, struct inode *inode,
                           const char *name, const void *value,
                           size_t size, int flags)
index c669922e1bdead57ae52e33f95d1f2e2ff0c9ea7..d777025121e0c6eaa521c0b7be4f03728ae73c7e 100644 (file)
@@ -175,7 +175,8 @@ __vfs_setxattr(struct dentry *dentry, struct inode *inode, const char *name,
                return -EOPNOTSUPP;
        if (size == 0)
                value = "";  /* empty EA, do not remove */
-       return handler->set(handler, dentry, inode, name, value, size, flags);
+       return handler->set(handler, &init_user_ns, dentry, inode, name, value,
+                           size, flags);
 }
 EXPORT_SYMBOL(__vfs_setxattr);
 
@@ -281,7 +282,7 @@ vfs_setxattr(struct dentry *dentry, const char *name, const void *value,
        int error;
 
        if (size && strcmp(name, XATTR_NAME_CAPS) == 0) {
-               error = cap_convert_nscap(dentry, &value, size);
+               error = cap_convert_nscap(&init_user_ns, dentry, &value, size);
                if (error < 0)
                        return error;
                size = error;
@@ -450,7 +451,8 @@ __vfs_removexattr(struct dentry *dentry, const char *name)
                return PTR_ERR(handler);
        if (!handler->set)
                return -EOPNOTSUPP;
-       return handler->set(handler, dentry, inode, name, NULL, 0, XATTR_REPLACE);
+       return handler->set(handler, &init_user_ns, dentry, inode, name, NULL,
+                           0, XATTR_REPLACE);
 }
 EXPORT_SYMBOL(__vfs_removexattr);
 
@@ -548,7 +550,8 @@ setxattr(struct dentry *d, const char __user *name, const void __user *value,
                }
                if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
                    (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
-                       posix_acl_fix_xattr_from_user(kvalue, size);
+                       posix_acl_fix_xattr_from_user(&init_user_ns, kvalue,
+                                                     size);
        }
 
        error = vfs_setxattr(d, kname, kvalue, size, flags);
@@ -642,7 +645,8 @@ getxattr(struct dentry *d, const char __user *name, void __user *value,
        if (error > 0) {
                if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
                    (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
-                       posix_acl_fix_xattr_to_user(kvalue, error);
+                       posix_acl_fix_xattr_to_user(&init_user_ns, kvalue,
+                                                   error);
                if (size && copy_to_user(value, kvalue, error))
                        error = -EFAULT;
        } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) {
index 779cb73b3d006f441bd83fce84cca04e6ff905f1..368351298bd5eb290021d304f03e19a89b7428e0 100644 (file)
@@ -252,7 +252,8 @@ xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
                return error;
 
        if (type == ACL_TYPE_ACCESS) {
-               error = posix_acl_update_mode(inode, &mode, &acl);
+               error = posix_acl_update_mode(&init_user_ns, inode, &mode,
+                                             &acl);
                if (error)
                        return error;
                set_mode = true;
index 08a478d25122bd3d384ad59fac3de355d9a9ae41..26d22edef7411d5218891593ed37c75f62feacb4 100644 (file)
@@ -807,7 +807,7 @@ xfs_setattr_nonsize(
         *           Posix ACL code seems to care about this issue either.
         */
        if (mask & ATTR_MODE) {
-               error = posix_acl_chmod(inode, inode->i_mode);
+               error = posix_acl_chmod(&init_user_ns, inode, inode->i_mode);
                if (error)
                        return error;
        }
index bca48b308c0230a1c74f4ab67dced6f5e4888dbc..12be32f66dc1b18561e19cfba97fdb7eca2a1e5f 100644 (file)
@@ -38,9 +38,10 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
 }
 
 static int
-xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
-               struct inode *inode, const char *name, const void *value,
-               size_t size, int flags)
+xfs_xattr_set(const struct xattr_handler *handler,
+             struct user_namespace *mnt_userns, struct dentry *unused,
+             struct inode *inode, const char *name, const void *value,
+             size_t size, int flags)
 {
        struct xfs_da_args      args = {
                .dp             = XFS_I(inode),
index 62bfa3ed84d78246cf2cc08b3d57d9226b8fb7df..da21ef118b04169eae07448fe8cc73db5c18d824 100644 (file)
@@ -273,6 +273,7 @@ static inline bool checkpoint_restore_ns_capable(struct user_namespace *ns)
 /* 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);
 
-extern int cap_convert_nscap(struct dentry *dentry, const void **ivalue, size_t size);
+int cap_convert_nscap(struct user_namespace *mnt_userns, struct dentry *dentry,
+                     const void **ivalue, size_t size);
 
 #endif /* !_LINUX_CAPABILITY_H */
index 85fb4c0c650a811be4c8f6ee4819438794c928b3..6dcd8b8f6ab5bb5bc6e3b182abff60a27a793213 100644 (file)
@@ -69,13 +69,15 @@ extern int __posix_acl_create(struct posix_acl **, gfp_t, umode_t *);
 extern int __posix_acl_chmod(struct posix_acl **, gfp_t, umode_t);
 
 extern struct posix_acl *get_posix_acl(struct inode *, int);
-extern int set_posix_acl(struct inode *, int, struct posix_acl *);
+extern int set_posix_acl(struct user_namespace *, struct inode *, int,
+                        struct posix_acl *);
 
 #ifdef CONFIG_FS_POSIX_ACL
-extern int posix_acl_chmod(struct inode *, umode_t);
+int posix_acl_chmod(struct user_namespace *, struct inode *, umode_t);
 extern int posix_acl_create(struct inode *, umode_t *, struct posix_acl **,
                struct posix_acl **);
-extern int posix_acl_update_mode(struct inode *, umode_t *, struct posix_acl **);
+int posix_acl_update_mode(struct user_namespace *, struct inode *, umode_t *,
+                         struct posix_acl **);
 
 extern int simple_set_acl(struct inode *, struct posix_acl *, int);
 extern int simple_acl_create(struct inode *, struct inode *);
@@ -95,7 +97,8 @@ static inline void cache_no_acl(struct inode *inode)
        inode->i_default_acl = NULL;
 }
 #else
-static inline int posix_acl_chmod(struct inode *inode, umode_t mode)
+static inline int posix_acl_chmod(struct user_namespace *mnt_userns,
+                                 struct inode *inode, umode_t mode)
 {
        return 0;
 }
index 2387709991b54a39a2726268b08185c9b50f9a6d..060e8d2031814404175c8635c9a6184ed2d7e885 100644 (file)
@@ -33,13 +33,17 @@ posix_acl_xattr_count(size_t size)
 }
 
 #ifdef CONFIG_FS_POSIX_ACL
-void posix_acl_fix_xattr_from_user(void *value, size_t size);
-void posix_acl_fix_xattr_to_user(void *value, size_t size);
+void posix_acl_fix_xattr_from_user(struct user_namespace *mnt_userns,
+                                  void *value, size_t size);
+void posix_acl_fix_xattr_to_user(struct user_namespace *mnt_userns,
+                                void *value, size_t size);
 #else
-static inline void posix_acl_fix_xattr_from_user(void *value, size_t size)
+static inline void posix_acl_fix_xattr_from_user(struct user_namespace *mnt_userns,
+                                                void *value, size_t size)
 {
 }
-static inline void posix_acl_fix_xattr_to_user(void *value, size_t size)
+static inline void posix_acl_fix_xattr_to_user(struct user_namespace *mnt_userns,
+                                              void *value, size_t size)
 {
 }
 #endif
index 10b4dc2709f07b367a5fadc34583815360682058..260c9bcb0edb609acff15fa419d9f066ac6ef569 100644 (file)
@@ -34,7 +34,8 @@ struct xattr_handler {
        int (*get)(const struct xattr_handler *, struct dentry *dentry,
                   struct inode *inode, const char *name, void *buffer,
                   size_t size);
-       int (*set)(const struct xattr_handler *, struct dentry *dentry,
+       int (*set)(const struct xattr_handler *,
+                  struct user_namespace *mnt_userns, struct dentry *dentry,
                   struct inode *inode, const char *name, const void *buffer,
                   size_t size, int flags);
 };
index 1cb451e131ecea25fb6504c18732ab155a21927b..23b8e9c15a4229ca4c0add778945ec708ffda936 100644 (file)
@@ -1143,7 +1143,7 @@ static int shmem_setattr(struct dentry *dentry, struct iattr *attr)
 
        setattr_copy(&init_user_ns, inode, attr);
        if (attr->ia_valid & ATTR_MODE)
-               error = posix_acl_chmod(inode, inode->i_mode);
+               error = posix_acl_chmod(&init_user_ns, inode, inode->i_mode);
        return error;
 }
 
@@ -3273,6 +3273,7 @@ static int shmem_xattr_handler_get(const struct xattr_handler *handler,
 }
 
 static int shmem_xattr_handler_set(const struct xattr_handler *handler,
+                                  struct user_namespace *mnt_userns,
                                   struct dentry *unused, struct inode *inode,
                                   const char *name, const void *value,
                                   size_t size, int flags)
index 33e8b6c4e1d38201893fc087052a395415baab49..c76703c6f480328167f0d49162e1120c842b8236 100644 (file)
@@ -334,6 +334,7 @@ static const struct xattr_handler sockfs_xattr_handler = {
 };
 
 static int sockfs_security_xattr_set(const struct xattr_handler *handler,
+                                    struct user_namespace *mnt_userns,
                                     struct dentry *dentry, struct inode *inode,
                                     const char *suffix, const void *value,
                                     size_t size, int flags)
index 88ee345f7bfa4e49176c4837e3a03ac9e7002168..c3fd9b86ea9a346ad87c250585edc292c17e681e 100644 (file)
@@ -450,16 +450,33 @@ int cap_inode_getsecurity(struct inode *inode, const char *name, void **buffer,
        return size;
 }
 
+/**
+ * rootid_from_xattr - translate root uid of vfs caps
+ *
+ * @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
+ *
+ * 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 *task_ns,
+                               struct user_namespace *mnt_userns)
 {
        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);
 
-       return make_kuid(task_ns, rootid);
+       rootkid = make_kuid(task_ns, rootid);
+       return kuid_from_mnt(mnt_userns, rootkid);
 }
 
 static bool validheader(size_t size, const struct vfs_cap_data *cap)
@@ -467,13 +484,27 @@ static bool validheader(size_t size, const struct vfs_cap_data *cap)
        return is_v2header(size, cap) || is_v3header(size, cap);
 }
 
-/*
+/**
+ * cap_convert_nscap - check vfs caps
+ *
+ * @mnt_userns:        user namespace of the mount the inode was found from
+ * @dentry:    used to retrieve inode to check permissions on
+ * @ivalue:    vfs caps value which may be modified by this function
+ * @size:      size of @ivalue
+ *
  * User requested a write of security.capability.  If needed, update the
  * xattr to change from v2 to v3, or to fixup the v3 rootid.
  *
+ * 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.
+ *
  * If all is ok, we return the new size, on error return < 0.
  */
-int cap_convert_nscap(struct dentry *dentry, const void **ivalue, size_t size)
+int cap_convert_nscap(struct user_namespace *mnt_userns, struct dentry *dentry,
+                     const void **ivalue, size_t size)
 {
        struct vfs_ns_cap_data *nscap;
        uid_t nsrootid;
@@ -489,14 +520,14 @@ int cap_convert_nscap(struct dentry *dentry, const void **ivalue, size_t size)
                return -EINVAL;
        if (!validheader(size, cap))
                return -EINVAL;
-       if (!capable_wrt_inode_uidgid(&init_user_ns, inode, CAP_SETFCAP))
+       if (!capable_wrt_inode_uidgid(mnt_userns, inode, CAP_SETFCAP))
                return -EPERM;
-       if (size == XATTR_CAPS_SZ_2)
+       if (size == XATTR_CAPS_SZ_2 && (mnt_userns == &init_user_ns))
                if (ns_capable(inode->i_sb->s_user_ns, CAP_SETFCAP))
                        /* user is privileged, just write the v2 */
                        return size;
 
-       rootid = rootid_from_xattr(*ivalue, size, task_ns);
+       rootid = rootid_from_xattr(*ivalue, size, task_ns, mnt_userns);
        if (!uid_valid(rootid))
                return -EINVAL;