29
29
import org .apache .commons .compress .archivers .zip .ZipFile ;
30
30
import org .codehaus .plexus .archiver .AbstractUnArchiver ;
31
31
import org .codehaus .plexus .archiver .ArchiverException ;
32
+ import org .apache .commons .io .input .BoundedInputStream ;
33
+ import org .apache .commons .io .input .CountingInputStream ;
32
34
import org .codehaus .plexus .components .io .resources .PlexusIoResource ;
33
35
34
36
/**
@@ -42,6 +44,8 @@ public abstract class AbstractZipUnArchiver
42
44
43
45
private String encoding = "UTF8" ;
44
46
47
+ private long maxOutputSize = Long .MAX_VALUE ;
48
+
45
49
public AbstractZipUnArchiver ()
46
50
{
47
51
}
@@ -66,6 +70,21 @@ public void setEncoding( String encoding )
66
70
this .encoding = encoding ;
67
71
}
68
72
73
+ /**
74
+ * Set maximum allowed size of the produced output.
75
+ *
76
+ * It may be used as a protection against <a href="https://en.wikipedia.org/wiki/Zip_bomb">zip bombs</a>.
77
+ *
78
+ * @param maxOutputSize max size of the produced output, in bytes. Must be greater than 0
79
+ * @throws IllegalArgumentException if specified output size is less or equal to 0
80
+ */
81
+ public void setMaxOutputSize ( long maxOutputSize ) {
82
+ if ( maxOutputSize <= 0 ) {
83
+ throw new IllegalArgumentException ( "Invalid max output size specified: " + maxOutputSize );
84
+ }
85
+ this .maxOutputSize = maxOutputSize ;
86
+ }
87
+
69
88
private static class ZipEntryFileInfo
70
89
implements PlexusIoResource
71
90
{
@@ -181,6 +200,7 @@ protected void execute( final String path, final File outputDirectory )
181
200
getLogger ().debug ( "Expanding: " + getSourceFile () + " into " + outputDirectory );
182
201
try ( ZipFile zipFile = new ZipFile ( getSourceFile (), encoding , true ) )
183
202
{
203
+ long remainingSpace = maxOutputSize ;
184
204
final Enumeration <ZipArchiveEntry > e = zipFile .getEntriesInPhysicalOrder ();
185
205
186
206
while ( e .hasMoreElements () )
@@ -196,10 +216,18 @@ protected void execute( final String path, final File outputDirectory )
196
216
{
197
217
try ( InputStream in = zipFile .getInputStream ( ze ) )
198
218
{
199
- extractFile ( getSourceFile (), outputDirectory , in ,
200
- ze .getName (), new Date ( ze .getTime () ), ze .isDirectory (),
201
- ze .getUnixMode () != 0 ? ze .getUnixMode () : null ,
202
- resolveSymlink ( zipFile , ze ), getFileMappers () );
219
+ BoundedInputStream bis = new BoundedInputStream ( in , remainingSpace + 1 );
220
+ CountingInputStream cis = new CountingInputStream ( bis );
221
+ extractFile ( getSourceFile (), outputDirectory , cis ,
222
+ ze .getName (), new Date ( ze .getTime () ), ze .isDirectory (),
223
+ ze .getUnixMode () != 0 ? ze .getUnixMode () : null ,
224
+ resolveSymlink ( zipFile , ze ), getFileMappers () );
225
+
226
+ remainingSpace -= cis .getByteCount ();
227
+ if ( remainingSpace < 0 )
228
+ {
229
+ throw new ArchiverException ("Maximum output size limit reached" );
230
+ }
203
231
}
204
232
}
205
233
}
0 commit comments