Blame SOURCES/01-CVE-2020-25654.patch

535fd1
From 975724044df52f558119008352a19b790ce874cd Mon Sep 17 00:00:00 2001
535fd1
From: Ken Gaillot <kgaillot@redhat.com>
535fd1
Date: Tue, 27 Mar 2018 15:05:47 -0500
535fd1
Subject: [PATCH 01/10] Refactor: lrmd: functionize creating reply
535fd1
535fd1
reduces duplication, and enforces consistency in reply XML and logging
535fd1
---
535fd1
 lrmd/lrmd.c | 94 ++++++++++++++++++++++++++-----------------------------------
535fd1
 1 file changed, 40 insertions(+), 54 deletions(-)
535fd1
535fd1
diff --git a/lrmd/lrmd.c b/lrmd/lrmd.c
535fd1
index 2e8ea41..ceeb10b 100644
535fd1
--- a/lrmd/lrmd.c
535fd1
+++ b/lrmd/lrmd.c
535fd1
@@ -373,23 +373,15 @@ schedule_lrmd_cmd(lrmd_rsc_t * rsc, lrmd_cmd_t * cmd)
535fd1
     }
535fd1
 }
535fd1
 
535fd1
-static void
535fd1
-send_reply(crm_client_t * client, int rc, uint32_t id, int call_id)
535fd1
+static xmlNode *
535fd1
+create_lrmd_reply(const char *origin, int rc, int call_id)
535fd1
 {
535fd1
-    int send_rc = 0;
535fd1
-    xmlNode *reply = NULL;
535fd1
+    xmlNode *reply = create_xml_node(NULL, T_LRMD_REPLY);
535fd1
 
535fd1
-    reply = create_xml_node(NULL, T_LRMD_REPLY);
535fd1
-    crm_xml_add(reply, F_LRMD_ORIGIN, __FUNCTION__);
535fd1
+    crm_xml_add(reply, F_LRMD_ORIGIN, origin);
535fd1
     crm_xml_add_int(reply, F_LRMD_RC, rc);
535fd1
     crm_xml_add_int(reply, F_LRMD_CALLID, call_id);
535fd1
-
535fd1
-    send_rc = lrmd_server_send_reply(client, id, reply);
535fd1
-
535fd1
-    free_xml(reply);
535fd1
-    if (send_rc < 0) {
535fd1
-        crm_warn("LRMD reply to %s failed: %d", client->name, send_rc);
535fd1
-    }
535fd1
+    return reply;
535fd1
 }
535fd1
 
535fd1
 static void
535fd1
@@ -1396,23 +1388,24 @@ free_rsc(gpointer data)
535fd1
     free(rsc);
535fd1
 }
535fd1
 
535fd1
-static int
535fd1
-process_lrmd_signon(crm_client_t * client, uint32_t id, xmlNode * request)
535fd1
+static xmlNode *
535fd1
+process_lrmd_signon(crm_client_t *client, xmlNode *request, int call_id)
535fd1
 {
535fd1
-    xmlNode *reply = create_xml_node(NULL, "reply");
535fd1
+    xmlNode *reply = NULL;
535fd1
+    int rc = pcmk_ok;
535fd1
     const char *is_ipc_provider = crm_element_value(request, F_LRMD_IS_IPC_PROVIDER);
535fd1
     const char *protocol_version = crm_element_value(request, F_LRMD_PROTOCOL_VERSION);
535fd1
 
535fd1
     if (compare_version(protocol_version, LRMD_MIN_PROTOCOL_VERSION) < 0) {
535fd1
         crm_err("Cluster API version must be greater than or equal to %s, not %s",
535fd1
                 LRMD_MIN_PROTOCOL_VERSION, protocol_version);
535fd1
-        crm_xml_add_int(reply, F_LRMD_RC, -EPROTO);
535fd1
+        rc = -EPROTO;
535fd1
     }
535fd1
 
535fd1
+    reply = create_lrmd_reply(__FUNCTION__, rc, call_id);
535fd1
     crm_xml_add(reply, F_LRMD_OPERATION, CRM_OP_REGISTER);
535fd1
     crm_xml_add(reply, F_LRMD_CLIENTID, client->id);
535fd1
     crm_xml_add(reply, F_LRMD_PROTOCOL_VERSION, LRMD_PROTOCOL_VERSION);
535fd1
-    lrmd_server_send_reply(client, id, reply);
535fd1
 
535fd1
     if (crm_is_true(is_ipc_provider)) {
535fd1
         /* this is a remote connection from a cluster nodes crmd */
535fd1
@@ -1420,9 +1413,7 @@ process_lrmd_signon(crm_client_t * client, uint32_t id, xmlNode * request)
535fd1
         ipc_proxy_add_provider(client);
535fd1
 #endif
535fd1
     }
535fd1
-
535fd1
-    free_xml(reply);
535fd1
-    return pcmk_ok;
535fd1
+    return reply;
535fd1
 }
535fd1
 
535fd1
 static int
535fd1
@@ -1450,52 +1441,34 @@ process_lrmd_rsc_register(crm_client_t * client, uint32_t id, xmlNode * request)
535fd1
     return rc;
535fd1
 }
535fd1
 
