File bsc#1209640-0001-Fix-controller-avoid-use-after-free-when-disconnecti.patch of Package pacemaker.34782
From db7f6f3e99524a613758747ffcedd29fc067bbc1 Mon Sep 17 00:00:00 2001
From: "Gao,Yan" <ygao@suse.com>
Date: Thu, 23 Mar 2023 19:05:13 +0100
Subject: [PATCH] Fix: controller: avoid use-after-free when disconnecting
proxy IPCs during shutdown
Previously internal_lrm_state_destroy() directly freed and removed any
relevant proxy entries from proxy_table, which could potentially leave
the proxy IPCs connected and cause use-after-free when
g_main_context_dispatch() -> ... -> remote_proxy_disconnected() was
later called in crmd_exit().
The solution is to make sure any connected proxies get disconnected. So
that remote_proxy_disconnected() will be called and as well remove the
entries from proxy_table.
---
daemons/controld/controld_execd_state.c | 86 ++++++++++++++-----------
1 file changed, 47 insertions(+), 39 deletions(-)
Index: pacemaker-2.1.5+20221208.a3f44794f/daemons/controld/controld_execd_state.c
===================================================================
--- pacemaker-2.1.5+20221208.a3f44794f.orig/daemons/controld/controld_execd_state.c
+++ pacemaker-2.1.5+20221208.a3f44794f/daemons/controld/controld_execd_state.c
@@ -150,6 +150,45 @@ remote_proxy_remove_by_node(gpointer key
return FALSE;
}
+static remote_proxy_t *
+find_connected_proxy_by_node(const char * node_name)
+{
+ GHashTableIter gIter;
+ remote_proxy_t *proxy = NULL;
+
+ CRM_CHECK(proxy_table != NULL, return NULL);
+
+ g_hash_table_iter_init(&gIter, proxy_table);
+
+ while (g_hash_table_iter_next(&gIter, NULL, (gpointer *) &proxy)) {
+ if (proxy->source
+ && pcmk__str_eq(node_name, proxy->node_name, pcmk__str_casei)) {
+ return proxy;
+ }
+ }
+
+ return NULL;
+}
+
+static void
+remote_proxy_disconnect_by_node(const char * node_name)
+{
+ remote_proxy_t *proxy = NULL;
+
+ CRM_CHECK(proxy_table != NULL, return);
+
+ while ((proxy = find_connected_proxy_by_node(node_name)) != NULL) {
+ /* mainloop_del_ipc_client() eventually calls remote_proxy_disconnected()
+ * , which removes the entry from proxy_table.
+ * Do not do this in a g_hash_table_iter_next() loop. */
+ if (proxy->source) {
+ mainloop_del_ipc_client(proxy->source);
+ }
+ }
+
+ return;
+}
+
static void
internal_lrm_state_destroy(gpointer data)
{
@@ -159,7 +198,16 @@ internal_lrm_state_destroy(gpointer data
return;
}
- crm_trace("Destroying proxy table %s with %d members", lrm_state->node_name, g_hash_table_size(proxy_table));
+ /* Rather than directly remove the recorded proxy entries from proxy_table,
+ * make sure any connected proxies get disconnected. So that
+ * remote_proxy_disconnected() will be called and as well remove the
+ * entries from proxy_table.
+ */
+ remote_proxy_disconnect_by_node(lrm_state->node_name);
+
+ crm_trace("Destroying proxy table %s with %u members",
+ lrm_state->node_name, g_hash_table_size(proxy_table));
+ // Just in case there's still any leftovers in proxy_table
g_hash_table_foreach_remove(proxy_table, remote_proxy_remove_by_node, (char *) lrm_state->node_name);
remote_ra_cleanup(lrm_state);
lrmd_api_delete(lrm_state->conn);
@@ -277,45 +325,6 @@ lrm_state_get_list(void)
return g_hash_table_get_values(lrm_state_table);
}
-static remote_proxy_t *
-find_connected_proxy_by_node(const char * node_name)
-{
- GHashTableIter gIter;
- remote_proxy_t *proxy = NULL;
-
- CRM_CHECK(proxy_table != NULL, return NULL);
-
- g_hash_table_iter_init(&gIter, proxy_table);
-
- while (g_hash_table_iter_next(&gIter, NULL, (gpointer *) &proxy)) {
- if (proxy->source
- && pcmk__str_eq(node_name, proxy->node_name, pcmk__str_casei)) {
- return proxy;
- }
- }
-
- return NULL;
-}
-
-static void
-remote_proxy_disconnect_by_node(const char * node_name)
-{
- remote_proxy_t *proxy = NULL;
-
- CRM_CHECK(proxy_table != NULL, return);
-
- while ((proxy = find_connected_proxy_by_node(node_name)) != NULL) {
- /* mainloop_del_ipc_client() eventually calls remote_proxy_disconnected()
- * , which removes the entry from proxy_table.
- * Do not do this in a g_hash_table_iter_next() loop. */
- if (proxy->source) {
- mainloop_del_ipc_client(proxy->source);
- }
- }
-
- return;
-}
-
void
lrm_state_disconnect_only(lrm_state_t * lrm_state)
{