netwind created PDFBOX-6297:
-------------------------------
Summary: cmap format 12/13: nbGroups is unbounded, a 1.2 MB font
takes 41 minutes to parse
Key: PDFBOX-6297
URL: https://issues.apache.org/jira/browse/PDFBOX-6297
Project: PDFBox
Issue Type: Bug
Components: FontBox
Affects Versions: 3.0.9 PDFBox
Environment: FontBox 3.0.8, JDK 21.0.11, Windows 11
Reporter: netwind
FontBox 3.0.8, Java 21.0.11, Windows 11. The trunk code of CmapSubtable is the
same except for the logging calls.
processSubtype12 and processSubtype13 read nbGroups as a 32-bit value and never
check it. processSubtype8 in the same file caps the same field at 65536, with
the comment "nbGroups shouldn't be greater than 65536".
For format 13 the inner loop runs once per character code of every group, so a
group of (0, 0x10FFFF, 0) is 12 bytes that become 1,114,112 map puts, and the
outer loop repeats that until the data ends. With a minimal but valid TTF (nine
tables, maxp claims 2 glyphs, one format 13 subtable, 100,000 groups, 1.2 MB)
TTFParser.parseEmbedded takes 41 minutes on one core. The parse succeeds, no
warnings, memory stays around 100 MB - it is just slow. 1,000 groups (12 KB)
already take 25 seconds.
Format 12 is affected as well, but its inner loop stops at the first glyph
index at or above numGlyphs, so a group is capped at numGlyphs puts; 10,000
groups (131 KB, numGlyphs=65535) take 16 seconds.
Expected: a font this small parses in a second or two. Actual: one core pinned
for minutes.
Both sample fonts and the generator are attached. "run-poc.bat 13 100000"
reproduces the 41 minute case. Suggested fix: give format 12 and 13 the same
65536 cap format 8 has, or compare nbGroups against the bytes left in the table.
{code:java}
// CmapSubtable.java, line 300 (13) and 243 (12) in 3.0.8
long nbGroups = data.readUnsignedInt(); // no upper bound
...
for (long j = 0; j <= endCode - firstCode; ++j) { // up to 0x110000 puts per
group
characterCodeToGlyphId.put((int) (firstCode + j), (int) glyphId);
}
{code}
One more thing in the same function: processSubtype13 checks "glyphId >
numGlyphs" and then indexes glyphIdToCharacterCode[glyphId], so glyphId ==
numGlyphs passes the check and throws AIOOBE instead of the intended warning.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]