Commit Graph

11 Commits

Author SHA1 Message Date
Brandon Thomas 20842c72e3 Never crash: Type 1 font programs can't hang or overflow the stack (skrifa 0.47)
The nightly fuzz job found a Type 1 font that hung hayro: read-fonts 0.39
(through skrifa 0.42) looked ahead after every integer by parsing the next
token, which looked ahead again, recursing through a whole run of numbers.
A long run hung; 20,000 numbers overflowed the stack and aborted the
process. Upstream fixed the tokenizer; the vendored hayro-interpret now uses
skrifa 0.47 (read-fonts 0.44), with its one API change. The finding finishes
in 0.5 s. Synthetic regression test (it aborts with the old skrifa).
Corpus sweep: 0 regressions; text oracle unchanged (median F1 0.980, mean
0.866, every per-file score identical).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 10:47:39 -04:00
Brandon Thomas 6e90710e4b Never crash: JBIG2 images can't decode billions of pixels
The nightly fuzz job found a JBIG2 symbol dictionary that decoded for
minutes: each bitmap side may be 65535, and up to 65535 symbols are decoded
pixel by pixel. Vendored hayro-jbig2 0.3.0 with two bounds: at most 2^28
pixels per bitmap (also the page bitmap, halftone grid and grayscale image),
and at most 2^26 symbol pixels per dictionary. The finding now finishes in
about a second. Synthetic regression test (a 65535 x 65535 page and region
behind a small /Width and /Height); the corpus sweep shows 0 regressions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 08:28:52 -04:00
Brandon Thomas 2f364665b8 Never crash: the fuzz job's eleven hangs finish (parser retries, inline images, Type 3 fan-out)
Every hang the nightly fuzz job found (11 findings, 8 source files) now
finishes in 0.1-2 s; each cause has a synthetic regression test that times
out without its fix.
- cos (7 findings, our own parser): a stream whose /Length pointed at
  itself, with no endstream, made every parse attempt fail and each attempt
  reload the same object: ~2^32 parses. Objects being loaded are a seen-set,
  /Length values are memoised per load, and the shifted-header retry only
  runs when the header is shifted.
- hayro-syntax (3): deciding where an inline image's data ends re-parsed the
  rest of the stream, nesting through every inline image; 50 images ran for
  over ten minutes. The look-ahead no longer nests and is bounded (256).
- hayro-interpret (1): a Type 3 glyph showing eight glyphs of its own font,
  sixteen deep. Nested paints share a per-page budget (50,000).
The pdf.js corpus sweep matches its baseline (963 ok, same 20 known).
xtask check writes its report under CARGO_TARGET_DIR too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 07:35:38 -04:00
Brandon Thomas a5d830bf25 Never crash: predictor rows and stroke widths from the input can't exhaust memory
The second full nightly fuzz run on main found two more:
- hayro-syntax computed a Flate/LZW predictor row as columns × bits in
  wrapping arithmetic: /Columns 9223372036854775807 asked for 2^61 bytes and
  aborted on any machine. Row widths are now saturating usize (colors × bits
  also overflowed u8), a zero width is refused (it divided by zero), and a
  row longer than the data is not allocated (empty output, as before).
- hayro stroked /LW 9223372036854775807 as given, and stroke expansion
  allocated 10 GB. Widths are clamped to 4 × (canvas width + height) device
  pixels, which covers the same pixels.
Both findings now run in 8 MB. Synthetic regression test in render.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 01:06:45 -04:00
Brandon Thomas 6058068266 Never crash: absurd image-mask and CCITT sizes are refused before decoding
The first full nightly fuzz run on main (now that the runner survives) found
two 4 GiB allocations, caught by the 4 GiB child cap:
- an inline stencil mask claiming /W 4294967295 was decoded in hayro-interpret
  before the renderer's MAX_IMAGE_PIXELS check could skip it (locally 9.6 GB,
  42 s). Vendored patch image_size_ok: images and masks over 2^28 pixels are
  not decoded.
- a CCITT image whose /DecodeParms claimed /Columns 4294967295 (with a small
  /Width) sized the decoder's line buffers (locally 4.3 GB). Vendored patch
  ccitt_size_ok in hayro-syntax: at most 2^20 columns and 2^28 pixels.
Both findings now run in 7 MB. Synthetic regression test in render.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 00:10:17 -04:00
Brandon Thomas 1449b71a19 Never crash: bound the allocations behind the nightly fuzz runner's out-of-memory deaths
Fuzzed inputs drove one check-one process to 2-6 GB (the 16 GB CI runner
running two of them was killed every night). Three causes, each with a test:
- lopdf (bootstrap inspector) sized PNG predictor rows from /Columns before
  reading data: /Columns 4294967295 allocated two 4 GiB rows. Vendored lopdf
  0.45.0 refuses rows longer than the data (and uses saturating row widths);
  its load-time stream decoding also gets a 256 MiB limit (it had none).
- hayro sized a tiling pattern's cell pixmap from /XStep x scale, bounded only
  by u16: a step far beyond /BBox allocated 2 GB. The vendored patch keeps
  the cell within 3000 px a side, lowering the resolution instead.
- cos decoded cross-reference streams up to the general 1 GiB limit; they now
  stop at what 8,388,607 objects' rows can hold (~200 MB at most), and the
  section is reconstructed (logged) instead.

On the nightly's seed (41) the worst captured input fell from 6.2 GB to 6 MB,
and a 300 s fuzz run had no process above 300 MB (before: many at 2-5 GB).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 17:59:25 -04:00
Brandon Thomas 859f03d26e M5: Comment polish: Mark with checkmark (hidden /StateModel /Marked reply; card toggle and menus), Locked comments (Properties ▸ Locked; refuse move/resize/restyle/delete), Copy text, Hide/Show all comments (render setting, vendored hayro patch), Summarize comments (Comments only layout, sort by page/author/date/type); comments panel "…" menu gains hide, summary, export, import; card menu anchored to its button; comment_mark/comment_lock/comments_hide/comments_summarize tools (79 tools)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 02:02:14 -04:00
Brandon Thomas ee254a91a2 M2.6: fuzz findings in the bootstrap renderer: paint-nesting cap now covers Type 3 glyphs (stack overflow), hayro skips images over 2^28 px (hang); regression tests
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 09:48:52 -04:00
Brandon Thomas 675b258e77 M2.6: hayro-interpret patches from fuzzing: tiling-pattern nesting cap (stack overflow), CID width ranges clamped to 65535 (hang)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 09:20:36 -04:00
Brandon Thomas 2849ad8922 M2.6: vendor hayro-syntax 0.7.2 with a page-tree cycle guard (stack overflow on /Kids loops in object streams)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 08:43:41 -04:00
Brandon Thomas 108fdc108c more progress, roadmap, wip 2026-09-30 11:00:02 -04:00