git: f6e1add0c9d3 - stable/14 - nfsd: Fix handling of credentials with cr_ngroups == 0

From: Rick Macklem <rmacklem_at_FreeBSD.org>
Date: Thu, 24 Oct 2024 01:07:32 UTC
The branch stable/14 has been updated by rmacklem:

URL: https://cgit.FreeBSD.org/src/commit/?id=f6e1add0c9d3a3629f6968cb02a031c1d78b24c5

commit f6e1add0c9d3a3629f6968cb02a031c1d78b24c5
Author:     Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2024-10-21 22:48:39 +0000
Commit:     Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2024-10-24 01:06:26 +0000

    nfsd: Fix handling of credentials with cr_ngroups == 0
    
    There has been a documented case in the exports(5) man
    page forever, which specifies that the -maproot or -mapall
    may have a single user entry, followed by a ':'.
    This case is defined as specifying no groups (aka cr_ngroups == 0).
    
    This patch fixes the NFS server so that it handles this case correctly.
    
    After MFC'ng this patch to stable/13 and stable/14, I propose that
    this unusual case be deprecated and no longer allowed in FreeBSD15.
    At that point, this patch can be reverted.
    
    (cherry picked from commit caa309c8811d62a24cd07e3a1f6e9095eaf10c90)
---
 sys/fs/nfsserver/nfs_nfsdsubs.c | 5 ++---
 sys/kern/kern_prot.c            | 7 +++++++
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/sys/fs/nfsserver/nfs_nfsdsubs.c b/sys/fs/nfsserver/nfs_nfsdsubs.c
index d80826993f23..2fd877775c79 100644
--- a/sys/fs/nfsserver/nfs_nfsdsubs.c
+++ b/sys/fs/nfsserver/nfs_nfsdsubs.c
@@ -1620,7 +1620,7 @@ nfsrv_checkuidgid(struct nfsrv_descript *nd, struct nfsvattr *nvap)
 	if (nd->nd_cred->cr_uid == 0)
 		goto out;
 	if ((NFSVNO_ISSETUID(nvap) && nvap->na_uid != nd->nd_cred->cr_uid) ||
-	    (NFSVNO_ISSETGID(nvap) && nvap->na_gid != nd->nd_cred->cr_gid &&
+	    (NFSVNO_ISSETGID(nvap) &&
 	    !groupmember(nvap->na_gid, nd->nd_cred)))
 		error = NFSERR_PERM;
 
@@ -1679,8 +1679,7 @@ nfsrv_fixattr(struct nfsrv_descript *nd, vnode_t vp,
 	}
 	if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_OWNERGROUP) &&
 	    NFSVNO_ISSETGID(nvap)) {
-		if (nvap->na_gid == nd->nd_cred->cr_gid ||
-		    groupmember(nvap->na_gid, nd->nd_cred)) {
+		if (groupmember(nvap->na_gid, nd->nd_cred)) {
 			nd->nd_cred->cr_uid = 0;
 			nva.na_gid = nvap->na_gid;
 			change++;
diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c
index 7d28475b5db8..d7de7deb2c0c 100644
--- a/sys/kern/kern_prot.c
+++ b/sys/kern/kern_prot.c
@@ -1310,6 +1310,13 @@ bool
 groupmember(gid_t gid, struct ucred *cred)
 {
 
+	/*
+	 * The nfsd server can use a credential with zero groups in it
+	 * when certain mapped export credentials are specified via exports(5).
+	 */
+	if (cred->cr_ngroups == 0)
+		return (false);
+
 	if (gid == cred->cr_groups[0])
 		return (true);