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/SPECS/cups.spec b/SPECS/cups.spec index bccdd43..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: 39%{?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 @@ -107,6 +107,10 @@ Patch59: cups-logs.patch 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 @@ -357,6 +361,10 @@ Sends IPP requests to the specified URI and tests and/or displays the results. %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 @@ -767,6 +775,10 @@ 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