From 76d17fd498bf0423ba1be081009cbf0e47aa704c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 26 Nov 2013 12:09:54 -0800 Subject: [PATCH] 3.4-stable patches added patches: nfsd-make-sure-to-balance-get-put_write_access.patch nfsd-split-up-nfsd_setattr.patch nfsv4-fix-a-use-after-free-situation-in-_nfs4_proc_getlk.patch --- ...sure-to-balance-get-put_write_access.patch | 70 +++++++ queue-3.4/nfsd-split-up-nfsd_setattr.patch | 197 ++++++++++++++++++ ...r-free-situation-in-_nfs4_proc_getlk.patch | 47 +++++ queue-3.4/series | 3 + 4 files changed, 317 insertions(+) create mode 100644 queue-3.4/nfsd-make-sure-to-balance-get-put_write_access.patch create mode 100644 queue-3.4/nfsd-split-up-nfsd_setattr.patch create mode 100644 queue-3.4/nfsv4-fix-a-use-after-free-situation-in-_nfs4_proc_getlk.patch diff --git a/queue-3.4/nfsd-make-sure-to-balance-get-put_write_access.patch b/queue-3.4/nfsd-make-sure-to-balance-get-put_write_access.patch new file mode 100644 index 00000000000..102447678bc --- /dev/null +++ b/queue-3.4/nfsd-make-sure-to-balance-get-put_write_access.patch @@ -0,0 +1,70 @@ +From 987da4791052fa298b7cfcde4dea9f6f2bbc786b Mon Sep 17 00:00:00 2001 +From: Christoph Hellwig +Date: Mon, 18 Nov 2013 05:07:47 -0800 +Subject: nfsd: make sure to balance get/put_write_access + +From: Christoph Hellwig + +commit 987da4791052fa298b7cfcde4dea9f6f2bbc786b upstream. + +Use a straight goto error label style in nfsd_setattr to make sure +we always do the put_write_access call after we got it earlier. + +Note that the we have been failing to do that in the case +nfsd_break_lease() returns an error, a bug introduced into 2.6.38 with +6a76bebefe15d9a08864f824d7f8d5beaf37c997 "nfsd4: break lease on nfsd +setattr". + +Signed-off-by: Christoph Hellwig +Signed-off-by: J. Bruce Fields +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfsd/vfs.c | 29 +++++++++++++++-------------- + 1 file changed, 15 insertions(+), 14 deletions(-) + +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -443,27 +443,28 @@ nfsd_setattr(struct svc_rqst *rqstp, str + + iap->ia_valid |= ATTR_CTIME; + +- err = nfserr_notsync; +- if (!check_guard || guardtime == inode->i_ctime.tv_sec) { +- host_err = nfsd_break_lease(inode); +- if (host_err) +- goto out_nfserr; +- fh_lock(fhp); +- +- host_err = notify_change(dentry, iap); +- err = nfserrno(host_err); +- fh_unlock(fhp); ++ if (check_guard && guardtime != inode->i_ctime.tv_sec) { ++ err = nfserr_notsync; ++ goto out_put_write_access; + } ++ ++ host_err = nfsd_break_lease(inode); ++ if (host_err) ++ goto out_put_write_access_nfserror; ++ ++ fh_lock(fhp); ++ host_err = notify_change(dentry, iap); ++ fh_unlock(fhp); ++ ++out_put_write_access_nfserror: ++ err = nfserrno(host_err); ++out_put_write_access: + if (size_change) + put_write_access(inode); + if (!err) + commit_metadata(fhp); + out: + return err; +- +-out_nfserr: +- err = nfserrno(host_err); +- goto out; + } + + #if defined(CONFIG_NFSD_V2_ACL) || \ diff --git a/queue-3.4/nfsd-split-up-nfsd_setattr.patch b/queue-3.4/nfsd-split-up-nfsd_setattr.patch new file mode 100644 index 00000000000..2754fa66bb3 --- /dev/null +++ b/queue-3.4/nfsd-split-up-nfsd_setattr.patch @@ -0,0 +1,197 @@ +From 818e5a22e907fbae75e9c1fd78233baec9fa64b6 Mon Sep 17 00:00:00 2001 +From: Christoph Hellwig +Date: Mon, 18 Nov 2013 05:07:30 -0800 +Subject: nfsd: split up nfsd_setattr + +From: Christoph Hellwig + +commit 818e5a22e907fbae75e9c1fd78233baec9fa64b6 upstream. + +Split out two helpers to make the code more readable and easier to verify +for correctness. + +Signed-off-by: Christoph Hellwig +Signed-off-by: J. Bruce Fields +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfsd/vfs.c | 144 +++++++++++++++++++++++++++++++++------------------------- + 1 file changed, 84 insertions(+), 60 deletions(-) + +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -297,41 +297,12 @@ commit_metadata(struct svc_fh *fhp) + } + + /* +- * Set various file attributes. +- * N.B. After this call fhp needs an fh_put ++ * Go over the attributes and take care of the small differences between ++ * NFS semantics and what Linux expects. + */ +-__be32 +-nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, +- int check_guard, time_t guardtime) ++static void ++nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap) + { +- struct dentry *dentry; +- struct inode *inode; +- int accmode = NFSD_MAY_SATTR; +- umode_t ftype = 0; +- __be32 err; +- int host_err; +- int size_change = 0; +- +- if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE)) +- accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE; +- if (iap->ia_valid & ATTR_SIZE) +- ftype = S_IFREG; +- +- /* Get inode */ +- err = fh_verify(rqstp, fhp, ftype, accmode); +- if (err) +- goto out; +- +- dentry = fhp->fh_dentry; +- inode = dentry->d_inode; +- +- /* Ignore any mode updates on symlinks */ +- if (S_ISLNK(inode->i_mode)) +- iap->ia_valid &= ~ATTR_MODE; +- +- if (!iap->ia_valid) +- goto out; +- + /* + * NFSv2 does not differentiate between "set-[ac]time-to-now" + * which only requires access, and "set-[ac]time-to-X" which +@@ -341,8 +312,7 @@ nfsd_setattr(struct svc_rqst *rqstp, str + * convert to "set to now" instead of "set to explicit time" + * + * We only call inode_change_ok as the last test as technically +- * it is not an interface that we should be using. It is only +- * valid if the filesystem does not define it's own i_op->setattr. ++ * it is not an interface that we should be using. + */ + #define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET) + #define MAX_TOUCH_TIME_ERROR (30*60) +@@ -368,30 +338,6 @@ nfsd_setattr(struct svc_rqst *rqstp, str + iap->ia_valid &= ~BOTH_TIME_SET; + } + } +- +- /* +- * The size case is special. +- * It changes the file as well as the attributes. +- */ +- if (iap->ia_valid & ATTR_SIZE) { +- if (iap->ia_size < inode->i_size) { +- err = nfsd_permission(rqstp, fhp->fh_export, dentry, +- NFSD_MAY_TRUNC|NFSD_MAY_OWNER_OVERRIDE); +- if (err) +- goto out; +- } +- +- host_err = get_write_access(inode); +- if (host_err) +- goto out_nfserr; +- +- size_change = 1; +- host_err = locks_verify_truncate(inode, NULL, iap->ia_size); +- if (host_err) { +- put_write_access(inode); +- goto out_nfserr; +- } +- } + + /* sanitize the mode change */ + if (iap->ia_valid & ATTR_MODE) { +@@ -414,8 +360,86 @@ nfsd_setattr(struct svc_rqst *rqstp, str + iap->ia_valid |= (ATTR_KILL_SUID | ATTR_KILL_SGID); + } + } ++} ++ ++static __be32 ++nfsd_get_write_access(struct svc_rqst *rqstp, struct svc_fh *fhp, ++ struct iattr *iap) ++{ ++ struct inode *inode = fhp->fh_dentry->d_inode; ++ int host_err; ++ ++ if (iap->ia_size < inode->i_size) { ++ __be32 err; ++ ++ err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, ++ NFSD_MAY_TRUNC | NFSD_MAY_OWNER_OVERRIDE); ++ if (err) ++ return err; ++ } ++ ++ host_err = get_write_access(inode); ++ if (host_err) ++ goto out_nfserrno; ++ ++ host_err = locks_verify_truncate(inode, NULL, iap->ia_size); ++ if (host_err) ++ goto out_put_write_access; ++ return 0; ++ ++out_put_write_access: ++ put_write_access(inode); ++out_nfserrno: ++ return nfserrno(host_err); ++} ++ ++/* ++ * Set various file attributes. After this call fhp needs an fh_put. ++ */ ++__be32 ++nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, ++ int check_guard, time_t guardtime) ++{ ++ struct dentry *dentry; ++ struct inode *inode; ++ int accmode = NFSD_MAY_SATTR; ++ umode_t ftype = 0; ++ __be32 err; ++ int host_err; ++ int size_change = 0; ++ ++ if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE)) ++ accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE; ++ if (iap->ia_valid & ATTR_SIZE) ++ ftype = S_IFREG; ++ ++ /* Get inode */ ++ err = fh_verify(rqstp, fhp, ftype, accmode); ++ if (err) ++ goto out; ++ ++ dentry = fhp->fh_dentry; ++ inode = dentry->d_inode; ++ ++ /* Ignore any mode updates on symlinks */ ++ if (S_ISLNK(inode->i_mode)) ++ iap->ia_valid &= ~ATTR_MODE; ++ ++ if (!iap->ia_valid) ++ goto out; ++ ++ nfsd_sanitize_attrs(inode, iap); + +- /* Change the attributes. */ ++ /* ++ * The size case is special, it changes the file in addition to the ++ * attributes. ++ */ ++ if (iap->ia_valid & ATTR_SIZE) { ++ err = nfsd_get_write_access(rqstp, fhp, iap); ++ if (err) ++ goto out; ++ size_change = 1; ++ } + + iap->ia_valid |= ATTR_CTIME; + diff --git a/queue-3.4/nfsv4-fix-a-use-after-free-situation-in-_nfs4_proc_getlk.patch b/queue-3.4/nfsv4-fix-a-use-after-free-situation-in-_nfs4_proc_getlk.patch new file mode 100644 index 00000000000..e81cc0528e8 --- /dev/null +++ b/queue-3.4/nfsv4-fix-a-use-after-free-situation-in-_nfs4_proc_getlk.patch @@ -0,0 +1,47 @@ +From a6f951ddbdfb7bd87d31a44f61abe202ed6ce57f Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Tue, 1 Oct 2013 14:24:58 -0400 +Subject: NFSv4: Fix a use-after-free situation in _nfs4_proc_getlk() + +From: Trond Myklebust + +commit a6f951ddbdfb7bd87d31a44f61abe202ed6ce57f upstream. + +In nfs4_proc_getlk(), when some error causes a retry of the call to +_nfs4_proc_getlk(), we can end up with Oopses of the form + + BUG: unable to handle kernel NULL pointer dereference at 0000000000000134 + IP: [] _raw_spin_lock+0xe/0x30 + + Call Trace: + [] _atomic_dec_and_lock+0x4d/0x70 + [] nfs4_put_lock_state+0x32/0xb0 [nfsv4] + [] nfs4_fl_release_lock+0x15/0x20 [nfsv4] + [] _nfs4_proc_getlk.isra.40+0x146/0x170 [nfsv4] + [] nfs4_proc_lock+0x399/0x5a0 [nfsv4] + +The problem is that we don't clear the request->fl_ops after the first +try and so when we retry, nfs4_set_lock_state() exits early without +setting the lock stateid. +Regression introduced by commit 70cc6487a4e08b8698c0e2ec935fb48d10490162 +(locks: make ->lock release private data before returning in GETLK case) + +Reported-by: Weston Andros Adamson +Reported-by: Jorge Mora +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + fs/nfs/nfs4proc.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/nfs/nfs4proc.c ++++ b/fs/nfs/nfs4proc.c +@@ -4207,6 +4207,7 @@ static int _nfs4_proc_getlk(struct nfs4_ + status = 0; + } + request->fl_ops->fl_release_private(request); ++ request->fl_ops = NULL; + out: + return status; + } diff --git a/queue-3.4/series b/queue-3.4/series index 30eea980e89..5945043d841 100644 --- a/queue-3.4/series +++ b/queue-3.4/series @@ -22,3 +22,6 @@ revert-ima-policy-for-ramfs.patch exec-ptrace-fix-get_dumpable-incorrect-tests.patch alsa-6fire-fix-probe-of-multiple-cards.patch alsa-msnd-avoid-duplicated-driver-name.patch +nfsv4-fix-a-use-after-free-situation-in-_nfs4_proc_getlk.patch +nfsd-split-up-nfsd_setattr.patch +nfsd-make-sure-to-balance-get-put_write_access.patch -- 2.47.3