You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 74 Next »

Failing to close files when they are no longer needed may allow attackers to exhaust, and possibly manipulate, system resources. This phenomenon is typically referred to as file descriptor leakage, although file pointers may also be used as an attack vector. To prevent file descriptor leaks, files should be closed when they are no longer needed.

Non-Compliant Code Example

In this non-compliant example derived from by a vulnerability in OpenBSD's chpass program [[NAI 98]], a file containing sensitive data is opened for reading. The program then retrieves the registered editor from the EDITOR environment variable and executes it using the system() command. If, the system() command is implemented in a way that spawns a child process, then the child process inherits the file descriptors opened by its parent. As a result, the child process, in this example whatever program is specified by the EDITOR environment variable, will be able to access the contents of the potentially sensitive file called file_name.

FILE* f;
char *editor;

f = fopen(file_name, "r");
if (f == NULL) {
  /* Handle fopen() error */
}
/* ... */
editor = getenv("EDITOR");
if (editor == NULL) {
  /* Handle getenv() error */
}
system(editor);

On UNIX-based systems, child processes are typically spawned using a form of fork() and exec() and the child process always receives copies of its parent's file descriptors. Under Microsoft Windows, the CreateProcess() function is typically used to start a child process. In Windows, file-handle inheritance is determined on a per-file bases. Additionally, the CreateProcess() function itself provides a mechanism to limit file-handle inheritance. As a result, the child process spawned by CreateProcess() may not receive copies of the parent process's open file handles.

Compliant Solution

In this compliant solution, file_name is be closed before launching the editor.

FILE* f;
char *editor;

f = fopen(file_name, "r");
if (f == NULL) {
  /* Handle fopen() error */
}
/* ... */
fclose(f);
f = NULL;
editor = getenv("EDITOR");
if (editor == NULL) {
  /* Handle getenv() error */
}
/* Sanitize environment before calling system()! */
system(editor);

Several security issues remain in this example. Compliance with recommendations, such as [[STR02-A. Sanitize data passed to complex subsystems]] and [[FIO02-A. Canonicalize path names originating from untrusted sources]] is necessary to prevent exploitation. However, these recommendations do not address the specific issue of file descriptor leakage addressed here.

Compliant Solution (POSIX)

Sometimes it is not practical for a program to close all active file descriptors before issuing a system call such as system() or exec(). An alternative on POSIX systems is to use the FD_CLOEXEC flag, or O_CLOEXEC when available, to set the close-on-exec flag for the file descriptor.

int fd;
int flags;
char *editor;

if ((fd = open(file_name, O_RDONLY)) == -1) {
  /* Handle Error */
}

if ((flags = fcntl(fd, F_GETFD))  == -1) {
  /* Handle Error */
}

if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
  /* Handle Error */
}

/* ... */

editor = getenv("EDITOR");
if (editor == NULL) {
  /* Handle getenv() error */
}
system(editor);

Some systems (Linux >= 2.6.23) have an O_CLOEXEC flag which provides the close-on-exec function directly in open(). This flag will be required by POSIX.1-2008. In multi-threaded programs this flag should be used if possible as it avoids a timing hole between open() and fcntl() when using FD_CLOEXEC, during which another thread could create a child process while the file descriptor does not have close-on-exec set.

int fd;
char *editor;

if ((fd = open(file_name, O_RDONLY|O_CLOEXEC)) == -1) {
  /* Handle Error */
}

/* ... */

editor = getenv("EDITOR");
if (editor == NULL) {
  /* Handle getenv() error */
}
system(editor);

Risk Assessment

Failing to properly close files may allow unintended access to, or exhaustion of, system resources.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

FIO42-C

medium

unlikely

medium

P4

L3

Automated Detection

The LDRA tool suite V 7.6.0 is able to detect violations of this recommendation.

Fortify SCA Version 5.0 with CERT C Rule Pack can detect violations of this recommendation.

Related Vulnerabilities

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

References

[[Dowd 06]] Chapter 10, "UNIX Processes" (File Descriptor Leaks 582-587)
[[MITRE 07]] CWE ID 403, "UNIX file descriptor leaks"
[[MSDN]] Inheritance (Windows)
[[NAI 98]] Bugtraq: Network Associates Inc. Advisory (OpenBSD)


FIO41-C. Do not call getc() or putc() with stream arguments that have side effects      09. Input Output (FIO)       FIO43-C. Temporary files must be dealt with in a secure manner

  • No labels