Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

nfsd: permit unauthenticated stat of export root

RFC 2623 section 2.3.2 permits the server to bypass gss authentication
checks for certain operations that a client may perform when mounting.
In the case of a client that doesn't have some form of credentials
available to it on boot, this allows it to perform the mount unattended.
(Presumably real file access won't be needed until a user with
credentials logs in.)

Being slightly more lenient allows lots of old clients to access
krb5-only exports, with the only loss being a small amount of
information leaked about the root directory of the export.

This affects only v2 and v3; v4 still requires authentication for all
access.

Thanks to Peter Staubach testing against a Solaris client, which
suggesting addition of v3 getattr, to the list, and to Trond for noting
that doing so exposes no additional information.

Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Cc: Peter Staubach <staubach@redhat.com>
Cc: Trond Myklebust <trond.myklebust@fys.uio.no>

+33 -18
+5 -3
fs/nfsd/nfs3proc.c
··· 63 63 SVCFH_fmt(&argp->fh)); 64 64 65 65 fh_copy(&resp->fh, &argp->fh); 66 - nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP); 66 + nfserr = fh_verify(rqstp, &resp->fh, 0, 67 + NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT); 67 68 if (nfserr) 68 69 RETURN_STATUS(nfserr); 69 70 ··· 531 530 dprintk("nfsd: FSSTAT(3) %s\n", 532 531 SVCFH_fmt(&argp->fh)); 533 532 534 - nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats); 533 + nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 0); 535 534 fh_put(&argp->fh); 536 535 RETURN_STATUS(nfserr); 537 536 } ··· 559 558 resp->f_maxfilesize = ~(u32) 0; 560 559 resp->f_properties = NFS3_FSF_DEFAULT; 561 560 562 - nfserr = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP); 561 + nfserr = fh_verify(rqstp, &argp->fh, 0, 562 + NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT); 563 563 564 564 /* Check special features of the file system. May request 565 565 * different read/write sizes for file systems known to have
+20 -10
fs/nfsd/nfsfh.c
··· 302 302 if (error) 303 303 goto out; 304 304 305 - if (!(access & NFSD_MAY_LOCK)) { 306 - /* 307 - * pseudoflavor restrictions are not enforced on NLM, 308 - * which clients virtually always use auth_sys for, 309 - * even while using RPCSEC_GSS for NFS. 310 - */ 311 - error = check_nfsd_access(exp, rqstp); 312 - if (error) 313 - goto out; 314 - } 305 + /* 306 + * pseudoflavor restrictions are not enforced on NLM, 307 + * which clients virtually always use auth_sys for, 308 + * even while using RPCSEC_GSS for NFS. 309 + */ 310 + if (access & NFSD_MAY_LOCK) 311 + goto skip_pseudoflavor_check; 312 + /* 313 + * Clients may expect to be able to use auth_sys during mount, 314 + * even if they use gss for everything else; see section 2.3.2 315 + * of rfc 2623. 316 + */ 317 + if (access & NFSD_MAY_BYPASS_GSS_ON_ROOT 318 + && exp->ex_path.dentry == dentry) 319 + goto skip_pseudoflavor_check; 315 320 321 + error = check_nfsd_access(exp, rqstp); 322 + if (error) 323 + goto out; 324 + 325 + skip_pseudoflavor_check: 316 326 /* Finally, check access permissions. */ 317 327 error = nfsd_permission(rqstp, exp, dentry, access); 318 328
+4 -2
fs/nfsd/nfsproc.c
··· 65 65 dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); 66 66 67 67 fh_copy(&resp->fh, &argp->fh); 68 - nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP); 68 + nfserr = fh_verify(rqstp, &resp->fh, 0, 69 + NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT); 69 70 return nfsd_return_attrs(nfserr, resp); 70 71 } 71 72 ··· 522 521 523 522 dprintk("nfsd: STATFS %s\n", SVCFH_fmt(&argp->fh)); 524 523 525 - nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats); 524 + nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 525 + NFSD_MAY_BYPASS_GSS_ON_ROOT); 526 526 fh_put(&argp->fh); 527 527 return nfserr; 528 528 }
+2 -2
fs/nfsd/vfs.c
··· 1866 1866 * N.B. After this call fhp needs an fh_put 1867 1867 */ 1868 1868 __be32 1869 - nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat) 1869 + nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat, int access) 1870 1870 { 1871 - __be32 err = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP); 1871 + __be32 err = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP | access); 1872 1872 if (!err && vfs_statfs(fhp->fh_dentry,stat)) 1873 1873 err = nfserr_io; 1874 1874 return err;
+2 -1
include/linux/nfsd/nfsd.h
··· 38 38 #define NFSD_MAY_LOCK 32 39 39 #define NFSD_MAY_OWNER_OVERRIDE 64 40 40 #define NFSD_MAY_LOCAL_ACCESS 128 /* IRIX doing local access check on device special file*/ 41 + #define NFSD_MAY_BYPASS_GSS_ON_ROOT 256 41 42 42 43 #define NFSD_MAY_CREATE (NFSD_MAY_EXEC|NFSD_MAY_WRITE) 43 44 #define NFSD_MAY_REMOVE (NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC) ··· 126 125 __be32 nfsd_readdir(struct svc_rqst *, struct svc_fh *, 127 126 loff_t *, struct readdir_cd *, filldir_t); 128 127 __be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *, 129 - struct kstatfs *); 128 + struct kstatfs *, int access); 130 129 131 130 int nfsd_notify_change(struct inode *, struct iattr *); 132 131 __be32 nfsd_permission(struct svc_rqst *, struct svc_export *,