NationalSecurityAgency/ghidra · error · IOException
Decompression limit exceeded: {}
Error message
Decompression limit exceeded: {} What it means
RestrictedInflaterInputStream wraps an inflater (zlib/deflate) with a hard readLimit to prevent decompression bombs. Each read() increments readCount and, if readCount already meets readLimit, throws before reading more. It is a deliberate safety cap supplied to the constructor (RestrictedInflaterInputStream(file, readLimit) or (byte[], readLimit)).
Source
Thrown at GPL/DMG/src/dmg/java/mobiledevices/dmg/reader/DmgFileReader.java:310
try {
super.close();
}
finally {
// Cleanup temporary file input stream and remove file
in.close();
if (tempCompressedFile != null) {
tempCompressedFile.delete();
}
}
}
@Override
public int read(byte[] b, int off, int length) throws IOException {
if (length == 0) {
return 0;
}
if (readCount >= readLimit) {
throw new IOException("Decompression limit exceeded: " + readLimit);
}
// Limit read length to avoid exceeding readLimit
int limit = Math.min(readLimit - readCount, length);
int count = super.read(b, off, limit);
if (count > 0) {
readCount += count;
}
return count;
}
}
public List<String> getInfo(String path) {
if (path != null) {
DmgInfoGenerator info = new DmgInfoGenerator(this, path, parser);
return info.getInformation();
}
return null;
}View on GitHub (pinned to d5f144c24d)
Solutions
- Raise readLimit to comfortably exceed the expected inflated size of the DMG block being processed.
- Verify the DMG block is not a decompression bomb by comparing its compressed size to the declared uncompressed size before decompressing.
- Confirm the readLimit is being passed in bytes (not a smaller unit) and matches the block's declared output size.
- If the limit is intentional policy, treat this as expected behavior and abort the untrusted image.
Example fix
// before new RestrictedInflaterInputStream(compressedBlock, 1024 * 1024); // after - size the limit to the declared uncompressed block size int limit = Math.toIntExact(Math.addExact(declaredUncompressedSize, safetyMargin)); new RestrictedInflaterInputStream(compressedBlock, limit);
Defensive patterns
Strategy: validation
Validate before calling
// Size the decompression cap to the declared uncompressed block size plus margin
int safeLimit = Math.toIntExact(Math.addExact(declaredUncompressedSize, safetyMarginBytes));
if (safeLimit <= 0) {
throw new IOException("Invalid decompression limit derived from declared size " + declaredUncompressedSize);
}
new RestrictedInflaterInputStream(compressedBlock, safeLimit); Type guard
boolean limitCoversExpected(int readLimit, long declaredUncompressed) {
return readLimit > 0 && ((long) readLimit) >= declaredUncompressed;
} Try / catch
try {
int n = stream.read(buf, off, len);
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Decompression limit exceeded")) {
// Treat as policy/security abort for untrusted input; do not silently raise the cap
throw new IOException("Decompression bomb or unexpectedly large block; aborting", e);
}
throw e;
} Prevention
- Set readLimit comfortably above each block's declared uncompressed size.
- Compare compressed vs. declared uncompressed size to detect bombs before decompressing.
- Keep a safety margin on the cap to absorb minor over-reads.
- For untrusted inputs, treat the limit as a hard security boundary, not a nuisance.
When it happens
Trigger: Decompressing a DMG block whose inflated output exceeds the readLimit passed when constructing RestrictedInflaterInputStream. The limit bounds total bytes read from the inflated stream, so a genuinely large (or malicious zip-bomb-like) block trips it.
Common situations: A legitimate but large compressed block whose decompressed size exceeds the configured cap; a malicious/adversarial DMG crafted as a decompression bomb; the readLimit was set too low for the expected image size; counting logic accumulating more than expected due to repeated reads.
Related errors
- Bad nodeSize: {}
- Invalid number of elements specified: {}
- Unable to read {} bytes
- GhidraRandomAccessFile is closed
- pos cannot be less than zero
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/0666b190a473e394.
Report an issue: GitHub.