Versions Compared

Key

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

Wiki Markup
The principle of least privilege states that every program and every user of the system should operate using the least set of privileges necessary to complete the job \[[Saltzer 74|AA. C References#Saltzer 74], [Saltzer 75|AA. C References#Saltzer 75]\]. The build security in website \[[DHS 06|AA. C References#DHS 06]\] provides additional definitions.

Programs should execute with the least set of privileges that are necessary for their successful completion. This is also the underlying principle behind assigning minimalistic privileges so that the damage caused due to software defects can be constrained.

 of this principle.  Executing with minimal privileges mitigates against exploitation, in case a vulnerability is discovered in the code.

Non-Compliant Code Example

Privileged operations are often 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.

...

Code Block
bgColor#ffcccc

int establish(void) {
  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(void) {
   int s = establish();

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

...

Code Block
bgColor#ccccff

/*  Code with elevated privileges  */

int establish(void) {
  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(void) {
   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 */
   }
} 

...