Versions Compared

Key

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

...

Wiki Markup
In this noncompliant code example derived from a [vulnerability|BB. Definitions#vulnerability] in OpenBSD's {{chpass}} program \[[NAI 98|AA. Bibliography#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, which in this example is the program specified by the {{EDITOR}} environment variable, will be able to access the contents of the potentially sensitive file called {{file_name}}.

Code Block
bgColor#FFcccc
langcpp
FILE* f;
const char *editor;
char *file_name;

/* Initialize file_name */

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

...

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

Code Block
bgColor#ccccff
langcpp
FILE* f;
const char *editor;
char *file_name;

/* Initialize file_name */

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()! */
if (system(editor) == -1) {
  /* Handle Error */
}

...

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.

Code Block
bgColor#ccccff
langcpp
int flags;
char *editor;
char *file_name;

/* Initialize file_name */

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

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

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

/* ... */

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

Wiki Markup
Some systems (such as those with Linux kernel versions greater than or equal to 2.6.23) have an {{O_CLOEXEC}} flag that provides the close-on-exec function directly in {{open()}}. This flag is required by POSIX.1-2008 \[[Austin Group 08|AA. Bibliography#Austin Group 08]\]. In multithreaded programs, this flag should be used if possible because it prevents a timing hole between {{open()}} and {{fcntl()}} when using {{FD_CLOEXEC}}, during which another thread can create a child process while the file descriptor does not have close-on-exec set.

Code Block
bgColor#ccccff
langcpp
char *editor;
char *file_name;

/* Initialize file_name */

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

/* ... */

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

...