Skip to content

GHSA-7j85-5r23-xhvh

CVE Information

Summary

cupsd removes client-supplied read-only IPP Job Status attributes with a deny-list that deletes only the first attribute of each name. Sending the same attribute twice in an unauthenticated Print-Job/Create-Job leaves the second copy, which is persisted into the job control file and — because attribute lookups are first-match — read back in place of the value cupsd computed. This yields, from one unauthenticated request:

  1. Persistent DoS (root daemon): a forged out-of-range job-state enum is adopted without validation on the next scheduler start and used as an unbounded array index in cupsdLogJob(), causing an out-of-bounds read and SIGSEGV during startup. cupsd then crashes on every restart until an admin deletes the spool file. Reached when ErrorLog syslog (or PageLog syslog) is set on a systemd-journal build.
  2. Persistent job-status / audit forgery (default config): the same bypass lets an unauthenticated client set arbitrary job-state, time-at-*, job-id, etc., returned to all clients ahead of the real values.

Details

1. Read-only filter deletes only the first duplicate — scheduler/ipp.c:1260, add_job():

for (i = 0; i < (int)(sizeof(readonly)/sizeof(readonly[0])); i ++)
  if ((attr = ippFindAttribute(con->request, readonly[i], IPP_TAG_ZERO)) != NULL)
    ippDeleteAttribute(con->request, attr);   /* deletes ONE only */
ippFindAttribute() returns the first match; the loop deletes it once. A repeated name survives. add_job() then does job->attrs = con->request and appends cupsd's own values, so the attacker's copy is ordered first and wins every later ippFindAttribute() lookup (in cupsd and in libcups clients).

2. Forged job-state adopted without a range check — scheduler/job.c:1727, cupsdLoadJob():

job->state_value = (ipp_jstate_t)job->state->values[0].integer;   /* no bounds check */

3. Unbounded index sink — scheduler/log.c:670, cupsdLogJob():

job->state_value < IPP_JSTATE_PENDING ? "" : job_states[job->state_value - IPP_JSTATE_PENDING]
job_states[] has 7 entries and only the lower bound is checked. 0x41414141 - 3 = 1094795582 reads far out of bounds; the resulting const char * is passed to sd_journal_send() as %s → SIGSEGV. A second unbounded site with no bounds check at all is at scheduler/log.c:1002 (PageLog syslog). Note libcups' own ippEnumString() (cups/ipp-support.c) is correctly range-checked — the scheduler reimplemented the mapping without the check.

PoC

Full build + config + scripts are in the attached REPRODUCTION.md. Minimal DoS: unauthenticated Print-Job to a real queue with two job-state attributes (the first is deleted, the second — 0x41414141 — survives), then reload the scheduler (systemctl reload cups, i.e. SIGHUP) or restart it.

Observed on cupsd 2.4.19 built with clang -fsanitize=address,undefined, ErrorLog syslog:

log.c:670:70: runtime error: index 1094795582 out of bounds for type 'const char *const[7]'
AddressSanitizer: SEGV (READ) in cupsdLogJob scheduler/log.c:670
  <- unload_job job.c:5102 <- load_job_cache job.c:4424
  <- cupsdLoadAllJobs job.c:1634 <- cupsdReadConfiguration conf.c:1687 <- main main.c:547
cupsd then fails to start on every subsequent launch until /var/spool/cups/c* is deleted.

Reachability: default cupsd listens on loopback and <Location /> Order allow,deny denies non-loopback clients, so this is a local attacker by default; a job to a non-existent queue is rejected (queue names are discoverable unauthenticated via CUPS-Get-Printers). The forgery impact needs no non-default setting; the crash additionally needs syslog-based logging on a systemd build.

Impact

  • Availability: unauthenticated permanent DoS of cupsd (runs as root); recovery needs manual spool cleanup. Detonates on the next reload/restart/upgrade/reboot.
  • Integrity: unauthenticated persistent forgery of print-job status and audit metadata served to all clients, plus injection of out-of-spec enums into third-party IPP clients. poc_cupsd_persistent_dos.py poc_readonly_bypass.py REPRODUCTION.md

Fix

[master 5d48d78790753c04078f9889538e41a5805f96a0] Fix job state validation (GHSA-7j85-5r23-xhvh) [2.4.x d641482ad909243bc331ebe5308297cd81a557b3] Improve job status attribute handling (GHSA-7j85-5r23-xhvh)