From: Andrew Burford Date: Fri, 13 May 2022 16:40:44 +0000 (-0400) Subject: add andrew-user-ns patch X-Git-Url: https://git.fsl.cs.sunysb.edu/?a=commitdiff_plain;h=61b001bd3d71ac0bfa61004dafb94f5f2b4a2a22;p=wrapfs-mgmt.git add andrew-user-ns patch --- diff --git a/bug-fixes/andrew-user-ns.log b/bug-fixes/andrew-user-ns.log new file mode 100644 index 0000000..0997e79 --- /dev/null +++ b/bug-fixes/andrew-user-ns.log @@ -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 diff --git a/bug-fixes/andrew-user-ns.patch b/bug-fixes/andrew-user-ns.patch new file mode 100644 index 0000000..e4fb4bf --- /dev/null +++ b/bug-fixes/andrew-user-ns.patch @@ -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; + }