From: Greg Kroah-Hartman Date: Mon, 10 Aug 2020 12:11:19 +0000 (+0200) Subject: 4.14-stable patches X-Git-Tag: v4.19.139~17 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4e4d64ce447591af48c39396ff519e51da483c69;p=thirdparty%2Fkernel%2Fstable-queue.git 4.14-stable patches added patches: xattr-break-delegations-in-set-remove-xattr.patch --- diff --git a/queue-4.14/series b/queue-4.14/series index 50396f75f14..e0a47b4cce0 100644 --- a/queue-4.14/series +++ b/queue-4.14/series @@ -26,3 +26,4 @@ igb-reinit_locked-should-be-called-with-rtnl_lock.patch atm-fix-atm_dev-refcnt-leaks-in-atmtcp_remove_persis.patch tools-lib-traceevent-fix-memory-leak-in-process_dyna.patch drivers-hv-vmbus-ignore-channelmsg_tl_connect_result.patch +xattr-break-delegations-in-set-remove-xattr.patch diff --git a/queue-4.14/xattr-break-delegations-in-set-remove-xattr.patch b/queue-4.14/xattr-break-delegations-in-set-remove-xattr.patch new file mode 100644 index 00000000000..4b67d85b4c0 --- /dev/null +++ b/queue-4.14/xattr-break-delegations-in-set-remove-xattr.patch @@ -0,0 +1,181 @@ +From 08b5d5014a27e717826999ad20e394a8811aae92 Mon Sep 17 00:00:00 2001 +From: Frank van der Linden +Date: Tue, 23 Jun 2020 22:39:18 +0000 +Subject: xattr: break delegations in {set,remove}xattr + +From: Frank van der Linden + +commit 08b5d5014a27e717826999ad20e394a8811aae92 upstream. + +set/removexattr on an exported filesystem should break NFS delegations. +This is true in general, but also for the upcoming support for +RFC 8726 (NFSv4 extended attribute support). Make sure that they do. + +Additionally, they need to grow a _locked variant, since callers might +call this with i_rwsem held (like the NFS server code). + +Cc: stable@vger.kernel.org # v4.9+ +Cc: linux-fsdevel@vger.kernel.org +Cc: Al Viro +Signed-off-by: Frank van der Linden +Signed-off-by: Chuck Lever +Signed-off-by: Greg Kroah-Hartman + +--- + fs/xattr.c | 84 +++++++++++++++++++++++++++++++++++++++++++++----- + include/linux/xattr.h | 2 + + 2 files changed, 79 insertions(+), 7 deletions(-) + +--- a/fs/xattr.c ++++ b/fs/xattr.c +@@ -204,10 +204,22 @@ int __vfs_setxattr_noperm(struct dentry + return error; + } + +- ++/** ++ * __vfs_setxattr_locked: set an extended attribute while holding the inode ++ * lock ++ * ++ * @dentry - object to perform setxattr on ++ * @name - xattr name to set ++ * @value - value to set @name to ++ * @size - size of @value ++ * @flags - flags to pass into filesystem operations ++ * @delegated_inode - on return, will contain an inode pointer that ++ * a delegation was broken on, NULL if none. ++ */ + int +-vfs_setxattr(struct dentry *dentry, const char *name, const void *value, +- size_t size, int flags) ++__vfs_setxattr_locked(struct dentry *dentry, const char *name, ++ const void *value, size_t size, int flags, ++ struct inode **delegated_inode) + { + struct inode *inode = dentry->d_inode; + int error; +@@ -216,15 +228,40 @@ vfs_setxattr(struct dentry *dentry, cons + if (error) + return error; + +- inode_lock(inode); + error = security_inode_setxattr(dentry, name, value, size, flags); + if (error) + goto out; + ++ error = try_break_deleg(inode, delegated_inode); ++ if (error) ++ goto out; ++ + error = __vfs_setxattr_noperm(dentry, name, value, size, flags); + + out: ++ return error; ++} ++EXPORT_SYMBOL_GPL(__vfs_setxattr_locked); ++ ++int ++vfs_setxattr(struct dentry *dentry, const char *name, const void *value, ++ size_t size, int flags) ++{ ++ struct inode *inode = dentry->d_inode; ++ struct inode *delegated_inode = NULL; ++ int error; ++ ++retry_deleg: ++ inode_lock(inode); ++ error = __vfs_setxattr_locked(dentry, name, value, size, flags, ++ &delegated_inode); + inode_unlock(inode); ++ ++ if (delegated_inode) { ++ error = break_deleg_wait(&delegated_inode); ++ if (!error) ++ goto retry_deleg; ++ } + return error; + } + EXPORT_SYMBOL_GPL(vfs_setxattr); +@@ -380,8 +417,18 @@ __vfs_removexattr(struct dentry *dentry, + } + EXPORT_SYMBOL(__vfs_removexattr); + ++/** ++ * __vfs_removexattr_locked: set an extended attribute while holding the inode ++ * lock ++ * ++ * @dentry - object to perform setxattr on ++ * @name - name of xattr to remove ++ * @delegated_inode - on return, will contain an inode pointer that ++ * a delegation was broken on, NULL if none. ++ */ + int +-vfs_removexattr(struct dentry *dentry, const char *name) ++__vfs_removexattr_locked(struct dentry *dentry, const char *name, ++ struct inode **delegated_inode) + { + struct inode *inode = dentry->d_inode; + int error; +@@ -390,11 +437,14 @@ vfs_removexattr(struct dentry *dentry, c + if (error) + return error; + +- inode_lock(inode); + error = security_inode_removexattr(dentry, name); + if (error) + goto out; + ++ error = try_break_deleg(inode, delegated_inode); ++ if (error) ++ goto out; ++ + error = __vfs_removexattr(dentry, name); + + if (!error) { +@@ -403,12 +453,32 @@ vfs_removexattr(struct dentry *dentry, c + } + + out: ++ return error; ++} ++EXPORT_SYMBOL_GPL(__vfs_removexattr_locked); ++ ++int ++vfs_removexattr(struct dentry *dentry, const char *name) ++{ ++ struct inode *inode = dentry->d_inode; ++ struct inode *delegated_inode = NULL; ++ int error; ++ ++retry_deleg: ++ inode_lock(inode); ++ error = __vfs_removexattr_locked(dentry, name, &delegated_inode); + inode_unlock(inode); ++ ++ if (delegated_inode) { ++ error = break_deleg_wait(&delegated_inode); ++ if (!error) ++ goto retry_deleg; ++ } ++ + return error; + } + EXPORT_SYMBOL_GPL(vfs_removexattr); + +- + /* + * Extended attribute SET operations + */ +--- a/include/linux/xattr.h ++++ b/include/linux/xattr.h +@@ -52,8 +52,10 @@ ssize_t vfs_getxattr(struct dentry *, co + ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size); + int __vfs_setxattr(struct dentry *, struct inode *, const char *, const void *, size_t, int); + int __vfs_setxattr_noperm(struct dentry *, const char *, const void *, size_t, int); ++int __vfs_setxattr_locked(struct dentry *, const char *, const void *, size_t, int, struct inode **); + int vfs_setxattr(struct dentry *, const char *, const void *, size_t, int); + int __vfs_removexattr(struct dentry *, const char *); ++int __vfs_removexattr_locked(struct dentry *, const char *, struct inode **); + int vfs_removexattr(struct dentry *, const char *); + + ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size);