kern: fix setgroups(2) and getgroups(2) to match other platforms

On most other platforms observed, including OpenBSD, NetBSD, and Linux,
these system calls have long since been converted to only touching the
supplementary groups of the process.  This poses both portability and
security concerns in porting software to and from FreeBSD, as this
subtle difference is a landmine waiting to happen.  Bugs have been
discovered even in FreeBSD-local sources, since this behavior is
somewhat unintuitive (see, e.g., fix 48fd05999b for chroot(8)).

Now that the egid is tracked outside of cr_groups in our ucred, convert
the syscalls to deal with only supplementary groups.  Some remaining
stragglers in base that had baked in assumptions about these syscalls
are fixed in the process to avoid heartburn in conversion.

For relnotes: application developers should audit their use of both
setgroups(2) and getgroups(2) for signs that they had assumed the
previous FreeBSD behavior of using the first element for the egid.  Any
calls to setgroups() to clear groups that used a single array of the
now or soon-to-be egid can be converted to setgroups(0, NULL) calls to
clear the supplementary groups entirely on all FreeBSD versions.

Co-authored-by:	olce (but bugs are likely mine)
Relnotes:	yes (see last paragraph)
Reviewed by:	kib
Differential Revision:	https://reviews.freebsd.org/D51648
This commit is contained in:
Kyle Evans
2025-08-14 23:06:09 -05:00
parent c75550e499
commit 9da2fe96ff
11 changed files with 145 additions and 98 deletions
+3
View File
@@ -69,6 +69,9 @@ __sym_compat(kevent, freebsd11_kevent, FBSD_1.0);
__sym_compat(swapoff, freebsd13_swapoff, FBSD_1.0);
__sym_compat(getgroups, freebsd14_getgroups, FBSD_1.0);
__sym_compat(setgroups, freebsd14_setgroups, FBSD_1.0);
#undef __sym_compat
#define __weak_reference(sym,alias) \
+2 -2
View File
@@ -89,7 +89,6 @@ FBSD_1.0 {
geteuid;
getfh;
getgid;
getgroups;
getitimer;
getpagesize;
getpeername;
@@ -204,7 +203,6 @@ FBSD_1.0 {
setegid;
seteuid;
setgid;
setgroups;
setitimer;
setlogin;
setpgid;
@@ -380,11 +378,13 @@ FBSD_1.7 {
FBSD_1.8 {
exterrctl;
fchroot;
getgroups;
getrlimitusage;
inotify_add_watch_at;
inotify_rm_watch;
kcmp;
setcred;
setgroups;
};
FBSDprivate_1.0 {
+11 -4
View File
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd January 21, 2011
.Dd August 1, 2025
.Dt GETGROUPS 2
.Os
.Sh NAME
@@ -41,8 +41,8 @@
The
.Fn getgroups
system call
gets the current group access list of the user process
and stores it in the array
gets the current supplementary groups of the user process and stores it in the
array
.Fa gidset .
The
.Fa gidsetlen
@@ -54,7 +54,7 @@ The
system call
returns the actual number of groups returned in
.Fa gidset .
At least one and as many as {NGROUPS_MAX}+1 values may be returned.
As many as {NGROUPS_MAX} values may be returned.
If
.Fa gidsetlen
is zero,
@@ -102,3 +102,10 @@ The
.Fn getgroups
system call appeared in
.Bx 4.2 .
.Pp
Before
.Fx 15.0 ,
the
.Fn getgroups
system call always returned the effective group ID for the process as the first
element of the array, before the supplementary groups.
+15 -21
View File
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd January 19, 2018
.Dd August 1, 2025
.Dt SETGROUPS 2
.Os
.Sh NAME
@@ -42,7 +42,7 @@
The
.Fn setgroups
system call
sets the group access list of the current user process
sets the supplementary group list of the current user process
according to the array
.Fa gidset .
The
@@ -50,26 +50,12 @@ The
argument
indicates the number of entries in the array and must be no
more than
.Dv {NGROUPS_MAX}+1 .
.Dv {NGROUPS_MAX} .
The
.Fa ngroups
argument may be set to 0 to clear the supplementary group list.
.Pp
Only the super-user may set a new group list.
.Pp
The first entry of the group array
.Pq Va gidset[0]
is used as the effective group-ID for the process.
This entry is over-written when a setgid program is run.
To avoid losing access to the privileges of the
.Va gidset[0]
entry, it should be duplicated later in the group array.
By convention,
this happens because the group value indicated
in the password file also appears in
.Pa /etc/group .
The group value in the password file is placed in
.Va gidset[0]
and that value then gets added a second time when the
.Pa /etc/group
file is scanned to create the group set.
Only the super-user may set a new supplementary group list.
.Sh RETURN VALUES
.Rv -std setgroups
.Sh ERRORS
@@ -99,3 +85,11 @@ The
.Fn setgroups
system call appeared in
.Bx 4.2 .
.Pp
Before
.Fx 15.0 ,
the
.Fn setgroups
system call would set the effective group ID for the process to the first
element of
.Fa gidset .