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 its field). 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 the extra ones to set the effective GID along,
without releasing the process lock in between.
Reported by: markj