From: Peter Staubach <staubach@redhat.com> Date: Fri, 29 May 2009 09:51:57 -0400 Subject: [nfs] v4: 'r'/'w' perms for user do not work on client Message-id: 4A1FE87D.8010701@redhat.com O-Subject: [PATCH RHEL-5.4] BZ502244 'r' and 'w' permission for user do not work on NFSv4 client Bugzilla: 502244 RH-Acked-by: Jerome Marchand <jmarchan@redhat.com> RH-Acked-by: Jeff Layton <jlayton@redhat.com> Hi. Attached is a patch to address bz502244, "'r' and 'w' permission for user do not work on NFSv4 client". The problem described is a situation where the owner of a file can access a file, even if the file modes indicate that the owner should not have access to the file. In particular, the owner can read from and write to a file with mode 0. The problem is really on the NFS server side. It is the entity that is used to calculate access permissions. In this case, the NFSv4 share and deny modes were being incorrectly used and the decision for whether the owner should be allowed to override the permissions was being incorrectly made. The owner is allowed to override the permissions for i/o being done to an open file. This is done so that the sequence: open, chmod(0), write, succeeds instead of fails due to the chmod(0) in the middle. This was tested by running the testcase as described in the bug report and also by writing a small test program to ensure that system calls that should work, continue to work, and that system calls that should fail, do fail. Thanx... ps diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index da5e7d4..3740220 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -69,20 +69,21 @@ fh_dup2(struct svc_fh *dst, struct svc_fh *src) } static int -do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) +do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, + struct nfsd4_open *open, int accmode) { - int accmode, status; + int status; if (open->op_truncate && - !(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) + !(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) return nfserr_inval; - accmode = MAY_NOP; if (open->op_share_access & NFS4_SHARE_ACCESS_READ) - accmode = MAY_READ; - if (open->op_share_deny & NFS4_SHARE_ACCESS_WRITE) + accmode |= MAY_READ; + if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) accmode |= (MAY_WRITE | MAY_TRUNC); - accmode |= MAY_OWNER_OVERRIDE; + if (open->op_share_deny & NFS4_SHARE_DENY_WRITE) + accmode |= MAY_WRITE; status = fh_verify(rqstp, current_fh, S_IFREG, accmode); @@ -132,7 +133,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o &resfh.fh_handle.fh_base, resfh.fh_handle.fh_size); - status = do_open_permission(rqstp, current_fh, open); + status = do_open_permission(rqstp, current_fh, open, MAY_NOP); } fh_put(&resfh); @@ -163,7 +164,8 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) && (open->op_iattr.ia_size == 0); - status = do_open_permission(rqstp, current_fh, open); + status = do_open_permission(rqstp, current_fh, open, + MAY_OWNER_OVERRIDE); return status; }