Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Verify that zip file entries don't try to escape the parent dir + test #1211

Merged
merged 5 commits into from Dec 19, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Next
Verify that zip file entries don't try to escape the parent dir + test
Signed-off-by: Bart Hanssens <bart.hanssens@bosa.fgov.be>
  • Loading branch information
barthanssens committed Dec 18, 2018
commit df15a4d7a8f2789c043b27c9eafe1b30316cfa79
32 changes: 17 additions & 15 deletions util/src/main/java/org/eclipse/rdf4j/common/io/ZipUtil.java
Expand Up @@ -26,9 +26,14 @@ public class ZipUtil {
*/
private final static byte MAGIC_NUMBER[] = { (byte)0x50, (byte)0x4B, (byte)0x03, (byte)0x04 };

public static boolean isZipStream(InputStream in)
throws IOException
{
/**
* Test if an input stream is a zip input stream by checking the "magic number"
*
* @param in input stream
* @return true if start of input stream matches magic number
* @throws IOException
*/
public static boolean isZipStream(InputStream in) throws IOException {
in.mark(MAGIC_NUMBER.length);
byte[] fileHeader = IOUtil.readBytes(in, MAGIC_NUMBER.length);
in.reset();
Expand All @@ -45,9 +50,7 @@ public static boolean isZipStream(InputStream in)
* @throws IOException
* when something untoward happens during the extraction process
*/
public static void extract(File zipFile, File destDir)
throws IOException
{
public static void extract(File zipFile, File destDir) throws IOException {
barthanssens marked this conversation as resolved.
Show resolved Hide resolved
try (ZipFile zf = new ZipFile(zipFile)) {
extract(zf, destDir);
}
Expand All @@ -61,11 +64,9 @@ public static void extract(File zipFile, File destDir)
* @param destDir
* the destination directory
* @throws IOException
* when something untowards happens during the extraction process
* when something untoward happens during the extraction process
*/
public static void extract(ZipFile zipFile, File destDir)
throws IOException
{
public static void extract(ZipFile zipFile, File destDir) throws IOException {
assert destDir.isDirectory();

Enumeration<? extends ZipEntry> entries = zipFile.entries();
Expand All @@ -87,15 +88,16 @@ public static void extract(ZipFile zipFile, File destDir)
* @throws IOException
* if the entry could not be processed
*/
public static void writeEntry(ZipFile zipFile, ZipEntry entry, File destDir)
throws IOException
{
public static void writeEntry(ZipFile zipFile, ZipEntry entry, File destDir) throws IOException {
File outFile = new File(destDir, entry.getName());

if (! outFile.getCanonicalFile().toPath().startsWith(destDir.toPath())) {
barthanssens marked this conversation as resolved.
Show resolved Hide resolved
throw new IOException("Zip entry outside destination directory: " + entry.getName());
}

if (entry.isDirectory()) {
outFile.mkdirs();
}
else {
} else {
outFile.getParentFile().mkdirs();

try (InputStream in = zipFile.getInputStream(entry)) {
Expand Down
69 changes: 69 additions & 0 deletions util/src/test/java/org/eclipse/rdf4j/common/io/ZipUtilTest.java
@@ -0,0 +1,69 @@
/*******************************************************************************
* Copyright (c) 2018 Eclipse RDF4J contributors.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*******************************************************************************/
package org.eclipse.rdf4j.common.io;

import static org.junit.Assert.assertEquals;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

public class ZipUtilTest {
@Rule
public TemporaryFolder dir = new TemporaryFolder();

@Test
public void testWriteEntryNormal() throws IOException {
File f = dir.newFile("testok.zip");

try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(f))) {
ZipEntry e = new ZipEntry("helloworld.txt");
out.putNextEntry(e);
out.write("hello world".getBytes());
out.closeEntry();
}

ZipFile zf = new ZipFile(f);
File subdir = dir.newFolder("extract");
ZipUtil.extract(zf, subdir);

assertTrue("File not extracted", new File(subdir, "helloworld.txt").exists());
}


@Test
public void testWriteEntryPathTraversing() throws IOException {
File f = dir.newFile("testnotok.zip");

try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(f))) {
ZipEntry e = new ZipEntry("hello/../../world.txt");
out.putNextEntry(e);
out.write("hello world".getBytes());
out.closeEntry();
}

ZipFile zf = new ZipFile(f);
File subdir = dir.newFolder("extract");
try {
ZipUtil.extract(zf, subdir);
fail("No exception thrown");
} catch (IOException ioe) {
assertTrue(ioe.getMessage().startsWith("Zip entry outside destination directory"));
}
}
}