535fd1
-static void
535fd1
-process_lrmd_get_rsc_info(crm_client_t * client, uint32_t id, xmlNode * request)
535fd1
+static xmlNode *
535fd1
+process_lrmd_get_rsc_info(xmlNode *request, int call_id)
535fd1
 {
535fd1
     int rc = pcmk_ok;
535fd1
-    int send_rc = 0;
535fd1
-    int call_id = 0;
535fd1
     xmlNode *rsc_xml = get_xpath_object("//" F_LRMD_RSC, request, LOG_ERR);
535fd1
     const char *rsc_id = crm_element_value(rsc_xml, F_LRMD_RSC_ID);
535fd1
     xmlNode *reply = NULL;
535fd1
     lrmd_rsc_t *rsc = NULL;
535fd1
 
535fd1
-    crm_element_value_int(request, F_LRMD_CALLID, &call_id);
535fd1
-
535fd1
-    if (!rsc_id) {
535fd1
-        rc = -ENODEV;
535fd1
-        goto get_rsc_done;
535fd1
-    }
535fd1
-
535fd1
-    if (!(rsc = g_hash_table_lookup(rsc_list, rsc_id))) {
535fd1
-        crm_info("Resource '%s' not found (%d active resources)",
535fd1
-                 rsc_id, g_hash_table_size(rsc_list));
535fd1
+    if (rsc_id == NULL) {
535fd1
         rc = -ENODEV;
535fd1
-        goto get_rsc_done;
535fd1
+    } else {
535fd1
+        rsc = g_hash_table_lookup(rsc_list, rsc_id);
535fd1
+        if (rsc == NULL) {
535fd1
+            crm_info("Resource '%s' not found (%d active resources)",
535fd1
+                     rsc_id, g_hash_table_size(rsc_list));
535fd1
+            rc = -ENODEV;
535fd1
+        }
535fd1
     }
535fd1
 
535fd1
-  get_rsc_done:
535fd1
-
535fd1
-    reply = create_xml_node(NULL, T_LRMD_REPLY);
535fd1
-    crm_xml_add(reply, F_LRMD_ORIGIN, __FUNCTION__);
535fd1
-    crm_xml_add_int(reply, F_LRMD_RC, rc);
535fd1
-    crm_xml_add_int(reply, F_LRMD_CALLID, call_id);
535fd1
-
535fd1
+    reply = create_lrmd_reply(__FUNCTION__, rc, call_id);
535fd1
     if (rsc) {
535fd1
         crm_xml_add(reply, F_LRMD_RSC_ID, rsc->rsc_id);
535fd1
         crm_xml_add(reply, F_LRMD_CLASS, rsc->class);
535fd1
         crm_xml_add(reply, F_LRMD_PROVIDER, rsc->provider);
535fd1
         crm_xml_add(reply, F_LRMD_TYPE, rsc->type);
535fd1
     }
535fd1
-
535fd1
-    send_rc = lrmd_server_send_reply(client, id, reply);
535fd1
-
535fd1
-    if (send_rc < 0) {
535fd1
-        crm_warn("LRMD reply to %s failed: %d", client->name, send_rc);
535fd1
-    }
535fd1
-
535fd1
-    free_xml(reply);
535fd1
+    return reply;
535fd1
 }
535fd1
 
535fd1
 static int
535fd1
@@ -1675,6 +1648,7 @@ process_lrmd_message(crm_client_t * client, uint32_t id, xmlNode * request)
535fd1
     const char *op = crm_element_value(request, F_LRMD_OPERATION);
535fd1
     int do_reply = 0;
535fd1
     int do_notify = 0;
535fd1
+    xmlNode *reply = NULL;
535fd1
 
535fd1
     crm_trace("Processing %s operation from %s", op, client->id);
535fd1
     crm_element_value_int(request, F_LRMD_CALLID, &call_id);
535fd1
@@ -1685,13 +1659,15 @@ process_lrmd_message(crm_client_t * client, uint32_t id, xmlNode * request)
535fd1
 #endif
535fd1
         do_reply = 1;
535fd1
     } else if (crm_str_eq(op, CRM_OP_REGISTER, TRUE)) {
535fd1
-        rc = process_lrmd_signon(client, id, request);
535fd1
+        reply = process_lrmd_signon(client, request, call_id);
535fd1
+        do_reply = 1;
535fd1
     } else if (crm_str_eq(op, LRMD_OP_RSC_REG, TRUE)) {
535fd1
         rc = process_lrmd_rsc_register(client, id, request);
535fd1
         do_notify = 1;
535fd1
         do_reply = 1;
535fd1
     } else if (crm_str_eq(op, LRMD_OP_RSC_INFO, TRUE)) {
535fd1
-        process_lrmd_get_rsc_info(client, id, request);
535fd1
+        reply = process_lrmd_get_rsc_info(request, call_id);
535fd1
+        do_reply = 1;
535fd1
     } else if (crm_str_eq(op, LRMD_OP_RSC_UNREG, TRUE)) {
535fd1
         rc = process_lrmd_rsc_unregister(client, id, request);
535fd1
         /* don't notify anyone about failed un-registers */
535fd1
@@ -1727,7 +1703,17 @@ process_lrmd_message(crm_client_t * client, uint32_t id, xmlNode * request)
535fd1
               op, client->id, rc, do_reply, do_notify);
535fd1
 
535fd1
     if (do_reply) {
535fd1
-        send_reply(client, rc, id, call_id);
535fd1
+        int send_rc = pcmk_ok;
535fd1
+
535fd1
+        if (reply == NULL) {
535fd1
+            reply = create_lrmd_reply(__FUNCTION__, rc, call_id);
535fd1
+        }
535fd1
+        send_rc = lrmd_server_send_reply(client, id, reply);
535fd1
+        free_xml(reply);
535fd1
+        if (send_rc < 0) {
535fd1
+            crm_warn("Reply to client %s failed: %s " CRM_XS " %d",
535fd1
+                     client->name, pcmk_strerror(send_rc), send_rc);
535fd1
+        }
535fd1
     }
535fd1
 
