Versions Compared

Key

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

Wiki Markup
The POSIX {{setuid()}} function has complex semantics and platform-specific behavior  \[[Open Group 04|AA. C References#Open Group 04]\].

If the process has appropriate privileges, setuid() shall set the real user ID, effective user ID, and the saved set-user-ID of the calling process to uid.

If the process does not have appropriate privileges, but uid is equal to the real user ID or the saved set-user-ID, setuid() shall set the effective user ID to uid; the real user ID and saved set-user-ID shall remain unchanged.

...

This non-compliant code example compiles cleanly on most POSIX systems, however but no explicit checks have been made to ensure that privilege relinquishment has succeeded. This may be dangerous depending on the sequence of the preceding privilege changes.

Code Block
bgColor#ffcccc
/*  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(0) != 0) {
    /* Handle Error */
  }

  /*  Code intended to run with elevated privileges   */
}

/* ... */

/* Permanently drop privileges */
if (setuid(getuid()) != 0) {
  /* Handle Error */
}

/*  Code intended to run with lower privileges,
    but if privilege relinquishment failed, 
    attacker could regain elevated privelegesprivileges! */

If the program is run with as a setuid root program, the state of the UID's over time might be as follows:

Description

Code

EUID

RUID

SSUID

program startup

 

0

user

0

temporary drop

seteuid(getuid())

user

user

0

restore

seteuid(0)

0

user

0

permanent drop

setuid(getuid())

user

user

user

restore (attacker)

setuid(0) (fails)

user

user

user

...

Description

Code

EUID

RUID

SSUID

program startup

 

0

user

0

temporary drop

seteuid(getuid())

user

user

0

restore

}}{{{}seteuid(0)

user

user

0

permanent drop

setuid(getuid())

user

user

0

restore (attacker)

setuid(0)

0

0

0

...

Wiki Markup
This compliant solution was implemented in sendmail, a popular mail transfer agent, to determine if superuser privileges were successfully dropped \[[Wheeler 03|AA. C References#Wheeler 03]\]. If the {{setuid()}} call succeeds after (supposedly) dropping privileges permanently , privileges were not dropped as intended.

Code Block
bgColor#ccccff
/*  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(0) != 0) {
    /* Handle error */
  }

  /*  Code intended to run with elevated privileges   */
}

/* ... */

/* 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 cancannot not regain elevated privileges */

...

Code Block
bgColor#ccccff
/* 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 can notcannot regain elevated privileges */

...

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

References

Wiki Markup
\[[CWEMITRE - 27307|AA. C References#CWEReferences#MITRE - 27307]\] CWE-273, [Failure to Check Whether Privileges Were Dropped Successfully | http://cwe.mitre.org/data/definitions/273.html]
\[[Dowd 06|AA. C References#Dowd 06]\] Chapter 9, "Unix I: Privileges and Files"
\[[Open Group 04|AA. C References#Open Group 04]\] [{{setuid()}}|http://www.opengroup.org/onlinepubs/009695399/functions/setuid.html], [{{getuid()}}|http://www.opengroup.org/onlinepubs/009695399/functions/getuid.html], [{{seteuid()}}|http://www.opengroup.org/onlinepubs/009695399/functions/seteuid.html]
\[[Wheeler 03|AA. C References#Wheeler 03]\] [Section 7.4, "Minimize Privileges"|http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/minimize-privileges.html]

...