From d29c2e3b2357bdecb7e1fb5a71303f768b99218f Mon Sep 17 00:00:00 2001 From: Zdenek Dohnal Date: Fri, 12 Dec 2025 10:05:06 +0100 Subject: [PATCH] RHEL-129740 CVE-2025-61915 cups: Local denial-of-service via cupsd.conf update and related issues Resolves: RHEL-129740 --- 0001-Fix-various-issues-in-cupsd.patch | 294 ++++++++++++++++++ ...pping-scheduler-on-unknown-directive.patch | 43 +++ cups.spec | 9 + 3 files changed, 346 insertions(+) create mode 100644 0001-Fix-various-issues-in-cupsd.patch create mode 100644 0001-conf.c-Fix-stopping-scheduler-on-unknown-directive.patch diff --git a/0001-Fix-various-issues-in-cupsd.patch b/0001-Fix-various-issues-in-cupsd.patch new file mode 100644 index 0000000..406be72 --- /dev/null +++ b/0001-Fix-various-issues-in-cupsd.patch @@ -0,0 +1,294 @@ +diff -up cups-2.3.3op2/conf/cups-files.conf.in.config-issues cups-2.3.3op2/conf/cups-files.conf.in +--- cups-2.3.3op2/conf/cups-files.conf.in.config-issues 2021-02-01 22:10:25.000000000 +0100 ++++ cups-2.3.3op2/conf/cups-files.conf.in 2025-12-09 18:41:09.687817899 +0100 +@@ -19,6 +19,9 @@ + SystemGroup @CUPS_SYSTEM_GROUPS@ + @CUPS_SYSTEM_AUTHKEY@ + ++# Are Unix domain socket peer credentials used for authorization? ++PeerCred @CUPS_PEER_CRED@ ++ + # User that is substituted for unauthenticated (remote) root accesses... + #RemoteRoot remroot + +diff -up cups-2.3.3op2/config.h.in.config-issues cups-2.3.3op2/config.h.in +--- cups-2.3.3op2/config.h.in.config-issues 2021-02-01 22:10:25.000000000 +0100 ++++ cups-2.3.3op2/config.h.in 2025-12-09 18:41:09.688176411 +0100 +@@ -95,6 +95,13 @@ + + + /* ++ * Default PeerCred value... ++ */ ++ ++#define CUPS_DEFAULT_PEER_CRED "on" ++ ++ ++/* + * Default MaxCopies value... + */ + +diff -up cups-2.3.3op2/config-scripts/cups-defaults.m4.config-issues cups-2.3.3op2/config-scripts/cups-defaults.m4 +--- cups-2.3.3op2/config-scripts/cups-defaults.m4.config-issues 2025-12-09 18:41:09.634850790 +0100 ++++ cups-2.3.3op2/config-scripts/cups-defaults.m4 2025-12-09 18:43:05.131232695 +0100 +@@ -121,6 +121,15 @@ AC_ARG_WITH(log_level, [ --with-log-lev + AC_SUBST(CUPS_LOG_LEVEL) + AC_DEFINE_UNQUOTED(CUPS_DEFAULT_LOG_LEVEL, "$CUPS_LOG_LEVEL") + ++dnl Default PeerCred ++AC_ARG_WITH([peer_cred], AS_HELP_STRING([--with-peer-cred], [set default PeerCred value (on/off/root-only), default=on]), [ ++ CUPS_PEER_CRED="$withval" ++], [ ++ CUPS_PEER_CRED="on" ++]) ++AC_SUBST([CUPS_PEER_CRED]) ++AC_DEFINE_UNQUOTED([CUPS_DEFAULT_PEER_CRED], ["$CUPS_PEER_CRED"], [Default PeerCred value.]) ++ + dnl Default AccessLogLevel + AC_ARG_WITH(access_log_level, [ --with-access-log-level set default AccessLogLevel value, default=none], + CUPS_ACCESS_LOG_LEVEL="$withval", +diff -up cups-2.3.3op2/doc/help/man-cups-files.conf.html.config-issues cups-2.3.3op2/doc/help/man-cups-files.conf.html +--- cups-2.3.3op2/doc/help/man-cups-files.conf.html.config-issues 2021-02-01 22:10:25.000000000 +0100 ++++ cups-2.3.3op2/doc/help/man-cups-files.conf.html 2025-12-09 18:41:09.688311554 +0100 +@@ -122,6 +122,13 @@ The default is "/var/log/cups/page_log". +
PassEnv variable [ ... variable ] +
Passes the specified environment variable(s) to child processes. + Note: the standard CUPS filter and backend environment variables cannot be overridden using this directive. ++
PeerCred off ++
PeerCred on ++
PeerCred root-only ++
Specifies whether peer credentials are used for authorization when communicating over the UNIX domain socket. ++When on, the peer credentials of any user are accepted for authorization. ++The value off disables the use of peer credentials entirely, while the value root-only allows peer credentials only for the root user. ++Note: for security reasons, the on setting is reduced to root-only for authorization of PUT requests. +
RemoteRoot username +
Specifies the username that is associated with unauthenticated accesses by clients claiming to be the root user. + The default is "remroot". +diff -up cups-2.3.3op2/man/cups-files.conf.5.config-issues cups-2.3.3op2/man/cups-files.conf.5 +--- cups-2.3.3op2/man/cups-files.conf.5.config-issues 2021-02-01 22:10:25.000000000 +0100 ++++ cups-2.3.3op2/man/cups-files.conf.5 2025-12-09 18:41:09.688443001 +0100 +@@ -166,6 +166,17 @@ The default is "/var/log/cups/page_log". + \fBPassEnv \fIvariable \fR[ ... \fIvariable \fR] + Passes the specified environment variable(s) to child processes. + Note: the standard CUPS filter and backend environment variables cannot be overridden using this directive. ++.\"#PeerCred ++.TP 5 ++\fBPeerCred off\fR ++.TP 5 ++\fBPeerCred on\fR ++.TP 5 ++\fBPeerCred root-only\fR ++Specifies whether peer credentials are used for authorization when communicating over the UNIX domain socket. ++When \fBon\fR, the peer credentials of any user are accepted for authorization. ++The value \fBoff\fR disables the use of peer credentials entirely, while the value \fBroot-only\fR allows peer credentials only for the root user. ++Note: for security reasons, the \fBon\fR setting is reduced to \fBroot-only\fR for authorization of PUT requests. + .\"#RemoteRoot + .TP 5 + \fBRemoteRoot \fIusername\fR +diff -up cups-2.3.3op2/scheduler/auth.c.config-issues cups-2.3.3op2/scheduler/auth.c +--- cups-2.3.3op2/scheduler/auth.c.config-issues 2025-12-09 18:41:09.679531444 +0100 ++++ cups-2.3.3op2/scheduler/auth.c 2025-12-09 18:41:09.688567136 +0100 +@@ -390,7 +390,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I + } + #endif /* HAVE_AUTHORIZATION_H */ + #if defined(SO_PEERCRED) && defined(AF_LOCAL) +- else if (!strncmp(authorization, "PeerCred ", 9) && ++ else if (PeerCred != CUPSD_PEERCRED_OFF && !strncmp(authorization, "PeerCred ", 9) && + con->http->hostaddr->addr.sa_family == AF_LOCAL && con->best) + { + /* +@@ -433,6 +433,12 @@ cupsdAuthorize(cupsd_client_t *con) /* I + } + #endif /* HAVE_AUTHORIZATION_H */ + ++ if ((PeerCred == CUPSD_PEERCRED_ROOTONLY || httpGetState(con->http) == HTTP_STATE_PUT_RECV) && strcmp(authorization + 9, "root")) ++ { ++ cupsdLogClient(con, CUPSD_LOG_INFO, "User \"%s\" is not allowed to use peer credentials.", authorization + 9); ++ return; ++ } ++ + if ((pwd = getpwnam(authorization + 9)) == NULL) + { + cupsdLogClient(con, CUPSD_LOG_ERROR, "User \"%s\" does not exist.", authorization + 9); +diff -up cups-2.3.3op2/scheduler/auth.h.config-issues cups-2.3.3op2/scheduler/auth.h +--- cups-2.3.3op2/scheduler/auth.h.config-issues 2021-02-01 22:10:25.000000000 +0100 ++++ cups-2.3.3op2/scheduler/auth.h 2025-12-09 18:44:14.355908987 +0100 +@@ -48,6 +48,10 @@ + #define CUPSD_AUTH_LIMIT_ALL 127 /* Limit all requests */ + #define CUPSD_AUTH_LIMIT_IPP 128 /* Limit IPP requests */ + ++#define CUPSD_PEERCRED_OFF 0 /* Don't allow PeerCred authorization */ ++#define CUPSD_PEERCRED_ON 1 /* Allow PeerCred authorization for all users */ ++#define CUPSD_PEERCRED_ROOTONLY 2 /* Allow PeerCred authorization for root user */ ++ + #define IPP_ANY_OPERATION (ipp_op_t)0 + /* Any IPP operation */ + #define IPP_BAD_OPERATION (ipp_op_t)-1 +@@ -105,6 +109,9 @@ typedef struct cupsd_client_s cupsd_clie + + VAR cups_array_t *Locations VALUE(NULL); + /* Authorization locations */ ++VAR int PeerCred VALUE(CUPSD_PEERCRED_ON); ++ /* Allow PeerCred authorization? */ ++ + #ifdef HAVE_SSL + VAR http_encryption_t DefaultEncryption VALUE(HTTP_ENCRYPT_REQUIRED); + /* Default encryption for authentication */ +diff -up cups-2.3.3op2/scheduler/client.c.config-issues cups-2.3.3op2/scheduler/client.c +--- cups-2.3.3op2/scheduler/client.c.config-issues 2025-12-09 18:41:09.684930590 +0100 ++++ cups-2.3.3op2/scheduler/client.c 2025-12-09 18:41:09.689126051 +0100 +@@ -2141,7 +2141,7 @@ cupsdSendHeader( + auth_size = sizeof(auth_str) - (size_t)(auth_key - auth_str); + + #if defined(SO_PEERCRED) && defined(AF_LOCAL) +- if (httpAddrFamily(httpGetAddress(con->http)) == AF_LOCAL) ++ if (PeerCred != CUPSD_PEERCRED_OFF && httpAddrFamily(httpGetAddress(con->http)) == AF_LOCAL) + { + strlcpy(auth_key, ", PeerCred", auth_size); + auth_key += 10; +diff -up cups-2.3.3op2/scheduler/conf.c.config-issues cups-2.3.3op2/scheduler/conf.c +--- cups-2.3.3op2/scheduler/conf.c.config-issues 2025-12-09 18:41:09.677898084 +0100 ++++ cups-2.3.3op2/scheduler/conf.c 2025-12-09 18:44:45.947226612 +0100 +@@ -46,6 +46,7 @@ typedef enum + { + CUPSD_VARTYPE_INTEGER, /* Integer option */ + CUPSD_VARTYPE_TIME, /* Time interval option */ ++ CUPSD_VARTYPE_NULLSTRING, /* String option or NULL/empty string */ + CUPSD_VARTYPE_STRING, /* String option */ + CUPSD_VARTYPE_BOOLEAN, /* Boolean option */ + CUPSD_VARTYPE_PATHNAME, /* File/directory name option */ +@@ -68,7 +69,7 @@ static const cupsd_var_t cupsd_vars[] = + { + { "AutoPurgeJobs", &JobAutoPurge, CUPSD_VARTYPE_BOOLEAN }, + #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) +- { "BrowseDNSSDSubTypes", &DNSSDSubTypes, CUPSD_VARTYPE_STRING }, ++ { "BrowseDNSSDSubTypes", &DNSSDSubTypes, CUPSD_VARTYPE_NULLSTRING }, + #endif /* HAVE_DNSSD || HAVE_AVAHI */ + { "BrowseWebIF", &BrowseWebIF, CUPSD_VARTYPE_BOOLEAN }, + { "Browsing", &Browsing, CUPSD_VARTYPE_BOOLEAN }, +@@ -121,7 +122,7 @@ static const cupsd_var_t cupsd_vars[] = + { "MaxSubscriptionsPerPrinter",&MaxSubscriptionsPerPrinter, CUPSD_VARTYPE_INTEGER }, + { "MaxSubscriptionsPerUser", &MaxSubscriptionsPerUser, CUPSD_VARTYPE_INTEGER }, + { "MultipleOperationTimeout", &MultipleOperationTimeout, CUPSD_VARTYPE_TIME }, +- { "PageLogFormat", &PageLogFormat, CUPSD_VARTYPE_STRING }, ++ { "PageLogFormat", &PageLogFormat, CUPSD_VARTYPE_NULLSTRING }, + { "PreserveJobFiles", &JobFiles, CUPSD_VARTYPE_TIME }, + { "PreserveJobHistory", &JobHistory, CUPSD_VARTYPE_TIME }, + { "ReloadTimeout", &ReloadTimeout, CUPSD_VARTYPE_TIME }, +@@ -800,6 +801,13 @@ cupsdReadConfiguration(void) + IdleExitTimeout = 60; + #endif /* HAVE_ONDEMAND */ + ++ if (!strcmp(CUPS_DEFAULT_PEER_CRED, "off")) ++ PeerCred = CUPSD_PEERCRED_OFF; ++ else if (!strcmp(CUPS_DEFAULT_PEER_CRED, "root-only")) ++ PeerCred = CUPSD_PEERCRED_ROOTONLY; ++ else ++ PeerCred = CUPSD_PEERCRED_ON; ++ + /* + * Setup environment variables... + */ +@@ -1809,7 +1817,7 @@ get_addr_and_mask(const char *value, /* + + family = AF_INET6; + +- for (i = 0, ptr = value + 1; *ptr && i < 8; i ++) ++ for (i = 0, ptr = value + 1; *ptr && i >= 0 && i < 8; i ++) + { + if (*ptr == ']') + break; +@@ -1958,7 +1966,7 @@ get_addr_and_mask(const char *value, /* + #ifdef AF_INET6 + if (family == AF_INET6) + { +- if (i > 128) ++ if (i < 0 || i > 128) + return (0); + + i = 128 - i; +@@ -1992,7 +2000,7 @@ get_addr_and_mask(const char *value, /* + else + #endif /* AF_INET6 */ + { +- if (i > 32) ++ if (i < 0 || i > 32) + return (0); + + mask[0] = 0xffffffff; +@@ -2902,7 +2910,17 @@ parse_variable( + cupsdSetString((char **)var->ptr, temp); + break; + ++ case CUPSD_VARTYPE_NULLSTRING : ++ cupsdSetString((char **)var->ptr, value); ++ break; ++ + case CUPSD_VARTYPE_STRING : ++ if (!value) ++ { ++ cupsdLogMessage(CUPSD_LOG_ERROR, "Missing value for %s on line %d of %s.", line, linenum, filename); ++ return (0); ++ } ++ + cupsdSetString((char **)var->ptr, value); + break; + } +@@ -3412,9 +3430,10 @@ read_cupsd_conf(cups_file_t *fp) /* I - + line, value ? " " : "", value ? value : "", linenum, + ConfigurationFile, CupsFilesFile); + } +- else +- parse_variable(ConfigurationFile, linenum, line, value, +- sizeof(cupsd_vars) / sizeof(cupsd_vars[0]), cupsd_vars); ++ else if (!parse_variable(ConfigurationFile, linenum, line, value, ++ sizeof(cupsd_vars) / sizeof(cupsd_vars[0]), cupsd_vars) && ++ (FatalErrors & CUPSD_FATAL_CONFIG)) ++ return (0); + } + + return (1); +@@ -3574,6 +3593,31 @@ read_cups_files_conf(cups_file_t *fp) /* + break; + } + } ++ else if (!_cups_strcasecmp(line, "PeerCred") && value) ++ { ++ /* ++ * PeerCred {off,on,root-only} ++ */ ++ ++ if (!_cups_strcasecmp(value, "off")) ++ { ++ PeerCred = CUPSD_PEERCRED_OFF; ++ } ++ else if (!_cups_strcasecmp(value, "on")) ++ { ++ PeerCred = CUPSD_PEERCRED_ON; ++ } ++ else if (!_cups_strcasecmp(value, "root-only")) ++ { ++ PeerCred = CUPSD_PEERCRED_ROOTONLY; ++ } ++ else ++ { ++ cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown PeerCred \"%s\" on line %d of %s.", value, linenum, CupsFilesFile); ++ if (FatalErrors & CUPSD_FATAL_CONFIG) ++ return (0); ++ } ++ } + else if (!_cups_strcasecmp(line, "PrintcapFormat") && value) + { + /* +diff -up cups-2.3.3op2/test/run-stp-tests.sh.config-issues cups-2.3.3op2/test/run-stp-tests.sh +--- cups-2.3.3op2/test/run-stp-tests.sh.config-issues 2025-12-09 18:41:09.632865921 +0100 ++++ cups-2.3.3op2/test/run-stp-tests.sh 2025-12-09 18:41:09.690311271 +0100 +@@ -511,7 +511,7 @@ fi + + cat >$BASE/cups-files.conf < +Date: Thu, 4 Dec 2025 09:04:37 +0100 +Subject: [PATCH] conf.c: Fix stopping scheduler on unknown directive + +Change the return value to do not trigger stopping the scheduler in case +of unknown directive, because stopping the scheduler on config errors +should only happen in case of syntax errors. +--- + scheduler/conf.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/scheduler/conf.c b/scheduler/conf.c +index 7d6da0252..0e7be0ef4 100644 +--- a/scheduler/conf.c ++++ b/scheduler/conf.c +@@ -2708,16 +2708,16 @@ parse_variable( + { + /* + * Unknown directive! Output an error message and continue... ++ * ++ * Return value 1 is on purpose - we ignore unknown directives to log ++ * error, but do not stop the scheduler in case error in configuration ++ * is set to be fatal. + */ + +- if (!value) +- cupsdLogMessage(CUPSD_LOG_ERROR, "Missing value for %s on line %d of %s.", +- line, linenum, filename); +- else +- cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown directive %s on line %d of %s.", +- line, linenum, filename); ++ cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown directive %s on line %d of %s.", ++ line, linenum, filename); + +- return (0); ++ return (1); + } + + switch (var->type) +-- +2.52.0 + diff --git a/cups.spec b/cups.spec index 4793710..b9a99fb 100644 --- a/cups.spec +++ b/cups.spec @@ -177,6 +177,11 @@ Patch55: 0001-_httpWait-s-usessl-parameter-wasn-t-being-used.patch Patch56: cups-CVE-2025-58436.patch Patch57: 0001-Fix-an-infinite-loop-issue-in-GTK-Issue-1439.patch Patch58: 0001-scheduler-Fix-possible-use_after_free-in-cupsdReadCl.patch +# RHEL-129740 CVE-2025-61915 cups: Local denial-of-service via cupsd.conf update and related issues +# 0001-Fix-various-issues-in-cupsd.patch +# 0001-conf.c-Fix-stopping-scheduler-on-unknown-directive.patch +Patch59: 0001-Fix-various-issues-in-cupsd.patch +Patch60: 0001-conf.c-Fix-stopping-scheduler-on-unknown-directive.patch ##### Patches removed because IMHO they aren't no longer needed @@ -478,6 +483,9 @@ to CUPS daemon. This solution will substitute printer drivers and raw queues in %patch57 -p1 -b .gtk-infinite-loop # fix use-after-free reported by OSH %patch58 -p1 -b .osh-use-after-free +# RHEL-129740 CVE-2025-61915 cups: Local denial-of-service via cupsd.conf update and related issues +%patch59 -p1 -b .config-issues +%patch60 -p1 -b .ignore-unknown %if %{lspp} @@ -947,6 +955,7 @@ rm -f %{cups_serverbin}/backend/smb %changelog * Fri Dec 12 2025 Zdenek Dohnal - 1:2.3.3op2-37 - RHEL-129747 CVE-2025-58436 cups: Slow client communication leads to a possible DoS attack +- RHEL-129740 CVE-2025-61915 cups: Local denial-of-service via cupsd.conf update and related issues * Tue Nov 18 2025 Zdenek Dohnal - 1:2.3.3op2-36 - RHEL-122629 [image-mode] Missing /var/log/cups