...
If the program is run as a setuid root program, over time, the state of the UIDs might look like the following:
Description | Code | EUID | RUID | SSUID |
---|
Program startup |
0 |
User | 0 |
Temporary drop |
|
User |
User | 0 |
Restore |
| 0 |
User | 0 |
Permanent drop |
|
User |
User |
User |
Restore (attacker) |
|
User |
User |
User |
If the program fails to restore privileges, it will be unable to permanently drop them later:
Description | Code | EUID | RUID | SSUID |
---|---|---|---|---|
program startup |
0 |
User | 0 |
Temporary drop |
|
User |
User | 0 |
Restore |
|
User |
User | 0 |
Permanent drop |
|
User |
User | 0 |
Restore (attacker) |
| 0 | 0 | 0 |
Compliant Solution
This compliant solution was implemented in sendmail, a popular mail transfer agent, to determine if superuser privileges were successfully dropped [Wheeler 2003]. If the setuid()
call succeeds after (supposedly) dropping privileges permanently, then the privileges were not dropped as intended.
...
A better solution is to ensure that proper privileges exist before attempting to perform a permanent drop.:
Code Block | ||||
---|---|---|---|---|
| ||||
/* Store the privileged ID for later verification */ uid_t privid = geteuid(); /* Code intended to run with elevated privileges */ /* Temporarily drop privileges */ if (seteuid(getuid()) != 0) { /* Handle error */ } /* Code intended to run with lower privileges */ if (need_more_privileges) { /* Restore Privileges */ if (seteuid(privid) != 0) { /* Handle error */ } /* Code intended to run with elevated privileges */ } /* ... */ /* Restore privileges if needed */ if (geteuid() != privid) { if (seteuid(privid) != 0) { /* Handle error */ } } /* Permanently drop privileges */ if (setuid(getuid()) != 0) { /* Handle error */ } if (setuid(0) != -1) { /* Privileges can be restored, handle error */ } /* * Code intended to run with lower privileges; * attacker cannot regain elevated privileges */ |
...
If privilege relinquishment conditions are left unchecked, any flaw in the program may lead to unintended system compromise corresponding to the more privileged user or group account.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
POS37-C | high | probable | low | P18 | L1 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Astrée |
| user_defined | Soundly supported | ||||||
Axivion Bauhaus Suite |
| CertC-POS37 | |||||||
Helix QAC |
| DF4876, DF4877, DF4878 | |||||||
Klocwork |
| SV. |
SV.USAGERULES.PERMISSIONS
USAGERULES.PERMISSIONS | |||||||||
Parasoft C/C++test |
| CERT_C-POS37-a | Ensure that privilege relinquishment is successful | ||||||
| CERT C: Rule POS37-C | Checks for priviledge drop not verified (rule fully covered) |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
Key here (explains table format and definitions)
Taxonomy | Taxonomy item | Relationship |
---|---|---|
ISO/IEC |
...
MITRE CWE: CWE-250, "Execution with unnecessary privileges"
...
TR 24772 | Privilege Sandbox Issues [XYO] | Prior to 2018-01-12: CERT: Unspecified Relationship |
CWE 2.11 | CWE-273, |
...
Failure to check whether privileges were dropped successfully |
...
2017-07-07: CERT: Exact |
Bibliography
...
[Chen 2002] | "Setuid Demystified" |
[Dowd 2006] | Chapter 9, "Unix I: Privileges and Files" |
[Open Group 2004] | setuid() |
...
...
seteuid() | |
[Tsafrir 2008] | "The Murky Issue of Changing Process Identity: Revising 'Setuid Demystified'" |
[Wheeler 2003] | Section 7.4, "Minimize |
...
...