Versions Compared

Key

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

...

Sometimes, certain privileged operations are required in a program, although subsequently, the program might not need to retain the special privileges. For instance, a network program may require superuser privileges to capture raw network packets but will not ideally use the same set of privileges for carrying out other tasks such as packet analysis. Dropping or elevating privileges alternately according to program requirements is a good design strategy. Moreover, assigning only the required privileges limits the window of exposure for any privilege escalation exploit to succeed.

Non-Compliant Code Example

Consider a custom service that that needs to bind to a well known port (below 1024). To avoid malicious entities from hijacking client connections, the kernel imposes a condition such that only the superuser can use the bind() system call to bind to these ports.

...

A vulnerability (if uncovered) in the main body of the program will allow an attacker to execute arbitrary code. This malicious code will end up running with elevated privileges.

Compliant Solution

The program must follow the principle of least privilege while carefully separating the binding and bookkeeping tasks. To minimize the chance of a flaw in the program from compromising the superuser level account, it must drop superuser privileges as soon as the privileged operations are completed. In the code shown below, privileges are dropped permanently as soon as the bind() operation is carried out. This solution is in compliance with [FIO42-C. Ensure files are properly closed when they are no longer needed].

Code Block
bgColor#ccccff

/*  Code with elevated privileges  */

int establish() 
{
  struct sockaddr_in sa;              /*  This will store the listening socket's address  */
  int s;                              /*  This will hold the listening socket  */

  /* Fill up the structure with address and port number */

  sa.sin_port = htons(portnum);

  /* Other system calls like socket() */

  if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0)  { 
  /* Perform cleanup */  }

  /* Return */  
}

int main()
{
   int s = establish();

   if(setuid(getuid()) == -1)    /* Drop privileges permanently */
   {
        /*  Handle the error  */
   }

  /* Block with accept() until a client connects */
      
   switch(fork())
   {
      case -1: /* Error, clean up and quit */
      case  0: /* Close all open file descriptors
                * This is the child, handle the client 
                */
      default: /* This is the parent, continue blocking */
   }
} 

Risk Assessment

Failure to follow the principle of least privilege may leave the program susceptible to a wide range of attacks that may result in full system compromise. Privilege escalation is possible in the worst case.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

POS38-C

high

likely

high

P9

L2

Related Vulnerabilities

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

References

Wiki Markup
\[[DHS 05|AA. C References#DHS 05]\] [Least Privilege | https://buildsecurityin.us-cert.gov/daisy/bsi/articles/knowledge/principles/351.html]

...