Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: wordsmithing

Multiuser systems allow multiple users with different privileges to share a filesystem. Each user, in such an environment, must be able to determine which files are shared and which are private and each user must be able to enforce these decisions.

Unfortunately, there are a wide variety of file system vulnerabilities that can be exploited by an attacker to gain access to files for which they lack sufficient privileges, particularly when operating on files that reside in shared directories in which multiple users may create, move, or delete files. Privilege escalation is also possible in cases where these programs run with elevated privileges. To prevent these exploits, a program must only operate on files in secure directories.

A directory is secure with respect to a particular user if the user has exclusive privileges to move or delete files inside the directory. Furthermore, each parent to the secure directory can only be be moved or deleted by the user and the system administrator. On most systems, home or user directories are secure by default and only shared directories are insecure.

There are a number of files system filesystem properties and capabilities that can be exploited by an attacker including file links, device files, and shared file access.

...

Linux implements both mandatory locks and advisory locks. Advisory locks are not enforced by the operating system, which diminishes their value from a security perspective. Unfortunately, the mandatory file lock in Linux is generally impractical because:

  • Mandatory locking is only supported by certain network file systems.
  • File systems must be mounted with support for mandatory locking, and this is disabled by default.
  • Locking relies on the group ID bit, which can be turned off by another process (thereby defeating the lock).
  • The lock is implicitly dropped if the holding process closes any descriptor of the file.

...

  • A TOCTOU race condition exists between the first check and open. During this race window, an attacker can replace the regular file with a symbolic link or other non-regular file. The second check detects this race condition but does not eliminate it; an attacker can still cause the system to block when opening the file.
  • An attacker could subvert this code by letting the check operate on a normal file, substituting the non-normal file for the open, and then resubstitute the normal file to circumvent the second check. This vulnerability exists because Java lacks any mechanism to obtain file attributes from a file by any means other than the file name, and the binding of the file name to a file object is reasserted every time the file name is used in an operation. Consequently, an attacker can still switch out a file for one of the file types shown in the following table with the specified effecta nefarious file, such as a symbolic link.
  • A system with hard links allows an attacker to construct a malicious file that is a hard link to a sensitive file. Hard links cannot be reliably detected by a program, and serve as a foil to canonicalization attempts , as recommended which are prescribed by IDS21-J. Canonicalize path names before validating them.

...

Because of the potential for race conditions, and the inherent accessibility of shared directories, files must only be operated upon in secure directories. Because programs may run with reduced privileges and lack the facilities to construct a secure directory, a program may need to throw an exception if it can determine that a given a path name is not in a secure directory.

Following is an implementation of an isInSecureDir() method. This method ensures that the supplied file and all directories above it are owned by either the user or the superuser, that each directory lacks write access for any other users, and that directories above the given file may not be deleted or renamed by any other users (except the superuser).

Code Block
bgColor#ccccff
/**
 * Indicates if file lives in a secure directory relative to the program's user
 * @param file Path to test
 * @return true if file's directory is secure
 */
public static boolean isInSecureDir(Path file) {
  return isInSecureDir( file, null);
}

/**
 * Indicates if file lives in a secure directory relative to the program's user
 * @param file Path to test
 * @param user User to test. If null defaults to current user
 * @return true if file's directory is secure
 */
