ghidra: Denial of Service via Uncontrolled Memory Allocation in DB DataBuffer
What fixes it
- 12.2ghidra, ghidraGitHub
A fixed version on one release line is not the upgrade target for every line. Check your exact version and any vendor backports.
Description
Summary
An uncontrolled memory allocation vulnerability in the DB data buffer get() function allows attackers to cause denial of service. An attacker can supply a crafted DB binary with an arbitrarily large size value, forcing the parser to allocate excessive heap memory, crashing the Ghidra JVM.
Details
When "length" is a very large value, it results in a Java Heap OOM error.
public byte[] get(int offset, int length) throws IndexOutOfBoundsException {
byte[] bytes = new byte[length]; // a very large length can result in heap OOM
System.arraycopy(data, offset, bytes, 0, bytes.length);
return bytes;
} int read(Buffer buf, int offset) throws IndexOutOfBoundsException, IOException {
checkImmutable();
int len = buf.getInt(offset);
offset += 4;
if (len < 0) {
data = null;
}
else {
data = buf.get(offset, len); // Bug; Passed unsanitized len to get(), Implement a maxlen check.
offset += len;
}
return offset;
} public void read(Buffer buf, int offset) throws IndexOutOfBoundsException, IOException {
for (Field fieldValue : fieldValues) {
offset = fieldValue.read(buf, offset);
}
dirty = false;
}Fix
- Implement a maxlen check in DataBuffer.java's get(). If it's less than 0 or excessively large for an integer, return 0. No need to read it.
- Implement a maxlen check in BinaryField.java:read()
- First read length with readLength() then sanitize it in DBRecord.java ( line 472):
public void read(Buffer buf, int offset) throws IndexOutOfBoundsException, IOException {
for (Field fieldValue : fieldValues) {
len = fieldValue.readLength(buf, offset); // Instead of reading directly, use readLength
if (len >= 0)
offset = fieldValue.read(buf, offset);
}
dirty = false;
}Stack trace
Java heap space java.lang.OutOfMemoryError: Java heap space at db.buffers.DataBuffer.get(DataBuffer.java:164) at db.BinaryField.read(BinaryField.java:112) at db.DBRecord.read(DBRecord.java:474) at db.VarRecNode.getRecord(VarRecNode.java:201) at db.Table$LongKeyRecordIterator.hasNext(Table.java:2232) at db.MasterTable.<init>(MasterTable.java:61) at db.DBHandle.<init>(DBHandle.java:111) at ghidra.framework.store.db.PackedDBHandle.<init>(PackedDBHandle.java:58) at ghidra.framework.store.db.PackedDatabase.open(PackedDatabase.java:775) at ghidra.app.util.opinion.GzfLoader.loadPackedProgramDatabase(GzfLoader.java:103) at ghidra.app.util.opinion.GzfLoader.load(GzfLoader.java:76) at ghidra.plugin.importer.ImporterUtilities.importSingleFile(ImporterUtilities.java:463) at ghidra.plugin.importer.ImporterDialog.lambda$okCallback$0(ImporterDialog.java:376) at ghidra.plugin.importer.ImporterDialog$$Lambda/0x000000004bcfd000.monitoredRun(Unknown Source) at ghidra.util.task.TaskBuilder$TaskBuilderTask.run(TaskBuilder.java:306) at ghidra.util.task.Task.monitoredRun(Task.java:134) at ghidra.util.task.TaskRunner.lambda$startTaskThread$0(TaskRunner.java:106) at ghidra.util.task.TaskRunner$$Lambda/0x000000004bac8000.run(Unknown Source) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1090) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:614) at java.base/java.lang.Thread.runWith(Thread.java:1529) at java.base/java.lang.Thread.run(Thread.java:1516)
Impact
This is a Denial of Service (DoS) vulnerability affecting automated binary analysis pipelines. An adversary distributing malicious software can intentionally supply malformed file, which when imported can instantly crash the Ghidra JVM, causing a loss of unsaved work and terminating the session. This is particularly damaging for automated triaging pipelines that use headless Ghidra instances, as a single malicious file can stall or crash the processing queue.
Text from GitHub Advisory Database
Affected versions 1
- ghidra, ghidra< 12.2GitHub