]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Fix various issues in cupsd
authorZdenek Dohnal <zdohnal@redhat.com>
Fri, 21 Nov 2025 06:36:36 +0000 (07:36 +0100)
committerZdenek Dohnal <zdohnal@redhat.com>
Thu, 27 Nov 2025 15:06:02 +0000 (16:06 +0100)
Various issues were found by @SilverPlate3, recognized as CVE-2025-61915:

- out of bound write when handling IPv6 addresses,
- cupsd crash caused by null dereference when ErrorPolicy value is empty,

On the top of that, Mike Sweet noticed vulnerability via domain socket,
exploitable locally if attacker has access to domain socket and knows username
of user within a group which is present in CUPS system groups:

- rewrite of cupsd.conf via PeerCred authorization via domain socket

The last vulnerability is fixed by introducing PeerCred directive for cups-files.conf,
which controls whether PeerCred is enabled/disabled for user in CUPS system groups.

Fixes CVE-2025-61915

14 files changed:
conf/cups-files.conf.in
config-scripts/cups-defaults.m4
config.h.in
configure
doc/help/man-cups-files.conf.html
man/cups-files.conf.5
scheduler/auth.c
scheduler/auth.h
scheduler/client.c
scheduler/conf.c
test/run-stp-tests.sh
vcnet/config.h
xcode/CUPS.xcodeproj/project.pbxproj
xcode/config.h

index f96f745ae11eb6ca7fc0ac759a133cfc8996ebb9..6db13929779303f2db953f1d1df22ce56fe0516c 100644 (file)
@@ -22,6 +22,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
 
