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. */