Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package pcp for openSUSE:Factory checked in 
at 2026-08-09 21:32:34
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/pcp (Old)
 and      /work/SRC/openSUSE:Factory/.pcp.new.16738 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "pcp"

Sun Aug  9 21:32:34 2026 rev:79 rq:1370102 version:6.3.8

Changes:
--------
--- /work/SRC/openSUSE:Factory/pcp/pcp.changes  2026-05-13 20:58:50.111896671 
+0200
+++ /work/SRC/openSUSE:Factory/.pcp.new.16738/pcp.changes       2026-08-09 
21:33:38.270699474 +0200
@@ -1,0 +2,26 @@
+Thu Jul 30 18:47:41 UTC 2026 - Martin Schreiner <[email protected]>
+
+- Fix bsc#1272922 / CVE-2026-16524.
+- Fix bsc#1272923 / CVE-2026-16526.
+- Fix bsc#1272924 / CVE-2026-16527.
+- Fix bsc#1272925 / CVE-2026-16529.
+- Fix bsc#1272926 / CVE-2026-16530.
+- Fix bsc#1272927 / CVE-2026-16531.
+- Fix bsc#1272928.
+- Fix bsc#1272930.
+- Add patches:
+  * pcp-CVE-2026-16524.patch
+  * pcp-CVE-2026-16526.patch
+  * pcp-CVE-2026-16527.patch
+  * pcp-CVE-2026-16529.patch
+  * pcp-CVE-2026-16530-1.patch
+  * pcp-CVE-2026-16530-2.patch
+  * pcp-CVE-2026-16530-3.patch
+  * pcp-CVE-2026-16530-4.patch
+  * pcp-CVE-2026-16530-5.patch
+  * pcp-CVE-2026-16530-6.patch
+  * pcp-CVE-2026-16531.patch
+  * pcp-bsc-1272928.patch
+  * pcp-bsc-1272930.patch
+
+-------------------------------------------------------------------

New:
----
  pcp-CVE-2026-16524.patch
  pcp-CVE-2026-16526.patch
  pcp-CVE-2026-16527.patch
  pcp-CVE-2026-16529.patch
  pcp-CVE-2026-16530-1.patch
  pcp-CVE-2026-16530-2.patch
  pcp-CVE-2026-16530-3.patch
  pcp-CVE-2026-16530-4.patch
  pcp-CVE-2026-16530-5.patch
  pcp-CVE-2026-16530-6.patch
  pcp-CVE-2026-16531.patch
  pcp-bsc-1272928.patch
  pcp-bsc-1272930.patch

----------(New B)----------
  New:- Add patches:
  * pcp-CVE-2026-16524.patch
  * pcp-CVE-2026-16526.patch
  New:  * pcp-CVE-2026-16524.patch
  * pcp-CVE-2026-16526.patch
  * pcp-CVE-2026-16527.patch
  New:  * pcp-CVE-2026-16526.patch
  * pcp-CVE-2026-16527.patch
  * pcp-CVE-2026-16529.patch
  New:  * pcp-CVE-2026-16527.patch
  * pcp-CVE-2026-16529.patch
  * pcp-CVE-2026-16530-1.patch
  New:  * pcp-CVE-2026-16529.patch
  * pcp-CVE-2026-16530-1.patch
  * pcp-CVE-2026-16530-2.patch
  New:  * pcp-CVE-2026-16530-1.patch
  * pcp-CVE-2026-16530-2.patch
  * pcp-CVE-2026-16530-3.patch
  New:  * pcp-CVE-2026-16530-2.patch
  * pcp-CVE-2026-16530-3.patch
  * pcp-CVE-2026-16530-4.patch
  New:  * pcp-CVE-2026-16530-3.patch
  * pcp-CVE-2026-16530-4.patch
  * pcp-CVE-2026-16530-5.patch
  New:  * pcp-CVE-2026-16530-4.patch
  * pcp-CVE-2026-16530-5.patch
  * pcp-CVE-2026-16530-6.patch
  New:  * pcp-CVE-2026-16530-5.patch
  * pcp-CVE-2026-16530-6.patch
  * pcp-CVE-2026-16531.patch
  New:  * pcp-CVE-2026-16530-6.patch
  * pcp-CVE-2026-16531.patch
  * pcp-bsc-1272928.patch
  New:  * pcp-CVE-2026-16531.patch
  * pcp-bsc-1272928.patch
  * pcp-bsc-1272930.patch
  New:  * pcp-bsc-1272928.patch
  * pcp-bsc-1272930.patch
----------(New E)----------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ pcp.spec ++++++
--- /var/tmp/diff_new_pack.wwonwV/_old  2026-08-09 21:33:39.274733550 +0200
+++ /var/tmp/diff_new_pack.wwonwV/_new  2026-08-09 21:33:39.294734228 +0200
@@ -97,6 +97,19 @@
 Patch7:         0001-selinux-add-permissions-allowing-proc_psi_t-access.patch
 # PATCH-FIX-OPENSUSE, [email protected]
 Patch8:         0008-selinux-additional-labeling-rules.patch
+Patch9:         pcp-bsc-1272928.patch
+Patch10:        pcp-bsc-1272930.patch
+Patch11:        pcp-CVE-2026-16524.patch
+Patch12:        pcp-CVE-2026-16526.patch
+Patch13:        pcp-CVE-2026-16527.patch
+Patch14:        pcp-CVE-2026-16529.patch
+Patch15:        pcp-CVE-2026-16530-1.patch
+Patch16:        pcp-CVE-2026-16530-2.patch
+Patch17:        pcp-CVE-2026-16530-3.patch
+Patch18:        pcp-CVE-2026-16530-4.patch
+Patch19:        pcp-CVE-2026-16530-5.patch
+Patch20:        pcp-CVE-2026-16530-6.patch
+Patch21:        pcp-CVE-2026-16531.patch
 
 %global disable_selinux 0
 %if 0%{?suse_version} < 1600

++++++ pcp-CVE-2026-16524.patch ++++++
References: CVE-2026-16524
Description: linux_sockets pmda: fix command injection via 
network.persocket.filter (CWE-78)
 The sockets_check_filter() validation helper returns 1 for safe input
 and 0 for unsafe input.  The guard in sockets_store() tested
 if (sockets_check_filter(av.cp)) — rejecting safe input and accepting
 malicious input containing shell metacharacters.  The accepted filter
 was later passed to popen() via shell interpretation, enabling arbitrary
 command execution as the PMDA process user.
 .
 Fix:
 - Invert the guard: if (!sockets_check_filter(av.cp))
 - Replace popen()/pclose() in ss_open_stream() with the libpcp
   __pmProcessAddArg()/__pmProcessPipe()/__pmProcessPipeClose() API
   which uses execvp() internally, eliminating shell interpretation
   of the filter string entirely
 - Add qa/2101 verifying that valid filters are accepted and shell
   metacharacters (semicolons, backticks, pipes) are rejected
 .
 Reported-by: Francisco Alisson Bezerra, TIM Security Red Team
 Reported-by: Lucas Gabriel Alves, TIM Security Red Team
 Reported-by: Massimiliano Brolli, TIM Security Red Team
 .
 Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
 .
Author: Nathan Scott <[email protected]>
Origin: upstream, 
https://github.com/performancecopilot/pcp/commit/c5cbeceb7d3c2af357c04065cdd911efdc270de0
Last-Update: 2026-07-25
 Backport-Note:
 Backported to PCP 6.3.8 (applies unchanged).


--- a/src/pmdas/linux_sockets/pmda.c
+++ b/src/pmdas/linux_sockets/pmda.c
@@ -162,11 +162,9 @@
     const char *p;
 
     for (p = string; *p; p++) {
-       if (isspace(*p))
+       if (isspace(*p) || isalnum(*p))
            continue;
-       if (isalnum(*p))
-           continue;
-       if (*p == '(' || *p == ')')
+       if (strchr("()=!<>:.*/-,", *p) != NULL)
            continue;
        return 0; /* disallow */
     }
