add andrew-user-ns patch
authorAndrew Burford <aburford@cs.stonybrook.edu>
Fri, 13 May 2022 16:40:44 +0000 (12:40 -0400)
committerAndrew Burford <aburford@cs.stonybrook.edu>
Fri, 13 May 2022 16:40:44 +0000 (12:40 -0400)
bug-fixes/andrew-user-ns.log [new file with mode: 0644]
bug-fixes/andrew-user-ns.patch [new file with mode: 0644]

diff --git a/bug-fixes/andrew-user-ns.log b/bug-fixes/andrew-user-ns.log
new file mode 100644 (file)
index 0000000..0997e79
--- /dev/null
@@ -0,0 +1,10 @@
+Wrapfs: respect the idmapped user_namespace of the lower filesystem
+
+Several i_ops functions were updated to have a struct user_namespace argument
+in order to support idmapped mounts. See here https://lwn.net/Articles/842423
+for an explanation of idmapped mounts. This patch allows wrapfs to stack on top
+of an idmapped mount and respect the lower idmap, but currently it does not
+support applying an idmap on wrapfs itself since this will require stacking
+multiple idmaps.
+
+Signed-off-by: Andrew Burford <aburford@cs.stonybrook.edu>
diff --git a/bug-fixes/andrew-user-ns.patch b/bug-fixes/andrew-user-ns.patch
new file mode 100644 (file)
index 0000000..e4fb4bf
--- /dev/null
@@ -0,0 +1,326 @@
+diff --git a/fs/wrapfs/inode.c b/fs/wrapfs/inode.c
+index ab0aff1abbd9..7adc0e7c6a2d 100644
+--- a/fs/wrapfs/inode.c
++++ b/fs/wrapfs/inode.c
+@@ -8,8 +8,8 @@
+ #include "wrapfs.h"
+-static int wrapfs_create(struct inode *dir, struct dentry *dentry,
+-                       umode_t mode, bool want_excl)
++static int wrapfs_create(struct user_namespace *mnt_userns, struct inode *dir,
++                       struct dentry *dentry, umode_t mode, bool want_excl)
+ {
+       int err;
+       struct dentry *lower_dentry;
+@@ -20,7 +20,8 @@ static int wrapfs_create(struct inode *dir, struct dentry *dentry,
+       lower_dentry = lower_path.dentry;
+       lower_parent_dentry = lock_parent(lower_dentry);
+-      err = vfs_create(d_inode(lower_parent_dentry), lower_dentry, mode,
++      err = vfs_create(mnt_user_ns(lower_path.mnt),
++                       d_inode(lower_parent_dentry), lower_dentry, mode,
+                        want_excl);
+       if (err)
+               goto out;
+@@ -53,8 +54,12 @@ static int wrapfs_link(struct dentry *old_dentry, struct inode *dir,
+       lower_new_dentry = lower_new_path.dentry;
+       lower_dir_dentry = lock_parent(lower_new_dentry);
+-      err = vfs_link(lower_old_dentry, d_inode(lower_dir_dentry),
+-                     lower_new_dentry, NULL);
++      /*
++       * It doesn't matter whether we take lower_new_path.mnt or
++       * lower_old_path.mnt because these will always be the same vfsmount.
++       */
++      err = vfs_link(lower_old_dentry, mnt_user_ns(lower_new_path.mnt),
++                     d_inode(lower_dir_dentry), lower_new_dentry, NULL);
+       if (err || d_really_is_negative(lower_new_dentry))
+               goto out;
+@@ -91,7 +96,8 @@ static int wrapfs_unlink(struct inode *dir, struct dentry *dentry)
+               goto out;
+       }
+-      err = vfs_unlink(lower_dir_inode, lower_dentry, NULL);
++      err = vfs_unlink(mnt_user_ns(lower_path.mnt), lower_dir_inode,
++                       lower_dentry, NULL);
+       /*
+        * Note: unlinking on top of NFS can cause silly-renamed files.
+@@ -117,8 +123,8 @@ static int wrapfs_unlink(struct inode *dir, struct dentry *dentry)
+       return err;
+ }
+-static int wrapfs_symlink(struct inode *dir, struct dentry *dentry,
+-                        const char *symname)
++static int wrapfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
++                        struct dentry *dentry, const char *symname)
+ {
+       int err;
+       struct dentry *lower_dentry;
+@@ -129,7 +135,8 @@ static int wrapfs_symlink(struct inode *dir, struct dentry *dentry,
+       lower_dentry = lower_path.dentry;
+       lower_parent_dentry = lock_parent(lower_dentry);
+-      err = vfs_symlink(d_inode(lower_parent_dentry), lower_dentry, symname);
++      err = vfs_symlink(mnt_user_ns(lower_path.mnt),
++                        d_inode(lower_parent_dentry), lower_dentry, symname);
+       if (err)
+               goto out;
+       err = wrapfs_interpose(dentry, dir->i_sb, &lower_path);
+@@ -144,7 +151,8 @@ static int wrapfs_symlink(struct inode *dir, struct dentry *dentry,
+       return err;
+ }
+-static int wrapfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
++static int wrapfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
++                      struct dentry *dentry, umode_t mode)
+ {
+       int err;
+       struct dentry *lower_dentry;
+@@ -155,7 +163,8 @@ static int wrapfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+       lower_dentry = lower_path.dentry;
+       lower_parent_dentry = lock_parent(lower_dentry);
+-      err = vfs_mkdir(d_inode(lower_parent_dentry), lower_dentry, mode);
++      err = vfs_mkdir(mnt_user_ns(lower_path.mnt),
++                      d_inode(lower_parent_dentry), lower_dentry, mode);
+       if (err)
+               goto out;
+@@ -190,7 +199,8 @@ static int wrapfs_rmdir(struct inode *dir, struct dentry *dentry)
+               goto out;
+       }
+-      err = vfs_rmdir(d_inode(lower_dir_dentry), lower_dentry);
++      err = vfs_rmdir(mnt_user_ns(lower_path.mnt), d_inode(lower_dir_dentry),
++                      lower_dentry);
+       if (err)
+               goto out;
+@@ -207,8 +217,8 @@ static int wrapfs_rmdir(struct inode *dir, struct dentry *dentry)
+       return err;
+ }
+-static int wrapfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
+-                      dev_t dev)
++static int wrapfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
++                      struct dentry *dentry, umode_t mode, dev_t dev)
+ {
+       int err;
+       struct dentry *lower_dentry;
+@@ -219,7 +229,8 @@ static int wrapfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
+       lower_dentry = lower_path.dentry;
+       lower_parent_dentry = lock_parent(lower_dentry);
+-      err = vfs_mknod(d_inode(lower_parent_dentry), lower_dentry, mode, dev);
++      err = vfs_mknod(mnt_user_ns(lower_path.mnt),
++                      d_inode(lower_parent_dentry), lower_dentry, mode, dev);
+       if (err)
+               goto out;
+@@ -239,7 +250,8 @@ static int wrapfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
+  * The locking rules in wrapfs_rename are complex.  We could use a simpler
+  * superblock-level name-space lock for renames and copy-ups.
+  */
+-static int wrapfs_rename(struct inode *old_dir, struct dentry *old_dentry,
++static int wrapfs_rename(struct user_namespace *mnt_userns,
++                       struct inode *old_dir, struct dentry *old_dentry,
+                        struct inode *new_dir, struct dentry *new_dentry,
+                        unsigned int flags)
+ {
+@@ -250,6 +262,7 @@ static int wrapfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+       struct dentry *lower_new_dir_dentry = NULL;
+       struct dentry *trap = NULL;
+       struct path lower_old_path, lower_new_path;
++      struct renamedata rd = {};
+       if (flags)
+               return -EINVAL;
+@@ -280,9 +293,13 @@ static int wrapfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+               goto out;
+       }
+-      err = vfs_rename(d_inode(lower_old_dir_dentry), lower_old_dentry,
+-                       d_inode(lower_new_dir_dentry), lower_new_dentry,
+-                       NULL, 0);
++      rd.old_mnt_userns = mnt_user_ns(lower_old_path.mnt);
++      rd.old_dir = d_inode(lower_old_dir_dentry);
++      rd.old_dentry = lower_old_dentry;
++      rd.new_mnt_userns = mnt_user_ns(lower_new_path.mnt);
++      rd.new_dir = d_inode(lower_new_dir_dentry);
++      rd.new_dentry = lower_new_dentry;
++      err = vfs_rename(&rd);
+       if (err)
+               goto out;
+@@ -348,17 +365,30 @@ static const char *wrapfs_get_link(struct dentry *dentry, struct inode *inode,
+       return buf;
+ }
+-static int wrapfs_permission(struct inode *inode, int mask)
++static int wrapfs_permission(struct user_namespace *mnt_userns,
++                           struct inode *inode, int mask)
+ {
+       struct inode *lower_inode;
++      struct dentry *dentry = NULL;
++      struct path lower_path;
+       int err;
++      /*
++       * Grab the first dentry for this inode. All dentries should belong
++       * to the same vfsmount so it doesn't matter which one we use.
++       */
++      hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias)
++              break;
++      BUG_ON(!dentry);
++      wrapfs_get_lower_path(dentry, &lower_path);
+       lower_inode = wrapfs_lower_inode(inode);
+-      err = inode_permission(lower_inode, mask);
++      err = inode_permission(mnt_user_ns(lower_path.mnt), lower_inode, mask);
++      wrapfs_put_lower_path(dentry, &lower_path);
+       return err;
+ }
+-static int wrapfs_setattr(struct dentry *dentry, struct iattr *ia)
++static int wrapfs_setattr(struct user_namespace *mnt_userns,
++                        struct dentry *dentry, struct iattr *ia)
+ {
+       int err;
+       struct dentry *lower_dentry;
+@@ -368,17 +398,17 @@ static int wrapfs_setattr(struct dentry *dentry, struct iattr *ia)
+       struct iattr lower_ia;
+       inode = d_inode(dentry);
++      wrapfs_get_lower_path(dentry, &lower_path);
+       /*
+        * Check if user has permission to change inode.  We don't check if
+        * this user can change the lower inode: that should happen when
+        * calling notify_change on the lower inode.
+        */
+-      err = setattr_prepare(dentry, ia);
++      err = setattr_prepare(mnt_user_ns(lower_path.mnt), dentry, ia);
+       if (err)
+-              goto out_err;
++              goto out;
+-      wrapfs_get_lower_path(dentry, &lower_path);
+       lower_dentry = lower_path.dentry;
+       lower_inode = wrapfs_lower_inode(inode);
+@@ -416,7 +446,8 @@ static int wrapfs_setattr(struct dentry *dentry, struct iattr *ia)
+        * tries to open(), unlink(), then ftruncate() a file.
+        */
+       inode_lock(d_inode(lower_dentry));
+-      err = notify_change(lower_dentry, &lower_ia, /* note: lower_ia */
++      err = notify_change(mnt_user_ns(lower_path.mnt), lower_dentry,
++                          &lower_ia, /* note: lower_ia */
+                           NULL);
+       inode_unlock(d_inode(lower_dentry));
+       if (err)
+@@ -432,11 +463,11 @@ static int wrapfs_setattr(struct dentry *dentry, struct iattr *ia)
+ out:
+       wrapfs_put_lower_path(dentry, &lower_path);
+-out_err:
+       return err;
+ }
+-static int wrapfs_getattr(const struct path *path, struct kstat *stat, 
++static int wrapfs_getattr(struct user_namespace *mnt_userns,
++                        const struct path *path, struct kstat *stat, 
+                           u32 request_mask, unsigned int flags)
+ {
+       int err;
+@@ -450,7 +481,7 @@ static int wrapfs_getattr(const struct path *path, struct kstat *stat,
+               goto out;
+       fsstack_copy_attr_all(d_inode(dentry),
+                             d_inode(lower_path.dentry));
+-      generic_fillattr(d_inode(dentry), stat);
++      generic_fillattr(mnt_user_ns(lower_path.mnt), d_inode(dentry), stat);
+       stat->blocks = lower_stat.blocks;
+ out:
+       wrapfs_put_lower_path(dentry, &lower_path);
+@@ -470,7 +501,8 @@ wrapfs_setxattr(struct dentry *dentry, struct inode *inode, const char *name,
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+-      err = vfs_setxattr(lower_dentry, name, value, size, flags);
++      err = vfs_setxattr(mnt_user_ns(lower_path.mnt), lower_dentry, name,
++                         value, size, flags);
+       if (err)
+               goto out;
+       fsstack_copy_attr_all(d_inode(dentry),
+@@ -496,7 +528,8 @@ wrapfs_getxattr(struct dentry *dentry, struct inode *inode,
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+-      err = vfs_getxattr(lower_dentry, name, buffer, size);
++      err = vfs_getxattr(mnt_user_ns(lower_path.mnt), lower_dentry, name,
++                         buffer, size);
+       if (err)
+               goto out;
+       fsstack_copy_attr_atime(d_inode(dentry),
+@@ -544,7 +577,7 @@ wrapfs_removexattr(struct dentry *dentry, struct inode *inode, const char *name)
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+-      err = vfs_removexattr(lower_dentry, name);
++      err = vfs_removexattr(mnt_user_ns(lower_path.mnt), lower_dentry, name);
+       if (err)
+               goto out;
+       fsstack_copy_attr_all(d_inode(dentry), lower_inode);
+@@ -592,6 +625,7 @@ static int wrapfs_xattr_get(const struct xattr_handler *handler,
+ }
+ static int wrapfs_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)
+diff --git a/fs/wrapfs/mmap.c b/fs/wrapfs/mmap.c
+index 9897fa585b97..7083a9b871ac 100644
+--- a/fs/wrapfs/mmap.c
++++ b/fs/wrapfs/mmap.c
+@@ -15,6 +15,7 @@ static vm_fault_t wrapfs_fault(struct vm_fault *vmf)
+       struct file *file, *lower_file;
+       const struct vm_operations_struct *lower_vm_ops;
+       struct vm_area_struct lower_vma;
++      struct vm_area_struct **vma_p = (struct vm_area_struct**)&vmf->vma;
+       memcpy(&lower_vma, vma, sizeof(struct vm_area_struct));
+       file = lower_vma.vm_file;
+@@ -33,9 +34,9 @@ static vm_fault_t wrapfs_fault(struct vm_fault *vmf)
+        * take an explicit file pointer.
+        */
+       lower_vma.vm_file = lower_file;
+-      vmf->vma = &lower_vma; /* override vma temporarily */
++      *vma_p = &lower_vma;
+       err = lower_vm_ops->fault(vmf);
+-      vmf->vma = vma; /* restore vma*/
++      *vma_p = vma;
+       return err;
+ }
+@@ -46,6 +47,7 @@ static vm_fault_t wrapfs_page_mkwrite(struct vm_fault *vmf)
+       struct file *file, *lower_file;
+       const struct vm_operations_struct *lower_vm_ops;
+       struct vm_area_struct lower_vma;
++      struct vm_area_struct **vma_p = (struct vm_area_struct**)&vmf->vma;
+       memcpy(&lower_vma, vma, sizeof(struct vm_area_struct));
+       file = lower_vma.vm_file;
+@@ -67,9 +69,9 @@ static vm_fault_t wrapfs_page_mkwrite(struct vm_fault *vmf)
+        * ->page_mkwrite to take an explicit file pointer.
+        */
+       lower_vma.vm_file = lower_file;
+-      vmf->vma = &lower_vma; /* override vma temporarily */
++      *vma_p = &lower_vma;
+       err = lower_vm_ops->page_mkwrite(vmf);
+-      vmf->vma = vma; /* restore vma */
++      *vma_p = vma;
+ out:
+       return err;
+ }