Versions Compared

Key

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

...

The phrase "appropriate privileges" varies from platform to platform. For example, on Solaris appropriate privileges for setuid() means that the PRIV_PROC_SETID privilege is in the effective privilege set of the process. On BSD, it means that the effective user ID (EUID) is zero (that is, the process is running as root) . On BSD, it means that EUID=0 or that uid=geteuid(). On Linux, it means that the process has CAP_SETUID capability and that setuid(geteuid()) will fail if the effective EUID is not equal to 0, the real user ID (RUID), or the saved set-user-ID (SSUID).

...

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  */ 

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

...

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

...

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  */ 

Non-Compliant Code Example

The function 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 */
}

Compliant Solution

The following code shows how the effective UID should be obtained and compared against 0 (superuser's EUID) to make sure privileges can be successfully dropped permanently. This constitutes a more portable and safe solution.

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 {
    /* 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.

...