Repository navigation
feat(hwp): resource limits and fuzzing for the document readers - #686
Merged
Merged
Conversation
Untrusted HWPX, DOCX and OFD files can no longer hang, exhaust the memory or crash Filee. The readers share Documents/DocumentLimits, which the HWP 5.0 reader and the layout engine will use too: packages are read by DocumentPackage (64 MB per part, 1 GB in all, counted while unpacking, an inflate ratio, 100,000 parts), XML by SafeXml (no DTD or resolver, 512 levels, 5 million elements; the tree builder GeoXml had, now shared), nesting of tables, text boxes, notes, groups and fields stops at 32 levels, paragraphs and objects are counted, and pictures whose header claims more than 16,384 x 16,384 pixels are left out. LayoutGuard holds the page, empty-page, time and cancellation checks and the clip-and-place rule for the layout loop. Passing a limit stops with the new error.document_too_complex. DocumentFuzzer mutates packages written in code; DocumentFuzzTests runs it briefly with every test run and for three minutes per reader every night (.github/workflows/fuzz.yml). Fixed with regression tests: HWPX column counts and spans at the end of the int range (OutOfMemoryException, ArgumentOutOfRangeException, overflowing width sums, endless row spans), DOCX duplicate numbering ids, page sizes that overflowed Math.Abs, raw XmlException from damaged DOCX parts, a footnote that refers to itself and long basedOn chains (stack overflows), and unclosed fields that slowed every run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3 of 8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this change?
Project 4 item "Layout engine: resource limits and fuzzing for readers and layout" (M0). Untrusted documents can no longer hang, exhaust the memory or crash Filee: the HWPX, DOCX and OFD readers now share one set of limits (
Documents/DocumentLimits.cs) that the HWP 5.0 reader and the layout entry point will use too, and a mutation fuzzer checks the readers on every test run and for a few minutes every night.Limits (a document that passes one stops with the new localized
error.document_too_complex, the detail says which):Documents/DocumentPackage.cs, built from whatOfdPackagealready did; OFD now uses it too): at most 100,000 parts; a part may unpack to 64 MB, all parts to 1 GB, counted while unpacking (a header that understates a size doesn't help), and a part over 4 MB to at most 200× its packed size. Parts are only found by name inside the package; extracted pictures get names Filee makes (an entryimage.png:evilno longer becomes an alternate data stream).Infrastructure/SafeXml.cs, the tree builderGeoXmlhad, now shared with KML/GPX): no DTD, no resolver, at most 512 levels and 5,000,000 elements per package. Before, HWPX and DOCX usedXDocument.Loadwith DTD parsing on and no depth limit.Documents/DocumentBudget.cs): tables in tables, text boxes, notes, groups and fields nest at most 32 levels; 1,000,000 paragraphs; 200,000 tables / pictures / drawing objects; table columns cut at 16,384 and row spans at the table's end; Word style chains followed 20 deep.Documents/PictureSize.cs): a PNG / JPEG / GIF / BMP / WebP whose header claims more than 16,384 × 16,384 pixels is left out before anything decodes it.Documents/LayoutGuard.cs, for the layout engine; wiring comes with the layout items): 20,000 pages, 64 empty pages in a row, a 10-minute budget, cancellation and time checked per paragraph, and an object larger than the page is clipped and placed.word/fonts, HWPX / OFD font files keep only their names); documented, with a test.Fuzzing:
DocumentFuzzermutates packages written in code (the 한글-style package fromHwpxReaderTests, a rich DOCX built here, and both written by Filee's own writers): attributes set to extreme or foreign values, elements removed / repeated / renamed / nested, text and bytes damaged, DTDs inserted, pictures given huge headers. A reader may only read a file or throwInvalidDataException/ConversionRefusedException, within 30 s, on a 1 MB stack.DocumentFuzzTestsruns 50 inputs per seed with a fixed seed in the normal test run (about a second per reader, so PR CI timing stays the same) and 3 minutes per reader with a new seed in the new nightly.github/workflows/fuzz.yml(ubuntu, 25-minute timeout; failing inputs are uploaded;FILEE_FUZZ_SEEDrepeats a run).Bugs found and fixed (each with a regression test in
DocumentHostileInputTests):main: HWPXcolCnt="2147483647"→OutOfMemoryException; HWPX cell address + span overflowing →ArgumentOutOfRangeExceptioninColumnWidths; DOCX duplicateabstractNumId→ArgumentException; DOCX page size-1e308→OverflowException(Math.Abs(int.MinValue)); DOCX damaged XML → rawXmlException.basedOnchain did the same; unclosed fields made every run / paragraph walk all of them (and HWPX nested links as deep as the fields); HWPX column widths overflowed their checked sum; a hugerowSpanmade writers loop billions of times; VML line ends at the end of the range overflowedMath.Abs.Left for later items: a cyclic-CFB test comes with the HWP 5.0 reader (Filee has no CFB reader yet; the limits note what it must check), wiring
LayoutGuardinto the layout loop, and fuzzing the HWP reader and the layout entry point (the harness takes anyAction<string, string>reader). The PPTX reader is not covered here.Type of change
How was it tested?
dotnet format --verify-no-changesdotnet test(Filee.Engines.Tests, Filee.Core.Tests, LocalizationTests)Fuzzing: 150 s per reader with the fixed code (~8,000 inputs each, no failures); the same harness on
mainfound the five fuzzer bugs above within two minutes.Checklist
src/Filee.App/Assets/i18n/*.jsonfilesTHIRD-PARTY-NOTICES.md(none)🤖 Generated with Claude Code