From 461df36a34042495d6520080bbc3923799ca56e1 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 31 Jul 2019 11:49:40 +0200 Subject: [PATCH] 4.14-stable patches added patches: arm64-compat-provide-definition-for-compat_sigminstksz.patch arm64-dts-marvell-fix-a37xx-uart0-register-size.patch binder-fix-possible-uaf-when-freeing-buffer.patch i2c-qup-fixed-releasing-dma-without-flush-operation-completion.patch nfs-fix-dentry-revalidation-on-nfsv4-lookup.patch nfs-refactor-nfs_lookup_revalidate.patch nfsv4-fix-lookup-revalidate-of-regular-files.patch --- ...de-definition-for-compat_sigminstksz.patch | 39 +++ ...arvell-fix-a37xx-uart0-register-size.patch | 46 +++ ...fix-possible-uaf-when-freeing-buffer.patch | 62 ++++ ...a-without-flush-operation-completion.patch | 50 +++ ...-dentry-revalidation-on-nfsv4-lookup.patch | 68 ++++ .../nfs-refactor-nfs_lookup_revalidate.patch | 295 ++++++++++++++++++ ...x-lookup-revalidate-of-regular-files.patch | 151 +++++++++ queue-4.14/series | 7 + 8 files changed, 718 insertions(+) create mode 100644 queue-4.14/arm64-compat-provide-definition-for-compat_sigminstksz.patch create mode 100644 queue-4.14/arm64-dts-marvell-fix-a37xx-uart0-register-size.patch create mode 100644 queue-4.14/binder-fix-possible-uaf-when-freeing-buffer.patch create mode 100644 queue-4.14/i2c-qup-fixed-releasing-dma-without-flush-operation-completion.patch create mode 100644 queue-4.14/nfs-fix-dentry-revalidation-on-nfsv4-lookup.patch create mode 100644 queue-4.14/nfs-refactor-nfs_lookup_revalidate.patch create mode 100644 queue-4.14/nfsv4-fix-lookup-revalidate-of-regular-files.patch diff --git a/queue-4.14/arm64-compat-provide-definition-for-compat_sigminstksz.patch b/queue-4.14/arm64-compat-provide-definition-for-compat_sigminstksz.patch new file mode 100644 index 00000000000..a5c17d92fc8 --- /dev/null +++ b/queue-4.14/arm64-compat-provide-definition-for-compat_sigminstksz.patch @@ -0,0 +1,39 @@ +From 24951465cbd279f60b1fdc2421b3694405bcff42 Mon Sep 17 00:00:00 2001 +From: Will Deacon +Date: Wed, 5 Sep 2018 15:34:43 +0100 +Subject: arm64: compat: Provide definition for COMPAT_SIGMINSTKSZ + +From: Will Deacon + +commit 24951465cbd279f60b1fdc2421b3694405bcff42 upstream. + +arch/arm/ defines a SIGMINSTKSZ of 2k, so we should use the same value +for compat tasks. + +Cc: Arnd Bergmann +Cc: Dominik Brodowski +Cc: "Eric W. Biederman" +Cc: Andrew Morton +Cc: Al Viro +Cc: Oleg Nesterov +Reviewed-by: Dave Martin +Reported-by: Steve McIntyre +Tested-by: Steve McIntyre <93sam@debian.org> +Signed-off-by: Will Deacon +Signed-off-by: Catalin Marinas +Signed-off-by: Greg Kroah-Hartman + +--- + arch/arm64/include/asm/compat.h | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm64/include/asm/compat.h ++++ b/arch/arm64/include/asm/compat.h +@@ -234,6 +234,7 @@ static inline compat_uptr_t ptr_to_compa + } + + #define compat_user_stack_pointer() (user_stack_pointer(task_pt_regs(current))) ++#define COMPAT_MINSIGSTKSZ 2048 + + static inline void __user *arch_compat_alloc_user_space(long len) + { diff --git a/queue-4.14/arm64-dts-marvell-fix-a37xx-uart0-register-size.patch b/queue-4.14/arm64-dts-marvell-fix-a37xx-uart0-register-size.patch new file mode 100644 index 00000000000..4c56093c4bd --- /dev/null +++ b/queue-4.14/arm64-dts-marvell-fix-a37xx-uart0-register-size.patch @@ -0,0 +1,46 @@ +From c737abc193d16e62e23e2fb585b8b7398ab380d8 Mon Sep 17 00:00:00 2001 +From: allen yan +Date: Thu, 7 Sep 2017 15:04:53 +0200 +Subject: arm64: dts: marvell: Fix A37xx UART0 register size + +From: allen yan + +commit c737abc193d16e62e23e2fb585b8b7398ab380d8 upstream. + +Armada-37xx UART0 registers are 0x200 bytes wide. Right next to them are +the UART1 registers that should not be declared in this node. + +Update the example in DT bindings document accordingly. + +Signed-off-by: allen yan +Signed-off-by: Miquel Raynal +Signed-off-by: Gregory CLEMENT +Signed-off-by: Amit Pundir +Signed-off-by: Greg Kroah-Hartman + +--- + Documentation/devicetree/bindings/serial/mvebu-uart.txt | 2 +- + arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/Documentation/devicetree/bindings/serial/mvebu-uart.txt ++++ b/Documentation/devicetree/bindings/serial/mvebu-uart.txt +@@ -8,6 +8,6 @@ Required properties: + Example: + serial@12000 { + compatible = "marvell,armada-3700-uart"; +- reg = <0x12000 0x400>; ++ reg = <0x12000 0x200>; + interrupts = <43>; + }; +--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi ++++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi +@@ -134,7 +134,7 @@ + + uart0: serial@12000 { + compatible = "marvell,armada-3700-uart"; +- reg = <0x12000 0x400>; ++ reg = <0x12000 0x200>; + interrupts = ; + status = "disabled"; + }; diff --git a/queue-4.14/binder-fix-possible-uaf-when-freeing-buffer.patch b/queue-4.14/binder-fix-possible-uaf-when-freeing-buffer.patch new file mode 100644 index 00000000000..bcc647f2e7f --- /dev/null +++ b/queue-4.14/binder-fix-possible-uaf-when-freeing-buffer.patch @@ -0,0 +1,62 @@ +From a370003cc301d4361bae20c9ef615f89bf8d1e8a Mon Sep 17 00:00:00 2001 +From: Todd Kjos +Date: Wed, 12 Jun 2019 13:29:27 -0700 +Subject: binder: fix possible UAF when freeing buffer + +From: Todd Kjos + +commit a370003cc301d4361bae20c9ef615f89bf8d1e8a upstream. + +There is a race between the binder driver cleaning +up a completed transaction via binder_free_transaction() +and a user calling binder_ioctl(BC_FREE_BUFFER) to +release a buffer. It doesn't matter which is first but +they need to be protected against running concurrently +which can result in a UAF. + +Signed-off-by: Todd Kjos +Cc: stable +Signed-off-by: Greg Kroah-Hartman + + + +--- + drivers/android/binder.c | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +--- a/drivers/android/binder.c ++++ b/drivers/android/binder.c +@@ -1903,8 +1903,18 @@ static struct binder_thread *binder_get_ + + static void binder_free_transaction(struct binder_transaction *t) + { +- if (t->buffer) +- t->buffer->transaction = NULL; ++ struct binder_proc *target_proc = t->to_proc; ++ ++ if (target_proc) { ++ binder_inner_proc_lock(target_proc); ++ if (t->buffer) ++ t->buffer->transaction = NULL; ++ binder_inner_proc_unlock(target_proc); ++ } ++ /* ++ * If the transaction has no target_proc, then ++ * t->buffer->transaction has already been cleared. ++ */ + kfree(t); + binder_stats_deleted(BINDER_STAT_TRANSACTION); + } +@@ -3426,10 +3436,12 @@ static int binder_thread_write(struct bi + buffer->debug_id, + buffer->transaction ? "active" : "finished"); + ++ binder_inner_proc_lock(proc); + if (buffer->transaction) { + buffer->transaction->buffer = NULL; + buffer->transaction = NULL; + } ++ binder_inner_proc_unlock(proc); + if (buffer->async_transaction && buffer->target_node) { + struct binder_node *buf_node; + struct binder_work *w; diff --git a/queue-4.14/i2c-qup-fixed-releasing-dma-without-flush-operation-completion.patch b/queue-4.14/i2c-qup-fixed-releasing-dma-without-flush-operation-completion.patch new file mode 100644 index 00000000000..a6a9e0e1727 --- /dev/null +++ b/queue-4.14/i2c-qup-fixed-releasing-dma-without-flush-operation-completion.patch @@ -0,0 +1,50 @@ +From 7239872fb3400b21a8f5547257f9f86455867bd6 Mon Sep 17 00:00:00 2001 +From: Abhishek Sahu +Date: Mon, 12 Mar 2018 18:44:51 +0530 +Subject: i2c: qup: fixed releasing dma without flush operation completion +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Abhishek Sahu + +commit 7239872fb3400b21a8f5547257f9f86455867bd6 upstream. + +The QUP BSLP BAM generates the following error sometimes if the +current I2C DMA transfer fails and the flush operation has been +scheduled + + “bam-dma-engine 7884000.dma: Cannot free busy channel” + +If any I2C error comes during BAM DMA transfer, then the QUP I2C +interrupt will be generated and the flush operation will be +carried out to make I2C consume all scheduled DMA transfer. +Currently, the same completion structure is being used for BAM +transfer which has already completed without reinit. It will make +flush operation wait_for_completion_timeout completed immediately +and will proceed for freeing the DMA resources where the +descriptors are still in process. + +Signed-off-by: Abhishek Sahu +Acked-by: Sricharan R +Reviewed-by: Austin Christ +Reviewed-by: Andy Gross +Signed-off-by: Wolfram Sang +Signed-off-by: Amit Pundir +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/i2c/busses/i2c-qup.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/i2c/busses/i2c-qup.c ++++ b/drivers/i2c/busses/i2c-qup.c +@@ -844,6 +844,8 @@ static int qup_i2c_bam_do_xfer(struct qu + } + + if (ret || qup->bus_err || qup->qup_err) { ++ reinit_completion(&qup->xfer); ++ + if (qup_i2c_change_state(qup, QUP_RUN_STATE)) { + dev_err(qup->dev, "change to run state timed out"); + goto desc_err; diff --git a/queue-4.14/nfs-fix-dentry-revalidation-on-nfsv4-lookup.patch b/queue-4.14/nfs-fix-dentry-revalidation-on-nfsv4-lookup.patch new file mode 100644 index 00000000000..cf2c5be3c43 --- /dev/null +++ b/queue-4.14/nfs-fix-dentry-revalidation-on-nfsv4-lookup.patch @@ -0,0 +1,68 @@ +From be189f7e7f03de35887e5a85ddcf39b91b5d7fc1 Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Thu, 27 Sep 2018 17:12:33 -0400 +Subject: NFS: Fix dentry revalidation on NFSv4 lookup + +From: Trond Myklebust + +commit be189f7e7f03de35887e5a85ddcf39b91b5d7fc1 upstream. + +We need to ensure that inode and dentry revalidation occurs correctly +on reopen of a file that is already open. Currently, we can end up +not revalidating either in the case of NFSv4.0, due to the 'cached open' +path. +Let's fix that by ensuring that we only do cached open for the special +cases of open recovery and delegation return. + +Reported-by: Stan Hu +Signed-off-by: Trond Myklebust +Signed-off-by: Qian Lu +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/nfs4proc.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -1317,12 +1317,20 @@ static bool nfs4_mode_match_open_stateid + return false; + } + +-static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode) ++static int can_open_cached(struct nfs4_state *state, fmode_t mode, ++ int open_mode, enum open_claim_type4 claim) + { + int ret = 0; + + if (open_mode & (O_EXCL|O_TRUNC)) + goto out; ++ switch (claim) { ++ case NFS4_OPEN_CLAIM_NULL: ++ case NFS4_OPEN_CLAIM_FH: ++ goto out; ++ default: ++ break; ++ } + switch (mode & (FMODE_READ|FMODE_WRITE)) { + case FMODE_READ: + ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0 +@@ -1617,7 +1625,7 @@ static struct nfs4_state *nfs4_try_open_ + + for (;;) { + spin_lock(&state->owner->so_lock); +- if (can_open_cached(state, fmode, open_mode)) { ++ if (can_open_cached(state, fmode, open_mode, claim)) { + update_open_stateflags(state, fmode); + spin_unlock(&state->owner->so_lock); + goto out_return_state; +@@ -2141,7 +2149,8 @@ static void nfs4_open_prepare(struct rpc + if (data->state != NULL) { + struct nfs_delegation *delegation; + +- if (can_open_cached(data->state, data->o_arg.fmode, data->o_arg.open_flags)) ++ if (can_open_cached(data->state, data->o_arg.fmode, ++ data->o_arg.open_flags, claim)) + goto out_no_action; + rcu_read_lock(); + delegation = rcu_dereference(NFS_I(data->state->inode)->delegation); diff --git a/queue-4.14/nfs-refactor-nfs_lookup_revalidate.patch b/queue-4.14/nfs-refactor-nfs_lookup_revalidate.patch new file mode 100644 index 00000000000..ed82db03904 --- /dev/null +++ b/queue-4.14/nfs-refactor-nfs_lookup_revalidate.patch @@ -0,0 +1,295 @@ +From 5ceb9d7fdaaf6d8ced6cd7861cf1deb9cd93fa47 Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Fri, 28 Sep 2018 09:04:05 -0400 +Subject: NFS: Refactor nfs_lookup_revalidate() + +From: Trond Myklebust + +commit 5ceb9d7fdaaf6d8ced6cd7861cf1deb9cd93fa47 upstream. + +Refactor the code in nfs_lookup_revalidate() as a stepping stone towards +optimising and fixing nfs4_lookup_revalidate(). + +Signed-off-by: Trond Myklebust +Signed-off-by: Qian Lu +Signed-off-by: Greg Kroah-Hartman +--- + fs/nfs/dir.c | 222 +++++++++++++++++++++++++++++++++-------------------------- + 1 file changed, 126 insertions(+), 96 deletions(-) + +--- a/fs/nfs/dir.c ++++ b/fs/nfs/dir.c +@@ -1059,6 +1059,100 @@ int nfs_neg_need_reval(struct inode *dir + return !nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU); + } + ++static int ++nfs_lookup_revalidate_done(struct inode *dir, struct dentry *dentry, ++ struct inode *inode, int error) ++{ ++ switch (error) { ++ case 1: ++ dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is valid\n", ++ __func__, dentry); ++ return 1; ++ case 0: ++ nfs_mark_for_revalidate(dir); ++ if (inode && S_ISDIR(inode->i_mode)) { ++ /* Purge readdir caches. */ ++ nfs_zap_caches(inode); ++ /* ++ * We can't d_drop the root of a disconnected tree: ++ * its d_hash is on the s_anon list and d_drop() would hide ++ * it from shrink_dcache_for_unmount(), leading to busy ++ * inodes on unmount and further oopses. ++ */ ++ if (IS_ROOT(dentry)) ++ return 1; ++ } ++ dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is invalid\n", ++ __func__, dentry); ++ return 0; ++ } ++ dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) lookup returned error %d\n", ++ __func__, dentry, error); ++ return error; ++} ++ ++static int ++nfs_lookup_revalidate_negative(struct inode *dir, struct dentry *dentry, ++ unsigned int flags) ++{ ++ int ret = 1; ++ if (nfs_neg_need_reval(dir, dentry, flags)) { ++ if (flags & LOOKUP_RCU) ++ return -ECHILD; ++ ret = 0; ++ } ++ return nfs_lookup_revalidate_done(dir, dentry, NULL, ret); ++} ++ ++static int ++nfs_lookup_revalidate_delegated(struct inode *dir, struct dentry *dentry, ++ struct inode *inode) ++{ ++ nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); ++ return nfs_lookup_revalidate_done(dir, dentry, inode, 1); ++} ++ ++static int ++nfs_lookup_revalidate_dentry(struct inode *dir, struct dentry *dentry, ++ struct inode *inode) ++{ ++ struct nfs_fh *fhandle; ++ struct nfs_fattr *fattr; ++ struct nfs4_label *label; ++ int ret; ++ ++ ret = -ENOMEM; ++ fhandle = nfs_alloc_fhandle(); ++ fattr = nfs_alloc_fattr(); ++ label = nfs4_label_alloc(NFS_SERVER(inode), GFP_KERNEL); ++ if (fhandle == NULL || fattr == NULL || IS_ERR(label)) ++ goto out; ++ ++ ret = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label); ++ if (ret < 0) { ++ if (ret == -ESTALE || ret == -ENOENT) ++ ret = 0; ++ goto out; ++ } ++ ret = 0; ++ if (nfs_compare_fh(NFS_FH(inode), fhandle)) ++ goto out; ++ if (nfs_refresh_inode(inode, fattr) < 0) ++ goto out; ++ ++ nfs_setsecurity(inode, fattr, label); ++ nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); ++ ++ /* set a readdirplus hint that we had a cache miss */ ++ nfs_force_use_readdirplus(dir); ++ ret = 1; ++out: ++ nfs_free_fattr(fattr); ++ nfs_free_fhandle(fhandle); ++ nfs4_label_free(label); ++ return nfs_lookup_revalidate_done(dir, dentry, inode, ret); ++} ++ + /* + * This is called every time the dcache has a lookup hit, + * and we should check whether we can really trust that +@@ -1070,58 +1164,36 @@ int nfs_neg_need_reval(struct inode *dir + * If the parent directory is seen to have changed, we throw out the + * cached dentry and do a new lookup. + */ +-static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags) ++static int ++nfs_do_lookup_revalidate(struct inode *dir, struct dentry *dentry, ++ unsigned int flags) + { +- struct inode *dir; + struct inode *inode; +- struct dentry *parent; +- struct nfs_fh *fhandle = NULL; +- struct nfs_fattr *fattr = NULL; +- struct nfs4_label *label = NULL; + int error; + +- if (flags & LOOKUP_RCU) { +- parent = ACCESS_ONCE(dentry->d_parent); +- dir = d_inode_rcu(parent); +- if (!dir) +- return -ECHILD; +- } else { +- parent = dget_parent(dentry); +- dir = d_inode(parent); +- } + nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE); + inode = d_inode(dentry); + +- if (!inode) { +- if (nfs_neg_need_reval(dir, dentry, flags)) { +- if (flags & LOOKUP_RCU) +- return -ECHILD; +- goto out_bad; +- } +- goto out_valid; +- } ++ if (!inode) ++ return nfs_lookup_revalidate_negative(dir, dentry, flags); + + if (is_bad_inode(inode)) { +- if (flags & LOOKUP_RCU) +- return -ECHILD; + dfprintk(LOOKUPCACHE, "%s: %pd2 has dud inode\n", + __func__, dentry); + goto out_bad; + } + + if (NFS_PROTO(dir)->have_delegation(inode, FMODE_READ)) +- goto out_set_verifier; ++ return nfs_lookup_revalidate_delegated(dir, dentry, inode); + + /* Force a full look up iff the parent directory has changed */ + if (!nfs_is_exclusive_create(dir, flags) && + nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU)) { + error = nfs_lookup_verify_inode(inode, flags); + if (error) { +- if (flags & LOOKUP_RCU) +- return -ECHILD; + if (error == -ESTALE) +- goto out_zap_parent; +- goto out_error; ++ nfs_zap_caches(dir); ++ goto out_bad; + } + nfs_advise_use_readdirplus(dir); + goto out_valid; +@@ -1133,81 +1205,39 @@ static int nfs_lookup_revalidate(struct + if (NFS_STALE(inode)) + goto out_bad; + +- error = -ENOMEM; +- fhandle = nfs_alloc_fhandle(); +- fattr = nfs_alloc_fattr(); +- if (fhandle == NULL || fattr == NULL) +- goto out_error; +- +- label = nfs4_label_alloc(NFS_SERVER(inode), GFP_NOWAIT); +- if (IS_ERR(label)) +- goto out_error; +- + trace_nfs_lookup_revalidate_enter(dir, dentry, flags); +- error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label); ++ error = nfs_lookup_revalidate_dentry(dir, dentry, inode); + trace_nfs_lookup_revalidate_exit(dir, dentry, flags, error); +- if (error == -ESTALE || error == -ENOENT) +- goto out_bad; +- if (error) +- goto out_error; +- if (nfs_compare_fh(NFS_FH(inode), fhandle)) +- goto out_bad; +- if ((error = nfs_refresh_inode(inode, fattr)) != 0) +- goto out_bad; +- +- nfs_setsecurity(inode, fattr, label); +- +- nfs_free_fattr(fattr); +- nfs_free_fhandle(fhandle); +- nfs4_label_free(label); ++ return error; ++out_valid: ++ return nfs_lookup_revalidate_done(dir, dentry, inode, 1); ++out_bad: ++ if (flags & LOOKUP_RCU) ++ return -ECHILD; ++ return nfs_lookup_revalidate_done(dir, dentry, inode, 0); ++} + +- /* set a readdirplus hint that we had a cache miss */ +- nfs_force_use_readdirplus(dir); ++static int ++nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags) ++{ ++ struct dentry *parent; ++ struct inode *dir; ++ int ret; + +-out_set_verifier: +- nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); +- out_valid: + if (flags & LOOKUP_RCU) { ++ parent = ACCESS_ONCE(dentry->d_parent); ++ dir = d_inode_rcu(parent); ++ if (!dir) ++ return -ECHILD; ++ ret = nfs_do_lookup_revalidate(dir, dentry, flags); + if (parent != ACCESS_ONCE(dentry->d_parent)) + return -ECHILD; +- } else ++ } else { ++ parent = dget_parent(dentry); ++ ret = nfs_do_lookup_revalidate(d_inode(parent), dentry, flags); + dput(parent); +- dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is valid\n", +- __func__, dentry); +- return 1; +-out_zap_parent: +- nfs_zap_caches(dir); +- out_bad: +- WARN_ON(flags & LOOKUP_RCU); +- nfs_free_fattr(fattr); +- nfs_free_fhandle(fhandle); +- nfs4_label_free(label); +- nfs_mark_for_revalidate(dir); +- if (inode && S_ISDIR(inode->i_mode)) { +- /* Purge readdir caches. */ +- nfs_zap_caches(inode); +- /* +- * We can't d_drop the root of a disconnected tree: +- * its d_hash is on the s_anon list and d_drop() would hide +- * it from shrink_dcache_for_unmount(), leading to busy +- * inodes on unmount and further oopses. +- */ +- if (IS_ROOT(dentry)) +- goto out_valid; + } +- dput(parent); +- dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is invalid\n", +- __func__, dentry); +- return 0; +-out_error: +- WARN_ON(flags & LOOKUP_RCU); +- nfs_free_fattr(fattr); +- nfs_free_fhandle(fhandle); +- nfs4_label_free(label); +- dput(parent); +- dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) lookup returned error %d\n", +- __func__, dentry, error); +- return error; ++ return ret; + } + + /* diff --git a/queue-4.14/nfsv4-fix-lookup-revalidate-of-regular-files.patch b/queue-4.14/nfsv4-fix-lookup-revalidate-of-regular-files.patch new file mode 100644 index 00000000000..3dd53bb3d12 --- /dev/null +++ b/queue-4.14/nfsv4-fix-lookup-revalidate-of-regular-files.patch @@ -0,0 +1,151 @@ +From c7944ebb9ce9461079659e9e6ec5baaf73724b3b Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Fri, 28 Sep 2018 12:42:51 -0400 +Subject: NFSv4: Fix lookup revalidate of regular files + +From: Trond Myklebust + +commit c7944ebb9ce9461079659e9e6ec5baaf73724b3b upstream. + +If we're revalidating an existing dentry in order to open a file, we need +to ensure that we check the directory has not changed before we optimise +away the lookup. + +Signed-off-by: Trond Myklebust +Signed-off-by: Qian Lu +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/dir.c | 79 +++++++++++++++++++++++++++++------------------------------ + 1 file changed, 39 insertions(+), 40 deletions(-) + +--- a/fs/nfs/dir.c ++++ b/fs/nfs/dir.c +@@ -1218,7 +1218,8 @@ out_bad: + } + + static int +-nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags) ++__nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags, ++ int (*reval)(struct inode *, struct dentry *, unsigned int)) + { + struct dentry *parent; + struct inode *dir; +@@ -1229,17 +1230,22 @@ nfs_lookup_revalidate(struct dentry *den + dir = d_inode_rcu(parent); + if (!dir) + return -ECHILD; +- ret = nfs_do_lookup_revalidate(dir, dentry, flags); ++ ret = reval(dir, dentry, flags); + if (parent != ACCESS_ONCE(dentry->d_parent)) + return -ECHILD; + } else { + parent = dget_parent(dentry); +- ret = nfs_do_lookup_revalidate(d_inode(parent), dentry, flags); ++ ret = reval(d_inode(parent), dentry, flags); + dput(parent); + } + return ret; + } + ++static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags) ++{ ++ return __nfs_lookup_revalidate(dentry, flags, nfs_do_lookup_revalidate); ++} ++ + /* + * A weaker form of d_revalidate for revalidating just the d_inode(dentry) + * when we don't really care about the dentry name. This is called when a +@@ -1590,62 +1596,55 @@ no_open: + } + EXPORT_SYMBOL_GPL(nfs_atomic_open); + +-static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags) ++static int ++nfs4_do_lookup_revalidate(struct inode *dir, struct dentry *dentry, ++ unsigned int flags) + { + struct inode *inode; +- int ret = 0; + + if (!(flags & LOOKUP_OPEN) || (flags & LOOKUP_DIRECTORY)) +- goto no_open; ++ goto full_reval; + if (d_mountpoint(dentry)) +- goto no_open; +- if (NFS_SB(dentry->d_sb)->caps & NFS_CAP_ATOMIC_OPEN_V1) +- goto no_open; ++ goto full_reval; + + inode = d_inode(dentry); + + /* We can't create new files in nfs_open_revalidate(), so we + * optimize away revalidation of negative dentries. + */ +- if (inode == NULL) { +- struct dentry *parent; +- struct inode *dir; +- +- if (flags & LOOKUP_RCU) { +- parent = ACCESS_ONCE(dentry->d_parent); +- dir = d_inode_rcu(parent); +- if (!dir) +- return -ECHILD; +- } else { +- parent = dget_parent(dentry); +- dir = d_inode(parent); +- } +- if (!nfs_neg_need_reval(dir, dentry, flags)) +- ret = 1; +- else if (flags & LOOKUP_RCU) +- ret = -ECHILD; +- if (!(flags & LOOKUP_RCU)) +- dput(parent); +- else if (parent != ACCESS_ONCE(dentry->d_parent)) +- return -ECHILD; +- goto out; +- } ++ if (inode == NULL) ++ goto full_reval; ++ ++ if (NFS_PROTO(dir)->have_delegation(inode, FMODE_READ)) ++ return nfs_lookup_revalidate_delegated(dir, dentry, inode); + + /* NFS only supports OPEN on regular files */ + if (!S_ISREG(inode->i_mode)) +- goto no_open; ++ goto full_reval; ++ + /* We cannot do exclusive creation on a positive dentry */ +- if (flags & LOOKUP_EXCL) +- goto no_open; ++ if (flags & (LOOKUP_EXCL | LOOKUP_REVAL)) ++ goto reval_dentry; ++ ++ /* Check if the directory changed */ ++ if (!nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU)) ++ goto reval_dentry; + + /* Let f_op->open() actually open (and revalidate) the file */ +- ret = 1; ++ return 1; ++reval_dentry: ++ if (flags & LOOKUP_RCU) ++ return -ECHILD; ++ return nfs_lookup_revalidate_dentry(dir, dentry, inode);; + +-out: +- return ret; ++full_reval: ++ return nfs_do_lookup_revalidate(dir, dentry, flags); ++} + +-no_open: +- return nfs_lookup_revalidate(dentry, flags); ++static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags) ++{ ++ return __nfs_lookup_revalidate(dentry, flags, ++ nfs4_do_lookup_revalidate); + } + + #endif /* CONFIG_NFSV4 */ diff --git a/queue-4.14/series b/queue-4.14/series index 2f0f177e7ba..d538c9fa31d 100644 --- a/queue-4.14/series +++ b/queue-4.14/series @@ -1,2 +1,9 @@ vsock-use-tcp-state-constants-for-sk_state.patch vsock-correct-removal-of-socket-from-the-list.patch +nfs-fix-dentry-revalidation-on-nfsv4-lookup.patch +nfs-refactor-nfs_lookup_revalidate.patch +nfsv4-fix-lookup-revalidate-of-regular-files.patch +arm64-dts-marvell-fix-a37xx-uart0-register-size.patch +i2c-qup-fixed-releasing-dma-without-flush-operation-completion.patch +arm64-compat-provide-definition-for-compat_sigminstksz.patch +binder-fix-possible-uaf-when-freeing-buffer.patch -- 2.47.3