QA 2101 referenced undefined $seq_full on the 6.3.7 testsuite, and QA 2105 shipped an empty pdu-getpdu-overflow file so the integer overflow case was never exercised. 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>
129 lines
3.8 KiB
Diff
129 lines
3.8 KiB
Diff
From ef848fb978 Mon Sep 17 00:00:00 2001
|
|
From: Nathan Scott <nathans@redhat.com>
|
|
Subject: [PATCH] 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) <noreply@anthropic.com>
|
|
|
|
Resolves: RHEL-213736 CVE-2026-16529
|
|
---
|
|
diff --git a/qa/2105 b/qa/2105
|
|
new file mode 100755
|
|
index 0000000000..44b849ad39
|
|
--- /dev/null
|
|
+++ b/qa/2105
|
|
@@ -0,0 +1,20 @@
|
|
+#!/bin/sh
|
|
+# PCP QA Test No. 2105
|
|
+# Verify __pmGetPDU rejects PDU with len near INT_MAX
|
|
+# (integer overflow in buffer size computation, CWE-190)
|
|
+#
|
|
+# Copyright (c) 2026 Red Hat. All Rights Reserved.
|
|
+#
|
|
+
|
|
+seq=`basename $0`
|
|
+echo "QA output created by $seq"
|
|
+
|
|
+mkdir -p pdudata
|
|
+printf '\177\377\377\377\000\000\200\000' >pdudata/pdu-getpdu-overflow
|
|
+
|
|
+pdu_data=pdudata/pdu-getpdu-overflow
|
|
+grep_pattern="bad PDU len=.*exceeds maximum|PDU len=.*too large"
|
|
+
|
|
+# this is one of the generic pmcd PDU exerciser tests ...
|
|
+#
|
|
+. ./common.pmcd.pdu
|
|
diff --git a/qa/2105.out b/qa/2105.out
|
|
new file mode 100644
|
|
index 0000000000..a304f9d913
|
|
--- /dev/null
|
|
+++ b/qa/2105.out
|
|
@@ -0,0 +1,10 @@
|
|
+QA output created by 2105
|
|
+expect error(s) to be logged ...
|
|
+__pmGetPDU: fd=N type=0x8000 bad PDU len=2147483647 in hdr exceeds maximum client PDU size (65536)
|
|
+
|
|
+and no valgrind badness ...
|
|
+Memcheck, a memory error detector
|
|
+LEAK SUMMARY:
|
|
+definitely lost: 0 bytes in 0 blocks
|
|
+indirectly lost: 0 bytes in 0 blocks
|
|
+ERROR SUMMARY: 0 errors from 0 contexts ...
|
|
diff --git a/qa/common.pmcd.pdu b/qa/common.pmcd.pdu
|
|
index d9e3c6c5c9..9882284b5c 100644
|
|
--- a/qa/common.pmcd.pdu
|
|
+++ b/qa/common.pmcd.pdu
|
|
@@ -55,6 +55,14 @@ _filter()
|
|
# end
|
|
}
|
|
|
|
+_filter_pmcd()
|
|
+{
|
|
+ sed \
|
|
+ -e 's/fd=[0-9][0-9]*/fd=N/g' \
|
|
+ -e 's/^\[.*\] pmcd([0-9]*) [A-Za-z]*: //' \
|
|
+ # end
|
|
+}
|
|
+
|
|
mkdir $tmp || exit 1
|
|
cd $tmp
|
|
grep sampledso $PCP_PMCDCONF_PATH >pmcd.conf
|
|
@@ -91,7 +99,7 @@ wait
|
|
[ -s $tmp.err ] && cat $tmp.err
|
|
|
|
echo "expect error(s) to be logged ..."
|
|
-grep -E "$grep_pattern" pmcd.log
|
|
+grep -E "$grep_pattern" pmcd.log | _filter_pmcd
|
|
|
|
echo
|
|
echo "and no valgrind badness ..."
|
|
diff --git a/qa/group b/qa/group
|
|
index d4da513ce2..80a861c5f6 100644
|
|
--- a/qa/group
|
|
+++ b/qa/group
|
|
@@ -2216,4 +2216,5 @@ pmcd.pdu
|
|
1990 pcp buddyinfo python local
|
|
1991 pcp netstat python local
|
|
1992 pmda.uwsgi local
|
|
+2105 libpcp local security
|
|
4751 libpcp threads valgrind local pcp helgrind
|
|
diff --git a/src/libpcp/src/pdu.c b/src/libpcp/src/pdu.c
|
|
index 5845932be1..0a4ae75b25 100644
|
|
--- a/src/libpcp/src/pdu.c
|
|
+++ b/src/libpcp/src/pdu.c
|
|
@@ -658,6 +658,14 @@ check_read_len:
|
|
|
|
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;
|
|
}
|