This is an automated email from the ASF dual-hosted git repository. bchapuis pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/incubator-baremaps.git
commit 0f29daf6183f9db8486fbc51d245fbc85b87aeec Author: Bertil Chapuis <[email protected]> AuthorDate: Thu Jun 13 14:29:51 2024 +0200 Prevent zip slip and path injection (#875) --- .../baremaps/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 6fca8f46..d06954bf 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.StandardCopyOption; 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 @@ public class DecompressFile implements Task { } } - 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 @@ public class DecompressFile implements Task { */ @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"); } } }