535fd1
     if (do_notify) {
535fd1
-- 
535fd1
1.8.3.1
535fd1
535fd1
535fd1
From 6ed12ce8ace8e0a1cc5b8ca233684ba4e70a021c Mon Sep 17 00:00:00 2001
535fd1
From: Ken Gaillot <kgaillot@redhat.com>
535fd1
Date: Fri, 9 Oct 2020 09:56:03 -0500
535fd1
Subject: [PATCH 02/10] Log: executor: show CRM_OP_REGISTER rc in debug message
535fd1
535fd1
Previously, process_lrmd_signon() would add the rc to the client reply
535fd1
but not pass it back to process_lrmd_message(), which would always log "OK" in
535fd1
its debug message, even if the sign-on was rejected.
535fd1
---
535fd1
 lrmd/lrmd.c | 21 +++++++++++----------
535fd1
 1 file changed, 11 insertions(+), 10 deletions(-)
535fd1
535fd1
diff --git a/lrmd/lrmd.c b/lrmd/lrmd.c
535fd1
index ceeb10b..a20f165 100644
535fd1
--- a/lrmd/lrmd.c
535fd1
+++ b/lrmd/lrmd.c
535fd1
@@ -1388,10 +1388,10 @@ free_rsc(gpointer data)
535fd1
     free(rsc);
535fd1
 }
535fd1
 
535fd1
-static xmlNode *
535fd1
-process_lrmd_signon(crm_client_t *client, xmlNode *request, int call_id)
535fd1
+static int
535fd1
+process_lrmd_signon(crm_client_t *client, xmlNode *request, int call_id,
535fd1
+                    xmlNode **reply)
535fd1
 {
535fd1
-    xmlNode *reply = NULL;
535fd1
     int rc = pcmk_ok;
535fd1
     const char *is_ipc_provider = crm_element_value(request, F_LRMD_IS_IPC_PROVIDER);
535fd1
     const char *protocol_version = crm_element_value(request, F_LRMD_PROTOCOL_VERSION);
535fd1
@@ -1402,18 +1402,19 @@ process_lrmd_signon(crm_client_t *client, xmlNode *request, int call_id)
535fd1
         rc = -EPROTO;
535fd1
     }
535fd1
 
535fd1
-    reply = create_lrmd_reply(__FUNCTION__, rc, call_id);
535fd1
-    crm_xml_add(reply, F_LRMD_OPERATION, CRM_OP_REGISTER);
535fd1
-    crm_xml_add(reply, F_LRMD_CLIENTID, client->id);
535fd1
-    crm_xml_add(reply, F_LRMD_PROTOCOL_VERSION, LRMD_PROTOCOL_VERSION);
535fd1
-
535fd1
     if (crm_is_true(is_ipc_provider)) {
535fd1
         /* this is a remote connection from a cluster nodes crmd */
535fd1
 #ifdef SUPPORT_REMOTE
535fd1
         ipc_proxy_add_provider(client);
535fd1
 #endif
535fd1
     }
535fd1
-    return reply;
535fd1
+
535fd1
+    *reply = create_lrmd_reply(__func__, rc, call_id);
535fd1
+    crm_xml_add(*reply, F_LRMD_OPERATION, CRM_OP_REGISTER);
535fd1
+    crm_xml_add(*reply, F_LRMD_CLIENTID, client->id);
535fd1
+    crm_xml_add(*reply, F_LRMD_PROTOCOL_VERSION, LRMD_PROTOCOL_VERSION);
535fd1
+
535fd1
+    return rc;
535fd1
 }
535fd1
 
535fd1
 static int
535fd1
@@ -1659,7 +1660,7 @@ process_lrmd_message(crm_client_t * client, uint32_t id, xmlNode * request)
535fd1
 #endif
535fd1
         do_reply = 1;