@@ -191,7 +189,7 @@
                case 0: /* network.persocket.filter */
                    if ((sts = pmExtractValue(vsp->valfmt, &vsp->vlist[0],
                        PM_TYPE_STRING, &av, PM_TYPE_STRING)) >= 0) {
-                       if (sockets_check_filter(av.cp)) {
+                       if (!sockets_check_filter(av.cp)) {
                            sts = PM_ERR_BADSTORE;
                            free(av.cp);
                            break;
--- a/src/pmdas/linux_sockets/ss_stream.c
+++ b/src/pmdas/linux_sockets/ss_stream.c
@@ -14,18 +14,19 @@
 
 #include <pcp/pmapi.h>
 #include <pcp/pmda.h>
+#include <pcp/libpcp.h>
 #include "ss_stats.h"
 
 #define SS_OPTIONS "-noemitauO"
 
-char *ss_filter = NULL; /* storable: network.persocket.filter */
+char *ss_filter;       /* storable: network.persocket.filter */
+static int using_pipe; /* pipe is normal operation, QA uses files */
 
 FILE *
 ss_open_stream()
 {
-    FILE *fp;
+    FILE *fp = NULL;
     char *path;
-    char cmd[MAXPATHLEN];
 
     if (ss_filter == NULL) {
        /* pmstore to network.persocket.filter frees this if changing */
@@ -38,17 +39,51 @@
        fp = fopen(path, "r");
        if (pmDebugOptions.appl0)
            fprintf(stderr, "ss_open_stream: open PCPQA_PMDA_SOCKETS=%s\n", 
path);
+       using_pipe = 0;
     } else {
+       __pmExecCtl_t   *argp = NULL;
+       int             sts;
+
        if (access((path = "/usr/sbin/ss"), X_OK) != 0) {
            if (access((path = "/usr/bin/ss"), X_OK) != 0) {
                fprintf(stderr, "Error: no \"ss\" binary found\n");
                return NULL;
            }
        }
-       pmsprintf(cmd, sizeof(cmd), "%s %s %s", path, SS_OPTIONS, ss_filter);
-       fp = popen(cmd, "r");
+       if ((sts = __pmProcessAddArg(&argp, path)) < 0 ||
+           (sts = __pmProcessAddArg(&argp, SS_OPTIONS)) < 0) {
+           if (pmDebugOptions.appl0)
+               fprintf(stderr, "ss_open_stream: __pmProcessAddArg failed: 
%s\n",
+                   pmErrStr(sts));
+           return NULL;
+       }
+       if (ss_filter[0] != '\0') {
+           char        *s, *tok, *saveptr;
+
+           if ((s = strdup(ss_filter)) == NULL)
+               return NULL;
+           for (tok = strtok_r(s, " \t", &saveptr); tok != NULL;
+                tok = strtok_r(NULL, " \t", &saveptr)) {
+               if ((sts = __pmProcessAddArg(&argp, tok)) < 0) {
+                   free(s);
+                   if (pmDebugOptions.appl0)
+                       fprintf(stderr, "ss_open_stream: __pmProcessAddArg 
failed: %s\n",
+                           pmErrStr(sts));
+                   return NULL;
+               }
+           }
+           free(s);
+       }
+       if ((sts = __pmProcessPipe(&argp, "r", PM_EXEC_TOSS_NONE, &fp)) < 0) {
+           if (pmDebugOptions.appl0)
+               fprintf(stderr, "ss_open_stream: __pmProcessPipe failed: %s\n",
+                   pmErrStr(sts));
+           return NULL;
+       }
        if (pmDebugOptions.appl0)
-           fprintf(stderr, "ss_open_stream: popen %s\n", cmd);
+           fprintf(stderr, "ss_open_stream: exec %s %s %s\n",
+               path, SS_OPTIONS, ss_filter);
+       using_pipe = 1;
     }
 
     return fp;
@@ -57,8 +92,8 @@
 void
 ss_close_stream(FILE *fp)
 {
-    if (getenv("PCPQA_PMDA_SOCKETS") != NULL)
-       fclose(fp);
+    if (using_pipe)
+       __pmProcessPipeClose(fp);
     else
-       pclose(fp);
+       fclose(fp);
 }

++++++ pcp-CVE-2026-16526.patch ++++++
References: CVE-2026-16526
Description: libpcp, libpcp_pmda: set FD_CLOEXEC on AF_UNIX sockets (CWE-403)
 The __pmInitSocket() function returns early for AF_UNIX sockets,
 skipping all subsequent socket hardening including FD_CLOEXEC.
 This causes the pmdaroot Unix socket fd to be inherited by child
 processes spawned via popen()/fork(), enabling privilege escalation
 when combined with the linux_sockets command injection (vuln 3):
 an attacker's popen() child inherits the pmdaroot fd and can send
 a PDUROOT_STARTPMDA_REQ to execute commands as root.
 .
 Fix:
 - Set FD_CLOEXEC on AF_UNIX sockets in __pmInitSocket() before the
   early return, matching the behavior TCP sockets get via
   __pmConnectRestoreFlags()
 - Set FD_CLOEXEC on pmdarootfd in pmdaRootConnect() after connect()
   succeeds, as belt-and-suspenders for this critical fd
 - Add qa/src/check_cloexec.c and qa/2104 verifying FD_CLOEXEC is set
   on sockets created by __pmCreateUnixSocket()
 .
 Note: SO_PEERCRED peer credential verification on the pmdaroot server
 side is a separate hardening measure to be addressed as a follow-up.
 .
 Reported-by: Francisco Alisson Bezerra, TIM Security Red Team
 Reported-by: Lucas Gabriel Alves, TIM Security Red Team
 Reported-by: Massimiliano Brolli, TIM Security Red Team
 .
 Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
 .
Author: Nathan Scott <[email protected]>
Origin: upstream, 
https://github.com/performancecopilot/pcp/commit/7e27614006ff6fc4925991edbedaf1eab6b14731
 
https://github.com/performancecopilot/pcp/commit/2a4bd9f81a3a59fcba4cf726cc615fd51d107054
Last-Update: 2026-07-25
 Backport-Note:
 Backported to PCP 6.3.8 (applies unchanged). No libpcp3 tree in 6.3.8, so that 
mirror hunk is dropped.


--- a/src/libpcp/src/auxconnect.c
+++ b/src/libpcp/src/auxconnect.c
@@ -516,8 +516,12 @@
     }
 
 #if defined(HAVE_STRUCT_SOCKADDR_UN)
-    if (family == AF_UNIX)
+    if (family == AF_UNIX) {
+       int     fdFlags;
+       if ((fdFlags = __pmGetFileDescriptorFlags(fd)) >= 0)
+           __pmSetFileDescriptorFlags(fd, fdFlags | FD_CLOEXEC);
        return fd;
+    }
 #endif
 
     /* Avoid 200 ms delay. This option is not supported for unix domain 
sockets. */
--- a/src/libpcp_pmda/src/root.c
+++ b/src/libpcp_pmda/src/root.c
@@ -32,7 +32,7 @@
     char               *tmpdir;
     char               socketpath[MAXPATHLEN];
     char               errmsg[PM_MAXERRMSGLEN];
-    int                        fd, sts, version, features;
+    int                        fd, sts, version, features, fdFlags;
 
     /* Initialize the socket address. */
     if ((addr = __pmSockAddrAlloc()) == NULL)
@@ -72,6 +72,9 @@
        return sts;
     }
 
+    if ((fdFlags = __pmGetFileDescriptorFlags(fd)) >= 0)
+       __pmSetFileDescriptorFlags(fd, fdFlags | FD_CLOEXEC);
+
     /* Check server connection information */
     if ((sts = __pmdaRecvRootPDUInfo(fd, &version, &features)) < 0) {
        pmNotifyErr(LOG_ERR,
--- a/src/pmdas/root/root.c
+++ b/src/pmdas/root/root.c
@@ -23,6 +23,9 @@
 #include "docker.h"
 #include "podman.h"
 #include "domain.h"
+#if defined(HAVE_PWD_H)
+#include <pwd.h>
+#endif
 
 #ifndef S_IRWXU
 /*
@@ -37,6 +40,7 @@
 static __pmSockAddr *socket_addr;
 static int socket_fd = -1;
 static int pmcd_fd = -1;
+static uid_t pcp_uid;
 
 static __pmFdSet connected_fds;
 int root_maximum_fd;
@@ -461,6 +465,42 @@
            exit(1);
        }
     }
+#if defined(HAVE_STRUCT_UCRED)
+    {
+       struct ucred    cred;
+       __pmSockLen     len = sizeof(cred);
+
+       if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) == 0) {
+           if (cred.uid != 0 && cred.uid != pcp_uid) {
+               pmNotifyErr(LOG_ERR,
+                   "root_accept_client: rejected uid=%d (expected root or 
pcp[%d])\n",
+                   cred.uid, pcp_uid);
+               close(fd);
+               root_client[i].fd = -1;
+               root_delete_client(&root_client[i]);
+               return NULL;
+           }
+       }
+    }
+#elif defined(HAVE_GETPEEREID)
+    {
+       uid_t           uid;
+       gid_t           gid;
+
+       if (getpeereid(fd, &uid, &gid) == 0) {
+           if (uid != 0 && uid != pcp_uid) {
+               pmNotifyErr(LOG_ERR,
+                   "root_accept_client: rejected uid=%d (expected root or 
pcp[%d])\n",
+                   uid, pcp_uid);
+               close(fd);
+               root_client[i].fd = -1;
+               root_delete_client(&root_client[i]);
+               return NULL;
+           }
+       }
+    }
+#endif
+
     if (fd > root_maximum_fd)
        root_maximum_fd = fd;
     __pmFD_SET(fd, &connected_fds);
@@ -797,6 +837,19 @@
 }
 
 static void
+root_get_pcp_uid(void)
+{
+#if defined(HAVE_PWD_H)
+    char               *username;
+    struct passwd      *pw;
+
+    pmGetUsername(&username);
+    if ((pw = getpwnam(username)) != NULL)
+       pcp_uid = pw->pw_uid;
+#endif
+}
+
+static void
 root_check_user(void)
 {
 #ifdef HAVE_GETUID
@@ -815,6 +868,7 @@
 root_prep(void)
 {
     root_check_user();
+    root_get_pcp_uid();
     root_setup_socket();
     atexit(root_close_socket);
 }

++++++ pcp-CVE-2026-16527.patch ++++++
References: CVE-2026-16527
Description: pmproxy: fix missing -Q and -S authentication flags (CWE-306)
 The pmproxy -Q (require client certificate) and -S (require
 authenticated clients) flags existed as case blocks in the option
 parser but were absent from the short_options string and the longopts
 table, making them permanently unreachable.  An unauthenticated HTTP
 client could access all REST API endpoints including /store and /derive.
 .
 Fix:
 - Add Q and S to short_options so pmgetopt_r() delivers them
 - Add --certreqd and --reqauth entries to the longopts table
 - Document both flags in the pmproxy(1) man page
 - Add qa/2100 verifying the flags are accepted and that -S correctly
   rejects unauthenticated REST API requests with HTTP 403
 .
 Note: -S enforcement in the REST API path already exists in http.c and
 webapi.c.  -Q (CERT_REQD) enforcement is only implemented for the
 legacy PCP wire protocol path, not the REST API; this is a pre-existing
 limitation to be addressed separately.
 .
 Reported-by: Francisco Alisson Bezerra, TIM Security Red Team
 Reported-by: Lucas Gabriel Alves, TIM Security Red Team
 Reported-by: Massimiliano Brolli, TIM Security Red Team
 .
 Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
 .
Author: Nathan Scott <[email protected]>
Origin: upstream, 
https://github.com/performancecopilot/pcp/commit/d96ba5a716eeff7840138eb08fbab0d11a57f641
 
https://github.com/performancecopilot/pcp/commit/81a9efe96db6f7764a1a1646b64eb85de5cdaf77
 
https://github.com/performancecopilot/pcp/commit/4121ae06f54ab2089adf7270197c774d60dd03c8
Last-Update: 2026-07-25
 Backport-Note:
 Backported to PCP 6.3.8 (applies unchanged). The logger-servlet authentication
  (logger.c, pmproxy.conf) and man page are absent in 6.3.8 and dropped; the 
core
  -Q/-S flag enablement and REST CERT_REQD enforcement are carried.


--- a/src/pmproxy/src/pmproxy.c
+++ b/src/pmproxy/src/pmproxy.c
@@ -82,7 +82,9 @@
     PMAPI_OPTIONS_HEADER("Connection options"),
     { "interface", 1, 'i', "ADDR", "accept connections on this IP address" },
     { "port", 1, 'p', "PORT", "accept connections on this port" },
+    { "certreqd", 0, 'Q', 0, "require client certificate authentication" },
     { "socket", 1, 's', "PATH", "Unix domain socket file [default 
$PCP_RUN_DIR/pmproxy.socket]" },
+    { "reqauth", 0, 'S', 0, "require all client connections to be 
authenticated" },
     { "keyport", 1, 'r', "PORT", "Connect to key server on this TCP/IP port 
(implies --timeseries)" },
     { "keyhost", 1, 'h', "HOST", "Connect to key server on this host name 
(implies --timeseries)" },
     { "redisport", 1, 'r', "PORT", "Backwards-compatibility option, do not 
use" },
@@ -95,7 +97,7 @@
 };
 
 static pmOptions opts = {
-    .short_options = "Ac:dD:Ffh:i:l:L:p:r:s:tT:U:x:?",
+    .short_options = "Ac:dD:Ffh:i:l:L:p:Qr:s:StT:U:x:?",
     .long_options = longopts,
 };
 
--- a/src/pmproxy/src/http.c
+++ b/src/pmproxy/src/http.c
@@ -1091,6 +1091,20 @@
        }
     }
 
+    /* client certificate required for all servlets */
+    if (__pmServerHasFeature(PM_SERVER_FEATURE_CERT_REQD)) {
+#ifdef HAVE_OPENSSL
+       if (!client->stream.secure ||
+           !client->secure.ssl ||
+           SSL_get_peer_certificate(client->secure.ssl) == NULL) {
+           client->u.http.parser.status_code = HTTP_STATUS_FORBIDDEN;
+       }
+#else
+       /* no TLS support compiled in, reject all connections */
+       client->u.http.parser.status_code = HTTP_STATUS_FORBIDDEN;
+#endif
+    }
+
     return sts;
 }
 

++++++ pcp-CVE-2026-16529.patch ++++++
References: CVE-2026-16529
Description: libpcp: fix integer overflow in __pmGetPDU() (CWE-190)
 When php->len is near INT_MAX (e.g. 0x7FFFFFFF), the buffer size
 computation PDU_CHUNK * (1 + php->len / PDU_CHUNK) overflows signed
 int, producing a negative value that permanently corrupts the static
 maxsize variable.  Every subsequent __pmFindPDUBuf() call returns NULL,
 rendering the affected daemon (pmlogger, pmcd) unable to process any
 further PDUs for the remainder of its lifetime — a persistent denial
 of service requiring a restart.
 .
 Fix: add an overflow guard (php->len > INT_MAX - PDU_CHUNK) before
 the multiplication, returning PM_ERR_TOOBIG for absurdly large PDU
 lengths.  This protects the NO_LIMIT code path used by pmcd and
 pmlogger that is not covered by the existing ceiling check.
 .
 Also add _filter_pmcd() to qa/common.pmcd.pdu to normalize fd=N in
 pmcd log output, and qa/2105 with a crafted PDU exercising the
 overflow.
 .
 Reported-by: Francisco Alisson Bezerra, TIM Security Red Team
 Reported-by: Lucas Gabriel Alves, TIM Security Red Team
 Reported-by: Massimiliano Brolli, TIM Security Red Team
 .
 Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
 .
Author: Nathan Scott <[email protected]>
Origin: upstream, 
https://github.com/performancecopilot/pcp/commit/ef848fb978d26335f9676933f541c73b58f130a6
Last-Update: 2026-07-25
 Backport-Note:
 Backported to PCP 6.3.8 (applies unchanged). No libpcp3 tree in 6.3.8, so that 
mirror hunk is dropped.


--- a/src/libpcp/src/pdu.c
+++ b/src/libpcp/src/pdu.c
@@ -658,6 +658,14 @@
 
        PM_LOCK(pdu_lock);
        if (php->len > maxsize) {
+           if (php->len > INT_MAX - PDU_CHUNK) {
+               PM_UNLOCK(pdu_lock);
+               if (pmDebugOptions.pdu)
+                   pmNotifyErr(LOG_ERR, "%s: fd=%d PDU len=%d too large",
+                               __FUNCTION__, fd, php->len);
+               __pmUnpinPDUBuf(pdubuf);
+               return PM_ERR_TOOBIG;
+           }
            tmpsize = PDU_CHUNK * ( 1 + php->len / PDU_CHUNK);
            maxsize = tmpsize;
        }

++++++ pcp-CVE-2026-16530-1.patch ++++++
References: CVE-2026-16530
Description: libpcp: fix arbitrary pointer deref in __pmLogLoadInDom 
(CWE-125/822)
 The bounds check on string indices (idx > max_idx) in __pmLogLoadInDom()
 was guarded by if (acp != NULL), making it unreachable from the streaming
 path used by pmproxy (which passes acp=NULL).  An attacker could submit
 a TYPE_INDOM record with an out-of-range stridx value via POST
 /logger/meta, causing namelist[i] to point to arbitrary heap memory.
 .
 Fix:
 - Add minimum rlen checks before reading fixed fields, using macros
   derived from the on-disk struct sizes (INDOM_V3_MINRLEN, INDOM_V2_MINRLEN)
 - Validate numinst against rlen before using it in arithmetic, preventing
   integer overflow in the max_idx computation
 - Make max_idx computation and idx bounds check unconditional (remove the
   acp != NULL guard) so they protect both archive and streaming paths
 - Extend qa/src/pducrash.c with decode_log_indom() exercising all four
   failure modes via __pmLogLoadInDom(NULL, ...)
 .
 Reported-by: Francisco Alisson Bezerra, TIM Security Red Team
 Reported-by: Lucas Gabriel Alves, TIM Security Red Team
 Reported-by: Massimiliano Brolli, TIM Security Red Team
 .
 Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
 .
Author: Nathan Scott <[email protected]>
Origin: upstream, 
https://github.com/performancecopilot/pcp/commit/ec81e2b35c7dc19a69406d2712d1b9904ac22112
 
https://github.com/performancecopilot/pcp/commit/b72da5135df7fb08ca432db1e2db24478f43aea2
 
https://github.com/performancecopilot/pcp/commit/edfd909edac8ad4762aa150e330f92211df98c1c
Last-Update: 2026-07-25
 Backport-Note:
 Backported to PCP 6.3.8 (applies unchanged). No libpcp3 tree in 6.3.8, so that 
mirror hunk is dropped.


--- a/src/libpcp/src/e_indom.c
+++ b/src/libpcp/src/e_indom.c
@@ -51,6 +51,10 @@
                                /* will be expanded if numinst > 0 */
 } __pmInDom_v2;
 
+/* Minimum rlen (record body without len+type header) to read fixed fields */
+#define INDOM_V3_MINRLEN       (sizeof(__pmInDom_v3) - 2 * sizeof(__int32_t))
+#define INDOM_V2_MINRLEN       (sizeof(__pmInDom_v2) - 2 * sizeof(__int32_t))
+
 /*
  * pack an indom into a physical metadata record
  * - lcp required to provide archive version (else NULL)
@@ -258,33 +262,55 @@
 
     if (type == TYPE_INDOM || type == TYPE_INDOM_DELTA) {
        __pmInDom_v3    *v3;
+       if (rlen < (int)INDOM_V3_MINRLEN) {
+           if (pmDebugOptions.logmeta)
+               fprintf(stderr, "__pmLogLoadInDom: v3 rlen=%d too small 
(min=%d)\n",
+                   rlen, (int)INDOM_V3_MINRLEN);
+           goto bad;
+       }
        v3 = (__pmInDom_v3 *)&lbuf[-2]; /* len+type not in buf */
        __pmLoadTimestamp(&v3->sec[0], &lidp->stamp);
        k = (sizeof(v3->sec)+sizeof(v3->nsec))/sizeof(__int32_t);
        lidp->indom = __ntohpmInDom(v3->indom);
        k++;
        lidp->numinst = ntohl(v3->numinst);
+       if (lidp->numinst < 0 ||
+           lidp->numinst > (rlen - (int)INDOM_V3_MINRLEN) / (2 * 
(int)sizeof(__int32_t))) {
+           if (pmDebugOptions.logmeta)
+               fprintf(stderr, "__pmLogLoadInDom: v3 numinst=%d not consistent 
with rlen=%d\n",
+                   lidp->numinst, rlen);
+           goto bad;
+       }
        k++;
        lidp->instlist = (int *)&v3->data;
-       if (acp != NULL) {
-           /* rlen minus fixed fields (plus len+type), minus instlist[], minus 
strindex[] */
-           max_idx = rlen - 5*sizeof(__int32_t) - 
2*lidp->numinst*sizeof(__int32_t);
-       }
+       /* rlen minus fixed fields (plus len+type), minus instlist[], minus 
strindex[] */
+       max_idx = rlen - (int)INDOM_V3_MINRLEN - 2 * lidp->numinst * 
(int)sizeof(__int32_t);
     }
     else if (type == TYPE_INDOM_V2) {
        __pmInDom_v2    *v2;
+       if (rlen < (int)INDOM_V2_MINRLEN) {
+           if (pmDebugOptions.logmeta)
+               fprintf(stderr, "__pmLogLoadInDom: v2 rlen=%d too small 
(min=%d)\n",
+                   rlen, (int)INDOM_V2_MINRLEN);
+           goto bad;
+       }
        v2 = (__pmInDom_v2 *)&lbuf[-2]; /* len+type not in lbuf */
        __pmLoadTimeval(&v2->sec, &lidp->stamp);
        k = (sizeof(v2->sec)+sizeof(v2->usec))/sizeof(__int32_t);
        lidp->indom = __ntohpmInDom(v2->indom);
        k++;
        lidp->numinst = ntohl(v2->numinst);
+       if (lidp->numinst < 0 ||
+           lidp->numinst > (rlen - (int)INDOM_V2_MINRLEN) / (2 * 
(int)sizeof(__int32_t))) {
+           if (pmDebugOptions.logmeta)
+               fprintf(stderr, "__pmLogLoadInDom: v2 numinst=%d not consistent 
with rlen=%d\n",
+                   lidp->numinst, rlen);
+           goto bad;
+       }
        k++;
        lidp->instlist = (int *)&v2->data;
-       if (acp != NULL) {
-           /* rlen minus fixed fields (plus len+type), minus instlist[], minus 
strindex[] */
-           max_idx = rlen - 4*sizeof(__int32_t) - 
2*lidp->numinst*sizeof(__int32_t);
-       }
+       /* rlen minus fixed fields (plus len+type), minus instlist[], minus 
strindex[] */
+       max_idx = rlen - (int)INDOM_V2_MINRLEN - 2 * lidp->numinst * 
(int)sizeof(__int32_t);
     }
     else {
        if (pmDebugOptions.logmeta)
@@ -327,21 +353,14 @@
            }
            idx = ntohl(stridx[i]);
            if (idx >= 0) {
-               if (acp != NULL) {
-                   /*
-                    * crude sanity check ... if the index points to the
-                    * start of the name that is past the end of the input
-                    * record, the record is corrupted
-                    */
-                   if (idx > max_idx) {
-                       if (pmDebugOptions.logmeta) {
-                           char        strbuf[20];
-                           fprintf(stderr, "__pmLogLoadInDom: InDom: %s 
instance[%d]: bad string index (%d) > max index based on record length (%d)\n",
-                               pmInDomStr_r(lidp->indom, strbuf, 
sizeof(strbuf)),
-                               i, idx, max_idx);
-                       }
-                       goto bad;
+               if (idx > max_idx) {
+                   if (pmDebugOptions.logmeta) {
+                       char    strbuf[20];
+                       fprintf(stderr, "__pmLogLoadInDom: InDom: %s 
instance[%d]: bad string index (%d) > max index based on record length (%d)\n",
+                           pmInDomStr_r(lidp->indom, strbuf, sizeof(strbuf)),
+                           i, idx, max_idx);
                    }
+                   goto bad;
                }
                lidp->namelist[i] = &namebase[idx];
                if (pmDebugOptions.logmeta && pmDebugOptions.desperate)
--- a/src/pmlogextract/pmlogextract.c
+++ b/src/pmlogextract/pmlogextract.c
@@ -1300,7 +1300,7 @@
                    memcpy(buf, rec->pdu, rlen);
 
                    ibuf = &buf[2];
-                   sts = __pmLogLoadInDom(NULL, 0, type, &lid, &ibuf);
+                   sts = __pmLogLoadInDom(NULL, rlen, type, &lid, &ibuf);
                    if (sts < 0) {
                        fprintf(stderr, "write_rec: __pmLogLoadInDom(type=%s 
(%d)): failed: %s\n", __pmLogMetaTypeStr(type), type, pmErrStr(sts));
                    }
--- a/src/pmlogrewrite/indom.c
+++ b/src/pmlogrewrite/indom.c
@@ -223,9 +223,10 @@
     }
     else {
        __int32_t       *buf;
+       int             len = htonl(hdr->len);
        /* buffer for __pmLogLoadInDom has to start AFTER the header */
        buf = &recbuf[2];
-       sts = __pmLogLoadInDom(NULL, 0, type, lidp, &buf);
+       sts = __pmLogLoadInDom(NULL, len, type, lidp, &buf);
        if (sts < 0) {
            fprintf(stderr, "_pmUnpackInDom: __pmLogLoadInDom(type=%d): failed: 
%s\n", type, pmErrStr(sts));
            abandon();

++++++ pcp-CVE-2026-16530-2.patch ++++++
References: CVE-2026-16530
Description: libpcp: fix OOB read in __pmLogLoadLabelSet (CWE-125)
 __pmLogLoadLabelSet() reads timestamp, type, ident, and nsets fields
 from tbuf at sequential offsets without checking that rlen is large
 enough to contain them.  When the pmproxy logger servlet delivers a
 TYPE_LABEL record with hdr.len=13 (minimum accepted by the dispatcher),
 rlen=1 and the function reads 20-24 bytes from a 1-byte buffer.
 .
 Fix: add minimum-length guard at the top of __pmLogLoadLabelSet()
 using LABELSET_V3_MINRLEN / LABELSET_V2_MINRLEN macros derived from
 the on-disk __pmExtLabelSet_v3/v2 struct sizes (minus the len+type
 header that rlen excludes).
 .
 Test coverage will be added in a consolidated pducrash.c extension
 covering vulns 9-13.
 .
 Reported-by: Francisco Alisson Bezerra, TIM Security Red Team
 Reported-by: Lucas Gabriel Alves, TIM Security Red Team
 Reported-by: Massimiliano Brolli, TIM Security Red Team
 .
 Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
 .
Author: Nathan Scott <[email protected]>
Origin: upstream, 
https://github.com/performancecopilot/pcp/commit/ccd1bb167934b5e4a60d39bacf25e12e0a2decb4
Last-Update: 2026-07-25
 Backport-Note:
 Backported to PCP 6.3.8 (applies unchanged). No libpcp3 tree in 6.3.8, so that 
mirror hunk is dropped.


--- a/src/libpcp/src/e_labels.c
+++ b/src/libpcp/src/e_labels.c
@@ -56,6 +56,10 @@
                                /* will be expanded if nsets > 0 */
 } __pmExtLabelSet_v2;
 
+/* Minimum rlen (record body without len+type header) to read fixed fields */
+#define LABELSET_V3_MINRLEN    (sizeof(__pmExtLabelSet_v3) - 2 * 
sizeof(__int32_t))
+#define LABELSET_V2_MINRLEN    (sizeof(__pmExtLabelSet_v2) - 2 * 
sizeof(__int32_t))
+
 /*
  * pack a set of labels into a physical metadata record
  * - lcp required to provide archive version
@@ -215,6 +219,23 @@
     *nsetsp = 0;
     *labelsetsp = NULL;
 
+    if (rtype == TYPE_LABEL_V2) {
+       if (rlen < (int)LABELSET_V2_MINRLEN) {
+           if (pmDebugOptions.logmeta)
+               fprintf(stderr, "%s: v2 rlen=%d too small (min=%d)\n",
+                       __FUNCTION__, rlen, (int)LABELSET_V2_MINRLEN);
+           return PM_ERR_LOGREC;
+       }
+    }
+    else {
+       if (rlen < (int)LABELSET_V3_MINRLEN) {
+           if (pmDebugOptions.logmeta)
+               fprintf(stderr, "%s: v3 rlen=%d too small (min=%d)\n",
+                       __FUNCTION__, rlen, (int)LABELSET_V3_MINRLEN);
+           return PM_ERR_LOGREC;
+       }
+    }
+
     k = 0;
     if (rtype == TYPE_LABEL_V2) {
        __pmLoadTimeval((__int32_t *)&tbuf[k], stamp);

++++++ pcp-CVE-2026-16530-3.patch ++++++
References: CVE-2026-16530
Description: libpcp_web: add numinst overflow check in 
pmDiscoverDecodeMetaInDom (CWE-125/190)
 Defense-in-depth for the __pmLogLoadInDom streaming path fix (commit 1).
 When __pmLogLoadInDom is called with acp=NULL from the pmproxy discover
 code, a garbage numinst value read from a too-small buffer could be
 passed to calloc(numinst, sizeof(char *)), causing an integer overflow
 in the allocation size.
 .
 Add explicit validation that numinst > 0 and does not overflow SIZE_MAX
 before the calloc in pmDiscoverDecodeMetaInDom().  The primary fix
 (rlen and numinst validation in __pmLogLoadInDom itself) prevents this
 value from being garbage in the first place.
 .
 Reported-by: Francisco Alisson Bezerra, TIM Security Red Team
 Reported-by: Lucas Gabriel Alves, TIM Security Red Team
 Reported-by: Massimiliano Brolli, TIM Security Red Team
 .
 Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
 .
Author: Nathan Scott <[email protected]>
Origin: upstream, 
https://github.com/performancecopilot/pcp/commit/7f42013d33a6717a45e8f9ac9e7dfcf76ee6384f
Last-Update: 2026-07-25
 Backport-Note:
 Backported to PCP 6.3.8. Adapted to the 6.3.8 allocation site (malloc form) in
  pmDiscoverDecodeMetaInDom(). Defence-in-depth: the read side is already 
closed by
  patch 01. The remote vector (pmproxy logger servlet) is absent in 6.3.8.


--- a/src/libpcp_web/src/discover.c
+++ b/src/libpcp_web/src/discover.c
@@ -1954,6 +1954,11 @@
             */
            char        **namelist;
            int         i;
+           if (lid.numinst <= 0 ||
+               (size_t)lid.numinst > SIZE_MAX / sizeof(char *)) {
+               __pmFreeLogInDom(&lid);
+               return -EINVAL;
+           }
            namelist = (char **)malloc(lid.numinst * sizeof(char *));
            if (namelist == NULL) {
                pmNoMem("pmDiscoverDecodeMetaInDom", lid.numinst * sizeof(char 
*), PM_FATAL_ERR);

++++++ pcp-CVE-2026-16530-4.patch ++++++
References: CVE-2026-16530
Description: libpcp: fix OOB read in __pmDecodeLabel via negative jsonoff 
(CWE-125)
 The bounds check 'if (pdu_length < jsonoff + jsonlen)' uses signed
 arithmetic.  When jsonoff is negative (high bit set after ntohl) and
 jsonlen is a small positive value, their sum wraps to a small positive
 number, passing the check.  The subsequent memcpy reads from
 label_pdu + jsonoff, an address before the start of the PDU buffer.
 .
 Fix: reject negative jsonoff and jsonlen explicitly, then use unsigned
 (size_t) arithmetic for the bounds check to prevent signed wraparound.
 .
 Reported-by: Francisco Alisson Bezerra, TIM Security Red Team
 Reported-by: Lucas Gabriel Alves, TIM Security Red Team
 Reported-by: Massimiliano Brolli, TIM Security Red Team
 .
 Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
 .
Author: Nathan Scott <[email protected]>
Origin: upstream, 
https://github.com/performancecopilot/pcp/commit/e512482e7d33aa6c46fbe569d0de7951c0fcec75
Last-Update: 2026-07-25
 Backport-Note:
 Backported to PCP 6.3.8 (applies unchanged). No libpcp3 tree in 6.3.8, so that 
mirror hunk is dropped.


--- a/src/libpcp/src/p_label.c
+++ b/src/libpcp/src/p_label.c
@@ -446,10 +446,11 @@
        }
 
        /* check JSON content fits within the PDU bounds */
-       if (pdu_length < jsonoff + jsonlen) {
+       if (jsonoff < 0 || jsonlen < 0 ||
+           (size_t)jsonoff + (size_t)jsonlen > pdu_length) {
            if (pmDebugOptions.pdu) {
-               fprintf(stderr, "__pmDecodeLabel: PM_ERR_IPC: labelset[%d] 
pdu_length %d < jsonoff %d + jsonlen %d\n",
-                   i, (int)pdu_length, jsonoff, jsonlen);
+               fprintf(stderr, "%s: PM_ERR_IPC: labelset[%d] pdu_length %d < 
jsonoff %d + jsonlen %d\n",
+                   __FUNCTION__, i, (int)pdu_length, jsonoff, jsonlen);
            }
            goto corrupt;
        }

++++++ pcp-CVE-2026-16530-5.patch ++++++
References: CVE-2026-16530
Description: libpcp: fix OOB read in __pmDecodeLogStatus (CWE-125)
 For each of the six length-prefixed string fields in PDU_LOG_STATUS
 (hostname, fqdn, timezone, zoneinfo for both pmcd and pmlogger),
 strdup(p) was called before verifying that p+len falls within the
 PDU buffer.  strdup reads until a null byte, so a non-null-terminated
 string causes reads past the PDU boundary into adjacent heap memory.
 .
 Fix: for all six fields, move the p+len > pduend bounds check before
 the string copy, and replace strdup(p) with strndup(p, len) to
 respect the declared length regardless of null terminator presence.
 .
 Reported-by: Francisco Alisson Bezerra, TIM Security Red Team
 Reported-by: Lucas Gabriel Alves, TIM Security Red Team
 Reported-by: Massimiliano Brolli, TIM Security Red Team
 .
 Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
 .
Author: Nathan Scott <[email protected]>
Origin: upstream, 
https://github.com/performancecopilot/pcp/commit/5366a546d66c0a085958dd84b08b3e1ca165f7ab
Last-Update: 2026-07-25
 Backport-Note:
 Backported to PCP 6.3.8 (applies unchanged). No libpcp3 tree in 6.3.8, so that 
mirror hunk is dropped.


--- a/src/libpcp/src/p_lstatus.c
+++ b/src/libpcp/src/p_lstatus.c
@@ -265,157 +265,157 @@
        if (len == 0)
            lsp->pmcd.hostname = NULL;
        else {
-           if (len > PM_MAX_HOSTNAMELEN) {
-               /* cannot be longer than hostname in archive label */
+           if (len < 0 || len > PM_MAX_HOSTNAMELEN) {
+               /* cannot be negative or longer than hostname in archive label 
*/
                if (pmDebugOptions.pmlc || pmDebugOptions.pdu) 
-                   fprintf(stderr, "__pmDecodeLogStatus: PM_ERR_IPC: 
pmcd.hostname too long (%d)\n", len);
+                   fprintf(stderr, "__pmDecodeLogStatus: PM_ERR_IPC: invalid 
pmcd.hostname (%d)\n", len);
                __pmFreeLogStatus(lsp, 1);
                return PM_ERR_IPC;
            }
-           if ((lsp->pmcd.hostname = strdup(p)) == NULL) {
+           if (p + len > pduend) {
+               if (pmDebugOptions.pmlc || pmDebugOptions.pdu)
+                   fprintf(stderr, "%s: PM_ERR_IPC: pmcd.hostname data[%ld] > 
PDU len (%d)\n",
+                       __FUNCTION__, (long)(p + len - (char *)&pp->data[0]), 
pp->hdr.len);
+               __pmFreeLogStatus(lsp, 1);
+               return PM_ERR_IPC;
+           }
+           if ((lsp->pmcd.hostname = strndup(p, len)) == NULL) {
                sts = -oserror();
                pmNoMem("__pmDecodeLogStatus: pmcd.hostname", len, 
PM_RECOV_ERR);
                __pmFreeLogStatus(lsp, 1);
                return sts;
            }
            p += len;
-           if (p > pduend) {
-               if (pmDebugOptions.pmlc || pmDebugOptions.pdu) 
-                   fprintf(stderr, "__pmDecodeLogStatus: PM_ERR_IPC: 
pmcd.hostname data[%ld] > PDU len (%d)\n", 
-                       (long)(p - (char *)&pp->data[0]), pp->hdr.len);
-               __pmFreeLogStatus(lsp, 1);
-               return PM_ERR_IPC;
-           }
        }
        len = ntohl(pp->pmcd_fqdn_len);
        if (len == 0)
            lsp->pmcd.fqdn = NULL;
        else {
-           if (len > PM_MAX_HOSTNAMELEN) {
-               /* cannot be longer than hostname in archive label */
+           if (len < 0 || len > PM_MAX_HOSTNAMELEN) {
+               /* cannot be negative or longer than hostname in archive label 
*/
                if (pmDebugOptions.pmlc || pmDebugOptions.pdu) 
-                   fprintf(stderr, "__pmDecodeLogStatus: PM_ERR_IPC: pmcd.fqdn 
too long (%d)\n", len);
+                   fprintf(stderr, "__pmDecodeLogStatus: PM_ERR_IPC: invalid 
pmcd.fqdn (%d)\n", len);
                __pmFreeLogStatus(lsp, 1);
                return PM_ERR_IPC;
            }
-           if ((lsp->pmcd.fqdn = strdup(p)) == NULL) {
+           if (p + len > pduend) {
+               if (pmDebugOptions.pmlc || pmDebugOptions.pdu)
+                   fprintf(stderr, "%s: PM_ERR_IPC: pmcd.fqdn data[%ld] > PDU 
len (%d)\n",
+                       __FUNCTION__, (long)(p + len - (char *)&pp->data[0]), 
pp->hdr.len);
+               __pmFreeLogStatus(lsp, 1);
+               return PM_ERR_IPC;
+           }
+           if ((lsp->pmcd.fqdn = strndup(p, len)) == NULL) {
                sts = -oserror();
                pmNoMem("__pmDecodeLogStatus: pmcd.fqdn", len, PM_RECOV_ERR);
                __pmFreeLogStatus(lsp, 1);
                return sts;
            }
            p += len;
-           if (p > pduend) {
-               if (pmDebugOptions.pmlc || pmDebugOptions.pdu) 
-                   fprintf(stderr, "__pmDecodeLogStatus: PM_ERR_IPC: pmcd.fqdn 
data[%ld] > PDU len (%d)\n", 
-                       (long)(p - (char *)&pp->data[0]), pp->hdr.len);
-               __pmFreeLogStatus(lsp, 1);
-               return PM_ERR_IPC;
-           }
        }
        len = ntohl(pp->pmcd_timezone_len);
        if (len == 0)
            lsp->pmcd.timezone = NULL;
        else {
-           if (len > PM_MAX_TIMEZONELEN) {
-               /* cannot be longer than timezone in archive label */
+           if (len < 0 || len > PM_MAX_TIMEZONELEN) {
+               /* cannot be negative or longer than timezone in archive label 
*/
                if (pmDebugOptions.pmlc || pmDebugOptions.pdu) 
-                   fprintf(stderr, "__pmDecodeLogStatus: PM_ERR_IPC: 
pmcd.timezone too long (%d)\n", len);
+                   fprintf(stderr, "__pmDecodeLogStatus: PM_ERR_IPC: invalid 
pmcd.timezone (%d)\n", len);
                __pmFreeLogStatus(lsp, 1);
                return PM_ERR_IPC;
            }
-           if ((lsp->pmcd.timezone = strdup(p)) == NULL) {
+           if (p + len > pduend) {
+               if (pmDebugOptions.pmlc || pmDebugOptions.pdu)
+                   fprintf(stderr, "%s: PM_ERR_IPC: pmcd.timezone data[%ld] > 
PDU len (%d)\n",
+                       __FUNCTION__, (long)(p + len - (char *)&pp->data[0]), 
pp->hdr.len);
+               __pmFreeLogStatus(lsp, 1);
+               return PM_ERR_IPC;
+           }
+           if ((lsp->pmcd.timezone = strndup(p, len)) == NULL) {
                sts = -oserror();
                pmNoMem("__pmDecodeLogStatus: pmcd.timezone", len, 
PM_RECOV_ERR);
                __pmFreeLogStatus(lsp, 1);
                return sts;
            }
            p += len;
-           if (p > pduend) {
-               if (pmDebugOptions.pmlc || pmDebugOptions.pdu) 
-                   fprintf(stderr, "__pmDecodeLogStatus: PM_ERR_IPC: 
pmcd.timezone data[%ld] > PDU len (%d)\n", 
-                       (long)(p - (char *)&pp->data[0]), pp->hdr.len);
-               __pmFreeLogStatus(lsp, 1);
-               return PM_ERR_IPC;
-           }
        }
        len = ntohl(pp->pmcd_zoneinfo_len);
        if (len == 0)
            lsp->pmcd.zoneinfo = NULL;
        else {
-           if (len > PM_MAX_ZONEINFOLEN) {
-               /* cannot be longer than zoneinfo in archive label */
+           if (len < 0 || len > PM_MAX_ZONEINFOLEN) {
+               /* cannot be negative or longer than zoneinfo in archive label 
*/
                if (pmDebugOptions.pmlc || pmDebugOptions.pdu) 
-                   fprintf(stderr, "__pmDecodeLogStatus: PM_ERR_IPC: 
pmcd.zoneinfo too long (%d)\n", len);
+                   fprintf(stderr, "__pmDecodeLogStatus: PM_ERR_IPC: invalid 
pmcd.zoneinfo (%d)\n", len);
                __pmFreeLogStatus(lsp, 1);
                return PM_ERR_IPC;
            }
-           if ((lsp->pmcd.zoneinfo = strdup(p)) == NULL) {
+           if (p + len > pduend) {
+               if (pmDebugOptions.pmlc || pmDebugOptions.pdu)
+                   fprintf(stderr, "%s: PM_ERR_IPC: pmcd.zoneinfo data[%ld] > 
PDU len (%d)\n",
+                       __FUNCTION__, (long)(p + len - (char *)&pp->data[0]), 
pp->hdr.len);
+               __pmFreeLogStatus(lsp, 1);
+               return PM_ERR_IPC;
+           }
+           if ((lsp->pmcd.zoneinfo = strndup(p, len)) == NULL) {
                sts = -oserror();
                pmNoMem("__pmDecodeLogStatus: pmcd.zoneinfo", len, 
PM_RECOV_ERR);
                __pmFreeLogStatus(lsp, 1);
                return sts;
            }
            p += len;
-           if (p > pduend) {
-               if (pmDebugOptions.pmlc || pmDebugOptions.pdu) 
-                   fprintf(stderr, "__pmDecodeLogStatus: PM_ERR_IPC: 
pmcd.zoneinfo data[%ld] > PDU len (%d)\n", 
-                       (long)(p - (char *)&pp->data[0]), pp->hdr.len);
-               __pmFreeLogStatus(lsp, 1);
-               return PM_ERR_IPC;
-           }
        }
        len = ntohl(pp->pmlogger_timezone_len);
        if (len == 0)
            lsp->pmlogger.timezone = NULL;
        else {
            if (len > PM_MAX_TIMEZONELEN) {
-               /* cannot be longer than timezone in archive label */
+               /* cannot be negative or longer than timezone in archive label 
*/
                if (pmDebugOptions.pmlc || pmDebugOptions.pdu) 
                    fprintf(stderr, "__pmDecodeLogStatusPM_ERR_IPC: : 
pmlogger.timezone too long (%d)\n", len);
                __pmFreeLogStatus(lsp, 1);
                return PM_ERR_IPC;
            }
-           if ((lsp->pmlogger.timezone = strdup(p)) == NULL) {
+           if (p + len > pduend) {
+               if (pmDebugOptions.pmlc || pmDebugOptions.pdu)
+                   fprintf(stderr, "%s: PM_ERR_IPC: pmlogger.timezone 
data[%ld] > PDU len (%d)\n",
+                       __FUNCTION__, (long)(p + len - (char *)&pp->data[0]), 
pp->hdr.len);
+               __pmFreeLogStatus(lsp, 1);
+               return PM_ERR_IPC;
+           }
+           if ((lsp->pmlogger.timezone = strndup(p, len)) == NULL) {
                sts = -oserror();
                pmNoMem("__pmDecodeLogStatus: pmlogger.timezone", len, 
PM_RECOV_ERR);
                __pmFreeLogStatus(lsp, 1);
                return sts;
            }
            p += len;
-           if (p > pduend) {
-               if (pmDebugOptions.pmlc || pmDebugOptions.pdu) 
-                   fprintf(stderr, "__pmDecodeLogStatus: PM_ERR_IPC: 
pmlogger.timezone data[%ld] > PDU len (%d)\n", 
-                       (long)(p - (char *)&pp->data[0]), pp->hdr.len);
-               __pmFreeLogStatus(lsp, 1);
-               return PM_ERR_IPC;
-           }
        }
        len = ntohl(pp->pmlogger_zoneinfo_len);
        if (len == 0)
            lsp->pmlogger.zoneinfo = NULL;
        else {
-           if (len > PM_MAX_ZONEINFOLEN) {
-               /* cannot be longer than zoneinfo in archive label */
+           if (len < 0 || len > PM_MAX_ZONEINFOLEN) {
+               /* cannot be negative or longer than zoneinfo in archive label 
*/
                if (pmDebugOptions.pmlc || pmDebugOptions.pdu) 
-                   fprintf(stderr, "__pmDecodeLogStatus: PM_ERR_IPC: 
pmlogger.zoneinfo too long (%d)\n", len);
+                   fprintf(stderr, "__pmDecodeLogStatus: PM_ERR_IPC: invalid 
pmlogger.zoneinfo (%d)\n", len);
+               __pmFreeLogStatus(lsp, 1);
+               return PM_ERR_IPC;
+           }
+           if (p + len > pduend) {
+               if (pmDebugOptions.pmlc || pmDebugOptions.pdu)
+                   fprintf(stderr, "%s: PM_ERR_IPC: pmlogger.zoneinfo 
data[%ld] > PDU len (%d)\n",
+                       __FUNCTION__, (long)(p + len - (char *)&pp->data[0]), 
pp->hdr.len);
                __pmFreeLogStatus(lsp, 1);
                return PM_ERR_IPC;
            }
-           if ((lsp->pmlogger.zoneinfo = strdup(p)) == NULL) {
+           if ((lsp->pmlogger.zoneinfo = strndup(p, len)) == NULL) {
                sts = -oserror();
                pmNoMem("__pmDecodeLogStatus: pmlogger.zoneinfo", len, 
PM_RECOV_ERR);
                __pmFreeLogStatus(lsp, 1);
                return sts;
            }
            p += len;
-           if (p > pduend) {
-               if (pmDebugOptions.pmlc || pmDebugOptions.pdu) 
-                   fprintf(stderr, "__pmDecodeLogStatus: PM_ERR_IPC: 
pmlogger.zoneinfo data[%ld] > PDU len (%d)\n", 
-                       (long)(p - (char *)&pp->data[0]), pp->hdr.len);
-               __pmFreeLogStatus(lsp, 1);
-               return PM_ERR_IPC;
-           }
        }
     }
     else if (version == LOG_PDU_VERSION2) {

++++++ pcp-CVE-2026-16530-6.patch ++++++
References: CVE-2026-16530
Description: libpcp: fix OOB read in __pmDecodeInstance (CWE-125/195)
 The __pmDecodeInstance() loop advances ip by the PDU alignment-padded
 entry size after each instance.  When namelen % 4 != 0, the padding
 advance can push ip past pdu_end.  The existing bounds check casts the
 pointer difference to size_t: (size_t)(pdu_end - (char *)ip).  When ip
 is past pdu_end, this produces a negative ptrdiff_t that wraps to a
 very large size_t, causing both bounds checks to silently pass.
 Execution falls through to memcpy reading past the PDU buffer.
 .
 Fix: add an explicit signed pointer guard at the top of each loop
 iteration — if ((char *)ip >= pdu_end) — before the size_t cast.
 This ensures the subsequent unsigned comparison is always valid.
 .
 Reported-by: Francisco Alisson Bezerra, TIM Security Red Team
 Reported-by: Lucas Gabriel Alves, TIM Security Red Team
 Reported-by: Massimiliano Brolli, TIM Security Red Team
 .
 Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
 .
Author: Nathan Scott <[email protected]>
Origin: upstream, 
https://github.com/performancecopilot/pcp/commit/b743fc58795bd3667b78e3b0759251fef27a983b
Last-Update: 2026-07-25
 Backport-Note:
 Backported to PCP 6.3.8 (applies unchanged). No libpcp3 tree in 6.3.8, so that 
mirror hunk is dropped.


--- a/src/libpcp/src/p_instance.c
+++ b/src/libpcp/src/p_instance.c
@@ -290,6 +290,13 @@
     pdu_used = (char *)&pp->rest[0];
     for (i = j = 0; i < res->numinst; i++) {
        ip = (instlist_t *)&pp->rest[j/sizeof(__pmPDU)];
+       if ((char *)ip >= pdu_end) {
+           if (pmDebugOptions.pdu)
+               fprintf(stderr, "%s: PM_ERR_IPC: inst[%d] ip past pdu_end\n",
+                   __FUNCTION__, i);
+           sts = PM_ERR_IPC;
+           goto badsts;
+       }
        if (sizeof(instlist_t) - sizeof(ip->name) > (size_t)(pdu_end - (char 
*)ip)) {
            if (pmDebugOptions.pdu) {
                fprintf(stderr, "__pmDecodeInstance: PM_ERR_IPC: 
sizeof(instlist_t) %d - sizeof(name) %d > remainder %d\n",

++++++ pcp-CVE-2026-16531.patch ++++++
References: CVE-2026-16531
Description: libpcp_web: fix path traversal via hostname in logger servlet 
(CWE-22)
 The pmproxy logger servlet (POST /logger/label) accepts a binary
 __pmLogLabel PDU and uses the hostname field directly in path
 construction without sanitization.  An attacker can supply
 hostname='../../../../tmp/target' causing pmproxy to create .meta
 and .index files at arbitrary paths writable by the pcp user.
 .
 Fix: add check_hostname() allowlist check — only alphanumeric, hyphen,
 dot, and underscore characters are permitted (per RFC 952/1123 plus
 underscore for real-world compatibility).  Leading dots are rejected
 to prevent relative path components.  Invalid hostnames are rejected
 with -EINVAL before any path construction occurs.
 .
 Add qa/2106 verifying that a label with a path-traversal hostname
 is rejected and no files are created outside the log directory.
 .
 Reported-by: Francisco Alisson Bezerra, TIM Security Red Team
 Reported-by: Lucas Gabriel Alves, TIM Security Red Team
 Reported-by: Massimiliano Brolli, TIM Security Red Team
 .
 Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
 .
Author: Nathan Scott <[email protected]>
Origin: upstream, 
https://github.com/performancecopilot/pcp/commit/dd6ed05f143f97e00198cb4b0180c6375d758cbe
 
https://github.com/performancecopilot/pcp/commit/f86c0f4cdac8df0b6fb05f60872f6f29bbc96429
Last-Update: 2026-07-25
 Backport-Note:
 PARTIAL / hardening-only for PCP 6.3.8. The pmproxy logger servlet 
(loggroup.c) does
  not exist in 6.3.8 (logpush is a post-6.3.8 feature), so the reported 
path-traversal
  vector is not present. Only the timezone/zoneinfo validation in pmNewZone() 
(tz.c) is
  carried, as defence-in-depth.


--- a/src/libpcp/src/tz.c
+++ b/src/libpcp/src/tz.c
@@ -25,6 +25,7 @@
  * lock initialization in pmNewContext().
  */
 
+#include <ctype.h>
 #include "pmapi.h"
 #include "libpcp.h"
 #include "sha256.h"
@@ -573,6 +574,22 @@
     return 0;
 }
 
+static int
+valid_tz(const char *tz)
+{
+    const char *p;
+
+    if (tz == NULL || tz[0] == '\0' || tz[0] == '/')
+       return 0;
+    for (p = tz; *p; p++) {
+       if (!isalnum((unsigned char)*p) && strchr("/_+-.:,\"'", *p) == NULL)
+           return 0;
+    }
+    if (strstr(tz, "..") != NULL)
+       return 0;
+    return 1;
+}
+
 int
 pmNewZone(const char *tz)
 {
@@ -580,6 +597,13 @@
     int                hack = 0;
     int                sts;
 
+    if (!valid_tz(tz)) {
+       if (pmDebugOptions.context)
+           fprintf(stderr, "%s: rejecting unsafe timezone: %s\n",
+               __FUNCTION__, tz ? tz : "(null)");
+       return -EINVAL;
+    }
+
     PM_LOCK(__pmLock_extcall);
 
     len = (int)strlen(tz);

++++++ pcp-bsc-1272928.patch ++++++
References: no CVE assigned (runs as the invoking user; no privilege boundary 
crossed)
Description: pmieconf: fix command injection via $HOME and -f (CWE-78)
 The write_pmiefile() function constructed a shell command via
 pmsprintf("/bin/mkdir -p %s", fname) and passed it to system().
 The fname value derives from either $HOME or the -f command-line
 argument without sanitization, enabling command injection through
 shell metacharacters in the path.
 .
 Fix: replace system("/bin/mkdir -p ...") with __pmMakePath() which
 creates directories recursively using mkdir() syscalls directly,
 with no shell involvement.
 .
 Add qa/2103 verifying that legitimate directory creation works and
 that shell metacharacters in -f and $HOME paths do not result in
 command execution.
 .
 Reported-by: Francisco Alisson Bezerra, TIM Security Red Team
 Reported-by: Lucas Gabriel Alves, TIM Security Red Team
 Reported-by: Massimiliano Brolli, TIM Security Red Team
 .
 Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
 .
Author: Nathan Scott <[email protected]>
Origin: upstream, 
https://github.com/performancecopilot/pcp/commit/cdc9676ab60176476a23f323c145d8d0fc71e165
Last-Update: 2026-07-25
 Backport-Note:
 Backported to PCP 6.3.8 (applies unchanged).


--- a/src/pmieconf/rules.c
+++ b/src/pmieconf/rules.c
@@ -1805,7 +1805,6 @@
 {
     time_t     now = time(NULL);
     char       *p, *msg = NULL;
-    char       buf[MAXPATHLEN+10];
     char       *fname = get_pmiefile();
     FILE       *fp;
     int                i;
@@ -1816,9 +1815,8 @@
 
        *p = '\0';      /* p is the dirname of fname */
        if (stat(fname, &sbuf) < 0) {
-           pmsprintf(buf, sizeof(buf), "/bin/mkdir -p %s", fname);
-           if (system(buf) < 0) {
-               pmsprintf(errmsg, sizeof(errmsg), "failed to create directory 
\"%s\"", p);
+           if (__pmMakePath(fname, 0755) < 0) {
+               pmsprintf(errmsg, sizeof(errmsg), "failed to create directory 
\"%s\"", fname);
                return errmsg;
            }
        }

++++++ pcp-bsc-1272930.patch ++++++
References: no CVE assigned (runs as the invoking user; no privilege boundary 
crossed)
Description: pmlogmv: fix command injection in pmlogcp/pmlogmv (CWE-78)
 The do_link() function used system("cp src dst") to copy archive files
 when link() fails with EXDEV.  The source filename was not validated by
 check_name() and was embedded directly into the shell command, enabling
 command injection via crafted archive filenames.  The do_checksum()
 function similarly used system() for command detection and popen() for
 checksum execution.
 .
 Fix:
 - Replace system("cp ...") with copy_file() using open/read/write
   syscalls directly, eliminating shell involvement entirely
 - Replace system("if which ...") checksum detection with access() checks
 - Replace popen("md5sum <file") with __pmProcessPipe() which uses
   execvp() internally, passing filenames as argv not shell words
 - Expand check_name() blocklist to include backtick, braces, backslash,
   bang, newline and tab (defense-in-depth, no longer the security
   boundary)
 - Apply check_name() to source names as well as destination names
 - Add qa/2102 verifying metacharacter rejection and normal copy
 .
 Reported-by: Francisco Alisson Bezerra, TIM Security Red Team
 Reported-by: Lucas Gabriel Alves, TIM Security Red Team
 Reported-by: Massimiliano Brolli, TIM Security Red Team
 .
 Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
 .
Author: Nathan Scott <[email protected]>
Origin: upstream, 
https://github.com/performancecopilot/pcp/commit/dc73ec0f579028620e408114427d27ad0afd24a8
 
https://github.com/performancecopilot/pcp/commit/3ae202a08b680944add196a30fe5fdc6f247e711
Last-Update: 2026-07-25
 Backport-Note:
 Minimal backport for PCP 6.3.8. pmlogmv.c differs structurally from the 7.x 
tree;
  rather than the full open/read/write copy + __pmProcessPipe rewrite, this 
closes the
  injection by validating the source name (oldname) as well as the destination 
and by
  hardening the check_name() blocklist (adds backtick, braces, backslash). This 
report
  item carries no CVE - pmlogmv runs as the invoking user, crossing no 
privilege boundary.


--- a/src/pmlogmv/pmlogmv.c
+++ b/src/pmlogmv/pmlogmv.c
@@ -73,7 +73,7 @@
 static int
 check_name(char *name)
 {
-    char       *meta = " $?*[(|;&<>";
+    char       *meta = " $?*[(|;&<>`{}\\";
     char       *p;
 
     for (p = meta; *p; p++) {
@@ -481,6 +481,11 @@
        /* error reported in check_name() */
        exit(1);
     }
+
+    if (!force && check_name(oldname) < 0) {
+       /* error reported in check_name() */
+       exit(1);
+    }
 
     if (setup_sufftab() < 0) {
        /* error reported in setup_sufftab() */

Reply via email to