Repository: ant Updated Branches: refs/heads/master 5f4c43ddc -> ae5a3e0ea
unzip and friends could monitor where they write more closely Project: http://git-wip-us.apache.org/repos/asf/ant/repo Commit: http://git-wip-us.apache.org/repos/asf/ant/commit/e56e5456 Tree: http://git-wip-us.apache.org/repos/asf/ant/tree/e56e5456 Diff: http://git-wip-us.apache.org/repos/asf/ant/diff/e56e5456 Branch: refs/heads/master Commit: e56e54565804991c62ec76dad385d2bdda8972a7 Parents: c851c31 Author: Stefan Bodewig <bode...@apache.org> Authored: Sat Apr 21 19:55:02 2018 +0200 Committer: Stefan Bodewig <bode...@apache.org> Committed: Sat Apr 21 19:55:32 2018 +0200 ---------------------------------------------------------------------- WHATSNEW | 13 ++++++ .../org/apache/tools/ant/taskdefs/Expand.java | 35 +++++++++++++- src/tests/antunit/taskdefs/unzip-test.xml | 46 +++++++++++++++++++ .../antunit/taskdefs/zip/direscape-absolute.zip | Bin 0 -> 332 bytes src/tests/antunit/taskdefs/zip/direscape.zip | Bin 0 -> 332 bytes 5 files changed, 92 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ant/blob/e56e5456/WHATSNEW ---------------------------------------------------------------------- diff --git a/WHATSNEW b/WHATSNEW index a40c4ed..3041bc5 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -1,6 +1,19 @@ Changes from Ant 1.9.11 TO Ant 1.9.12 ===================================== +Changes that could break older environments: +------------------------------------------- + + * <unzip>, <unjar> and <untar> will no longer extract entries whose + names would make the created files be placed outside of the + destination directory anymore by default. A new attribute + allowFilesToEscapeDest can be used to override the behavior. + Another special case is when stripAbsolutePathSpec is false (which + still is the default) and the entry's name starts with a + (back)slash and allowFilesToEscapeDest hasn't been specified + explicitly, in this case the file may be created outside of the + dest directory as well. + Fixed bugs: ----------- http://git-wip-us.apache.org/repos/asf/ant/blob/e56e5456/src/main/org/apache/tools/ant/taskdefs/Expand.java ---------------------------------------------------------------------- diff --git a/src/main/org/apache/tools/ant/taskdefs/Expand.java b/src/main/org/apache/tools/ant/taskdefs/Expand.java index a586556..a3a2745 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Expand.java +++ b/src/main/org/apache/tools/ant/taskdefs/Expand.java @@ -69,6 +69,7 @@ public class Expand extends Task { private boolean failOnEmptyArchive = false; private boolean stripAbsolutePathSpec = false; private boolean scanForUnicodeExtraFields = true; + private Boolean allowFilesToEscapeDest = null; public static final String NATIVE_ENCODING = "native-encoding"; @@ -259,14 +260,17 @@ public class Expand extends Task { boolean isDirectory, FileNameMapper mapper) throws IOException { - if (stripAbsolutePathSpec && entryName.length() > 0 + final boolean entryNameStartsWithPathSpec = entryName.length() > 0 && (entryName.charAt(0) == File.separatorChar || entryName.charAt(0) == '/' - || entryName.charAt(0) == '\\')) { + || entryName.charAt(0) == '\\'); + if (stripAbsolutePathSpec && entryNameStartsWithPathSpec) { log("stripped absolute path spec from " + entryName, Project.MSG_VERBOSE); entryName = entryName.substring(1); } + boolean allowedOutsideOfDest = Boolean.TRUE == getAllowFilesToEscapeDest() + || null == getAllowFilesToEscapeDest() && !stripAbsolutePathSpec && entryNameStartsWithPathSpec; if (patternsets != null && patternsets.size() > 0) { String name = entryName.replace('/', File.separatorChar) @@ -332,6 +336,12 @@ public class Expand extends Task { mappedNames = new String[] {entryName}; } File f = fileUtils.resolveFile(dir, mappedNames[0]); + if (!allowedOutsideOfDest && !fileUtils.isLeadingPath(dir, f)) { + log("skipping " + entryName + " as its target " + f + " is outside of " + + dir + ".", Project.MSG_VERBOSE); + return; + } + try { if (!overwrite && f.exists() && f.lastModified() >= entryDate.getTime()) { @@ -533,4 +543,25 @@ public class Expand extends Task { return scanForUnicodeExtraFields; } + /** + * Whether to allow the extracted file or directory to be outside of the dest directory. + * + * @param b the flag + * @since Ant 1.9.12 + */ + public void setAllowFilesToEscapeDest(boolean b) { + allowFilesToEscapeDest = b; + } + + /** + * Whether to allow the extracted file or directory to be outside of the dest directory. + * + * @return {@code null} if the flag hasn't been set explicitly, + * otherwise the value set by the user. + * @since Ant 1.9.12 + */ + public Boolean getAllowFilesToEscapeDest() { + return allowFilesToEscapeDest; + } + } http://git-wip-us.apache.org/repos/asf/ant/blob/e56e5456/src/tests/antunit/taskdefs/unzip-test.xml ---------------------------------------------------------------------- diff --git a/src/tests/antunit/taskdefs/unzip-test.xml b/src/tests/antunit/taskdefs/unzip-test.xml index b2c2105..a220bc1 100644 --- a/src/tests/antunit/taskdefs/unzip-test.xml +++ b/src/tests/antunit/taskdefs/unzip-test.xml @@ -24,6 +24,10 @@ <mkdir dir="${output}" /> </target> + <target name="tearDown" depends="antunit-base.tearDown"> + <delete dir="/tmp/testdir"/> + </target> + <target name="testFailureOnBrokenCentralDirectoryStructure"> <au:expectfailure expectedmessage="central directory is empty, can't expand corrupt archive."> @@ -67,4 +71,46 @@ <!-- failed on Windows and other OSes with implicit file locking --> <au:assertFileDoesntExist file="${input}/test.zip"/> </target> + + <target name="testEntriesDontEscapeDestByDefault"> + <mkdir dir="${input}/"/> + <mkdir dir="${output}/"/> + <unzip src="zip/direscape.zip" dest="${output}"/> + <au:assertFileDoesntExist file="${input}/a"/> + </target> + + <target name="testEntriesCanEscapeDestIfRequested"> + <mkdir dir="${input}/"/> + <mkdir dir="${output}/"/> + <unzip src="zip/direscape.zip" dest="${output}" allowFilesToEscapeDest="true"/> + <au:assertFileExists file="${input}/a"/> + </target> + + <target name="-can-write-to-tmp?"> + <mkdir dir="${input}"/> + <echo file="${input}/A.java"><![CDATA[ +public class A { + public static void main(String[] args) { + new java.io.File("/tmp/testdir/").mkdirs(); + } +} +]]></echo> + <mkdir dir="${output}"/> + <javac srcdir="${input}" destdir="${output}"/> + <java classname="A" classpath="${output}"/> + <available property="can-write-to-tmp!" file="/tmp/testdir/"/> + </target> + + <target name="testEntriesCanEscapeDestViaAbsolutePathByDefault" + depends="-can-write-to-tmp?" if="can-write-to-tmp!"> + <unzip src="zip/direscape-absolute.zip" dest="${output}"/> + <au:assertFileExists file="/tmp/testdir/a"/> + </target> + + <target name="testEntriesDontEscapeDestViaAbsolutePathIfProhibited" + depends="-can-write-to-tmp?" if="can-write-to-tmp!"> + <unzip src="zip/direscape-absolute.zip" dest="${output}" + allowFilesToEscapeDest="false"/> + <au:assertFileDoesntExist file="/tmp/testdir/a"/> + </target> </project> http://git-wip-us.apache.org/repos/asf/ant/blob/e56e5456/src/tests/antunit/taskdefs/zip/direscape-absolute.zip ---------------------------------------------------------------------- diff --git a/src/tests/antunit/taskdefs/zip/direscape-absolute.zip b/src/tests/antunit/taskdefs/zip/direscape-absolute.zip new file mode 100644 index 0000000..0bae4aa Binary files /dev/null and b/src/tests/antunit/taskdefs/zip/direscape-absolute.zip differ http://git-wip-us.apache.org/repos/asf/ant/blob/e56e5456/src/tests/antunit/taskdefs/zip/direscape.zip ---------------------------------------------------------------------- diff --git a/src/tests/antunit/taskdefs/zip/direscape.zip b/src/tests/antunit/taskdefs/zip/direscape.zip new file mode 100644 index 0000000..63cefd2 Binary files /dev/null and b/src/tests/antunit/taskdefs/zip/direscape.zip differ