535fd1
     } else if (crm_str_eq(op, CRM_OP_REGISTER, TRUE)) {
535fd1
-        reply = process_lrmd_signon(client, request, call_id);
535fd1
+        rc = process_lrmd_signon(client, request, call_id, &reply);
535fd1
         do_reply = 1;
535fd1
     } else if (crm_str_eq(op, LRMD_OP_RSC_REG, TRUE)) {
535fd1
         rc = process_lrmd_rsc_register(client, id, request);
535fd1
-- 
535fd1
1.8.3.1
535fd1
535fd1
535fd1
From fd9ee715ce26a2bc2f7546afe8e7fbfb778cb861 Mon Sep 17 00:00:00 2001
535fd1
From: Ken Gaillot <kgaillot@redhat.com>
535fd1
Date: Fri, 9 Oct 2020 15:16:39 -0500
535fd1
Subject: [PATCH 03/10] Low: executor: mark controller connections to
535fd1
 pacemaker-remoted as privileged
535fd1
535fd1
Previously, crm_client_flag_ipc_privileged was only set when local clients connected
535fd1
(as root or hacluster). Now, set it when pacemaker-remoted successfully
535fd1
completes the TLS handshake with a remote client (i.e., the controller on a
535fd1
cluster node).
535fd1
535fd1
This has no effect as of this commit but will with later commits.
535fd1
---
535fd1
 lrmd/tls_backend.c | 5 +++++
535fd1
 1 file changed, 5 insertions(+)
535fd1
535fd1
diff --git a/lrmd/tls_backend.c b/lrmd/tls_backend.c
535fd1
index 8934ae3..509f4fa 100644
535fd1
--- a/lrmd/tls_backend.c
535fd1
+++ b/lrmd/tls_backend.c
535fd1
@@ -84,6 +84,11 @@ remoted__read_handshake_data(crm_client_t *client)
535fd1
     client->remote->tls_handshake_complete = TRUE;
535fd1
     crm_notice("Remote client connection accepted");
535fd1
 
535fd1
+    /* Only a client with access to the TLS key can connect, so we can treat
535fd1
+     * it as privileged.
535fd1
+     */
535fd1
+    set_bit(client->flags, crm_client_flag_ipc_privileged);
535fd1
+
535fd1
     // Alert other clients of the new connection
535fd1
     notify_of_new_client(client);
535fd1
     return 0;
535fd1
-- 
535fd1
1.8.3.1
535fd1
535fd1
535fd1
From 755290ec01e0f955700e6e726461eca9cc27edab Mon Sep 17 00:00:00 2001
535fd1
From: Ken Gaillot <kgaillot@redhat.com>
535fd1
Date: Thu, 15 Oct 2020 15:33:13 -0500
535fd1
Subject: [PATCH 04/10] Low: executor: return appropriate error code when no
535fd1
 remote support
535fd1
535fd1
---
535fd1
 lrmd/lrmd.c | 6 +++++-
535fd1
 1 file changed, 5 insertions(+), 1 deletion(-)
535fd1
535fd1
diff --git a/lrmd/lrmd.c b/lrmd/lrmd.c
535fd1
index a20f165..07f68ed 100644
535fd1
--- a/lrmd/lrmd.c
535fd1
+++ b/lrmd/lrmd.c
535fd1
@@ -1403,9 +1403,11 @@ process_lrmd_signon(crm_client_t *client, xmlNode *request, int call_id,
535fd1
     }
535fd1
 
535fd1
     if (crm_is_true(is_ipc_provider)) {
535fd1
-        /* this is a remote connection from a cluster nodes crmd */
535fd1
 #ifdef SUPPORT_REMOTE
535fd1
+        // This is a remote connection from a cluster node's controller
535fd1
         ipc_proxy_add_provider(client);
535fd1
+#else
535fd1
+        rc = -EPROTONOSUPPORT;
535fd1
 #endif
535fd1
     }
535fd1
 
535fd1
@@ -1657,6 +1659,8 @@ process_lrmd_message(crm_client_t * client, uint32_t id, xmlNode * request)
535fd1
     if (crm_str_eq(op, CRM_OP_IPC_FWD, TRUE)) {
535fd1
 #ifdef SUPPORT_REMOTE
535fd1
         ipc_proxy_forward_client(client, request);
535fd1
+#else
535fd1
+        rc = -EPROTONOSUPPORT;
535fd1
 #endif
535fd1
         do_reply = 1;
535fd1
     } else if (crm_str_eq(op, CRM_OP_REGISTER, TRUE)) {
535fd1
-- 
535fd1
1.8.3.1
535fd1
535fd1
535fd1
From 540b7d4f5689b90ac466844f31fd161bdf446bed Mon Sep 17 00:00:00 2001
535fd1
From: Ken Gaillot <kgaillot@redhat.com>
535fd1
Date: Thu, 15 Oct 2020 15:33:57 -0500
535fd1
Subject: [PATCH 05/10] High: executor: restrict certain IPC requests to
535fd1
 Pacemaker daemons
535fd1
535fd1
(partial fix for CVE-2020-25654 with two later commits)
535fd1
535fd1
The executor IPC API allows clients to register resources, request agent
535fd1
execution, and so forth.
535fd1
535fd1
If ACLs are enabled, this could allow an ACL-restricted user to bypass ACLs and
535fd1
execute any code as root. (If ACLs are not enabled, users in the haclient group
535fd1
have full access to the CIB, which already gives them that ability, so there is
535fd1
no additional exposure in that case.)
535fd1
535fd1
When ACLs are supported, this commit effectively disables the executor IPC API
535fd1
for clients that aren't connecting as root or hacluster. Such clients can only
535fd1
register and poke now.
535fd1
---
535fd1
 lrmd/lrmd.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++-------------
535fd1
 1 file changed, 69 insertions(+), 18 deletions(-)
535fd1
535fd1
diff --git a/lrmd/lrmd.c b/lrmd/lrmd.c
535fd1
index 07f68ed..774b45b 100644
535fd1
--- a/lrmd/lrmd.c
535fd1
+++ b/lrmd/lrmd.c
535fd1
@@ -1,5 +1,5 @@
535fd1
 /*
535fd1
- * Copyright 2012-2019 the Pacemaker project contributors
535fd1
+ * Copyright 2012-2020 the Pacemaker project contributors
535fd1
  *
535fd1
  * The version control history for this file may have further details.
535fd1
  *
535fd1
@@ -1404,8 +1404,12 @@ process_lrmd_signon(crm_client_t *client, xmlNode *request, int call_id,
535fd1
 
535fd1
     if (crm_is_true(is_ipc_provider)) {
535fd1
 #ifdef SUPPORT_REMOTE
535fd1
-        // This is a remote connection from a cluster node's controller
535fd1
-        ipc_proxy_add_provider(client);
535fd1
+        if ((client->remote != NULL) && client->remote->tls_handshake_complete) {
535fd1
+            // This is a remote connection from a cluster node's controller
535fd1
+            ipc_proxy_add_provider(client);
535fd1
+        } else {
535fd1
+            rc = -EACCES;
535fd1
+        }
535fd1
 #else
535fd1
         rc = -EPROTONOSUPPORT;
535fd1
 #endif
535fd1
@@ -1653,12 +1657,26 @@ process_lrmd_message(crm_client_t * client, uint32_t id, xmlNode * request)
535fd1
     int do_notify = 0;
535fd1
     xmlNode *reply = NULL;
535fd1
 
535fd1
+#if ENABLE_ACL
535fd1
+    /* Certain IPC commands may be done only by privileged users (i.e. root or
535fd1
+     * hacluster) when ACLs are enabled, because they would otherwise provide a
535fd1
+     * means of bypassing ACLs.
535fd1
+     */
535fd1
+    bool allowed = is_set(client->flags, crm_client_flag_ipc_privileged);
535fd1
+#else
535fd1
+    bool allowed = true;
535fd1
+#endif
535fd1
+
535fd1
     crm_trace("Processing %s operation from %s", op, client->id);
535fd1
     crm_element_value_int(request, F_LRMD_CALLID, &call_id);
535fd1
 
535fd1
     if (crm_str_eq(op, CRM_OP_IPC_FWD, TRUE)) {
535fd1
 #ifdef SUPPORT_REMOTE
535fd1
-        ipc_proxy_forward_client(client, request);
535fd1
+        if (allowed) {
535fd1
+            ipc_proxy_forward_client(client, request);
535fd1
+        } else {
535fd1
+            rc = -EACCES;
535fd1
+        }
535fd1
 #else
535fd1
         rc = -EPROTONOSUPPORT;
535fd1
 #endif
535fd1
@@ -1667,35 +1685,63 @@ process_lrmd_message(crm_client_t * client, uint32_t id, xmlNode * request)
535fd1
         rc = process_lrmd_signon(client, request, call_id, &reply);
535fd1
         do_reply = 1;
535fd1
     } else if (crm_str_eq(op, LRMD_OP_RSC_REG, TRUE)) {
535fd1
-        rc = process_lrmd_rsc_register(client, id, request);
535fd1
-        do_notify = 1;
535fd1
+        if (allowed) {
535fd1
+            rc = process_lrmd_rsc_register(client, id, request);
535fd1
+            do_notify = 1;
535fd1
+        } else {
535fd1
+            rc = -EACCES;
535fd1
+        }
535fd1
         do_reply = 1;
535fd1
     } else if (crm_str_eq(op, LRMD_OP_RSC_INFO, TRUE)) {
535fd1
-        reply = process_lrmd_get_rsc_info(request, call_id);
535fd1
+        if (allowed) {
535fd1
+            reply = process_lrmd_get_rsc_info(request, call_id);
535fd1
+        } else {
535fd1
+            rc = -EACCES;
535fd1
+        }
535fd1
         do_reply = 1;
535fd1
     } else if (crm_str_eq(op, LRMD_OP_RSC_UNREG, TRUE)) {
535fd1
-        rc = process_lrmd_rsc_unregister(client, id, request);
535fd1
-        /* don't notify anyone about failed un-registers */
535fd1
-        if (rc == pcmk_ok || rc == -EINPROGRESS) {
535fd1
-            do_notify = 1;
535fd1
+        if (allowed) {
535fd1
+            rc = process_lrmd_rsc_unregister(client, id, request);
535fd1
+            /* don't notify anyone about failed un-registers */
535fd1
+            if (rc == pcmk_ok || rc == -EINPROGRESS) {
535fd1
+                do_notify = 1;
535fd1
+            }
535fd1
+        } else {
535fd1
+            rc = -EACCES;
535fd1
         }
535fd1
         do_reply = 1;
535fd1
     } else if (crm_str_eq(op, LRMD_OP_RSC_EXEC, TRUE)) {
535fd1
-        rc = process_lrmd_rsc_exec(client, id, request);
535fd1
+        if (allowed) {
535fd1
+            rc = process_lrmd_rsc_exec(client, id, request);
535fd1
+        } else {
535fd1
+            rc = -EACCES;
535fd1
+        }
535fd1
         do_reply = 1;
535fd1
     } else if (crm_str_eq(op, LRMD_OP_RSC_CANCEL, TRUE)) {
535fd1
-        rc = process_lrmd_rsc_cancel(client, id, request);
535fd1
+        if (allowed) {
535fd1
+            rc = process_lrmd_rsc_cancel(client, id, request);
535fd1
+        } else {
535fd1
+            rc = -EACCES;
535fd1
+        }
535fd1
         do_reply = 1;
535fd1
     } else if (crm_str_eq(op, LRMD_OP_POKE, TRUE)) {
535fd1
         do_notify = 1;
535fd1
         do_reply = 1;
535fd1
     } else if (crm_str_eq(op, LRMD_OP_CHECK, TRUE)) {
535fd1
-        xmlNode *data = get_message_xml(request, F_LRMD_CALLDATA); 
535fd1
-        const char *timeout = crm_element_value(data, F_LRMD_WATCHDOG);
535fd1
-        CRM_LOG_ASSERT(data != NULL);
535fd1
-        check_sbd_timeout(timeout);
535fd1
+        if (allowed) {
535fd1
+            xmlNode *data = get_message_xml(request, F_LRMD_CALLDATA);
535fd1
+
535fd1
+            CRM_LOG_ASSERT(data != NULL);
535fd1
+            check_sbd_timeout(crm_element_value(data, F_LRMD_WATCHDOG));
535fd1
+        } else {
535fd1
+            rc = -EACCES;
535fd1
+        }
535fd1
     } else if (crm_str_eq(op, LRMD_OP_ALERT_EXEC, TRUE)) {
535fd1
-        rc = process_lrmd_alert_exec(client, id, request);
535fd1
+        if (allowed) {
535fd1
+            rc = process_lrmd_alert_exec(client, id, request);
535fd1
+        } else {
535fd1
+            rc = -EACCES;
535fd1
+        }
535fd1
         do_reply = 1;
535fd1
     } else {
535fd1
         rc = -EOPNOTSUPP;
535fd1
@@ -1704,6 +1750,11 @@ process_lrmd_message(crm_client_t * client, uint32_t id, xmlNode * request)
535fd1
         crm_log_xml_warn(request, "UnknownOp");
535fd1
     }
535fd1
 
535fd1
+    if (rc == -EACCES) {
535fd1
+        crm_warn("Rejecting IPC request '%s' from unprivileged client %s",
535fd1
+                 op, crm_client_name(client));
535fd1
+    }
535fd1
+
535fd1
     crm_debug("Processed %s operation from %s: rc=%d, reply=%d, notify=%d",
535fd1
               op, client->id, rc, do_reply, do_notify);
535fd1
 
535fd1
-- 
535fd1
1.8.3.1
535fd1
535fd1
535fd1
From 34605b42d32e6f63eacd72e0ed971e8286102a98 Mon Sep 17 00:00:00 2001
535fd1
From: Ken Gaillot <kgaillot@redhat.com>
535fd1
Date: Fri, 9 Oct 2020 11:16:43 -0500
535fd1
Subject: [PATCH 06/10] Low: pacemakerd: check client for NULL before using it
535fd1
535fd1
... to guard against bugs in client tracking
535fd1
---
535fd1
 mcp/pacemaker.c | 5 ++++-
535fd1
 1 file changed, 4 insertions(+), 1 deletion(-)
535fd1
535fd1
diff --git a/mcp/pacemaker.c b/mcp/pacemaker.c
535fd1
index 05515c8..736c25c 100644
535fd1
--- a/mcp/pacemaker.c
535fd1
+++ b/mcp/pacemaker.c
535fd1
@@ -567,9 +567,12 @@ pcmk_ipc_dispatch(qb_ipcs_connection_t * qbc, void *data, size_t size)
535fd1
     uint32_t id = 0;
535fd1
     uint32_t flags = 0;
535fd1
     const char *task = NULL;
535fd1
+    xmlNode *msg = NULL;
535fd1
     crm_client_t *c = crm_client_get(qbc);
535fd1
-    xmlNode *msg = crm_ipcs_recv(c, data, size, &id, &flags);
535fd1
 
535fd1
+    CRM_CHECK(c != NULL, return 0);
535fd1
+
535fd1
+    msg = crm_ipcs_recv(c, data, size, &id, &flags);
535fd1
     crm_ipcs_send_ack(c, id, flags, "ack", __FUNCTION__, __LINE__);
535fd1
     if (msg == NULL) {
535fd1
         return 0;
535fd1
-- 
535fd1
1.8.3.1
535fd1
535fd1
535fd1
From 3388b4f76dfb951f9d7e27e39f7cea6be63c3f5c Mon Sep 17 00:00:00 2001
535fd1
From: Ken Gaillot <kgaillot@redhat.com>
535fd1
Date: Fri, 9 Oct 2020 11:17:18 -0500
535fd1
Subject: [PATCH 07/10] High: pacemakerd: ignore shutdown requests from
535fd1
 unprivileged users
535fd1
535fd1
(partial fix for CVE-2020-25654 with one previous commit and one later commit)
535fd1
535fd1
The pacemakerd IPC API supports a shutdown request, along with a
535fd1
command-line interface for using it (pacemakerd --shutdown).
535fd1
535fd1
Only the haclient group has access to the IPC. Without ACLs, that group can
535fd1
already shut down Pacemaker via the CIB, so there's no security implication.
535fd1
535fd1
However, it might not be desired to allow ACL-restricted users to shut down
535fd1
Pacemaker, so block users other than root or hacluster if ACLs are supported.
535fd1
---
535fd1
 mcp/pacemaker.c | 26 +++++++++++++++++++++-----
535fd1
 1 file changed, 21 insertions(+), 5 deletions(-)
535fd1
535fd1
diff --git a/mcp/pacemaker.c b/mcp/pacemaker.c
535fd1
index 736c25c..94ef949 100644
535fd1
--- a/mcp/pacemaker.c
535fd1
+++ b/mcp/pacemaker.c
535fd1
@@ -1,5 +1,5 @@
535fd1
 /*
535fd1
- * Copyright 2010-2019 the Pacemaker project contributors
535fd1
+ * Copyright 2010-2020 the Pacemaker project contributors
535fd1
  *
535fd1
  * The version control history for this file may have further details.
535fd1
  *
535fd1
@@ -580,10 +580,26 @@ pcmk_ipc_dispatch(qb_ipcs_connection_t * qbc, void *data, size_t size)
535fd1
 
535fd1
     task = crm_element_value(msg, F_CRM_TASK);
535fd1
     if (crm_str_eq(task, CRM_OP_QUIT, TRUE)) {
535fd1
-        /* Time to quit */
535fd1
-        crm_notice("Shutting down in response to ticket %s (%s)",
535fd1
-                   crm_element_value(msg, F_CRM_REFERENCE), crm_element_value(msg, F_CRM_ORIGIN));
535fd1
-        pcmk_shutdown(15);
535fd1
+#if ENABLE_ACL
535fd1
+        /* Only allow privileged users (i.e. root or hacluster)
535fd1
+         * to shut down Pacemaker from the command line (or direct IPC).
535fd1
+         *
535fd1
+         * We only check when ACLs are enabled, because without them, any client
535fd1
+         * with IPC access could shut down Pacemaker via the CIB anyway.
535fd1
+         */
535fd1
+        bool allowed = is_set(c->flags, crm_client_flag_ipc_privileged);
535fd1
+#else
535fd1
+        bool allowed = true;
535fd1
+#endif
535fd1
+        if (allowed) {
535fd1
+            crm_notice("Shutting down in response to IPC request %s from %s",
535fd1
+                       crm_element_value(msg, F_CRM_REFERENCE),
535fd1
+                       crm_element_value(msg, F_CRM_ORIGIN));
535fd1
+            pcmk_shutdown(15);
535fd1
+        } else {
535fd1
+            crm_warn("Ignoring shutdown request from unprivileged client %s",
535fd1
+                     crm_client_name(c));
535fd1
+        }
535fd1
 
535fd1
     } else if (crm_str_eq(task, CRM_OP_RM_NODE_CACHE, TRUE)) {
535fd1
         /* Send to everyone */
535fd1
-- 
535fd1
1.8.3.1
535fd1
535fd1
535fd1
From 7babd406e7195fcce57850a8589b06e095642c33 Mon Sep 17 00:00:00 2001
535fd1
From: Ken Gaillot <kgaillot@redhat.com>
535fd1
Date: Fri, 9 Oct 2020 11:55:26 -0500
535fd1
Subject: [PATCH 08/10] Fix: fencer: restrict certain IPC requests to
535fd1
 privileged users
535fd1
535fd1
(partial fix for CVE-2020-25654 along with 2 previous commits)
535fd1
535fd1
The fencer IPC API allows clients to register fence devices.
535fd1
535fd1
If ACLs are enabled, this could allow an ACL-restricted user to bypass ACLs to
535fd1
configure fencing. If the user is able to install executables to the standard
535fd1
fencing agent locations, have arbitrary code executed as root (the standard
535fd1
locations generally require root for write access, so that is unlikely to be an
535fd1
issue).
535fd1
535fd1
If ACLs are not enabled, users in the haclient group have full access to the
535fd1
CIB, which already gives them these capabilities, so there is no additional
535fd1
exposure in that case.
535fd1
535fd1
This commit does not restrict unprivileged users from using other fencing API,
535fd1
such as requesting actual fencing.
535fd1
---
535fd1
 fencing/commands.c | 44 +++++++++++++++++++++++++++++++++++++++-----
535fd1
 1 file changed, 39 insertions(+), 5 deletions(-)
535fd1
535fd1
diff --git a/fencing/commands.c b/fencing/commands.c
535fd1
index 26952e9..a2abcdd 100644
535fd1
--- a/fencing/commands.c
535fd1
+++ b/fencing/commands.c
535fd1
@@ -1,5 +1,5 @@
535fd1
 /*
535fd1
- * Copyright 2009-2018 Andrew Beekhof <andrew@beekhof.net>
535fd1
+ * Copyright 2009-2020 the Pacemaker project contributors
535fd1
  *
535fd1
  * This source code is licensed under the GNU General Public License version 2
535fd1
  * or later (GPLv2+) WITHOUT ANY WARRANTY.
535fd1
@@ -2575,6 +2575,19 @@ handle_request(crm_client_t * client, uint32_t id, uint32_t flags, xmlNode * req
535fd1
     const char *op = crm_element_value(request, F_STONITH_OPERATION);
535fd1
     const char *client_id = crm_element_value(request, F_STONITH_CLIENTID);
535fd1
 
535fd1
+#if ENABLE_ACL
535fd1
+    /* IPC commands related to fencing configuration may be done only by
535fd1
+     * privileged users (i.e. root or hacluster) when ACLs are supported,
535fd1
+     * because all other users should go through the CIB to have ACLs applied.
535fd1
+     *
535fd1
+     * If no client was given, this is a peer request, which is always allowed.
535fd1
+     */
535fd1
+    bool allowed = (client == NULL)
535fd1
+                   || is_set(client->flags, crm_client_flag_ipc_privileged);
535fd1
+#else
535fd1
+    bool allowed = true;
535fd1
+#endif
535fd1
+
535fd1
     crm_element_value_int(request, F_STONITH_CALLOPTS, &call_options);
535fd1
 
535fd1
     if (is_set(call_options, st_opt_sync_call)) {
535fd1
@@ -2731,27 +2744,43 @@ handle_request(crm_client_t * client, uint32_t id, uint32_t flags, xmlNode * req
535fd1
     } else if (crm_str_eq(op, STONITH_OP_DEVICE_ADD, TRUE)) {
535fd1
         const char *device_id = NULL;
535fd1
 
535fd1
-        rc = stonith_device_register(request, &device_id, FALSE);
535fd1
+        if (allowed) {
535fd1
+            rc = stonith_device_register(request, &device_id, FALSE);
535fd1
+        } else {
535fd1
+            rc = -EACCES;
535fd1
+        }
535fd1
         do_stonith_notify_device(call_options, op, rc, device_id);
535fd1
 
535fd1
     } else if (crm_str_eq(op, STONITH_OP_DEVICE_DEL, TRUE)) {
535fd1
         xmlNode *dev = get_xpath_object("//" F_STONITH_DEVICE, request, LOG_ERR);
535fd1
         const char *device_id = crm_element_value(dev, XML_ATTR_ID);
535fd1
 
535fd1
-        rc = stonith_device_remove(device_id, FALSE);
535fd1
+        if (allowed) {
535fd1
+            rc = stonith_device_remove(device_id, FALSE);
535fd1
+        } else {
535fd1
+            rc = -EACCES;
535fd1
+        }
535fd1
         do_stonith_notify_device(call_options, op, rc, device_id);
535fd1
 
535fd1
     } else if (crm_str_eq(op, STONITH_OP_LEVEL_ADD, TRUE)) {
535fd1
         char *device_id = NULL;
535fd1
 
535fd1
-        rc = stonith_level_register(request, &device_id);
535fd1
+        if (allowed) {
535fd1
+            rc = stonith_level_register(request, &device_id);
535fd1
+        } else {
535fd1
+            rc = -EACCES;
535fd1
+        }
535fd1
         do_stonith_notify_level(call_options, op, rc, device_id);
535fd1
         free(device_id);
535fd1
 
535fd1
     } else if (crm_str_eq(op, STONITH_OP_LEVEL_DEL, TRUE)) {
535fd1
         char *device_id = NULL;
535fd1
 
535fd1
-        rc = stonith_level_remove(request, &device_id);
535fd1
+        if (allowed) {
535fd1
+            rc = stonith_level_remove(request, &device_id);
535fd1
+        } else {
535fd1
+            rc = -EACCES;
535fd1
+        }
535fd1
         do_stonith_notify_level(call_options, op, rc, device_id);
535fd1
 
535fd1
     } else if (crm_str_eq(op, STONITH_OP_CONFIRM, TRUE)) {
535fd1
@@ -2782,6 +2811,11 @@ handle_request(crm_client_t * client, uint32_t id, uint32_t flags, xmlNode * req
535fd1
 
535fd1
   done:
535fd1
 
535fd1
+    if (rc == -EACCES) {
535fd1
+        crm_warn("Rejecting IPC request '%s' from unprivileged client %s",
535fd1
+                 crm_str(op), crm_client_name(client));
535fd1
+    }
535fd1
+
535fd1
     /* Always reply unless the request is in process still.
535fd1
      * If in progress, a reply will happen async after the request
535fd1
      * processing is finished */
535fd1
-- 
535fd1
1.8.3.1
535fd1
535fd1
535fd1
From 74f3866cc23dad76fe914c341924ed17ece6b80b Mon Sep 17 00:00:00 2001
535fd1
From: Ken Gaillot <kgaillot@redhat.com>
535fd1
Date: Wed, 1 Jul 2020 20:38:16 -0500
535fd1
Subject: [PATCH 09/10] Test: CTS: libqb shared memory creates directories now
535fd1
535fd1
... so use "rm -rf" instead of "rm -f"
535fd1
---
535fd1
 cts/CTS.py       | 2 +-
535fd1
 cts/CTSaudits.py | 2 +-
535fd1
 2 files changed, 2 insertions(+), 2 deletions(-)
535fd1
535fd1
diff --git a/cts/CTS.py b/cts/CTS.py
535fd1
index cca2697..28e0e9c 100644
535fd1
--- a/cts/CTS.py
535fd1
+++ b/cts/CTS.py
535fd1
@@ -635,7 +635,7 @@ class ClusterManager(UserDict):
535fd1
         if self.rsh(node, self.templates["StopCmd"]) == 0:
535fd1
             # Make sure we can continue even if corosync leaks
535fd1
             # fdata-* is the old name
535fd1
-            #self.rsh(node, "rm -f /dev/shm/qb-* /dev/shm/fdata-*")
535fd1
+            #self.rsh(node, "rm -rf /dev/shm/qb-* /dev/shm/fdata-*")
535fd1
             self.ShouldBeStatus[node] = "down"
535fd1
             self.cluster_stable(self.Env["DeadTime"])
535fd1
             return 1
535fd1
diff --git a/cts/CTSaudits.py b/cts/CTSaudits.py
535fd1
index d9fbeb9..572d3ab 100755
535fd1
--- a/cts/CTSaudits.py
535fd1
+++ b/cts/CTSaudits.py
535fd1
@@ -245,7 +245,7 @@ class FileAudit(ClusterAudit):
535fd1
                     for line in lsout:
535fd1
                         self.CM.debug("ps[%s]: %s" % (node, line))
535fd1
 
535fd1
-                    self.CM.rsh(node, "rm -f /dev/shm/qb-*")
535fd1
+                    self.CM.rsh(node, "rm -rf /dev/shm/qb-*")
535fd1
 
535fd1
             else:
535fd1
                 self.CM.debug("Skipping %s" % node)
535fd1
-- 
535fd1
1.8.3.1
535fd1
535fd1
535fd1
From aa4ebe27b392a4b613d0ddd4480470659d89106f Mon Sep 17 00:00:00 2001
535fd1
From: Ken Gaillot <kgaillot@redhat.com>
535fd1
Date: Thu, 2 Jul 2020 16:09:20 -0500
535fd1
Subject: [PATCH 10/10] Test: CTS: ignore error logged by recent pcs versions
535fd1
535fd1
... because it is expected when a node is fenced, and we should already see
535fd1
pacemaker errors if a node is unexpectedly fenced
535fd1
---
535fd1
 cts/patterns.py | 4 ++++
535fd1
 1 file changed, 4 insertions(+)
535fd1
535fd1
diff --git a/cts/patterns.py b/cts/patterns.py
535fd1
index e908714..47a9067 100644
535fd1
--- a/cts/patterns.py
535fd1
+++ b/cts/patterns.py
535fd1
@@ -12,6 +12,10 @@ class BasePatterns:
535fd1
 
535fd1
             # Logging bug in some versions of libvirtd
535fd1
             r"libvirtd.*: internal error: Failed to parse PCI config address",
535fd1
+
535fd1
+            # pcs can log this when node is fenced, but fencing is OK in some
535fd1
+            # tests (and we will catch it in pacemaker logs when not OK)
535fd1
+            r"pcs.daemon:No response from: .* request: get_configs, error:",
535fd1
         ]
535fd1
         self.BadNews = []
535fd1
         self.components = {}
535fd1
-- 
535fd1
1.8.3.1
535fd1