]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Fix various issues in cupsd
authorMichael R Sweet <msweet@msweet.org>
Fri, 21 Nov 2025 06:29:53 +0000 (07:29 +0100)
committerZdenek Dohnal <zdohnal@redhat.com>
Thu, 27 Nov 2025 15:05:37 +0000 (16:05 +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 9fd3c4e4b613fbf19e50dfff6e41010882de3836..e2fdee6a10ede9c409b779f731b0ec8081ad828a 100644 (file)
@@ -1,7 +1,7 @@
 dnl
 dnl Default cupsd configuration settings for CUPS.
 dnl
-dnl Copyright © 2020-2024 by OpenPrinting.
+dnl Copyright © 2020-2025 by OpenPrinting.
 dnl Copyright © 2007-2018 by Apple Inc.
 dnl Copyright © 2006-2007 by Easy Software Products, all rights reserved.
 dnl
@@ -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 ff0b324e2131d9cb90b279c335c62007480cfe25..06c842878368c300c3b626d5d2ea8e5113eafaec 100644 (file)
 #define CUPS_DEFAULT_ERROR_POLICY "stop-printer"
 
 
+/*
+ * Default PeerCred value...
+ */
+
+#define CUPS_DEFAULT_PEER_CRED "on"
+
+
 /*
  * Default MaxCopies value...
  */
index 79efebb9c8ae5091495b7dac1f8ca351c37bcbf4..8f19056edf8f2ab885097d639188e47fe7640fd9 100755 (executable)
--- a/configure
+++ b/configure
@@ -669,6 +669,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
@@ -917,6 +918,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
@@ -1648,6 +1650,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
@@ -11290,6 +11294,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 0ceca13162808ef049908d3277b1f974aeb076d8..f8d4188ada36a7911bd3e10d5af6052bca439766 100644 (file)
@@ -157,6 +157,16 @@ The server name may be included in filenames using the string &quot;%s&quot;, fo
     <p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>PassEnv </strong><em>variable </em>[ ... <em>variable </em>]<br>
 Passes the specified environment variable(s) to child processes.
 Note: the standard CUPS filter and backend environment variables cannot be overridden using this directive.
+</p>
+    <p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>PeerCred off</strong><br>
+</p>
+    <p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>PeerCred on</strong><br>
+</p>
+    <p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>PeerCred root-only</strong><br>
+Specifies whether peer credentials are used for authorization when communicating over the UNIX domain socket.
+When <strong>on</strong>, the peer credentials of any user are accepted for authorization.
+The value <strong>off</strong> disables the use of peer credentials entirely, while the value <strong>root-only</strong> allows peer credentials only for the root user.
+Note: for security reasons, the <strong>on</strong> setting is reduced to <strong>root-only</strong> for authorization of PUT requests.
 </p>
     <p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>RemoteRoot </strong><em>username</em><br>
 Specifies the username that is associated with unauthenticated accesses by clients claiming to be the root user.
@@ -279,6 +289,6 @@ command is used instead.
 CUPS Online Help (<a href="http://localhost:631/help">http://localhost:631/help</a>)
 </p>
     <h2 id="cups-files.conf-5.copyright">Copyright</h2>
-<p>Copyright &copy; 2020-2024 by OpenPrinting.
+<p>Copyright &copy; 2020-2025 by OpenPrinting.
   </body>
 </html>
index 619d625eb9a4cf81604603571689cecc63a203d5..3caa50e855f9ad023f6dccbae99671f56abf6dec 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" "2024-04-16" "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
@@ -170,6 +170,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
@@ -293,4 +304,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 3f537f7693a9f2938f5056742057862cddd5b475..802659481a0aa9a0e9c3c2076df3437e7ddbfea7 100644 (file)
@@ -462,7 +462,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)
   {
    /*
@@ -505,6 +505,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 37f458b581f01a9753db36209c24f85163af9f44..e1421cb1e855a935341c0409aae060db0bfcf96b 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
@@ -115,6 +119,9 @@ VAR http_encryption_t       DefaultEncryption VALUE(HTTP_ENCRYPTION_REQUIRED);
 VAR cups_array_t       *Locations      VALUE(NULL);
                                        /* Authorization locations */
 
+VAR int                        PeerCred        VALUE(CUPSD_PEERCRED_ON);
+                                       /* Allow PeerCred authorization? */
+
 VAR cups_array_t       *OAuthGroups    VALUE(NULL);
                                        /* OAuthGroup entries */
 VAR cups_json_t                *OAuthJWKS      VALUE(NULL),
index 065e873ee853248f237492e2b520bffcca82aa77..f6166091e8df2e97cb6aea4e03d1a51e1c39743e 100644 (file)
@@ -2214,7 +2214,7 @@ cupsdSendHeader(
       auth_size = sizeof(auth_str) - (size_t)(auth_key - auth_str);
 
 #if defined(SO_PEERCRED) && defined(AF_LOCAL)
-      if (httpAddrGetFamily(httpGetAddress(con->http)) == AF_LOCAL)
+      if (PeerCred != CUPSD_PEERCRED_OFF && httpAddrGetFamily(httpGetAddress(con->http)) == AF_LOCAL)
       {
         cupsCopyString(auth_key, ", PeerCred", auth_size);
         auth_key += 10;
index 387c02a6c8b296dbdc125bcecc3ea8a6beeac07b..33bbf0514fa85d2c43c03955f938914dd3bfbdad 100644 (file)
@@ -44,6 +44,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 */
@@ -65,7 +66,7 @@ typedef struct
 static const cupsd_var_t       cupsd_vars[] =
 {
   { "AutoPurgeJobs",           &JobAutoPurge,          CUPSD_VARTYPE_BOOLEAN },
-  { "BrowseDNSSDSubTypes",     &DNSSDSubTypes,         CUPSD_VARTYPE_STRING },
+  { "BrowseDNSSDSubTypes",     &DNSSDSubTypes,         CUPSD_VARTYPE_NULLSTRING },
   { "BrowseWebIF",             &BrowseWebIF,           CUPSD_VARTYPE_BOOLEAN },
   { "Browsing",                        &Browsing,              CUPSD_VARTYPE_BOOLEAN },
   { "Classification",          &Classification,        CUPSD_VARTYPE_STRING },
@@ -114,7 +115,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 },
@@ -811,6 +812,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...
   */
@@ -1899,7 +1907,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;
@@ -2045,7 +2053,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;
@@ -2079,7 +2087,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;
@@ -2996,7 +3004,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;
   }
@@ -3505,9 +3523,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);
@@ -3720,6 +3739,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 e4330bf9f4342a424624e31bd92a962cacb9a275..65e1d3793239493419ab6ffc185c62366e83a560 100755 (executable)
@@ -497,7 +497,7 @@ fi
 
 cat >$BASE/cups-files.conf <<EOF
 FileDevice yes
-Printcap
+Printcap $BASE/printcap
 User $user
 ServerRoot $BASE
 StateDir $BASE
index c1df0c95ec7307d6f8b769bac755023490675f33..5d93837aab3570ba2f3caf7b4cbba43a87aac83d 100644 (file)
@@ -167,6 +167,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 b7e1cd7581a74c731c8ba0ff25099af1e4e4ccfe..e3bfcb257a4d3f90334a04c365915643a6c5da91 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 f3995667cd5b603a50e277b5bf08fd88f12fa202..70ea25a12c84a348f324ee906903e8424766a5ee 100644 (file)
 #define CUPS_DEFAULT_ERROR_POLICY "stop-printer"
 
 
+/*
+ * Default PeerCred value...
+ */
+
+#define CUPS_DEFAULT_PEER_CRED "on"
+
+
 /*
  * Default MaxCopies value...
  */