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]

Reply via email to