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");
         }
       }
     }

Reply via email to