Skip to content

pclmtoraster: reject a page with an unsupported /Rotate value - #277

Open
ManasBagul23 wants to merge 1 commit into
OpenPrinting:masterfrom
ManasBagul23:fix-pclmtoraster-unsupported-rotation-uaf
Open

ManasBagul23 wants to merge 1 commit into
OpenPrinting:masterfrom
ManasBagul23:fix-pclmtoraster-unsupported-rotation-uaf

Conversation

@ManasBagul23

Copy link
Copy Markdown
Contributor

Fixes #186

rotate_bitmap() only implements rotations of 90, 180 and 270 degrees. For any other nonzero value it logs an error and returns its src argument unchanged — not the dst buffer the caller allocated for the rotated result.

out_page() cannot tell the two outcomes apart: it always treats the return value as the new bitmap, frees the original data->bitmap, and assigns the (for an unsupported rotation, identical) returned pointer to data->bitmap. That frees the buffer the caller is about to keep using (use-after-free, read by every row of the subsequent raster-conversion loop), and the function's own end-of-page cleanup frees data->bitmap a second time (double free). The destination buffer allocated right before the call is also leaked, since the local holding it is overwritten with the return value.

/Rotate is read straight from the PDF page dictionary with no range check, so a page declaring any value outside {0, 90, 180, 270} (e.g. 45) reaches this.

Reject the page as soon as /Rotate is read, before the allocate/rotate/free sequence that depends on it ever runs — matching the function's existing return (1) convention, used a few lines below for an invalid mediaBox.

Verified by tracing rotate_bitmap()'s only non-aliasing-safe return paths (90/180/270, which fill and return the actual dst) against the one aliasing path this guard removes (the else branch, which returns src) and confirming out_page()'s use of the return value only assumes the former.

rotate_bitmap() only implements rotations of 90, 180 and 270 degrees. For
any other nonzero value it logs an error and returns its *src* argument
unchanged -- not the *dst* buffer the caller allocated for the rotated
result.

out_page() cannot tell the two outcomes apart: it always treats the
return value as the new bitmap, frees the original data->bitmap, and
assigns the (for an unsupported rotation, identical) returned pointer to
data->bitmap. That frees the buffer the caller is about to keep using
(use-after-free, read by every row of the subsequent raster-conversion
loop), and the function's own end-of-page cleanup frees data->bitmap a
second time (double free). The destination buffer allocated right before
the call is also leaked, since the local holding it is overwritten with
the return value.

/Rotate is read straight from the PDF page dictionary with no range
check, so a page declaring any value outside {0, 90, 180, 270} (e.g. 45)
reaches this.

Reject the page as soon as /Rotate is read, before the allocate/rotate/
free sequence that depends on it ever runs -- matching the function's
existing `return (1)` convention, used a few lines below for an invalid
mediaBox.

Verified by tracing rotate_bitmap()'s only non-aliasing-safe return paths
(90/180/270, which fill and return the actual `dst`) against the one
aliasing path this guard removes (the `else` branch, which returns `src`)
and confirming out_page()'s use of the return value only assumes the
former. No C build toolchain available locally to compile-check.

Fixes OpenPrinting#186
Copilot AI balanced review requested due to automatic review settings October 10, 2026 19:34

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.

PCLm unsupported rotation UAF and double free

2 participants