The branch main has been updated by kevans: URL: https://cgit.FreeBSD.org/src/commit/?id=f61c48f4403fc8c69f9b933d3f1bd9663008b0eb
commit f61c48f4403fc8c69f9b933d3f1bd9663008b0eb Author: Kyle Evans <kev...@freebsd.org> AuthorDate: 2025-08-01 00:50:48 +0000 Commit: Kyle Evans <kev...@freebsd.org> CommitDate: 2025-08-01 00:50:48 +0000 kern: rename crsetgroups_fallback, document it in ucred(9) As of FreeBSD 15.0, crsetgroups() *only* sets supplementary groups, while crsetgroups_and_egid() will do both using an array of the same style that previous versions used for crsetgroups() -- i.e., the first element is the egid, and the remainder are supplementary groups. Unlike the previous iteration of crsetgroups(), crsetgroups_and_egid() is less prone to misuse as the caller must provide a default egid to use in case the array is empty. This is particularly useful for groups being set from data provided by userland. Reviewed by: olce Suggested by: olce Differential Revision: https://reviews.freebsd.org/D51647 --- share/man/man9/ucred.9 | 19 +++++++++++++++++-- sys/fs/nfs/nfs_commonport.c | 2 +- sys/fs/nfs/nfs_commonsubs.c | 2 +- sys/fs/nfsserver/nfs_nfsdport.c | 2 +- sys/fs/nfsserver/nfs_nfsdsocket.c | 2 +- sys/kern/kern_prot.c | 10 +++++----- sys/kern/vfs_export.c | 4 ++-- sys/rpc/rpcsec_gss/svc_rpcsec_gss.c | 2 +- sys/rpc/svc_auth.c | 4 ++-- sys/sys/ucred.h | 4 ++-- 10 files changed, 33 insertions(+), 18 deletions(-) diff --git a/share/man/man9/ucred.9 b/share/man/man9/ucred.9 index 16de37dd8b35..38759bddb5b0 100644 --- a/share/man/man9/ucred.9 +++ b/share/man/man9/ucred.9 @@ -54,6 +54,9 @@ .Ft void .Fn crsetgroups "struct ucred *cr" "int ngrp" "gid_t *groups" .Ft void +.Fn crsetgroups_and_egid "struct ucred *cr" "int ngrp" "gid_t *groups" \ + "gid_t default_egid" +.Ft void .Fn cru2x "struct ucred *cr" "struct xucred *xcr" .Sh DESCRIPTION The @@ -110,16 +113,28 @@ The actual copying is performed by .Pp The .Fn crsetgroups -function sets the +and +.Fn crsetgroups_and_egid +functions set the .Va cr_groups and .Va cr_ngroups variables and allocates space as needed. -It also truncates the group list to the current maximum number of +They also truncate the group list to the current maximum number of groups. No other mechanism should be used to modify the .Va cr_groups array. +Note that +.Fn crsetgroups_and_egid +will interpret the first element of +.Va groups +as the new effective GID and the rest of the array as the supplementary groups, +and +.Va default_egid +will be used as the new effective GID only if +.Va groups +is empty. .Pp The .Fn cru2x diff --git a/sys/fs/nfs/nfs_commonport.c b/sys/fs/nfs/nfs_commonport.c index e382b22fed74..e5fdb395c9f7 100644 --- a/sys/fs/nfs/nfs_commonport.c +++ b/sys/fs/nfs/nfs_commonport.c @@ -258,7 +258,7 @@ newnfs_copycred(struct nfscred *nfscr, struct ucred *cr) KASSERT(nfscr->nfsc_ngroups >= 0, ("newnfs_copycred: negative nfsc_ngroups")); cr->cr_uid = nfscr->nfsc_uid; - crsetgroups_fallback(cr, nfscr->nfsc_ngroups, nfscr->nfsc_groups, + crsetgroups_and_egid(cr, nfscr->nfsc_ngroups, nfscr->nfsc_groups, GID_NOGROUP); } diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c index a957315aaa12..4ffc4ce5c29f 100644 --- a/sys/fs/nfs/nfs_commonsubs.c +++ b/sys/fs/nfs/nfs_commonsubs.c @@ -4143,7 +4143,7 @@ nfssvc_idname(struct nfsd_idargs *nidp) */ cr = crget(); cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid; - crsetgroups_fallback(cr, nidp->nid_ngroup, grps, + crsetgroups_and_egid(cr, nidp->nid_ngroup, grps, GID_NOGROUP); cr->cr_rgid = cr->cr_svgid = cr->cr_gid; cr->cr_prison = curthread->td_ucred->cr_prison; diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c index 9e1a198bf34a..8c427c66c156 100644 --- a/sys/fs/nfsserver/nfs_nfsdport.c +++ b/sys/fs/nfsserver/nfs_nfsdport.c @@ -3466,7 +3466,7 @@ nfsd_excred(struct nfsrv_descript *nd, struct nfsexstuff *exp, nd->nd_cred->cr_gid = credanon->cr_gid; /* * 'credanon' is already a 'struct ucred' that was built - * internally with calls to crsetgroups_fallback(), so + * internally with calls to crsetgroups_and_egid(), so * we don't need a fallback here. */ crsetgroups(nd->nd_cred, credanon->cr_ngroups, diff --git a/sys/fs/nfsserver/nfs_nfsdsocket.c b/sys/fs/nfsserver/nfs_nfsdsocket.c index d1b6198ba0e1..d6832b4f74be 100644 --- a/sys/fs/nfsserver/nfs_nfsdsocket.c +++ b/sys/fs/nfsserver/nfs_nfsdsocket.c @@ -1425,7 +1425,7 @@ nfsrv_createrootcred(void) cr = crget(); cr->cr_uid = cr->cr_ruid = cr->cr_svuid = UID_ROOT; - crsetgroups_fallback(cr, 0, NULL, GID_WHEEL); + crsetgroups_and_egid(cr, 0, NULL, GID_WHEEL); cr->cr_rgid = cr->cr_svgid = cr->cr_gid; cr->cr_prison = curthread->td_ucred->cr_prison; prison_hold(cr->cr_prison); diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c index 632be229af5b..6bdef84a34c1 100644 --- a/sys/kern/kern_prot.c +++ b/sys/kern/kern_prot.c @@ -2928,19 +2928,19 @@ crsetgroups(struct ucred *cr, int ngrp, const gid_t *groups) } /* - * Same as crsetgroups() but accepts an empty groups array. + * Same as crsetgroups() but sets the effective GID as well. * * This function ensures that an effective GID is always present in credentials. - * An empty array will only set the effective GID to the fallback, while a + * An empty array will only set the effective GID to the default_egid, while a * non-empty array will peel off groups[0] to set as the effective GID and use * the remainder, if any, as supplementary groups. */ void -crsetgroups_fallback(struct ucred *cr, int ngrp, const gid_t *groups, - const gid_t fallback) +crsetgroups_and_egid(struct ucred *cr, int ngrp, const gid_t *groups, + const gid_t default_egid) { if (ngrp == 0) { - cr->cr_gid = fallback; + cr->cr_gid = default_egid; cr->cr_ngroups = 0; cr->cr_flags |= CRED_FLAG_GROUPSET; return; diff --git a/sys/kern/vfs_export.c b/sys/kern/vfs_export.c index a314bda164de..bd7caa01e153 100644 --- a/sys/kern/vfs_export.c +++ b/sys/kern/vfs_export.c @@ -134,7 +134,7 @@ vfs_hang_addrlist(struct mount *mp, struct netexport *nep, np->netc_exflags = argp->ex_flags; np->netc_anon = crget(); np->netc_anon->cr_uid = argp->ex_uid; - crsetgroups_fallback(np->netc_anon, argp->ex_ngroups, + crsetgroups_and_egid(np->netc_anon, argp->ex_ngroups, argp->ex_groups, GID_NOGROUP); np->netc_anon->cr_prison = &prison0; prison_hold(np->netc_anon->cr_prison); @@ -213,7 +213,7 @@ vfs_hang_addrlist(struct mount *mp, struct netexport *nep, np->netc_exflags = argp->ex_flags; np->netc_anon = crget(); np->netc_anon->cr_uid = argp->ex_uid; - crsetgroups_fallback(np->netc_anon, argp->ex_ngroups, argp->ex_groups, + crsetgroups_and_egid(np->netc_anon, argp->ex_ngroups, argp->ex_groups, GID_NOGROUP); np->netc_anon->cr_prison = &prison0; prison_hold(np->netc_anon->cr_prison); diff --git a/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c b/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c index b1790dd167d5..51077c71822c 100644 --- a/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c +++ b/sys/rpc/rpcsec_gss/svc_rpcsec_gss.c @@ -537,7 +537,7 @@ rpc_gss_svc_getcred(struct svc_req *req, struct ucred **crp, int *flavorp) cr = client->cl_cred = crget(); cr->cr_uid = cr->cr_ruid = cr->cr_svuid = uc->uid; cr->cr_rgid = cr->cr_svgid = uc->gid; - crsetgroups_fallback(cr, uc->gidlen, uc->gidlist, uc->gid); + crsetgroups_and_egid(cr, uc->gidlen, uc->gidlist, uc->gid); cr->cr_prison = curthread->td_ucred->cr_prison; prison_hold(cr->cr_prison); *crp = crhold(cr); diff --git a/sys/rpc/svc_auth.c b/sys/rpc/svc_auth.c index 838fa9ed313a..acbb1112e270 100644 --- a/sys/rpc/svc_auth.c +++ b/sys/rpc/svc_auth.c @@ -192,7 +192,7 @@ svc_getcred(struct svc_req *rqst, struct ucred **crp, int *flavorp) return (FALSE); cr = crget(); cr->cr_uid = cr->cr_ruid = cr->cr_svuid = xprt->xp_uid; - crsetgroups_fallback(cr, xprt->xp_ngrps, xprt->xp_gidp, GID_NOGROUP); + crsetgroups_and_egid(cr, xprt->xp_ngrps, xprt->xp_gidp, GID_NOGROUP); cr->cr_rgid = cr->cr_svgid = cr->cr_gid; cr->cr_prison = curthread->td_ucred->cr_prison; prison_hold(cr->cr_prison); @@ -207,7 +207,7 @@ svc_getcred(struct svc_req *rqst, struct ucred **crp, int *flavorp) return (FALSE); cr = crget(); cr->cr_uid = cr->cr_ruid = cr->cr_svuid = xcr->cr_uid; - crsetgroups_fallback(cr, xcr->cr_ngroups, xcr->cr_groups, GID_NOGROUP); + crsetgroups_and_egid(cr, xcr->cr_ngroups, xcr->cr_groups, GID_NOGROUP); cr->cr_rgid = cr->cr_svgid = cr->cr_gid; cr->cr_prison = curthread->td_ucred->cr_prison; prison_hold(cr->cr_prison); diff --git a/sys/sys/ucred.h b/sys/sys/ucred.h index cd4efcb71c0d..9c1d8545af34 100644 --- a/sys/sys/ucred.h +++ b/sys/sys/ucred.h @@ -242,8 +242,8 @@ void crcowfree(struct thread *td); void cru2x(struct ucred *cr, struct xucred *xcr); void cru2xt(struct thread *td, struct xucred *xcr); void crsetgroups(struct ucred *cr, int ngrp, const gid_t *groups); -void crsetgroups_fallback(struct ucred *cr, int ngrp, const gid_t *groups, - const gid_t fallback); +void crsetgroups_and_egid(struct ucred *cr, int ngrp, const gid_t *groups, + const gid_t default_egid); bool cr_xids_subset(struct ucred *active_cred, struct ucred *obj_cred); /*