diff options
author | J. Bruce Fields <bfields@citi.umich.edu> | 2009-11-25 17:42:05 -0500 |
---|---|---|
committer | J. Bruce Fields <bfields@citi.umich.edu> | 2009-11-25 17:55:46 -0500 |
commit | 864f0f61f829bac5f150a903aad9619322a25424 (patch) | |
tree | 77a864ab5538255dfba454d13f67de60807f2973 /fs/nfsd | |
parent | 9b8b317d58084b9a44f6f33b355c4278d9f841fb (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/nfsd')
-rw-r--r-- | fs/nfsd/nfsfh.c | 50 |
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) |