index 999a8849ded170b5ed0f2e8f5ed96fb1d30537c5..fc9ba4a02f4786696ae07362bd49940178a2897f 100644 (file)
@@ -95,6 +95,15 @@ AC_ARG_WITH([log_level], AS_HELP_STRING([--with-log-level], [set default LogLeve
 AC_SUBST([CUPS_LOG_LEVEL])
 AC_DEFINE_UNQUOTED([CUPS_DEFAULT_LOG_LEVEL], ["$CUPS_LOG_LEVEL"], [Default LogLevel value.])
 
+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",
index 207df66a79a4573901ca3b541632225bdf8e182e..37c279088ed054aadfe0ad08a07a8e2c5782ec7f 100644 (file)
 #define CUPS_DEFAULT_ERROR_POLICY "stop-printer"
 
 
+/*
+ * Default PeerCred value...
+ */
+
+#define CUPS_DEFAULT_PEER_CRED "on"
+
+
 /*
  * Default MaxCopies value...
  */
index a38ebded94f4e7ece770d9d105d1935a23c30f58..1721634bac19ddea2e5cdd5ebabb461de2c8c325 100755 (executable)
--- a/configure
+++ b/configure
@@ -670,6 +670,7 @@ CUPS_BROWSING
 CUPS_SYNC_ON_CLOSE
 CUPS_PAGE_LOG_FORMAT
 CUPS_ACCESS_LOG_LEVEL
+CUPS_PEER_CRED
 CUPS_LOG_LEVEL
 CUPS_FATAL_ERRORS
 CUPS_ERROR_POLICY
@@ -919,6 +920,7 @@ with_max_log_size
 with_error_policy
 with_fatal_errors
 with_log_level
+with_peer_cred
 with_access_log_level
 enable_page_logging
 enable_sync_on_close
@@ -1652,6 +1654,8 @@ Optional Packages:
   --with-error-policy     set default ErrorPolicy value, default=stop-printer
   --with-fatal-errors     set default FatalErrors value, default=config
   --with-log-level        set default LogLevel value, default=warn
+  --with-peer-cred        set default PeerCred value (on/off/root-only),
+                          default=on
   --with-access-log-level set default AccessLogLevel value, default=none
   --with-local-protocols  set default BrowseLocalProtocols, default=""
   --with-cups-user        set default user for CUPS
@@ -11651,6 +11655,24 @@ printf "%s\n" "#define CUPS_DEFAULT_LOG_LEVEL \"$CUPS_LOG_LEVEL\"" >>confdefs.h
 
 
 
+# Check whether --with-peer_cred was given.
+if test ${with_peer_cred+y}
+then :
+  withval=$with_peer_cred;
+    CUPS_PEER_CRED="$withval"
+
+else $as_nop
+
+    CUPS_PEER_CRED="on"
+
+fi
+
+
+
+printf "%s\n" "#define CUPS_DEFAULT_PEER_CRED \"$CUPS_PEER_CRED\"" >>confdefs.h
+
+
+
 # Check whether --with-access_log_level was given.
 if test ${with_access_log_level+y}
 then :
index 440f033d5122a895a6674cfc3a039c381e3be68a..5a9ddefeb666671e0e722ee5308a1ae98a8562c0 100644 (file)
@@ -119,6 +119,13 @@ The default is "/var/log/cups/page_log".
 <dt><a name="PassEnv"></a><b>PassEnv </b><i>variable </i>[ ... <i>variable </i>]
 <dd style="margin-left: 5.0em">Passes the specified environment variable(s) to child processes.
 Note: the standard CUPS filter and backend environment variables cannot be overridden using this directive.
+<dt><a name="PeerCred"></a><b>PeerCred off</b>
+<dd style="margin-left: 5.0em"><dt><b>PeerCred on</b>
+<dd style="margin-left: 5.0em"><dt><b>PeerCred root-only</b>
+<dd style="margin-left: 5.0em">Specifies whether peer credentials are used for authorization when communicating over the UNIX domain socket.
+When <b>on</b>, the peer credentials of any user are accepted for authorization.
+The value <b>off</b> disables the use of peer credentials entirely, while the value <b>root-only</b> allows peer credentials only for the root user.
+Note: for security reasons, the <b>on</b> setting is reduced to <b>root-only</b> for authorization of PUT requests.
 <dt><a name="RemoteRoot"></a><b>RemoteRoot </b><i>username</i>
 <dd style="margin-left: 5.0em">Specifies the username that is associated with unauthenticated accesses by clients claiming to be the root user.
 The default is "remroot".
@@ -207,7 +214,7 @@ command is used instead.
 <a href="man-subscriptions.conf.html?TOPIC=Man+Pages"><b>subscriptions.conf</b>(5),</a>
 CUPS Online Help (<a href="http://localhost:631/help">http://localhost:631/help</a>)
 <h2 class="title"><a name="COPYRIGHT">Copyright</a></h2>
-Copyright &copy; 2020-2024 by OpenPrinting.
+Copyright &copy; 2020-2025 by OpenPrinting.
 
 </body>
 </html>
index ec16c9e1371f68a775fb38533adeaa6332db9090..18ce2be00f0e6f1e0ee58aec21ba62e1614a748d 100644 (file)
@@ -1,14 +1,14 @@
 .\"
 .\" cups-files.conf man page for CUPS.
 .\"
-.\" Copyright © 2020-2024 by OpenPrinting.
+.\" Copyright © 2020-2025 by OpenPrinting.
 .\" Copyright © 2007-2019 by Apple Inc.
 .\" Copyright © 1997-2006 by Easy Software Products.
 .\"
 .\" Licensed under Apache License v2.0.  See the file "LICENSE" for more
 .\" information.
 .\"
-.TH cups-files.conf 5 "CUPS" "2021-03-06" "OpenPrinting"
+.TH cups-files.conf 5 "CUPS" "2025-10-08" "OpenPrinting"
 .SH NAME
 cups\-files.conf \- file and directory configuration file for cups
 .SH DESCRIPTION
@@ -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
@@ -289,4 +300,4 @@ command is used instead.
 .BR subscriptions.conf (5),
 CUPS Online Help (http://localhost:631/help)
 .SH COPYRIGHT
-Copyright \[co] 2020-2024 by OpenPrinting.
+Copyright \[co] 2020-2025 by OpenPrinting.
index 3c9aa72aaf24ac026faaadbd7733403e0b9818e0..bd0d28a0e6852c2b572ac651679baac80883aadb 100644 (file)
@@ -398,7 +398,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
   }
 #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)
   {
    /*
@@ -441,6 +441,12 @@ cupsdAuthorize(cupsd_client_t *con)        /* I - Client connection */
     }
 #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);
index ee98e92c70588dc4f5a506a347a920be42976061..fdf71213f53d2e1a96091cd6f3fcc847b4dafe91 100644 (file)
 #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
 
 VAR cups_array_t       *Locations      VALUE(NULL);
                                        /* Authorization locations */
+VAR int                        PeerCred        VALUE(CUPSD_PEERCRED_ON);
+                                       /* Allow PeerCred authorization? */
+
 #ifdef HAVE_TLS
 VAR http_encryption_t  DefaultEncryption VALUE(HTTP_ENCRYPT_REQUIRED);
                                        /* Default encryption for authentication */
index 9593c9138c4373fda41256fadd8cb63daa086a97..d961c15db2836b5230a184d958a2f2984c31787f 100644 (file)
@@ -2208,7 +2208,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;
index db4104ec5f879ca628b969521714ae9299fdc521..7d6da025298b92fac24cda9b01d938767e10f868 100644 (file)
@@ -47,6 +47,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 */
@@ -69,7 +70,7 @@ static const cupsd_var_t      cupsd_vars[] =
 {
   { "AutoPurgeJobs",           &JobAutoPurge,          CUPSD_VARTYPE_BOOLEAN },
 #ifdef HAVE_DNSSD
-  { "BrowseDNSSDSubTypes",     &DNSSDSubTypes,         CUPSD_VARTYPE_STRING },
+  { "BrowseDNSSDSubTypes",     &DNSSDSubTypes,         CUPSD_VARTYPE_NULLSTRING },
 #endif /* HAVE_DNSSD */
   { "BrowseWebIF",             &BrowseWebIF,           CUPSD_VARTYPE_BOOLEAN },
   { "Browsing",                        &Browsing,              CUPSD_VARTYPE_BOOLEAN },
@@ -120,7 +121,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 },
@@ -791,6 +792,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...
   */
@@ -1842,7 +1850,7 @@ get_addr_and_mask(const char *value,      /* I - String from config file */
 
     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;
@@ -1988,7 +1996,7 @@ get_addr_and_mask(const char *value,      /* I - String from config file */
 #ifdef AF_INET6
       if (family == AF_INET6)
       {
-        if (i > 128)
+        if (i < 0 || i > 128)
          return (0);
 
         i = 128 - i;
@@ -2022,7 +2030,7 @@ get_addr_and_mask(const char *value,      /* I - String from config file */
       else
 #endif /* AF_INET6 */
       {
-        if (i > 32)
+        if (i < 0 || i > 32)
          return (0);
 
         mask[0] = 0xffffffff;
@@ -2932,7 +2940,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;
   }
@@ -3449,9 +3467,10 @@ read_cupsd_conf(cups_file_t *fp) /* I - File to read from */
                      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);
@@ -3610,6 +3629,31 @@ read_cups_files_conf(cups_file_t *fp)    /* I - File to read from */
            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)
     {
      /*
index 1c447edd7b25748e09f269e5961ada99d0561344..8d677db7118a9b3c13f4194c2fb084fed2a44f1e 100755 (executable)
@@ -512,7 +512,7 @@ fi
 
 cat >$BASE/cups-files.conf <<EOF
 FileDevice yes
-Printcap
+Printcap $BASE/printcap
 User $user
 ServerRoot $BASE
 StateDir $BASE
index dbc6f05d57f35d589cfa58f72348ed85097ab240..317c956a6dc3b64148408ccd28f3052467995e27 100644 (file)
@@ -169,6 +169,13 @@ typedef unsigned long useconds_t;
 #define CUPS_DEFAULT_ERROR_POLICY "stop-printer"
 
 
+/*
+ * Default PeerCred value...
+ */
+
+#define CUPS_DEFAULT_PEER_CRED "on"
+
+
 /*
  * Default MaxCopies value...
  */
index 597946440b95f3997dd14e1fd93ffd79d0b1154e..54ac652a1d5f8f680b86ce5bd55b4cbd3699e548 100644 (file)
                72220FB313330BCE00FCA411 /* mime.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mime.c; path = ../scheduler/mime.c; sourceTree = "<group>"; };
                72220FB413330BCE00FCA411 /* mime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mime.h; path = ../scheduler/mime.h; sourceTree = "<group>"; };
                72220FB513330BCE00FCA411 /* type.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = type.c; path = ../scheduler/type.c; sourceTree = "<group>"; };
-               7226369B18AE6D19004ED309 /* org.cups.cups-lpd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "org.cups.cups-lpd.plist"; path = "../scheduler/org.cups.cups-lpd.plist"; sourceTree = SOURCE_ROOT; };
                7226369C18AE6D19004ED309 /* org.cups.cupsd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = org.cups.cupsd.plist; path = ../scheduler/org.cups.cupsd.plist; sourceTree = SOURCE_ROOT; };
                7226369D18AE73BB004ED309 /* config.h.in */ = {isa = PBXFileReference; lastKnownFileType = text; name = config.h.in; path = ../config.h.in; sourceTree = "<group>"; };
                722A24EE2178D00C000CAB20 /* debug-internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "debug-internal.h"; path = "../cups/debug-internal.h"; sourceTree = "<group>"; };
                        isa = PBXGroup;
                        children = (
                                72E65BDC18DC852700097E89 /* Makefile */,
-                               7226369B18AE6D19004ED309 /* org.cups.cups-lpd.plist */,
                                72E65BD518DC818400097E89 /* org.cups.cups-lpd.plist.in */,
                                7226369C18AE6D19004ED309 /* org.cups.cupsd.plist */,
                                72220F6913330B0C00FCA411 /* auth.c */,
index e0ddd09dcdef1c6a9f2dd53a62e37582ebe55197..caec083caf118156ca8c8923c3f1b93864d61069 100644 (file)
 #define CUPS_DEFAULT_ERROR_POLICY "stop-printer"
 
 
+/*
+ * Default PeerCred value...
+ */
+
+#define CUPS_DEFAULT_PEER_CRED "on"
+
+
 /*
  * Default MaxCopies value...
  */