aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@fieldses.org>2006-10-17 03:10:13 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-17 11:18:45 -0400
commitdc730e173785e29b297aa605786c94adaffe2544 (patch)
tree3ff7089bcc454d730cbf39b5609472dfc52b56b4 /fs
parente956edd0523b6b48ed367c63b0c82d8f4c447a58 (diff)
[PATCH] knfsd: nfsd4: fix owner-override on open
If a client creates a file using an open which sets the mode to 000, or if a chmod changes permissions after a file is opened, then situations may arise where an NFS client knows that some IO is permitted (because a process holds the file open), but the NFS server does not (because it doesn't know about the open, and only sees that the IO conflicts with the current mode of the file). As a hack to solve this problem, NFS servers normally allow the owner to override permissions on IO. The client can still enforce correct permissions-checking on open by performing an explicit access check. In NFSv4 the client can rely on the explicit on-the-wire open instead of an access check. Therefore we should not be allowing the owner to override permissions on an over-the-wire open! However, we should still allow the owner to override permissions in the case where the client is claiming an open that it already made either before a reboot, or while it was holding a delegation. Thanks to Jim Rees for reporting the bug. Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfsd/nfs4proc.c12
1 files changed, 5 insertions, 7 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 8333db12caca..a05d3376cc46 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -68,20 +68,18 @@ fh_dup2(struct svc_fh *dst, struct svc_fh *src)
68} 68}
69 69
70static int 70static int
71do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) 71do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, int accmode)
72{ 72{
73 int accmode, status; 73 int status;
74 74
75 if (open->op_truncate && 75 if (open->op_truncate &&
76 !(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) 76 !(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
77 return nfserr_inval; 77 return nfserr_inval;
78 78
79 accmode = MAY_NOP;
80 if (open->op_share_access & NFS4_SHARE_ACCESS_READ) 79 if (open->op_share_access & NFS4_SHARE_ACCESS_READ)
81 accmode = MAY_READ; 80 accmode |= MAY_READ;
82 if (open->op_share_deny & NFS4_SHARE_ACCESS_WRITE) 81 if (open->op_share_deny & NFS4_SHARE_ACCESS_WRITE)
83 accmode |= (MAY_WRITE | MAY_TRUNC); 82 accmode |= (MAY_WRITE | MAY_TRUNC);
84 accmode |= MAY_OWNER_OVERRIDE;
85 83
86 status = fh_verify(rqstp, current_fh, S_IFREG, accmode); 84 status = fh_verify(rqstp, current_fh, S_IFREG, accmode);
87 85
@@ -124,7 +122,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
124 &resfh.fh_handle.fh_base, 122 &resfh.fh_handle.fh_base,
125 resfh.fh_handle.fh_size); 123 resfh.fh_handle.fh_size);
126 124
127 status = do_open_permission(rqstp, current_fh, open); 125 status = do_open_permission(rqstp, current_fh, open, MAY_NOP);
128 } 126 }
129 127
130 fh_put(&resfh); 128 fh_put(&resfh);
@@ -155,7 +153,7 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_
155 open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) && 153 open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) &&
156 (open->op_iattr.ia_size == 0); 154 (open->op_iattr.ia_size == 0);
157 155
158 status = do_open_permission(rqstp, current_fh, open); 156 status = do_open_permission(rqstp, current_fh, open, MAY_OWNER_OVERRIDE);
159 157
160 return status; 158 return status;
161} 159}