...
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 | ||
---|---|---|
| ||
/** * 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); } public static boolean isInSecureDir(Path file, UserPrincipal user) { return isInSecureDir( file, null, 5); // maximun number of nested symlinks } /** * 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 * @param symlinkDepth Number of symbolic links to tolerate before aborting * @return true * @return true if file's directory is secure */ public static boolean isInSecureDir(Path file, UserPrincipal user, int symlinkDepth) { if (!file.isAbsolute()) { file = file.toAbsolutePath(); } if (symlinkDepth <= 0) { // Too many levels of symbolic links return false; } // Get UserPincipal for specified user and superuser FileSystem fileSystem = Paths.get(file.getRoot().toString()).getFileSystem(); UserPrincipalLookupService upls = fileSystem.getUserPrincipalLookupService(); UserPrincipal root = null; try { root = upls.lookupPrincipalByName("root"); if (user == null) { user = upls.lookupPrincipalByName(System.getProperty("user.name")); } if (root == null || user == null) { return false; } } catch (IOException x) { return false; } // 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), user, symlinkDepth - 1)) { // Symbolic link, linked-to dir not secure return false; } } else { UserPrincipal owner = Files.getOwner(partialPath); if (!user.equals( owner) && !root.equals( owner)) { // 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; } |
...
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="4d153019f72cc6b8-dcd85d8d-4b3f4e9d-ab5ca90b-466f591a5f6fc1157569a262"><ac:plain-text-body><![CDATA[ | [[API 2006 | AA. Bibliography#API 06]] | Class File, methods | ]]></ac:plain-text-body></ac:structured-macro> | |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="ebda95eeb339ca64-38e9e720-439b468e-a5c48f39-08ee548396e1621ec3afe9ac"><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="982f3eacad1de9eb-fa5443fe-47394ca9-b40ab073-8d1adbb6469f6b374b5ca60b"><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="62e3cf0e56a1db6f-ea2817b9-415b4ab3-a3edb5b7-ad92e37dd7105223dd21b074"><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="06eb20ab5b4dcb5e-b5431a00-442145b6-8b30962f-b3dbd8345a42efd0427a8cc4"><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="a4da79c358b3d6c4-be139fcc-4f414855-9664b991-7d6021c5864ad074deab9c3b"><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="568e8763935ab879-97cea76f-425e415c-ac918e6a-5dd10446f26cb96643dad026"><ac:plain-text-body><![CDATA[ | [[Open Group 2004 | AA. Bibliography#Open Group 04]] | [ | 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="6366f85f20569aaf-9535ada0-4530413b-a50e96d6-efd6c82d2cdf80004d8ff230"><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="d78ef61d677dfc19-e7599ac0-42a549f5-9d6eaabc-72287b0e6453d5fd725fb2b3"><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> |
...