Closed Bug 453225 Opened 16 years ago Closed 7 years ago

[@font-face] font fuzzer

Categories

(Core :: Graphics, defect)

defect
Not set
major

Tracking

()

RESOLVED FIXED

People

(Reporter: jtd, Unassigned)

References

(Blocks 1 open bug)

Details

(Keywords: meta, sec-other, Whiteboard: [sg:nse meta])

Attachments

(3 files, 1 obsolete file)

With the addition of downloadable fonts as a feature in Gecko, our text rendering components are now potentially open to attacks using bogus font data. Need to create some simple tools for creating bogus font data. Probably a simple first step is to create some scripts that take existing fonts and start swapping bytes around in selected font tables. Interesting things to fuzz: - basic table structure (huge tables, num tables, table lengths) - cmap's that we use (gfxFontUtils) - metrics info - glyph data in TT, CFF formats - shaping info (GSUB, GDEF, mort, morx) for complex scripts More complex tasks: - simple ways to fuzz TT hints? - tests of limits of rasterizer (num glyphs, odd curves, stack depth, proc calls) - vulnerable places within shaping engines (e.g. ATSUI!) The TTX set of python scripts might be a handy starting place but I'm not sure those are well-maintained.
Blocks: fuzz
I think I can build this directly into my javascript-based file fuzzer (bug 413380), but fonts (at least truetype; I don't know about others) have checksums, which makes them hard to fuzz. Would it be a good idea just to disable the checksum check on a custom firefox build for fuzzing and then recalculate the checksums for testcases? If so, would somebody please show me the needed code change? Thanks.
There's a bunch of code in gfxFontUtils::ValidateSFNTHeaders (in gfx/thebes/src/gfxFontUtils.cpp). But I suspect that the OS font code that we hand the font off to will likely also check the checksum and perhaps other things, so the necessary code change there (assuming the fuzzer doesn't generate correct checksums) would probably be to correct the checksums before passing the data off to the OS, rather than to ignore the check. But John should confirm...
To continue loading fonts even if the checksum is incorrect, it should be sufficient to comment out the appropriate "return" statement in gfxFontUtils::ValidateSFNTHeaders; see attachment. (Just for testing, NOT intended to ever be applied to the real tree!)
At least on Mac OS X, the system will load fonts even if the checksum is bad; I happened to run into this recently, with a font that Firefox wouldn't load because the checksum failed, but simply disabling this check allowed it to be used successfully. (Aside: I fixed the checksum in the font concerned by dumping it to XML with ttx, and then re-creating a .ttf file, as ttx doesn't fail on bad checksums but does recalculate them when rebuilding the font.)
It makes most sense to me to just add code to the fuzzer to calculate the correct checksum. Then it can work with stock Firefox builds and we don't have to worry about OS behaviour.
I have no knowledge of font file structure, so I figured disabling the check would be easier. If someone knows how to do it in javascript, please let me know and I'll do that.
...Calculating the checksum that is
Paul, do you just need javascript code to fixup the checksums? If so, I can probably write that for you, the code is relatively simple as long as the data provided is unstructured, i.e. just a sequence of bytes: function fixupFontChecksums(fontBytes) { } What exactly is the type of the return value of readContents? An array? Do you have a quick example of how your fuzzer works? I think fuzzing randomly may catch some errors but fuzzing within particular font tables will probably provide more interesting results, especially for tables that contain data which we use a lot, metrics info for example.
We should probably switch the conversation over to the secure thread. I'll post a reply at bug 413380.
I can't currently see that bug; could you add me to the cc list, or whatever else it takes? Thanks.
I didn't realize this was already a secure thread :) Everything just uses javascript variables. I read the files like this: var bytes = bstream.readBytes(bstream.available()); then unintelligently fuzz and save it. If you could write the code to fix the font checksums, I would appreciate it. Also, about fuzzing particular tables, do you think it would be worth it to write the file parsing code in javascript or to use ttx?
Paul, here's some code to recalculate the checksums for TrueType data. It will work if you tweak any of the table data. Since it relies on table header information to locate the actual table data, I don't know what will happen if you start messing about with the sfnt header and table headers, haven't tested that far yet. This code: - parses sfnt header - parses table headers - does checksum calculations on table data In it's current form, the code loads an existing font based on gFontPath, parses and checks the checksums, swizzles 4 bytes at offset 0x1000, and recomputes the checksums. For random byte swizzling, I think javascript is fine. Using ttx will also be interesting for more higher level attacks like messing around with sequences of hinting instructions, duplicating them, trying to test specific internal limits of TrueType rasterizers.
Summary: font fuzzer → [@font-face] font fuzzer
I thought I already replied to this thread, but I don't see my comment. Perhaps I didn't press commit. John, the code you attached works perfectly. Thanks for doing that for me. I'm adding the ability to fuzz ttx output in addition to the random fuzzing of font files, so a new version of the fuzzer will probably be available within a week, but I've got finals so I can't promise anything.
Keywords: meta
Whiteboard: [sg:nse meta]
Hey. I'm sorry this has taken so long, but I'll get this uploaded as soon as I can fix a last major bug.
Ok, finally got this thing done, and I'm pretty excited about the results. I integrated it into JSFF, which can be found in bug 413380. I'll need help porting it to nonwindows, but it shouldn't be too hard.
Is the exciting thing about the results "hey, everything's great!" or "oh boy, lots of problems found.."? :)
The fuzzer works well and looks really cool when running, but so far no problems have been found.
I've got an awesome, fast fuzzer written, but there's a problem. As soon as firefox fails to render a font, it stops trying to render custom fonts in the current window or even child frames. Does anybody know why?
(In reply to comment #18) > As soon as > firefox fails to render a font, it stops trying to render custom fonts in the > current window or even child frames. Does anybody know why? That's curious. Which platform are you running on - or does this apply on all platforms? (And are you running a release Firefox or a trunk build, or what?)
Attached file font fuzzer (obsolete) (deleted) —
I forgot that I changed it to use new windows on every iteration to try to fix the problem - it didn't. I'm on Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3. It currently runs quite slow, but I'm sure I can speed it up by disabling checksum calculations and compiling a build of Firefox that doesn't check them.
I'd like to fuzz within an iframe since onload fires once after the font has been rendered. That way, I don't have to use timeouts and guess.
Nevermind, I found the problem. I had a bug in my own code that caused testcase changes to persist ;)
(In reply to comment #23) > Nevermind, I found the problem. I had a bug in my own code that caused testcase > changes to persist ;) Could you post an updated version of your code when you get a chance?
Attached file font fuzzer (deleted) —
This one should work. For efficiency, it uses a child iframe to load the testcase with an onload event to know when the font has been loaded, and this event fires a callback in the parent window to tell it to fuzz+load the next testcase. If I'm not mistaken, this should still allow every fuzzed font enough time to be tested, right?
Attachment #437148 - Attachment is obsolete: true
Also, I spent a considerable amount of time earlier last month trying to figure out how I could fuzz fonts within a standalone c++ program using xpcom glue like I did with images and libpr0n. It should be possible, but it's a lot more complicated than image parsing. Anybody have any suggestions? The font fuzzer is a bit slower than I'd like, and I was able to get hundreds of testcases fuzzed with a standalone image fuzzer.
Group: core-security → gfx-core-security
Status: NEW → RESOLVED
Closed: 7 years ago
Resolution: --- → FIXED
Group: gfx-core-security
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: