From nobody Wed Sep 30 09:06:56 2026 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4hvq1D3QtBz6v5m4 for ; Wed, 30 Sep 2026 09:06:56 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR2" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hvq1D2wyGz3FSn for ; Wed, 30 Sep 2026 09:06:56 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1790759216; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=lfEXnwv8ta1Vz01ZS2cgpUvodna9xkqEpSqkjBeqhL0=; b=i1UqDIdTyKofdAhel2CXND1CE/OIKoTf6cY6MdwjYzWLQ9R4FMxG9ArN+ULdEt1JZ+J7oV E8gWv5BArTwMXy8ZyzT1QxbHzWhYurxtLhQwlFgj3SMtrSsOmvXfJ+nhvutIrG5s3qnjMN mdBEveUD0QumRS7Ma4E/N9FmQohfQUQ1PLVlbfnpqjiuPq52EKt1590fjiGBo1CQb6cHyv Ksic/I+FXbuz6jpelZuMfZo4JFKouGgAosz76NeqIViQDP0e+a9AeiTOBGjODeYDDARq8Z nsju0HV1GevHx0I4FQ3MAVl8aH+RDULGsCkWjd9SYzwy8RPlgd/6pzqbOQpSlQ== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1790759216; b=EFV1gHyDPVWg51uA7qChSw5dkhwEQPrymYoXZkHsrlRcL+y0GPtNOkHsnkblWGu6mda2MZ I17/5/0foawgsZGWdbi+VRtwTHhJQ8OjElfb3vospjNRR78Y0rbfc8dQeC8BsAkR9Z5r4R hNpaWmzVYJMWVO/cCaCOhQXJ0OL45qZ/vN2JDTZwejbmbiylMxVlzJ1md9TejYfs9Lmobv BjKgM0oLs3iYMbsasBUATnRt9+oDbo6wxLIrje2lvCWajW8cLCYRal65YnXoyzS+hQSB8z 8ee9PAWwWaet4n4qzQatQ+j03xKJxqbRfzAyNDoD6kNbyk3uJNHgkFftM4OaVw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1790759216; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=lfEXnwv8ta1Vz01ZS2cgpUvodna9xkqEpSqkjBeqhL0=; b=yL15zrwNyL3qr14KgWD4E5r9fax4S7wEs2vaeiPdXk64YpyASprPoHTK8Xy4oEbA3gajE1 5L8fB0Sggq3rNdaqdlTjI1xs5V2YBiCLPy6eAgQHUWEeuIRb1mCE8pNZF+xvgyuezdy02T UQtAmwhlw87VKZmI53lLAGHxKpxf7dUctJdUxGT13KxDLIKGSLTFDxVZ+F1bXHrtxC1r48 rHOU+J730zXSpilxVNCpnG8G7/Jr6rFpOHWK6bmZtwOjCfy48pUE9RltOLgHGjt4kvLSZ7 Butf3mrU5MYtLZwnjeqtfb6ESY4gWZWagAygIJNyu67KGP0RcBtiuWc9cRZotA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hvq1D20Pjzg72 for ; Wed, 30 Sep 2026 09:06:56 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 30281 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Wed, 30 Sep 2026 09:06:56 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Olivier Certner Subject: git: e6fbef451dd4 - main - cred: Fix a race in the FreeBSD-14-compatible setgroups(2) List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: olce X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: e6fbef451dd45159071a1b234cd13c66fbb654fa Auto-Submitted: auto-generated Date: Wed, 30 Sep 2026 09:06:56 +0000 Message-Id: <6abcd130.30281.43f89845@gitrepo.freebsd.org> The branch main has been updated by olce: URL: https://cgit.FreeBSD.org/src/commit/?id=e6fbef451dd45159071a1b234cd13c66fbb654fa commit e6fbef451dd45159071a1b234cd13c66fbb654fa Author: Olivier Certner AuthorDate: 2026-09-25 17:27:25 +0000 Commit: Olivier Certner CommitDate: 2026-09-30 09:05:02 +0000 cred: Fix a race in the FreeBSD-14-compatible setgroups(2) The freebsd14_setgroups() function would try to modify the effective GID on the current process' credentials without holding the process lock, allowing races with other threads concurrently modifying the process credentials. In the worst case, freebsd14_setgroups() could be manipulating a 'struct ucred' already freed by another thread (in the very small window after reading 'p_ucred' without lock but before modifying the effective GID). Concurrent uses of freebsd14_setgroups() or setcred() could also lead to non-atomic credentials modifications. Fix this by making kern_setgroups() take a new boolean indicating whether the passed array includes the effective GID in its first slot. When this boolean is true, it internally keeps the effective GID in a separate variable, pretends that the groups[] array that was passed actually starts at 'groups + 1', do the usual steps to set the supplementary groups and new extra ones to set the effective GID along, without releasing the process lock in between. Reported by: markj Reviewed by: markj MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D60028 --- sys/kern/kern_prot.c | 58 ++++++++++++++++++++++++++++++++++++++------------- sys/sys/syscallsubr.h | 3 ++- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c index 5370028f4490..bfb95508b64e 100644 --- a/sys/kern/kern_prot.c +++ b/sys/kern/kern_prot.c @@ -1219,9 +1219,7 @@ freebsd14_setgroups(struct thread *td, struct freebsd14_setgroups_args *uap) /* * Before FreeBSD 15.0, we allow one more group to be supplied to - * account for the egid appearing before the supplementary groups. This - * may technically allow one more supplementary group for systems that - * did use the default NGROUPS_MAX if we round it back up to 1024. + * account for the egid appearing before the supplementary groups. */ gidsetsize = uap->gidsetsize; if (gidsetsize > ngroups_max + 1 || gidsetsize < 0) @@ -1234,11 +1232,9 @@ freebsd14_setgroups(struct thread *td, struct freebsd14_setgroups_args *uap) error = copyin(uap->gidset, groups, gidsetsize * sizeof(gid_t)); if (error == 0) { - int ngroups = gidsetsize > 0 ? gidsetsize - 1 /* egid */ : 0; + int ngroups = gidsetsize; - error = kern_setgroups(td, &ngroups, groups + 1); - if (error == 0 && gidsetsize > 0) - td->td_proc->p_ucred->cr_gid = groups[0]; + error = kern_setgroups(td, &ngroups, groups, true); } if (groups != smallgroups) @@ -1281,7 +1277,7 @@ sys_setgroups(struct thread *td, struct setgroups_args *uap) error = copyin(uap->gidset, groups, gidsetsize * sizeof(gid_t)); if (error == 0) - error = kern_setgroups(td, &gidsetsize, groups); + error = kern_setgroups(td, &gidsetsize, groups, false); if (groups != smallgroups) free(groups, M_TEMP); @@ -1289,25 +1285,43 @@ sys_setgroups(struct thread *td, struct setgroups_args *uap) } /* - * CAUTION: This function normalizes 'groups', possibly also changing the value - * of '*ngrpp' as a consequence. + * 'includes_egid' indicates that the first element of groups[] (if any) is the + * desired effective GID and that only the other elements will be used to set + * the supplementary groups. If true, and groups[] is empty, the effective GID + * is left unchanged and all supplementary groups deleted (see setgroups(2)). + * + * CAUTION: This function normalizes 'groups' (only the supplementary groups on + * 'includes_egid') and may need to update the value of '*ngrpp' as + * a consequence. */ int -kern_setgroups(struct thread *td, int *ngrpp, gid_t *groups) +kern_setgroups(struct thread *td, int *ngrpp, gid_t *groups, bool includes_egid) { struct proc *p = td->td_proc; struct ucred *newcred, *oldcred; + gid_t egid; int ngrp, error; ngrp = *ngrpp; /* Sanity check size. */ - if (ngrp < 0 || ngrp > ngroups_max) + if (ngrp < 0 || ngrp > (includes_egid ? ngroups_max + 1 : ngroups_max)) return (EINVAL); + if (includes_egid) { + if (ngrp > 0) { + egid = groups[0]; + groups++; + ngrp--; + } else + includes_egid = false; + } + AUDIT_ARG_GROUPSET(groups, ngrp); + if (includes_egid) + AUDIT_ARG_EGID(egid); groups_normalize(&ngrp, groups); - *ngrpp = ngrp; + *ngrpp = includes_egid ? ngrp + 1 : ngrp; newcred = crget(); crextend(newcred, ngrp); @@ -1324,15 +1338,29 @@ kern_setgroups(struct thread *td, int *ngrpp, gid_t *groups) */ error = mac_cred_check_setgroups(oldcred, ngrp, ngrp == 0 ? NULL : groups); - if (error) + if (error != 0) goto fail; + + if (includes_egid) { + error = mac_cred_check_setegid(oldcred, egid); + if (error != 0) + goto fail; + } #endif error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS); - if (error) + if (error != 0) goto fail; + if (includes_egid) { + error = priv_check_cred(oldcred, PRIV_CRED_SETEGID); + if (error != 0) + goto fail; + } + crsetgroups_internal(newcred, ngrp, groups); + if (includes_egid) + change_egid(newcred, egid); setsugid(p); proc_set_cred(p, newcred); PROC_UNLOCK(p); diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h index d767ba29cdf6..d55426cf7d98 100644 --- a/sys/sys/syscallsubr.h +++ b/sys/sys/syscallsubr.h @@ -365,7 +365,8 @@ int kern_sendit(struct thread *td, int s, struct msghdr *mp, int flags, struct mbuf *control, enum uio_seg segflg); int kern_setcred(struct thread *const td, const u_int flags, struct setcred *const wcred); -int kern_setgroups(struct thread *td, int *ngrpp, gid_t *groups); +int kern_setgroups(struct thread *td, int *ngrpp, gid_t *groups, + bool includes_egid); int kern_setitimer(struct thread *, u_int, struct itimerval *, struct itimerval *); int kern_setpriority(struct thread *td, int which, int who, int prio);