Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions core/src/main/scala/flatgraph/storage/Deserialization.scala
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,9 @@ object Deserialization {
}

val manifestOffset = header.getLong()
val manifestSize = channel.size() - manifestOffset
if (manifestSize > fileSize)
throw new DeserializationException(s"corrupt file: manifest size ($manifestSize) cannot be larger than the file's size ($fileSize)")
if (manifestOffset < 0 || manifestOffset >= channel.size())
throw new DeserializationException(s"corrupt file: manifest offset ($manifestOffset) is out of bounds (file size: ${channel.size()})")
val manifestSize = channel.size() - manifestOffset
if (manifestSize > Int.MaxValue)
throw new DeserializationException(s"corrupt file: unreasonably large manifest size ($manifestSize)... aborting")

Expand Down
27 changes: 26 additions & 1 deletion core/src/test/scala/flatgraph/SerializationTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,25 @@ class SerializationTests extends AnyWordSpec with Matchers {
// `java.lang.OutOfMemoryError: Requested array size exceeds VM limit`
intercept[DeserializationException] {
Deserialization.readGraph(storagePath, Option(graph.schema))
}.getMessage should include("corrupt file: manifest size")
}.getMessage should include("corrupt file: manifest offset")
}

/* Show that a truncated file (manifest offset beyond EOF) produces a clear error instead of
* `java.lang.IllegalArgumentException: capacity < 0` deep in ByteBuffer.allocate.
*/
"rejects a truncated file where manifest offset points beyond EOF" in {
val schema = TestSchema.make(1, 0)
val graph = Graph(schema)
val diff = DiffGraphBuilder(schema).addNode(new GenericDNode(0))
DiffGraphApplier.applyDiff(graph, diff)

val storagePath = Files.createTempFile(s"flatgraph-${getClass.getSimpleName}", "fg")
Serialization.writeGraph(graph, storagePath)
truncateFile(storagePath)

intercept[DeserializationException] {
Deserialization.readGraph(storagePath, Option(graph.schema))
}.getMessage should include("corrupt file: manifest offset")
}

/** manipulate file as detailed in https: //github.com/joernio/flatgraph/security/advisories/GHSA-jqmx-3x2p-69vh */
Expand All @@ -89,4 +107,11 @@ class SerializationTests extends AnyWordSpec with Matchers {
}
}

/** simulate a truncated file: keep only the header so the manifest offset always points past EOF */
private def truncateFile(path: Path): Unit = {
Using.resource(new RandomAccessFile(path.toFile, "rw")) { file =>
file.setLength(storage.HeaderSize)
}
}

}
Loading