public static boolean isInSecureDir(Path file, UserPrincipal user) {
  if (!file.isAbsolute()) {
    file = file.toAbsolutePath();
  }

  // If any parent dirs (from root on down) are not secure, dir is not secure
  for (int i = 1; i <= file.getNameCount(); i++) {
    Path partialPath = Paths.get(file.getRoot().toString(), file.subpath(0, i).toString());

    try {
      if (Files.isSymbolicLink(partialPath)) {
        if (!isInSecureDir(Files.readSymbolicLink(partialPath))) {
          // Symbolic link, linked-to dir not secure
          return false;
        }
      } else {
        FileSystem fileSystem = partialPath.getFileSystem();
        UserPrincipalLookupService upls = fileSystem.getUserPrincipalLookupService();
        UserPrincipal root = upls.lookupPrincipalByName("root");
        if (user == null) {
          user = upls.lookupPrincipalByName(System.getProperty("user.name"));
        }
        UserPrincipal owner = Files.getOwner(partialPath);
        if (!owner.equals(user) && !owner.equals(root)) {
          // dir owned by someone else, not secure
          return false;
        }
        PosixFileAttributes attr = Files.readAttributes(partialPath, PosixFileAttributes.class);
        Set<PosixFilePermission> perms = attr.permissions();
        if (perms.contains(PosixFilePermission.GROUP_WRITE) ||
            perms.contains(PosixFilePermission.OTHERS_WRITE)) {
          // someone else can write files, not secure
          return false;
        }
      }
    } catch (IOException x) {
      return false;
    }
  }

  return true;
}

...

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

FIO04-J

medium

unlikely

medium

P4

L3

Related Vulnerabilities

GERONIMO-3489

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

...

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="ba2e2c3eb8dfee16-c4eb32d5-47634e7f-906cbbea-381bbe52de18e4d1a2a9816e"><ac:plain-text-body><![CDATA[

[[API 2006

AA. Bibliography#API 06]]

Class File, methods createTempFile, delete, deleteOnExit

]]></ac:plain-text-body></ac:structured-macro>

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="5421137f1946b024-56ca8abb-4bc54452-b722a084-9e8883e01e6d8ab6a2fb70d2"><ac:plain-text-body><![CDATA[

[[CVE 2008

AA. Bibliography#CVE 08]]

[CVE-2008-5354

http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-5354]

]]></ac:plain-text-body></ac:structured-macro>

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="88c890414faa12a4-a1554def-4d804a29-b97da581-37787129d73806d33282f493"><ac:plain-text-body><![CDATA[

[[Darwin 2004

AA. Bibliography#Darwin 04]]

11.5 Creating a Transient File

]]></ac:plain-text-body></ac:structured-macro>

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="4eb3041aa4efeee8-9d591148-4da14369-90ebb8bb-683d1e44072fce37134045c1"><ac:plain-text-body><![CDATA[

[[Garfinkel 1996

AA. Bibliography#Garfinkel 96]]

Section 5.6, "Device Files"

]]></ac:plain-text-body></ac:structured-macro>

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="bb31eacc87249a00-62ec132a-47424c45-bb209654-9d7bce3ac12f2ce904873c17"><ac:plain-text-body><![CDATA[

[[Howard 2002

AA. Bibliography#Howard 02]]

Chapter 11, "Canonical Representation Issues"

]]></ac:plain-text-body></ac:structured-macro>

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="dafef668004a58d3-794c7245-41ab4e19-b348a8b5-d801a2f2af567067f55736b7"><ac:plain-text-body><![CDATA[

[[J2SE 2011

AA. Bibliography#J2SE 11]]

The try-with-resources Statement

]]></ac:plain-text-body></ac:structured-macro>

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="de12c06f7e54e2c8-e99ed41f-44a9453c-980ea028-6553fcd36624a244f932e98b"><ac:plain-text-body><![CDATA[

[[Open Group 2004

AA. Bibliography#Open Group 04]]

[open()

http://www.opengroup.org/onlinepubs/009695399/functions/open.html]

]]></ac:plain-text-body></ac:structured-macro>

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="50257bc3211f55f6-0c4bb231-406f4c82-94aa9cf2-18196ab0854b14e9b9bfa83c"><ac:plain-text-body><![CDATA[

[[SDN 2008

AA. Bibliography#SDN 08]]

Bug IDs: 4171239, 4405521, 4635827, 4631820

]]></ac:plain-text-body></ac:structured-macro>

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="dd66527f85290537-2582ad52-4a7641e0-89e9abdf-46d8b538a31b33704ab61b18"><ac:plain-text-body><![CDATA[

[[Secunia 2008

AA. Bibliography#Secunia 08]]

[Secunia Advisory 20132

http://secunia.com/advisories/20132/]

]]></ac:plain-text-body></ac:structured-macro>

...