Skip to content

Commit e56e545

Browse files
committed
unzip and friends could monitor where they write more closely
1 parent c851c31 commit e56e545

File tree

5 files changed

+92
-2
lines changed

5 files changed

+92
-2
lines changed

WHATSNEW

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
11
Changes from Ant 1.9.11 TO Ant 1.9.12
22
=====================================
33

4+
Changes that could break older environments:
5+
-------------------------------------------
6+
7+
* <unzip>, <unjar> and <untar> will no longer extract entries whose
8+
names would make the created files be placed outside of the
9+
destination directory anymore by default. A new attribute
10+
allowFilesToEscapeDest can be used to override the behavior.
11+
Another special case is when stripAbsolutePathSpec is false (which
12+
still is the default) and the entry's name starts with a
13+
(back)slash and allowFilesToEscapeDest hasn't been specified
14+
explicitly, in this case the file may be created outside of the
15+
dest directory as well.
16+
417
Fixed bugs:
518
-----------
619

src/main/org/apache/tools/ant/taskdefs/Expand.java

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ public class Expand extends Task {
6969
private boolean failOnEmptyArchive = false;
7070
private boolean stripAbsolutePathSpec = false;
7171
private boolean scanForUnicodeExtraFields = true;
72+
private Boolean allowFilesToEscapeDest = null;
7273

7374
public static final String NATIVE_ENCODING = "native-encoding";
7475

@@ -259,14 +260,17 @@ protected void extractFile(FileUtils fileUtils, File srcF, File dir,
259260
boolean isDirectory, FileNameMapper mapper)
260261
throws IOException {
261262

262-
if (stripAbsolutePathSpec && entryName.length() > 0
263+
final boolean entryNameStartsWithPathSpec = entryName.length() > 0
263264
&& (entryName.charAt(0) == File.separatorChar
264265
|| entryName.charAt(0) == '/'
265-
|| entryName.charAt(0) == '\\')) {
266+
|| entryName.charAt(0) == '\\');
267+
if (stripAbsolutePathSpec && entryNameStartsWithPathSpec) {
266268
log("stripped absolute path spec from " + entryName,
267269
Project.MSG_VERBOSE);
268270
entryName = entryName.substring(1);
269271
}
272+
boolean allowedOutsideOfDest = Boolean.TRUE == getAllowFilesToEscapeDest()
273+
|| null == getAllowFilesToEscapeDest() && !stripAbsolutePathSpec && entryNameStartsWithPathSpec;
270274

271275
if (patternsets != null && patternsets.size() > 0) {
272276
String name = entryName.replace('/', File.separatorChar)
@@ -332,6 +336,12 @@ protected void extractFile(FileUtils fileUtils, File srcF, File dir,
332336
mappedNames = new String[] {entryName};
333337
}
334338
File f = fileUtils.resolveFile(dir, mappedNames[0]);
339+
if (!allowedOutsideOfDest && !fileUtils.isLeadingPath(dir, f)) {
340+
log("skipping " + entryName + " as its target " + f + " is outside of "
341+
+ dir + ".", Project.MSG_VERBOSE);
342+
return;
343+
}
344+
335345
try {
336346
if (!overwrite && f.exists()
337347
&& f.lastModified() >= entryDate.getTime()) {
@@ -533,4 +543,25 @@ public boolean getScanForUnicodeExtraFields() {
533543
return scanForUnicodeExtraFields;
534544
}
535545

546+
/**
547+
* Whether to allow the extracted file or directory to be outside of the dest directory.
548+
*
549+
* @param b the flag
550+
* @since Ant 1.9.12
551+
*/
552+
public void setAllowFilesToEscapeDest(boolean b) {
553+
allowFilesToEscapeDest = b;
554+
}
555+
556+
/**
557+
* Whether to allow the extracted file or directory to be outside of the dest directory.
558+
*
559+
* @return {@code null} if the flag hasn't been set explicitly,
560+
* otherwise the value set by the user.
561+
* @since Ant 1.9.12
562+
*/
563+
public Boolean getAllowFilesToEscapeDest() {
564+
return allowFilesToEscapeDest;
565+
}
566+
536567
}

src/tests/antunit/taskdefs/unzip-test.xml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
<mkdir dir="${output}" />
2525
</target>
2626

27+
<target name="tearDown" depends="antunit-base.tearDown">
28+
<delete dir="/tmp/testdir"/>
29+
</target>
30+
2731
<target name="testFailureOnBrokenCentralDirectoryStructure">
2832
<au:expectfailure
2933
expectedmessage="central directory is empty, can't expand corrupt archive.">
@@ -67,4 +71,46 @@
6771
<!-- failed on Windows and other OSes with implicit file locking -->
6872
<au:assertFileDoesntExist file="${input}/test.zip"/>
6973
</target>
74+
75+
<target name="testEntriesDontEscapeDestByDefault">
76+
<mkdir dir="${input}/"/>
77+
<mkdir dir="${output}/"/>
78+
<unzip src="zip/direscape.zip" dest="${output}"/>
79+
<au:assertFileDoesntExist file="${input}/a"/>
80+
</target>
81+
82+
<target name="testEntriesCanEscapeDestIfRequested">
83+
<mkdir dir="${input}/"/>
84+
<mkdir dir="${output}/"/>
85+
<unzip src="zip/direscape.zip" dest="${output}" allowFilesToEscapeDest="true"/>
86+
<au:assertFileExists file="${input}/a"/>
87+
</target>
88+
89+
<target name="-can-write-to-tmp?">
90+
<mkdir dir="${input}"/>
91+
<echo file="${input}/A.java"><![CDATA[
92+
public class A {
93+
public static void main(String[] args) {
94+
new java.io.File("/tmp/testdir/").mkdirs();
95+
}
96+
}
97+
]]></echo>
98+
<mkdir dir="${output}"/>
99+
<javac srcdir="${input}" destdir="${output}"/>
100+
<java classname="A" classpath="${output}"/>
101+
<available property="can-write-to-tmp!" file="/tmp/testdir/"/>
102+
</target>
103+
104+
<target name="testEntriesCanEscapeDestViaAbsolutePathByDefault"
105+
depends="-can-write-to-tmp?" if="can-write-to-tmp!">
106+
<unzip src="zip/direscape-absolute.zip" dest="${output}"/>
107+
<au:assertFileExists file="/tmp/testdir/a"/>
108+
</target>
109+
110+
<target name="testEntriesDontEscapeDestViaAbsolutePathIfProhibited"
111+
depends="-can-write-to-tmp?" if="can-write-to-tmp!">
112+
<unzip src="zip/direscape-absolute.zip" dest="${output}"
113+
allowFilesToEscapeDest="false"/>
114+
<au:assertFileDoesntExist file="/tmp/testdir/a"/>
115+
</target>
70116
</project>
332 Bytes
Binary file not shown.
332 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)