Creating a jail isolates a program from the rest of the file system. The 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 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 when there is no way to elevate privileges in the event of program failure.
Additionally, care must be taken to ensure that all the required resources (such as libraries, files, and so on) are replicated within the jail directory and that no reference is made to other parts of the file system from within this directory. It is also advisable to administer restrictive read/write permissions on the jail directories and resources based on the basis of the program's privilege requirements. Although , creating jails is an effective security measure when used correctly, it is not a surrogate for compliance with the other rules and recommendations in this standard.
Noncompliant Code Example
A security flaw exists in the this noncompliant code shown below example resulting from the absence of proper canonicalization measures on the file path. This allows an attacker to traverse the file system and possibly write to a file of his the attacker's choice , with the privileges of the vulnerable program. For example, it may be possible to overwrite the password file (such as the /etc/passwd
, common to many POSIX-based systems) or a device file, such as the mouse, which in turn can aid further exploitation or cause a denial of service to occur.
Code Block | ||||
---|---|---|---|---|
| ||||
enum { array_max = 100 }; /* * Program running with elevated privileges where argv[1] * and argv[2] are supplied by the user */ char x[array_max]; FILE *fp = fopen(argv[1], "w"); strncpy(x, argv[2], array_max); x[array_max - 1] = '\0'; /* * Write operation to an unintended file such likeas /etc/passwd * gets executed */ if (fwrite(x, sizeof(x[0]), sizeof(x)/sizeof(x[0]), fp) < sizeof(x)/sizeof(x[0])) { /* Handle Errorerror */ } |
An attacker can control the value of {{ Wiki Markup argv
\[1
\]
}} and consequently access any resource on the file system.
This noncompliant code example also violates FIO02-C. Canonicalize path names originating from untrusted tainted sources and FIO03-C. Do not make assumptions about fopen() and file creation.
Compliant Solution (
...
UNIX)
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 subsequent {{chdir()}} is required to restrict access to the jail chroot()
jail requires care to implement securely [Wheeler 2003]. It 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 might be expected. A subsequent chdir()
is required to restrict access to 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). Successful jail creation prevents unintentional file system access even if an attacker gives malicious input, such as through command-line arguments.
Code Block | ||||
---|---|---|---|---|
| ||||
/* * 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 error */ } if (chroot("chroot/jail") == -1) { /* Handle error */ } if (chdir("/") == -1) { /* Handle error */ } /* Drop privileges permanently */ if (setgid(getgid()) == -1) { /* Handle error */ } if (setuid(getuid()) == -1) { /* Handle error */ } /* Perform unprivileged operations */ enum {array_max = 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 error */ } |
An alternative sequence is to first call chdir("chroot/jail")
first and then call chroot(".")
. However, calling chdir("/some/path")
, then chroot("/some/path")
, should be avoided because this sequence may be susceptible to a race condition: 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.
Risk Assessment
Failing to follow this recommendation , wherever possible, may lead to full-system compromise if a security file system vulnerability is uncovered in a program or daemondiscovered and exploited.
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|
POS05-C |
Medium |
Probable |
High | P4 | L3 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
CodeSonar |
| BADFUNC.CHROOT MISC.CHROOT.NOCHDIR | Use of chroot | ||||||
Polyspace Bug Finder |
| CERT C: Rec. POS05-C | Checks for file manipulation after chroot() without chdir("/") (rec. fully covered) |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Other Languages
This rule appears in the C++ Secure Coding Standard as FIO16-CPP. Limit access to files by creating a jail.
References
...
Bibliography
...
...
...
...
|http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/minimize-privileges.html] 09. Input Output (FIO)