diff --git a/SOURCES/cups-cve202010001.patch b/SOURCES/cups-cve202010001.patch new file mode 100644 index 0000000..efc6492 --- /dev/null +++ b/SOURCES/cups-cve202010001.patch @@ -0,0 +1,61 @@ +Fix for CVE-2020-10001, which is a bug in the CUPS ippReadIO function when it +reads tagged string values (nameWithLanguage and textWithLanguage). The +previous code verified that the length of the sub-strings (language identifier +and name/text value) did not exceed the size of the allocated buffer (1 byte +larger than the maximum IPP value size of 32767 bytes), but did not validate +against the length of the actual IPP value. + +The issues introduced by this vulnerability include: + +- Potential information disclosure by copying uninitialized areas of memory into + an IPP string value. +- Potential Denial of Service by supplying/using invalid string values when + strict validation has been disabled by the system administrator. + +This change ensures that: + +1. The language identifier does not extend beyond the end of the IPP value. +2. The length of the name/text string is within the IPP value. +3. The name/text string is within the IPP value. + +diff --git a/cups/ipp.c b/cups/ipp.c +index 3d529346c..adbb26fba 100644 +--- a/cups/ipp.c ++++ b/cups/ipp.c +@@ -2866,7 +2866,8 @@ ippReadIO(void *src, /* I - Data source */ + unsigned char *buffer, /* Data buffer */ + string[IPP_MAX_TEXT], + /* Small string buffer */ +- *bufptr; /* Pointer into buffer */ ++ *bufptr, /* Pointer into buffer */ ++ *bufend; /* End of buffer */ + ipp_attribute_t *attr; /* Current attribute */ + ipp_tag_t tag; /* Current tag */ + ipp_tag_t value_tag; /* Current value tag */ +@@ -3441,6 +3442,7 @@ ippReadIO(void *src, /* I - Data source */ + } + + bufptr = buffer; ++ bufend = buffer + n; + + /* + * text-with-language and name-with-language are composite +@@ -3454,7 +3456,7 @@ ippReadIO(void *src, /* I - Data source */ + + n = (bufptr[0] << 8) | bufptr[1]; + +- if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE) || n >= (int)sizeof(string)) ++ if ((bufptr + 2 + n + 2) > bufend || n >= (int)sizeof(string)) + { + _cupsSetError(IPP_STATUS_ERROR_INTERNAL, + _("IPP language length overflows value."), 1); +@@ -3481,7 +3483,7 @@ ippReadIO(void *src, /* I - Data source */ + bufptr += 2 + n; + n = (bufptr[0] << 8) | bufptr[1]; + +- if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE)) ++ if ((bufptr + 2 + n) > bufend) + { + _cupsSetError(IPP_STATUS_ERROR_INTERNAL, + _("IPP string length overflows value."), 1); + diff --git a/SOURCES/cups-fix-preservejob-times.patch b/SOURCES/cups-fix-preservejob-times.patch new file mode 100644 index 0000000..beed408 --- /dev/null +++ b/SOURCES/cups-fix-preservejob-times.patch @@ -0,0 +1,110 @@ +diff --git a/scheduler/job.c b/scheduler/job.c +index 82ef2eb..5d5e3aa 100644 +--- a/scheduler/job.c ++++ b/scheduler/job.c +@@ -448,10 +448,20 @@ cupsdCleanJobs(void) + curtime = time(NULL); + JobHistoryUpdate = 0; + ++ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCleanJobs: curtime=%d", (int)curtime); ++ + for (job = (cupsd_job_t *)cupsArrayFirst(Jobs); + job; + job = (cupsd_job_t *)cupsArrayNext(Jobs)) + { ++ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCleanJobs: Job %d, state=%d, printer=%p, history_time=%d, file_time=%d", job->id, (int)job->state_value, (void *)job->printer, (int)job->history_time, (int)job->file_time); ++ ++ if ((job->history_time && job->history_time < JobHistoryUpdate) || !JobHistoryUpdate) ++ JobHistoryUpdate = job->history_time; ++ ++ if ((job->file_time && job->file_time < JobHistoryUpdate) || !JobHistoryUpdate) ++ JobHistoryUpdate = job->file_time; ++ + if (job->state_value >= IPP_JOB_CANCELED && !job->printer) + { + /* +@@ -462,26 +472,14 @@ cupsdCleanJobs(void) + (job->history_time && job->history_time <= curtime)) + { + cupsdLogJob(job, CUPSD_LOG_DEBUG, "Removing from history."); +- cupsdDeleteJob(job, CUPSD_JOB_PURGE); ++ cupsdDeleteJob(job, CUPSD_JOB_PURGE); + } + else if (job->file_time && job->file_time <= curtime) + { + cupsdLogJob(job, CUPSD_LOG_DEBUG, "Removing document files."); +- cupsdLogJob(job, CUPSD_LOG_DEBUG2, "curtime=%ld, job->file_time=%ld", (long)curtime, (long)job->file_time); + remove_job_files(job); + + cupsdMarkDirty(CUPSD_DIRTY_JOBS); +- +- if (job->history_time < JobHistoryUpdate || !JobHistoryUpdate) +- JobHistoryUpdate = job->history_time; +- } +- else +- { +- if (job->history_time < JobHistoryUpdate || !JobHistoryUpdate) +- JobHistoryUpdate = job->history_time; +- +- if (job->file_time < JobHistoryUpdate || !JobHistoryUpdate) +- JobHistoryUpdate = job->file_time; + } + } + } +@@ -1873,7 +1871,7 @@ cupsdLoadJob(cupsd_job_t *job) /* I - Job */ + job->completed_time = attr->values[0].integer; + + if (JobHistory < INT_MAX) +- job->history_time = attr->values[0].integer + JobHistory; ++ job->history_time = job->completed_time + JobHistory; + else + job->history_time = INT_MAX; + +@@ -1884,7 +1882,7 @@ cupsdLoadJob(cupsd_job_t *job) /* I - Job */ + JobHistoryUpdate = job->history_time; + + if (JobFiles < INT_MAX) +- job->file_time = attr->values[0].integer + JobFiles; ++ job->file_time = job->completed_time + JobFiles; + else + job->file_time = INT_MAX; + +@@ -3100,8 +3098,10 @@ cupsdUpdateJobs(void) + * Update history/file expiration times... + */ + ++ job->completed_time = attr->values[0].integer; ++ + if (JobHistory < INT_MAX) +- job->history_time = attr->values[0].integer + JobHistory; ++ job->history_time = job->completed_time + JobHistory; + else + job->history_time = INT_MAX; + +@@ -3115,7 +3115,7 @@ cupsdUpdateJobs(void) + JobHistoryUpdate = job->history_time; + + if (JobFiles < INT_MAX) +- job->file_time = attr->values[0].integer + JobFiles; ++ job->file_time = job->completed_time + JobFiles; + else + job->file_time = INT_MAX; + +@@ -4909,7 +4909,7 @@ set_time(cupsd_job_t *job, /* I - Job to update */ + job->completed_time = curtime; + + if (JobHistory < INT_MAX && attr) +- job->history_time = attr->values[0].integer + JobHistory; ++ job->history_time = job->completed_time + JobHistory; + else + job->history_time = INT_MAX; + +@@ -4917,7 +4917,7 @@ set_time(cupsd_job_t *job, /* I - Job to update */ + JobHistoryUpdate = job->history_time; + + if (JobFiles < INT_MAX && attr) +- job->file_time = curtime + JobFiles; ++ job->file_time = job->completed_time + JobFiles; + else + job->file_time = INT_MAX; + diff --git a/SOURCES/cups-logs.patch b/SOURCES/cups-logs.patch new file mode 100644 index 0000000..5698618 --- /dev/null +++ b/SOURCES/cups-logs.patch @@ -0,0 +1,100 @@ +diff --git a/scheduler/log.c b/scheduler/log.c +index 33cdac6..d66bbf9 100644 +--- a/scheduler/log.c ++++ b/scheduler/log.c +@@ -597,51 +597,6 @@ cupsdLogJob(cupsd_job_t *job, /* I - Job */ + if (level > LogLevel && LogDebugHistory <= 0) + return (1); + +-#ifdef HAVE_SYSTEMD_SD_JOURNAL_H +- if (!strcmp(ErrorLog, "syslog")) +- { +- cupsd_printer_t *printer = job ? (job->printer ? job->printer : (job->dest ? cupsdFindDest(job->dest) : NULL)) : NULL; +- static const char * const job_states[] = +- { /* job-state strings */ +- "Pending", +- "PendingHeld", +- "Processing", +- "ProcessingStopped", +- "Canceled", +- "Aborted", +- "Completed" +- }; +- +- va_start(ap, message); +- +- do +- { +- va_copy(ap2, ap); +- status = format_log_line(message, ap2); +- va_end(ap2); +- } +- while (status == 0); +- +- va_end(ap); +- +- if (job) +- sd_journal_send("MESSAGE=%s", log_line, +- "PRIORITY=%i", log_levels[level], +- PWG_Event"=JobStateChanged", +- PWG_ServiceURI"=%s", printer ? printer->uri : "", +- PWG_JobID"=%d", job->id, +- PWG_JobState"=%s", job->state_value < IPP_JSTATE_PENDING ? "" : job_states[job->state_value - IPP_JSTATE_PENDING], +- PWG_JobImpressionsCompleted"=%d", ippGetInteger(job->impressions, 0), +- NULL); +- else +- sd_journal_send("MESSAGE=%s", log_line, +- "PRIORITY=%i", log_levels[level], +- NULL); +- +- return (1); +- } +-#endif /* HAVE_SYSTEMD_SD_JOURNAL_H */ +- + /* + * Format and write the log message... + */ +@@ -705,7 +660,43 @@ cupsdLogJob(cupsd_job_t *job, /* I - Job */ + return (1); + } + else if (level <= LogLevel) ++ { ++#ifdef HAVE_SYSTEMD_SD_JOURNAL_H ++ if (!strcmp(ErrorLog, "syslog")) ++ { ++ cupsd_printer_t *printer = job ? (job->printer ? job->printer : (job->dest ? cupsdFindDest(job->dest) : NULL)) : NULL; ++ static const char * const job_states[] = ++ { /* job-state strings */ ++ "Pending", ++ "PendingHeld", ++ "Processing", ++ "ProcessingStopped", ++ "Canceled", ++ "Aborted", ++ "Completed" ++ }; ++ ++ if (job) ++ sd_journal_send("MESSAGE=%s", log_line, ++ "PRIORITY=%i", log_levels[level], ++ PWG_Event"=JobStateChanged", ++ PWG_ServiceURI"=%s", printer ? printer->uri : "", ++ PWG_JobID"=%d", job->id, ++ PWG_JobState"=%s", job->state_value < IPP_JSTATE_PENDING ? "" : job_states[job->state_value - IPP_JSTATE_PENDING], ++ PWG_JobImpressionsCompleted"=%d", ippGetInteger(job->impressions, 0), ++ NULL); ++ else ++ sd_journal_send("MESSAGE=%s", log_line, ++ "PRIORITY=%i", log_levels[level], ++ NULL); ++ ++ return (1); ++ } ++ else ++#endif /* HAVE_SYSTEMD_SD_JOURNAL_H */ ++ + return (cupsdWriteErrorLog(level, log_line)); ++ } + else + return (1); + } diff --git a/SOURCES/cups-sssd.patch b/SOURCES/cups-sssd.patch new file mode 100644 index 0000000..b0a7d76 --- /dev/null +++ b/SOURCES/cups-sssd.patch @@ -0,0 +1,13 @@ +diff --git a/scheduler/org.cups.cupsd.service.in b/scheduler/org.cups.cupsd.service.in +index 11e0662..6fb7a32 100644 +--- a/scheduler/org.cups.cupsd.service.in ++++ b/scheduler/org.cups.cupsd.service.in +@@ -1,7 +1,7 @@ + [Unit] + Description=CUPS Scheduler + Documentation=man:cupsd(8) +-After=network.target ypbind.service ++After=network.target nss-user-lookup.target + + [Service] + ExecStart=@sbindir@/cupsd -l diff --git a/SOURCES/cups-validate-1st.patch b/SOURCES/cups-validate-1st.patch new file mode 100644 index 0000000..e7b9070 --- /dev/null +++ b/SOURCES/cups-validate-1st.patch @@ -0,0 +1,28 @@ +diff --git a/backend/ipp.c b/backend/ipp.c +index 0a70a87..f8bf7e1 100644 +--- a/backend/ipp.c ++++ b/backend/ipp.c +@@ -327,6 +327,7 @@ main(int argc, /* I - Number of command-line args */ + get_job_attrs = 0, /* Does printer support Get-Job-Attributes? */ + send_document = 0, /* Does printer support Send-Document? */ + validate_job = 0, /* Does printer support Validate-Job? */ ++ validation_retried = 0, /* Indicate whether Validate-Job was retried */ + copies, /* Number of copies for job */ + copies_remaining; /* Number of copies remaining */ + const char *content_type, /* CONTENT_TYPE environment variable */ +@@ -1597,7 +1598,15 @@ main(int argc, /* I - Number of command-line args */ + ipp_status == IPP_BAD_REQUEST) + break; + else if (job_auth == NULL && ipp_status > IPP_BAD_REQUEST) ++ { ++ if (!validation_retried) ++ { ++ validation_retried = 1; ++ sleep(10); ++ continue; ++ } + goto cleanup; ++ } + } + + /* diff --git a/SPECS/cups.spec b/SPECS/cups.spec index 5110061..8051d01 100644 --- a/SPECS/cups.spec +++ b/SPECS/cups.spec @@ -15,7 +15,7 @@ Summary: CUPS printing system Name: cups Epoch: 1 Version: 2.2.6 -Release: 38%{?dist} +Release: 40%{?dist} License: GPLv2+ and LGPLv2 with exceptions and AML Url: http://www.cups.org/ Source0: https://github.com/apple/cups/releases/download/v%{VERSION}/cups-%{VERSION}-source.tar.gz @@ -101,6 +101,16 @@ Patch56: cups-failover-backend.patch Patch57: cups-dirtyclean.patch # 1775590 - rastertoepson filter crashes with paper size A6 Patch58: cups-rastertoepson-crash.patch +# 1941437 - cupsd doesn't log job ids when logging into journal +Patch59: cups-logs.patch +# 1782216 - Print queue is paused after ipp backend ends with CUPS_BACKEND_STOP +Patch60: cups-validate-1st.patch +# 1938384 - CUPS doesn't start if sssd starts after cupsd +Patch61: cups-sssd.patch +# 1955964 - PreserveJobHistory doesn't work with seconds +Patch62: cups-fix-preservejob-times.patch +# 1927452 - CVE-2020-10001 cups: access to uninitialized buffer in ipp.c [rhel-8] +Patch63: cups-cve202010001.patch Patch100: cups-lspp.patch @@ -345,6 +355,16 @@ Sends IPP requests to the specified URI and tests and/or displays the results. %patch57 -p1 -b .dirtyclean # 1775590 - rastertoepson filter crashes with paper size A6 %patch58 -p1 -b .rastertoepson-crash +# 1941437 - cupsd doesn't log job ids when logging into journal +%patch59 -p1 -b .logs +# 1782216 - Print queue is paused after ipp backend ends with CUPS_BACKEND_STOP +%patch60 -p1 -b .validate-1st +# 1938384 - CUPS doesn't start if sssd starts after cupsd +%patch61 -p1 -b .sssd +# 1955964 - PreserveJobHistory doesn't work with seconds +%patch62 -p1 -b .cups-fix-preservejob-times +# 1927452 - CVE-2020-10001 cups: access to uninitialized buffer in ipp.c [rhel-8] +%patch63 -p1 -b .cve202010001 sed -i -e '1iMaxLogSize 0' conf/cupsd.conf.in @@ -755,6 +775,15 @@ rm -f %{cups_serverbin}/backend/smb %{_mandir}/man5/ipptoolfile.5.gz %changelog +* Fri May 14 2021 Zdenek Dohnal - 1:2.2.6-40 +- 1955964 - PreserveJobHistory doesn't work with seconds +- 1927452 - CVE-2020-10001 cups: access to uninitialized buffer in ipp.c [rhel-8] + +* Wed May 05 2021 Zdenek Dohnal - 1:2.2.6-39 +- 1941437 - cupsd doesn't log job ids when logging into journal +- 1782216 - Print queue is paused after ipp backend ends with CUPS_BACKEND_STOP +- 1938384 - CUPS doesn't start if sssd starts after cupsd + * Tue May 26 2020 Zdenek Dohnal - 1:2.2.6-38 - 1775590 - rastertoepson filter crashes with paper size A6