update
authorErez Zadok <ezk@cs.sunysb.edu>
Fri, 13 May 2022 21:54:08 +0000 (17:54 -0400)
committerErez Zadok <ezk@cs.sunysb.edu>
Fri, 13 May 2022 21:54:08 +0000 (17:54 -0400)
bug-fixes/basic-user-ns.patch [new file with mode: 0644]

diff --git a/bug-fixes/basic-user-ns.patch b/bug-fixes/basic-user-ns.patch
new file mode 100644 (file)
index 0000000..6e43540
--- /dev/null
@@ -0,0 +1,326 @@
+diff --git a/fs/wrapfs/inode.c b/fs/wrapfs/inode.c
+index ab0aff1abbd9..0eb68b3e3e25 100644
+--- a/fs/wrapfs/inode.c
++++ b/fs/wrapfs/inode.c
+@@ -8,7 +8,8 @@
+ #include "wrapfs.h"
+-static int wrapfs_create(struct inode *dir, struct dentry *dentry,
++static int wrapfs_create(struct user_namespace *mnt_userns,
++                       struct inode *dir, struct dentry *dentry,
+                        umode_t mode, bool want_excl)
+ {
+       int err;
+@@ -20,7 +21,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(&init_user_ns, d_inode(lower_parent_dentry),
++                       lower_dentry, mode,
+                        want_excl);
+       if (err)
+               goto out;
+@@ -53,8 +55,8 @@ 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);
++      err = vfs_link(lower_old_dentry, &init_user_ns,
++                     d_inode(lower_dir_dentry), lower_new_dentry, NULL);
+       if (err || d_really_is_negative(lower_new_dentry))
+               goto out;
+@@ -91,7 +93,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(&init_user_ns, lower_dir_inode, lower_dentry,
++                       NULL);
+       /*
+        * Note: unlinking on top of NFS can cause silly-renamed files.
+@@ -117,7 +120,8 @@ static int wrapfs_unlink(struct inode *dir, struct dentry *dentry)
+       return err;
+ }
+-static int wrapfs_symlink(struct inode *dir, struct dentry *dentry,
++static int wrapfs_symlink(struct user_namespace *mnt_userns,
++                        struct inode *dir, struct dentry *dentry,
+                         const char *symname)
+ {
+       int err;
+@@ -129,7 +133,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(&init_user_ns, d_inode(lower_parent_dentry),
++                        lower_dentry, symname);
+       if (err)
+               goto out;
+       err = wrapfs_interpose(dentry, dir->i_sb, &lower_path);
+@@ -144,7 +149,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 +161,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(&init_user_ns, d_inode(lower_parent_dentry),
++                      lower_dentry, mode);
+       if (err)
+               goto out;
+@@ -190,7 +197,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(&init_user_ns, d_inode(lower_dir_dentry),
++                      lower_dentry);
+       if (err)
+               goto out;
+@@ -207,8 +215,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 +227,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(&init_user_ns, d_inode(lower_parent_dentry),
++                      lower_dentry, mode, dev);
+       if (err)
+               goto out;
+@@ -239,7 +248,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 +260,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 +291,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       = &init_user_ns;
++      rd.old_dir              = d_inode(lower_old_dir_dentry);
++      rd.old_dentry           = lower_old_dentry;
++      rd.new_mnt_userns       = &init_user_ns;
++      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 +363,19 @@ 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;
+       int err;
+       lower_inode = wrapfs_lower_inode(inode);
+-      err = inode_permission(lower_inode, mask);
++      err = inode_permission(&init_user_ns, lower_inode, mask);
+       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;
+@@ -374,7 +391,7 @@ static int wrapfs_setattr(struct dentry *dentry, struct iattr *ia)
+        * 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(&init_user_ns, dentry, ia);
+       if (err)
+               goto out_err;
+@@ -416,8 +433,7 @@ 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 */
+-                          NULL);
++      err = notify_change(&init_user_ns, lower_dentry, &lower_ia, NULL);
+       inode_unlock(d_inode(lower_dentry));
+       if (err)
+               goto out;
+@@ -436,7 +452,8 @@ static int wrapfs_setattr(struct dentry *dentry, struct iattr *ia)
+       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 +467,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(&init_user_ns, d_inode(dentry), stat);
+       stat->blocks = lower_stat.blocks;
+ out:
+       wrapfs_put_lower_path(dentry, &lower_path);
+@@ -470,7 +487,7 @@ 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(&init_user_ns, lower_dentry, name, value, size, flags);
+       if (err)
+               goto out;
+       fsstack_copy_attr_all(d_inode(dentry),
+@@ -496,7 +513,7 @@ wrapfs_getxattr(struct dentry *dentry, struct inode *inode,
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+-      err = vfs_getxattr(lower_dentry, name, buffer, size);
++      err = vfs_getxattr(&init_user_ns, lower_dentry, name, buffer, size);
+       if (err)
+               goto out;
+       fsstack_copy_attr_atime(d_inode(dentry),
+@@ -544,7 +561,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(&init_user_ns, lower_dentry, name);
+       if (err)
+               goto out;
+       fsstack_copy_attr_all(d_inode(dentry), lower_inode);
+@@ -592,6 +609,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/main.c b/fs/wrapfs/main.c
+index 3df02cc778b3..15c97a78d765 100644
+--- a/fs/wrapfs/main.c
++++ b/fs/wrapfs/main.c
+@@ -9,6 +9,8 @@
+ #include "wrapfs.h"
+ #include <linux/module.h>
++static struct file_system_type wrapfs_fs_type;
++
+ /*
+  * There is no need to lock the wrapfs_super_info's rwsem as there is no
+  * way anyone can have a reference to the superblock at this point in time.
+@@ -37,6 +39,21 @@ static int wrapfs_read_super(struct super_block *sb, void *raw_data, int silent)
+               goto out;
+       }
++        if (lower_path.dentry->d_sb->s_type == &wrapfs_fs_type) {
++              err = -EINVAL;
++              printk(KERN_ERR "Mount on filesystem of type "
++                     "wrapfs explicitly disallowed due to "
++                     "known incompatibilities\n");
++              goto out_pput;
++      }
++
++      if (mnt_user_ns(lower_path.mnt) != &init_user_ns) {
++              err = -EINVAL;
++              printk(KERN_ERR "Mounting on idmapped mounts currently "
++                     "disallowed\n");
++              goto out_pput;
++      }
++
+       /* allocate superblock private data */
+       sb->s_fs_info = kzalloc(sizeof(struct wrapfs_sb_info), GFP_KERNEL);
+       if (!WRAPFS_SB(sb)) {
+diff --git a/fs/wrapfs/mmap.c b/fs/wrapfs/mmap.c
+index 9897fa585b97..d3ae80c9ded1 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;    /* override vma temporarily */
+       err = lower_vm_ops->fault(vmf);
+-      vmf->vma = vma; /* restore vma*/
++      *vma_p = vma;           /* restore 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;    /* override vma temporarily */
+       err = lower_vm_ops->page_mkwrite(vmf);
+-      vmf->vma = vma; /* restore vma */
++      *vma_p = vma;           /* restore vma */
+ out:
+       return err;
+ }