aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2007-05-09 05:34:57 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-09 15:30:54 -0400
commitb41eeef14d7c73af6d16c7d02b7a939082a137ff (patch)
treeeafe41b86a825f7effc4ba596c56507451c60367
parent072f62ed85a71bbb3429a52678500ec9f9441e0d (diff)
knfsd: avoid Oops if buggy userspace performs confusing filehandle->dentry mapping
When a lookup request arrives, nfsd uses information provided by userspace (mountd) to find the right filesystem. It then assumes that the same filehandle type as the incoming filehandle can be used to create an outgoing filehandle. However if mountd is buggy, or maybe just being creative, the filesystem may not support that filesystem type, and the kernel could oops, particularly if 'ex_uuid' is NULL but a FSID_UUID* filehandle type is used. So add some proper checking that the fsid version/type from the incoming filehandle is actually supportable, and ignore that information if it isn't supportable. Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/nfsd/nfsfh.c56
1 files changed, 50 insertions, 6 deletions
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 739dd3c5c3b2..6ca2d24fc216 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -323,7 +323,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
323 * 323 *
324 */ 324 */
325 325
326 u8 version = 1; 326 u8 version;
327 u8 fsid_type = 0; 327 u8 fsid_type = 0;
328 struct inode * inode = dentry->d_inode; 328 struct inode * inode = dentry->d_inode;
329 struct dentry *parent = dentry->d_parent; 329 struct dentry *parent = dentry->d_parent;
@@ -341,15 +341,59 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
341 * the reference filehandle (if it is in the same export) 341 * the reference filehandle (if it is in the same export)
342 * or the export options. 342 * or the export options.
343 */ 343 */
344 retry:
345 version = 1;
344 if (ref_fh && ref_fh->fh_export == exp) { 346 if (ref_fh && ref_fh->fh_export == exp) {
345 version = ref_fh->fh_handle.fh_version; 347 version = ref_fh->fh_handle.fh_version;
346 if (version == 0xca) 348 fsid_type = ref_fh->fh_handle.fh_fsid_type;
349
350 if (ref_fh == fhp)
351 fh_put(ref_fh);
352 ref_fh = NULL;
353
354 switch (version) {
355 case 0xca:
347 fsid_type = FSID_DEV; 356 fsid_type = FSID_DEV;
348 else 357 break;
349 fsid_type = ref_fh->fh_handle.fh_fsid_type; 358 case 1:
350 /* We know this version/type works for this export 359 break;
351 * so there is no need for further checks. 360 default:
361 goto retry;
362 }
363
364 /* Need to check that this type works for this
365 * export point. As the fsid -> filesystem mapping
366 * was guided by user-space, there is no guarantee
367 * that the filesystem actually supports that fsid
368 * type. If it doesn't we loop around again without
369 * ref_fh set.
352 */ 370 */
371 switch(fsid_type) {
372 case FSID_DEV:
373 if (!old_valid_dev(ex_dev))
374 goto retry;
375 /* FALL THROUGH */
376 case FSID_MAJOR_MINOR:
377 case FSID_ENCODE_DEV:
378 if (!(exp->ex_dentry->d_inode->i_sb->s_type->fs_flags
379 & FS_REQUIRES_DEV))
380 goto retry;
381 break;
382 case FSID_NUM:
383 if (! (exp->ex_flags & NFSEXP_FSID))
384 goto retry;
385 break;
386 case FSID_UUID8:
387 case FSID_UUID16:
388 if (!root_export)
389 goto retry;
390 /* fall through */
391 case FSID_UUID4_INUM:
392 case FSID_UUID16_INUM:
393 if (exp->ex_uuid == NULL)
394 goto retry;
395 break;
396 }
353 } else if (exp->ex_uuid) { 397 } else if (exp->ex_uuid) {
354 if (fhp->fh_maxsize >= 64) { 398 if (fhp->fh_maxsize >= 64) {
355 if (root_export) 399 if (root_export)