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 cb617a5b6898cf71ba7547e1a391c077e75ac5c7 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, 37 insertions(+), 27 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..1cff323d 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,26 @@ public class DecompressFile implements Task { } } - private static void decompressTar(Path target, TarArchiveInputStream tarInputStream) - throws IOException { + 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); + Path resolvedPath = target.resolve(entry.getName()).normalize(); + File file = resolvedPath.toFile(); + + String canonicalDestinationPath = file.getCanonicalPath(); + String canonicalTargetPath = target.toFile().getCanonicalPath(); + + if (canonicalDestinationPath.startsWith(canonicalTargetPath)) { + if (entry.isDirectory()) { + Files.createDirectories(resolvedPath); + } else { + Files.createDirectories(resolvedPath.getParent()); + try (BufferedOutputStream outputStream = new BufferedOutputStream(Files.newOutputStream(resolvedPath, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING))) { + tarInputStream.transferTo(outputStream); + } } + } else { + throw new IOException("Entry is outside of the target directory"); } } } @@ -183,23 +188,28 @@ 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(); + Path resolvedPath = target.resolve(entry.getName()).normalize(); + File file = resolvedPath.toFile(); + + String canonicalDestinationPath = file.getCanonicalPath(); + String canonicalTargetPath = target.toFile().getCanonicalPath(); + + if (canonicalDestinationPath.startsWith(canonicalTargetPath)) { + if (entry.isDirectory()) { + Files.createDirectories(resolvedPath); + } else { + Files.createDirectories(resolvedPath.getParent()); + try (BufferedInputStream input = new BufferedInputStream(zipFile.getInputStream(entry)); + BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(file))) { + input.transferTo(output); + } } + } else { + throw new IOException("Entry is outside of the target directory"); } } }
