From 2e571a4c0a82de181e782e434a30967f0ba358ff Mon Sep 17 00:00:00 2001 From: andreer Date: Sat, 26 Sep 2026 14:57:04 +0200 Subject: [PATCH] Fix use-after-free deleting an in-use printer. create_local_bg_thread() holds a reference to the printer via printer->use while it generates the IPP Everywhere PPD. cupsdDeleteTemporaryPrinters() respected that reference, but cupsdDeletePrinter() did not, so an explicit CUPS-Delete-Printer (as cups-browsed issues when it replaces a discovered queue) freed the printer mid-thread and corrupted the heap ("corrupted double-linked list"). Defer deletion while printer->use > 0 by flagging the printer under printer->lock; cupsdDeleteTemporaryPrinters() then reaps it once the thread releases its reference. Extends the use-count protection from #1655 to the explicit deletion path. --- CHANGES.md | 1 + scheduler/printers.c | 25 +++++++++++++++++++++++-- scheduler/printers.h | 1 + 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 18580cb36..2bab342fb 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -188,6 +188,7 @@ v2.5b1 - YYYY-MM-DD - Fixed renewal of expired self-signed certificates (Issue #1590) - Fixed potential crash bug in `cupsCheckDestSupported` function. - Fixed validation of "job-hold-until" time values (Issue #1708) +- Fixed use-after-free when deleting a printer during background PPD creation. - Removed hash support for SHA2-512-224 and SHA2-512-256. - Removed `mantohtml` script for generating html pages (use `https://www.msweet.org/mantohtml/`) diff --git a/scheduler/printers.c b/scheduler/printers.c index 1e3f7c080..ec2ffe588 100644 --- a/scheduler/printers.c +++ b/scheduler/printers.c @@ -661,6 +661,25 @@ cupsdDeletePrinter( cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDeletePrinter(p=%p(%s), update=%d)", (void *)p, p->name, update); + /* + * Don't free the printer while a background thread still holds a + * reference (create_local_bg_thread() generating the PPD); flag it and + * let cupsdDeleteTemporaryPrinters() reap it once the thread is done. + */ + + cupsRWLockWrite(&p->lock); + if (p->use > 0) + { + p->pending_delete = 1; + cupsRWUnlock(&p->lock); + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "Deferring deletion of printer \"%s\" (use=%d) until " + "background thread finishes.", p->name, p->use); + return (0); + } + cupsRWUnlock(&p->lock); + /* * Save the current position in the Printers array... */ @@ -829,8 +848,10 @@ cupsdDeleteTemporaryPrinters(int force) /* I - Force deletion instead of auto? * for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; p = (cupsd_printer_t *)cupsArrayNext(Printers)) { - if (p->temporary && p->use == 0 && - (force || (p->state_time < unused_time && p->state != IPP_PSTATE_PROCESSING))) + if (p->use == 0 && + (p->pending_delete || + (p->temporary && + (force || (p->state_time < unused_time && p->state != IPP_PSTATE_PROCESSING))))) cupsdDeletePrinter(p, 0); } } diff --git a/scheduler/printers.h b/scheduler/printers.h index bd2375bdb..102633339 100644 --- a/scheduler/printers.h +++ b/scheduler/printers.h @@ -49,6 +49,7 @@ struct cupsd_printer_s int shared; /* Shared? */ int temporary; /* Temporary queue? */ int use; /* Use count */ + int pending_delete; /* Deletion deferred while use > 0? */ int accepting; /* Accepting jobs? */ int holding_new_jobs; /* Holding new jobs for printing? */ int in_implicit_class; /* In an implicit class? */