| From 7007c90fb9fef593b4aeaeee57e6a6754276c97c Mon Sep 17 00:00:00 2001 |
| From: Neil Brown <neilb@suse.de> |
| Date: Fri, 7 Dec 2012 15:40:55 -0500 |
| Subject: nfsd: avoid permission checks on EXCLUSIVE_CREATE replay |
| |
| From: Neil Brown <neilb@suse.de> |
| |
| commit 7007c90fb9fef593b4aeaeee57e6a6754276c97c upstream. |
| |
| With NFSv4, if we create a file then open it we explicit avoid checking |
| the permissions on the file during the open because the fact that we |
| created it ensures we should be allow to open it (the create and the |
| open should appear to be a single operation). |
| |
| However if the reply to an EXCLUSIVE create gets lots and the client |
| resends the create, the current code will perform the permission check - |
| because it doesn't realise that it did the open already.. |
| |
| This patch should fix this. |
| |
| Note that I haven't actually seen this cause a problem. I was just |
| looking at the code trying to figure out a different EXCLUSIVE open |
| related issue, and this looked wrong. |
| |
| (Fix confirmed with pynfs 4.0 test OPEN4--bfields) |
| |
| Signed-off-by: NeilBrown <neilb@suse.de> |
| [bfields: use OWNER_OVERRIDE and update for 4.1] |
| Signed-off-by: J. Bruce Fields <bfields@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/nfsd/nfs4proc.c | 8 +++++--- |
| fs/nfsd/vfs.c | 10 ++++++++-- |
| 2 files changed, 13 insertions(+), 5 deletions(-) |
| |
| --- a/fs/nfsd/nfs4proc.c |
| +++ b/fs/nfsd/nfs4proc.c |
| @@ -194,6 +194,7 @@ static __be32 |
| do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) |
| { |
| struct svc_fh *resfh; |
| + int accmode; |
| __be32 status; |
| |
| resfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL); |
| @@ -253,9 +254,10 @@ do_open_lookup(struct svc_rqst *rqstp, s |
| /* set reply cache */ |
| fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh, |
| &resfh->fh_handle); |
| - if (!open->op_created) |
| - status = do_open_permission(rqstp, resfh, open, |
| - NFSD_MAY_NOP); |
| + accmode = NFSD_MAY_NOP; |
| + if (open->op_created) |
| + accmode |= NFSD_MAY_OWNER_OVERRIDE; |
| + status = do_open_permission(rqstp, resfh, open, accmode); |
| set_change_info(&open->op_cinfo, current_fh); |
| fh_dup2(current_fh, resfh); |
| out: |
| --- a/fs/nfsd/vfs.c |
| +++ b/fs/nfsd/vfs.c |
| @@ -1485,13 +1485,19 @@ do_nfsd_create(struct svc_rqst *rqstp, s |
| case NFS3_CREATE_EXCLUSIVE: |
| if ( dchild->d_inode->i_mtime.tv_sec == v_mtime |
| && dchild->d_inode->i_atime.tv_sec == v_atime |
| - && dchild->d_inode->i_size == 0 ) |
| + && dchild->d_inode->i_size == 0 ) { |
| + if (created) |
| + *created = 1; |
| break; |
| + } |
| case NFS4_CREATE_EXCLUSIVE4_1: |
| if ( dchild->d_inode->i_mtime.tv_sec == v_mtime |
| && dchild->d_inode->i_atime.tv_sec == v_atime |
| - && dchild->d_inode->i_size == 0 ) |
| + && dchild->d_inode->i_size == 0 ) { |
| + if (created) |
| + *created = 1; |
| goto set_attr; |
| + } |
| /* fallthru */ |
| case NFS3_CREATE_GUARDED: |
| err = nfserr_exist; |