Skip to content

texttopdf: range-check the column-width computation - #268

Open
ManasBagul23 wants to merge 1 commit into
OpenPrinting:masterfrom
ManasBagul23:fix-texttopdf-columnwidth-overflow
Open

ManasBagul23 wants to merge 1 commit into
OpenPrinting:masterfrom
ManasBagul23:fix-texttopdf-columnwidth-overflow

Conversation

@ManasBagul23

Copy link
Copy Markdown

Problem

write_prolog() derives ColumnWidth from the "columns" option
(doc->PageColumns), which only has a lower-bound check (>= 1) — there is
no upper bound. The computation itself:

doc->ColumnWidth = (doc->SizeColumns - doc->ColumnGutter *
                    (doc->PageColumns - 1)) /
                    doc->PageColumns;

is done entirely in plain int arithmetic. A large PageColumns value
(e.g. columns=429496747) overflows the ColumnGutter * (PageColumns - 1)
product (and/or the final division), wrapping what should be a deeply
negative/rejected result into a small positive ColumnWidth instead.

That bogus ColumnWidth then corrupts the page-column write-site math in
cfFilterTextToPDF(): i = column + page_column * (ColumnWidth + ColumnGutter) is used to index doc->Page[line][i] directly with no
further bound check, and page_column is only bounds-checked against the
(also wrong, since it mirrors the same user input) doc->PageColumns. With
ColumnWidth wrongly small, page_column can climb far past what
doc->SizeColumns cells were actually allocated for, producing a
heap-buffer-overflow write.

Fixes #195

Fix

Do the gutter product and the resulting column width in long long first,
and reject the page (matching write_prolog()'s existing error convention
— log and return 1, already used a few lines above for a bad charset file)
if the real result doesn't fit between 1 and doc->SizeColumns, instead of
silently using a wrapped value.

Verified

No C build toolchain available locally to compile-check. Verified by
tracing doc->ColumnWidth's only two downstream uses that matter for
allocation safety: the page_column >= doc->PageColumns page-wrap check
(which the corrupted PageColumns value itself doesn't protect) and the
direct doc->Page[line][i] write in cfFilterTextToPDF(), confirming the
invariant page_column * (ColumnWidth + ColumnGutter) + column < SizeColumns only holds when ColumnWidth is computed without overflow.

write_prolog() derives ColumnWidth from the "columns" option
(doc->PageColumns), which only has a lower-bound check (>= 1) -- there
is no upper bound. The computation itself:

    doc->ColumnWidth = (doc->SizeColumns - doc->ColumnGutter *
                        (doc->PageColumns - 1)) / doc->PageColumns;

is done entirely in plain "int" arithmetic. A large PageColumns value
(e.g. columns=429496747) overflows the ColumnGutter * (PageColumns - 1)
product (and/or the final division), wrapping what should be a deeply
negative/rejected result into a small positive ColumnWidth instead.

That bogus ColumnWidth then corrupts the page-column write-site math in
cfFilterTextToPDF(): "i = column + page_column * (ColumnWidth +
ColumnGutter)" is used to index doc->Page[line][i] directly with no
further bound check, and page_column is only bounds-checked against the
(also wrong, since it mirrors the same user input) doc->PageColumns.
With ColumnWidth wrongly small, page_column can climb far past what
doc->SizeColumns cells were actually allocated for, producing a
heap-buffer-overflow write.

Do the gutter product and the resulting column width in "long long"
first, and reject the page (matching write_prolog()'s existing error
convention -- log and return 1, already used a few lines above for a
bad charset file) if the real result doesn't fit between 1 and
doc->SizeColumns, instead of silently using a wrapped value.

Verified by tracing doc->ColumnWidth's only two downstream uses that
matter for allocation safety: the "page_column >= doc->PageColumns"
page-wrap check (which the corrupted PageColumns value itself doesn't
protect) and the direct doc->Page[line][i] write in
cfFilterTextToPDF() circa line 1404, confirming the invariant
page_column * (ColumnWidth + ColumnGutter) + column < SizeColumns only
holds when ColumnWidth is computed without overflow. No C build
toolchain available locally to compile-check.

Fixes OpenPrinting#195
Copilot AI balanced review requested due to automatic review settings October 5, 2026 18:44

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

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.

texttopdf: column-layout integer overflow causes heap out-of-bounds access

2 participants