pcp/pcp-6.3.7-OOB-pmDecodeLogStatus.patch
Jan Kurik d6aade7578
Backport PCP security CVE fixes and hardening for 6.3.7-11
Backport applicable private-pcp security fixes to PCP 6.3.7 for RHEL 9.9.
CVE-2026-16531 is not applicable because the pmproxy logger servlet is
absent in this release.

Resolves: RHEL-213747 CVE-2026-16530
Resolves: RHEL-213736 CVE-2026-16529
Resolves: RHEL-213711 CVE-2026-16527
Resolves: RHEL-213687 CVE-2026-16526
Resolves: RHEL-213658 CVE-2026-16524
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-13 08:10:41 +02:00

248 lines
9.7 KiB
Diff

From 5366a546d6 Mon Sep 17 00:00:00 2001
From: Nathan Scott <nathans@redhat.com>
Subject: [PATCH] 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) <noreply@anthropic.com>
---
diff --git a/src/libpcp/src/p_lstatus.c b/src/libpcp/src/p_lstatus.c
index d9053b5d1a..099ef7b5ff 100644
--- a/src/libpcp/src/p_lstatus.c
+++ b/src/libpcp/src/p_lstatus.c
@@ -265,157 +265,157 @@ __pmDecodeLogStatus(__pmPDU *pdubuf, __pmLoggerStatus **result)
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) {