Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

There may be cases where the desired privilege drops are unsuccessful. For example, the range of Linux Kernel versions (2.2.0-2.2.15) was is vulnerable to an insufficient privilege attack wherein setuid(getuid()) did not drop privileges as expected when the capability bits were set to zero. As a precautionary measure, subtle behavior and error conditions for the targeted implementation must be carefully noted.

Non-Compliant Code Example

The following non-compliant code snippet example compiles cleanly on most POSIX based systems, however no explicit checks have been made to vouchsafe that privilege relinquishment will be is carried out successfully. This may be dangerous depending on the sequence of the preceding privilege changes.

...

Code Block
bgColor#ccccff

/*  Code intended to run with elevated privileges  */

setuid(getuid());

if  (setuid(0) == -1) {    /*  setuid returns -1 on error  */
{
   /* Setuid failed, handle error */
}

/*  Code intended to run with lower privileges  */ 

Non-Compliant Code Example

The function shown below in this non-compliant code example correctly follows the principle of least privilege, however, due to inconsistencies and implementation defined behavior of certain functions (such as setuid()) across various Operating Systems, the final result may be unexpected. Here, when privileges are given up temporarily for the final time, the effective User ID of the process is set to the real user ID. Unexpectedly, the call to setuid(realuid) that follows, does not affect the saved set-user-ID since effective UID is no longer 0 (Except on FreeBSD and NetBSD). If a seteuid(0) gets executed maliciously after this statement, root privileges would be recovered from the saved set-user-ID.

Code Block
bgColor#ffcccc

void doSomething(void)
 {
  uid_t realuid = getuid();
  seteuid(realuid);      /* Give up privileges temporarily  */
  
  seteuid(0);            /* Regain superuser privileges  */

  /* Carry out the privileged task */ 

  seteuid(realuid);      /* Give up privileges temporarily */
 
  setuid(realuid);       /* Failed attempt at giving up privileges permanently */
}

...

Code Block
bgColor#ccccff

void doSomething(void)
 {
  uid_t realuid = getuid();
  seteuid(realuid);      /* Give up privileges temporarily */
  
  seteuid(0);            /* Regain superuser privileges */

  /* Carry out privileged task */ 

  seteuid(realuid);      /* Give up privileges temporarily */
 
  if (!geteuid()) {         /*  Check if the effective uid is still that of the superuser  */
    setuid(realuid);     /*  Go ahead and give up privileges permanently  */
  else}
  else {
      /* Handle the possible implementation defined behavior */
  } 

}

Risk Assessment

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.

...

Wiki Markup
\[[CWE - 273|AA. C References#CWE - 273]\] [Failure to Check Whether Privileges Were Dropped Successfully | http://cwe.mitre.org/data/definitions/273.html]
Wiki Markup

\[[Dowd 06|AA. C References#Dowd 06]\] Chapter 9, "Unix I: Privileges and Files"
\[[Wheeler 03|AA. C References#Wheeler 03]\] [Section 7.4, "Minimize Privileges"|http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/minimize-privileges.html]
Wiki Markup
\[[Dowd 06|AA. C References#Dowd 06]\] Chapter 9, "Unix I: Privileges and Files"

...

      50. POSIX (POS)       CERT C Secure Coding Standard