From 0f29daf6183f9db8486fbc51d245fbc85b87aeec Mon Sep 17 00:00:00 2001 From: Bertil Chapuis Date: Thu, 13 Jun 2024 14:29:51 +0200 Subject: [PATCH] Prevent zip slip and path injection (#875) --- .../workflow/tasks/DecompressFile.java | 64 +++++++++++-------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/baremaps-core/src/main/java/org/apache/baremaps/workflow/tasks/DecompressFile.java b/baremaps-core/src/main/java/org/apache/baremaps/workflow/tasks/DecompressFile.java index 6fca8f465..d06954bf1 100644 --- a/baremaps-core/src/main/java/org/apache/baremaps/workflow/tasks/DecompressFile.java +++ b/baremaps-core/src/main/java/org/apache/baremaps/workflow/tasks/DecompressFile.java @@ -24,6 +24,7 @@ import java.nio.file.StandardOpenOption; import java.util.StringJoiner; import java.util.zip.GZIPInputStream; +import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.apache.baremaps.workflow.Task; import org.apache.baremaps.workflow.WorkflowContext; @@ -154,22 +155,27 @@ protected static void decompressTarBz2(Path source, Path target) throws IOExcept } } - private static void decompressTar(Path target, TarArchiveInputStream tarInputStream) + public static void decompressTar(Path target, TarArchiveInputStream tarInputStream) throws IOException { TarArchiveEntry entry; while ((entry = tarInputStream.getNextEntry()) != null) { - var path = target.resolve(entry.getName()); - if (entry.isDirectory()) { - Files.createDirectories(path); - } else { - Files.createDirectories(path.getParent()); - Files.write(path, new byte[] {}, - StandardOpenOption.CREATE, - StandardOpenOption.TRUNCATE_EXISTING); - try (BufferedOutputStream outputStream = - new BufferedOutputStream(Files.newOutputStream(path))) { - tarInputStream.transferTo(outputStream); + File destination = target.resolve(entry.getName()).normalize().toFile(); + String canonicalDestinationPath = destination.getCanonicalPath(); + String canonicalTargetPath = target.toFile().getCanonicalPath(); + if (canonicalDestinationPath.startsWith(canonicalTargetPath)) { + if (entry.isDirectory()) { + Files.createDirectories(destination.toPath()); + } else { + Files.createDirectories(destination.toPath().getParent()); + try (BufferedOutputStream outputStream = + new BufferedOutputStream(Files.newOutputStream(destination.toPath(), + StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING))) { + tarInputStream.transferTo(outputStream); + } } + } else { + throw new IOException("Entry is outside of the target directory"); } } } @@ -183,23 +189,29 @@ private static void decompressTar(Path target, TarArchiveInputStream tarInputStr */ @SuppressWarnings("squid:S5042") protected static void decompressZip(Path source, Path target) throws IOException { - Files.createDirectories(target); - try (var zipFile = new ZipFile(source.toFile())) { + try (ZipFile zipFile = new ZipFile(source.toFile())) { var entries = zipFile.entries(); while (entries.hasMoreElements()) { - var entry = entries.nextElement(); - var path = target.resolve(entry.getName()); - if (entry.isDirectory()) { - Files.createDirectories(path); - } else { - Files.createDirectories(path.getParent()); - Files.write(path, new byte[] {}, - StandardOpenOption.CREATE, - StandardOpenOption.TRUNCATE_EXISTING); - try (var input = new BufferedInputStream(zipFile.getInputStream(entry)); - var output = new BufferedOutputStream(new FileOutputStream(path.toFile()))) { - input.transferTo(output); + ZipEntry entry = entries.nextElement(); + File destination = target.resolve(entry.getName()).normalize().toFile(); + String canonicalDestinationPath = destination.getCanonicalPath(); + String canonicalTargetPath = target.toFile().getCanonicalPath(); + + if (canonicalDestinationPath.startsWith(canonicalTargetPath)) { + if (entry.isDirectory()) { + Files.createDirectories(destination.toPath()); + } else { + Files.createDirectories(destination.toPath().getParent()); + try (BufferedInputStream input = new BufferedInputStream(zipFile.getInputStream(entry)); + BufferedOutputStream output = + new BufferedOutputStream(Files.newOutputStream(destination.toPath(), + StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING))) { + input.transferTo(output); + } } + } else { + throw new IOException("Entry is outside of the target directory"); } } }