Versions Compared

Key

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

Creating a jail aims at isolating a program from the rest of the file system. The central idea is to create a sandbox so that entities that the program does not need to access under normal operation are made inaccessible. This makes it much harder to abuse a potential flaw any vulnerability that can otherwise lead to unconstrained system compromise , and consequently functions as a defense-in-depth strategy. A jail may consist of world-viewable programs that require fewer resources to execute than those that exist on that system. Jails are useful only useful when there is no way to elevate privileges in the event of program failure.

...

Wiki Markup
Some UNIX-based systems (such as OpenBSD) can restrict file system access by creating a {{chroot()}} jail. The {{chroot}} jail requires care to implement securely \[[Wheeler 03|AA. C References#Wheeler 03]\]. This is achieved by passing a predefined directory name as an argument to {{chroot()}}. The call to {{chroot()}} requires superuser privileges. However, this call does not _leave_ the process inside the jail directory as one would expect. A Thesubsequent {{chdir()}} call that follows does just this and is indispensable when access isrequired to berestrict restrictedaccess to within the jail boundaries.

Another essential step is to drop superuser privileges permanently after these calls (see POS02-C. Follow the principle of least privilege). The chroot() system call is not secure against the superuser changing the current root directory (if privileges are not dropped) and may be ineffective if the current working directory is not set to the new root directory immediately following the call to chroot(). Successful jail creation prevents unintentional file system access even if an attacker gives malicious input, such as through command-line arguments.

Code Block
bgColor#ccccff
/*
 * Make sure that the chroot/jail directory exists within 
 * the current working directory. Also assign appropriate 
 * permissions to the directory to restrict access. Close 
 * all file system descriptors to outside resources lest 
 * they escape the jail.
 */

if (setuid(0) == -1) {
  /* Handle Errorerror */
}

if (chroot("chroot/jail") == -1) {
  /* Handle Errorerror */
}

if (chdir("/") == -1) {
  /* Handle Errorerror */
}

/* Drop privileges permanently */
if (setgid(getgid()) == -1) {
  /* Handle Errorerror */
}

if (setuid(getuid()) == -1) {
  /* Handle Errorerror */
}

/* Perform unprivileged operations */
enum {array_mex = 100};

FILE *fp = fopen(argv[1], "w");
char x[array_max];
strncpy(x, argv[2], array_max);
x[array_max - 1] = '\0';

/* Write operation safe is safe within jail */
if (fwrite(x, sizeof(x[0]), sizeof(x)/sizeof(x[0]), fp) <
    sizeof(x)/sizeof(x[0])) {
  /* Handle Errorerror */
}

An alternative sequence is to call chdir("chroot/jail") first and then chroot("."). However, calling chdir("/some/path") then chroot("/some/path") should be avoided as because this sequence may be susceptible to a race condition. This is because : an attacker with sufficient privileges can arrange for /some/path to refer to different directories in the two system calls. Consequently, the program will not have its current working directory set to the new root directory. Using either chdir("/") after chroot() or chroot(".") after chdir() guarantees that the current working directory will be the same directory as the new root.

...