Skip to content

fix: do not pre-size the xref table from the untrusted /Size - #98

Open
prostomarkeloff wants to merge 1 commit into
ledongthuc:masterfrom
prostomarkeloff:fix-xref-size-overalloc
Open

prostomarkeloff wants to merge 1 commit into
ledongthuc:masterfrom
prostomarkeloff:fix-xref-size-overalloc

Conversation

@prostomarkeloff

Copy link
Copy Markdown

Found with find-dup-defs using its converge pass, which flagged readXrefStream against readXrefTable.

read.go readXrefStream pre-sizes the xref table from the attacker-controlled /Size entry: table := make([]xref, size), with size read unchecked from the xref-stream dictionary. A ~130-byte PDF whose xref stream declares a large /Size (e.g. 50,000,000) forces a multi-gigabyte allocation before any stream data is read. The recover() in NewReaderEncrypted catches the makeslice: len out of range panic for absurd sizes, but a large-yet-allocatable size drives a genuine runtime: out of memory, which is fatal and unrecoverable — a memory-exhaustion DoS from a tiny file.

The twin readXrefTable does not trust /Size: it grows its table incrementally via ensureXrefLen and only truncates with /Size at the end. readXrefStreamData likewise grows the slice via ensureXrefLen, so the eager pre-size in readXrefStream is unnecessary.

Fix: drop the eager pre-size (table := []xref(nil)); the table is grown on demand.

Added a regression test asserting a 134-byte PDF with /Size = 50,000,000 no longer allocates gigabytes.

Disclosure: prepared with the help of an AI tool; I have reviewed the change and test and understand each line.

readXrefStream did `table := make([]xref, size)` where size is the /Size
entry read straight from the xref-stream dictionary, with no bound. A ~130
byte PDF declaring a huge /Size forces a multi-gigabyte allocation (OOM;
the fatal runtime out-of-memory is not caught by the recover() in
NewReaderEncrypted). readXrefStreamData already grows the table on demand
via ensureXrefLen, so the eager pre-size is unnecessary.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant