In case of set-user-ID and set-group-ID programs, when the effective user ID and group ID are different from those of the real user, it is important to drop not only the user-level privileges but also the group privileges. While doing so, the order of revocation must be correct.
setgid() to have the following behavior [Open Group 2004]:
If the process has appropriate privileges,
setgid()shall set the real group ID, effective group ID, and the saved set-group-ID of the calling process to
If the process does not have appropriate privileges, but
gidis equal to the real group ID or the saved set-group-ID,
setgid()shall set the effective group ID to
gid; the real group ID and saved set-group-ID shall remain unchanged.
Noncompliant Code Example
This noncompliant code example drops privileges to those of the real user and similarly drops the group privileges. However, the order is incorrect because the
setgid() function must be run with superuser privileges, but the call to
setuid() leaves the effective user ID as nonzero. As a result, if a vulnerability is discovered in the program that allows for the execution of arbitrary code, an attacker can regain the original group privileges.
This compliant solution relinquishes group privileges before taking away the user-level privileges so that both operations execute as intended.
Supplementary Group IDs
A process may have a number of supplementary group IDs in addition to its effective group ID, and the supplementary groups can allow privileged access to files. The
getgroups() function returns an array that contains the supplementary group IDs and may also contain the effective group ID. The
setgroups() function can set the supplementary group IDs and may also set the effective group ID on some systems. Using
setgroups() usually requires privileges. Although POSIX defines the
getgroups() function, it does not define
Under normal circumstances,
setuid() and related calls do not alter the supplementary group IDs. However, a setuid-root program can alter its supplementary group IDs and then relinquish root privileges, in which case it maintains the supplementary group IDs but lacks the privilege necessary to relinquish them. Consequently, it is recommended that a program relinquish supplementary group IDs immediately before relinquishing root privileges. The following code defines a
set_sups() function that will set the supplementary group IDs to a specific array on systems that support the
Failing to observe the correct revocation order while relinquishing privileges allows an attacker to regain elevated privileges.
|Axivion Bauhaus Suite|
Can detect some violations of this rule. In particular, it warns when calls to
DF4891, DF4892, DF4893
Observe correct revocation order while relinquishing privileges
|CERT C: Rule POS36-C||Checks for bad order of dropping privileges (rule fully covered)|
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Key here (explains table format and definitions)
|ISO/IEC TR 24772||Privilege Sandbox Issues [XYO]||Prior to 2018-01-12: CERT: Unspecified Relationship|
|CWE 2.11||CWE-696, Incorrect behavior order||2017-07-07: CERT: Rule subset of CWE|
CERT-CWE Mapping Notes
Key here for mapping notes
CWE-696 and POS36-C
CWE-696 = Union( POS36-C, list) where list =
- Misordered executions besides dropping group privileges before dropping user privileges
|[Chen 2002]||"Setuid Demystified"|
|[Dowd 2006]||Chapter 9, "UNIX I: Privileges and Files"|
|[Open Group 2004]|
|[Tsafrir 2008]||"The Murky Issue of Changing Process Identity: Revising 'Setuid Demystified'"|