aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@citi.umich.edu>2009-11-25 17:42:05 -0500
committerJ. Bruce Fields <bfields@citi.umich.edu>2009-11-25 17:55:46 -0500
commit864f0f61f829bac5f150a903aad9619322a25424 (patch)
tree77a864ab5538255dfba454d13f67de60807f2973 /fs
parent9b8b317d58084b9a44f6f33b355c4278d9f841fb (diff)
nfsd: simplify fh_verify access checks
All nfsd security depends on the security checks in fh_verify, and especially on nfsd_setuser(). It therefore bothers me that the nfsd_setuser call may be made from three different places, depending on whether the filehandle has already been mapped to a dentry, and on whether subtreechecking is in force. Instead, make an unconditional call in fh_verify(), so it's trivial to verify that the call always occurs. That leaves us with a redundant nfsd_setuser() call in the subtreecheck case--it needs the correct user set earlier in order to check execute permissions on the path to this filehandle--but I'm willing to accept that minor inefficiency in the subtreecheck case in return for more straightforward permission checking. Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfsd/nfsfh.c50
1 files changed, 21 insertions, 29 deletions
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index d0d8a217a3ea..a77efb8c2243 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -233,14 +233,6 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
233 goto out; 233 goto out;
234 } 234 }
235 235
236 if (exp->ex_flags & NFSEXP_NOSUBTREECHECK) {
237 error = nfsd_setuser_and_check_port(rqstp, exp);
238 if (error) {
239 dput(dentry);
240 goto out;
241 }
242 }
243
244 if (S_ISDIR(dentry->d_inode->i_mode) && 236 if (S_ISDIR(dentry->d_inode->i_mode) &&
245 (dentry->d_flags & DCACHE_DISCONNECTED)) { 237 (dentry->d_flags & DCACHE_DISCONNECTED)) {
246 printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n", 238 printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n",
@@ -295,28 +287,28 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
295 error = nfsd_set_fh_dentry(rqstp, fhp); 287 error = nfsd_set_fh_dentry(rqstp, fhp);
296 if (error) 288 if (error)
297 goto out; 289 goto out;
298 dentry = fhp->fh_dentry;
299 exp = fhp->fh_export;
300 } else {
301 /*
302 * just rechecking permissions
303 * (e.g. nfsproc_create calls fh_verify, then nfsd_create
304 * does as well)
305 */
306 dprintk("nfsd: fh_verify - just checking\n");
307 dentry = fhp->fh_dentry;
308 exp = fhp->fh_export;
309 /*
310 * Set user creds for this exportpoint; necessary even
311 * in the "just checking" case because this may be a
312 * filehandle that was created by fh_compose, and that
313 * is about to be used in another nfsv4 compound
314 * operation.
315 */
316 error = nfsd_setuser_and_check_port(rqstp, exp);
317 if (error)
318 goto out;
319 } 290 }
291 dentry = fhp->fh_dentry;
292 exp = fhp->fh_export;
293 /*
294 * We still have to do all these permission checks, even when
295 * fh_dentry is already set:
296 * - fh_verify may be called multiple times with different
297 * "access" arguments (e.g. nfsd_proc_create calls
298 * fh_verify(...,NFSD_MAY_EXEC) first, then later (in
299 * nfsd_create) calls fh_verify(...,NFSD_MAY_CREATE).
300 * - in the NFSv4 case, the filehandle may have been filled
301 * in by fh_compose, and given a dentry, but further
302 * compound operations performed with that filehandle
303 * still need permissions checks. In the worst case, a
304 * mountpoint crossing may have changed the export
305 * options, and we may now need to use a different uid
306 * (for example, if different id-squashing options are in
307 * effect on the new filesystem).
308 */
309 error = nfsd_setuser_and_check_port(rqstp, exp);
310 if (error)
311 goto out;
320 312
321 error = nfsd_mode_check(rqstp, dentry->d_inode->i_mode, type); 313 error = nfsd_mode_check(rqstp, dentry->d_inode->i_mode, type);
322 if (error) 314 if (error)