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>
114 lines
2.8 KiB
Diff
114 lines
2.8 KiB
Diff
From 2a4bd9f81a Mon Sep 17 00:00:00 2001
|
|
From: Nathan Scott <nathans@redhat.com>
|
|
Subject: [PATCH] pmdaroot: add peer credential verification on Unix socket (CWE-403)
|
|
|
|
Defense-in-depth for the FD_CLOEXEC fix: verify the UID of connecting
|
|
clients on the pmdaroot Unix socket using SO_PEERCRED (Linux) or
|
|
getpeereid (macOS/FreeBSD). Only root (UID 0) and the PCP service
|
|
user (typically 'pcp') are permitted to connect. Connections from
|
|
other UIDs are rejected with a log message.
|
|
|
|
This prevents exploitation even if the pmdaroot socket fd were to
|
|
leak to an unprivileged process through a path not covered by
|
|
FD_CLOEXEC (e.g., direct socket file access).
|
|
|
|
The PCP service UID is resolved once at startup via pmGetUsername()
|
|
and getpwnam(), cached in a static for use in the accept path.
|
|
|
|
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
|
|
|
---
|
|
diff --git a/src/pmdas/root/root.c b/src/pmdas/root/root.c
|
|
index 2e65a2ea6d..7ec2e5bf9c 100644
|
|
--- 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 char socket_path[MAXPATHLEN];
|
|
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 @@ root_accept_client(void)
|
|
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);
|
|
@@ -796,6 +836,19 @@ root_main(pmdaInterface *dp)
|
|
}
|
|
}
|
|
|
|
+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)
|
|
{
|
|
@@ -815,6 +868,7 @@ static void
|
|
root_prep(void)
|
|
{
|
|
root_check_user();
|
|
+ root_get_pcp_uid();
|
|
root_setup_socket();
|
|
atexit(root_close_socket);
|
|
}
|