File sbt-CVE-2023-46122.patch of Package sbt.34548

--- sbt-0.13.18/util/io/src/main/scala/sbt/IO.scala	2023-10-24 10:27:13.257340189 +0200
+++ sbt-0.13.18/util/io/src/main/scala/sbt/IO.scala	2023-10-24 10:48:58.190343108 +0200
@@ -10,6 +10,7 @@
 import java.io.{ ObjectInputStream, ObjectStreamClass }
 import java.net.{ URI, URISyntaxException, URL }
 import java.nio.charset.Charset
+import java.nio.file.{ Path => NioPath, _ }
 import java.util.Properties
 import java.util.jar.{ Attributes, JarEntry, JarFile, JarInputStream, JarOutputStream, Manifest }
 import java.util.zip.{ CRC32, GZIPOutputStream, ZipEntry, ZipFile, ZipInputStream, ZipOutputStream }
@@ -266,11 +267,16 @@
   def unzipStream(from: InputStream, toDirectory: File, filter: NameFilter = AllPassFilter, preserveLastModified: Boolean = true): Set[File] =
     {
       createDirectory(toDirectory)
-      zipInputStream(from) { zipInput => extract(zipInput, toDirectory, filter, preserveLastModified) }
+      zipInputStream(from) { zipInput => extract(zipInput, toDirectory.toPath, filter, preserveLastModified) }
     }
-  private def extract(from: ZipInputStream, toDirectory: File, filter: NameFilter, preserveLastModified: Boolean) =
+  private def extract(from: ZipInputStream, toDirectory: NioPath, filter: NameFilter, preserveLastModified: Boolean) =
     {
-      val set = new HashSet[File]
+      val set = new HashSet[NioPath]
+      val canonicalDirPath = toDirectory.normalize().toString
+      def validateExtractPath(name: String, target: NioPath): Unit =
+        if (!target.normalize().toString.startsWith(canonicalDirPath)) {
+          throw new RuntimeException(s"Entry ($name) is outside of the target directory")
+        }
       def next(): Unit = {
         val entry = from.getNextEntry
         if (entry == null)
@@ -278,18 +284,19 @@
         else {
           val name = entry.getName
           if (filter.accept(name)) {
-            val target = new File(toDirectory, name)
+            val target = toDirectory.resolve(name)
+            validateExtractPath(name, target)
             //log.debug("Extracting zip entry '" + name + "' to '" + target + "'")
             if (entry.isDirectory)
-              createDirectory(target)
+              createDirectory(target.toFile)
             else {
               set += target
               translate("Error extracting zip entry '" + name + "' to '" + target + "': ") {
-                fileOutputStream(false)(target) { out => transfer(from, out) }
+                fileOutputStream(false)(target.toFile) { out => transfer(from, out) }
               }
             }
             if (preserveLastModified)
-              target.setLastModified(entry.getTime)
+              target.toFile.setLastModified(entry.getTime)
           } else {
             //log.debug("Ignoring zip entry '" + name + "'")
           }
@@ -298,7 +305,7 @@
         }
       }
       next()
-      Set() ++ set
+      (Set() ++ set).map(_.toFile)
     }
 
   /** Retrieves the content of the given URL and writes it to the given File. */
openSUSE Build Service is sponsored by