diff --git a/WHATSNEW b/WHATSNEW index 78a1fbcca..ae3b1c71f 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -1,6 +1,19 @@ Changes from Ant 1.10.3 TO Ant 1.10.4 ===================================== +Changes that could break older environments: +------------------------------------------- + + * , and 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: ----------- diff --git a/src/main/org/apache/tools/ant/taskdefs/Expand.java b/src/main/org/apache/tools/ant/taskdefs/Expand.java index 8a3aafca8..51f4043ff 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Expand.java +++ b/src/main/org/apache/tools/ant/taskdefs/Expand.java @@ -77,6 +77,7 @@ public class Expand extends Task { private boolean failOnEmptyArchive = false; private boolean stripAbsolutePathSpec = false; private boolean scanForUnicodeExtraFields = true; + private Boolean allowFilesToEscapeDest = null; private String encoding; @@ -256,14 +257,17 @@ public class Expand extends Task { boolean isDirectory, FileNameMapper mapper) throws IOException { - if (stripAbsolutePathSpec && !entryName.isEmpty() + final boolean entryNameStartsWithPathSpec = !entryName.isEmpty() && (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.isEmpty()) { String name = entryName.replace('/', File.separatorChar) @@ -328,6 +332,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()) { @@ -520,4 +530,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.10.4 + */ + 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.10.4 + */ + public Boolean getAllowFilesToEscapeDest() { + return allowFilesToEscapeDest; + } + } diff --git a/src/tests/antunit/taskdefs/unzip-test.xml b/src/tests/antunit/taskdefs/unzip-test.xml index b2c2105dd..a220bc186 100644 --- a/src/tests/antunit/taskdefs/unzip-test.xml +++ b/src/tests/antunit/taskdefs/unzip-test.xml @@ -24,6 +24,10 @@ + + + + @@ -67,4 +71,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 000000000..0bae4aaf1 Binary files /dev/null and b/src/tests/antunit/taskdefs/zip/direscape-absolute.zip differ diff --git a/src/tests/antunit/taskdefs/zip/direscape.zip b/src/tests/antunit/taskdefs/zip/direscape.zip new file mode 100644 index 000000000..63cefd2d8 Binary files /dev/null and b/src/tests/antunit/taskdefs/zip/direscape.zip differ