Versions Compared

Key

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

File operations should be performed in a secure directory. In most cases, a secure directory is a directory in which no one other than the user, or possibly the administrator, has the ability to create, rename, delete or otherwise manipulate files. (Other users may read or search the directory, but generally may not modify the directory's contents in any way.) Also, other users must not be able to delete or rename files in the parent of the secure directory and all higher directories, although creating new files and , deleting or renaming files they own are is permissible.

Performing file operations in a secure directory eliminates the possibility that an attacker might tamper with the files or file system to exploit a file system vulnerability in a program. These vulnerabilities often exist because there is a loose binding between the file name and the actual file (see FIO01-C. Be careful using functions that use file names for identification). In some cases, file operations can be performed securely (and should be)anywhere. In other cases, the only way to ensure secure file operations is to perform the operation within a secure directory.

...

Compliant Solution (POSIX)

This example sample implementation of a secure_dir() function will ensure ensures that path and all directories above it are owned by either the user or the superuser, that path does not have write access for any other users, and that directories above path may not be deleted or renamed by any other users. When checking directories, it is important to traverse from the root to the leaf to avoid a dangerous race condition where an attacker who has privileges to at least one of the directories can rename and recreate a directory after the privilege verification.

...

Code Block
bgColor#ccccff
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <libgen.h>
#include <sys/stat.h>
#include <string.h>

/* Returns nonzero if directory is secure, zero otherwise */
int secure_dir(const char *fullpath) {
  char *path_copy = NULL;
  char *dirname_res = NULL;
  char ** dirs = NULL;
  int num_of_dirs = 0;
  int secure = 1;
  int i;
  struct stat buf;
  uid_t my_uid = geteuid();

  if (!(path_copy = strdup(fullpath))) {
    /* Handle error */
  }

  dirname_res = path_copy;
  /* Figure out how far it is to the root */
  while (1) {
    dirname_res = dirname(dirname_res);

    num_of_dirs++;

    if ((strcmp(dirname_res, "/") == 0) ||
	(strcmp(dirname_res, "//") == 0)) {
      break;
    }
  }
  free(path_copy);
  path_copy = NULL;

  /* Now allocate and fill the dirs array */
  if (!(dirs = (char **)malloc(num_of_dirs*sizeof(*dirs)))) {
    /* Handle error */
  }
  if (!(dirs[num_of_dirs - 1] = strdup(fullpath))) {
    /* Handle error */
  }

  if (!(path_copy = strdup(fullpath))) {
    /* Handle error */
  }

  dirname_res = path_copy;
  for (i = 1; i < num_of_dirs; i++) {
    dirname_res = dirname(dirname_res);

    dirs[num_of_dirs - i - 1] = strdup(dirname_res);

  }
  free(path_copy);
  path_copy = NULL;

  /* Traverse from the root to the leaf, checking
   * permissions along the way */
  for (i = 0; i < num_of_dirs; i++) {
    if (stat(dirs[i], &buf) != 0) {
       /* Handle error */
    }
    if ((buf.st_uid != my_uid) && (buf.st_uid != 0)) {
      /* Directory is owned by someone besides user or root */
      secure = 0;
    } else if ((buf.st_mode & (S_IWGRP | S_IWOTH))
      && ((i == num_of_dirs - 1) || !(buf.st_mode & S_ISVTX))) {
        /* Others have permissions to the leaf directory
         * or are able to delete or rename files along the way */
        secure = 0;
     }
            
    free(dirs[i]);
    dirs[i] = NULL;
  }

  free(dirs);
  dirs = NULL;

  return secure;
}

This compliant solution uses the this secure_dir() function above to ensure that an attacker may not tamper with the file to be opened and subsequently removed. Note that once the path name has been canonicalized and checked using secure_dir(), all further file operations must be performed using the canonicalized path.

...

Risk Assessment

Failing to ensure proper permissions perform file I/O operations in a directory may lead to sensitive data getting saved to (or critical configuration or other input files being read from) public directories to which an attacker has accesssecure directory that cannot otherwise be securely performed can result in a broad range of file system vulnerabilities.

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

FIO15-C

medium

probable

high

P4

L3

...