From f91a961112ec9796181b42aa52f9c36dfa3c6a99 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Pokorn=C3=BD?= <jpokorny@redhat.com>
Date: Tue, 2 Apr 2019 10:13:21 +0200
Subject: [PATCH 1/7] High: libservices: fix use-after-free wrt. alert handling

This could possibly lead to unsolicited information disclosure by the
means of standard output of the immediately preceding agent/resource
execution leaking into the log stream under some circumstances.
It was hence assigned CVE-2019-3885.

The provoked pathological state of pacemaker-execd daemon progresses
towards crashing it for hitting segmentation fault.
---
 lib/services/services.c       | 40 +---------------------------------------
 lib/services/services_linux.c | 35 +++++++++++++++++++++++++++++++----
 2 files changed, 32 insertions(+), 43 deletions(-)

diff --git a/lib/services/services.c b/lib/services/services.c
index ef2c5fc3e..1d06c5df4 100644
--- a/lib/services/services.c
+++ b/lib/services/services.c
@@ -450,35 +450,6 @@ services_action_user(svc_action_t *op, const char *user)
     return crm_user_lookup(user, &(op->opaque->uid), &(op->opaque->gid));
 }
 
-static void
-set_alert_env(gpointer key, gpointer value, gpointer user_data)
-{
-    int rc;
-
-    if (value) {
-        rc = setenv(key, value, 1);
-    } else {
-        rc = unsetenv(key);
-    }
-
-    if (rc < 0) {
-        crm_perror(LOG_ERR, "setenv %s=%s",
-                  (char*)key, (value? (char*)value : ""));
-    } else {
-        crm_trace("setenv %s=%s", (char*)key, (value? (char*)value : ""));
-    }
-}
-
-static void
-unset_alert_env(gpointer key, gpointer value, gpointer user_data)
-{
-    if (unsetenv(key) < 0) {
-        crm_perror(LOG_ERR, "unset %s", (char*)key);
-    } else {
-        crm_trace("unset %s", (char*)key);
-    }
-}
-
 /*!
  * \brief Execute an alert agent action
  *
@@ -493,18 +464,9 @@ unset_alert_env(gpointer key, gpointer value, gpointer user_data)
 gboolean
 services_alert_async(svc_action_t *action, void (*cb)(svc_action_t *op))
 {
-    gboolean responsible;
-
     action->synchronous = false;
     action->opaque->callback = cb;
-    if (action->params) {
-        g_hash_table_foreach(action->params, set_alert_env, NULL);
-    }
-    responsible = services_os_action_execute(action);
-    if (action->params) {
-        g_hash_table_foreach(action->params, unset_alert_env, NULL);
-    }
-    return responsible;
+    return services_os_action_execute(action);
 }
 
 #if SUPPORT_DBUS
diff --git a/lib/services/services_linux.c b/lib/services/services_linux.c
index 705901e31..2047b641f 100644
--- a/lib/services/services_linux.c
+++ b/lib/services/services_linux.c
@@ -159,6 +159,25 @@ set_ocf_env_with_prefix(gpointer key, gpointer value, gpointer user_data)
     set_ocf_env(buffer, value, user_data);
 }
 
+static void
+set_alert_env(gpointer key, gpointer value, gpointer user_data)
+{
+    int rc;
+
+    if (value != NULL) {
+        rc = setenv(key, value, 1);
+    } else {
+        rc = unsetenv(key);
+    }
+
+    if (rc < 0) {
+        crm_perror(LOG_ERR, "setenv %s=%s",
+                  (char*)key, (value? (char*)value : ""));
+    } else {
+        crm_trace("setenv %s=%s", (char*)key, (value? (char*)value : ""));
+    }
+}
+
 /*!
  * \internal
  * \brief Add environment variables suitable for an action
@@ -168,12 +187,20 @@ set_ocf_env_with_prefix(gpointer key, gpointer value, gpointer user_data)
 static void
 add_action_env_vars(const svc_action_t *op)
 {
-    if (safe_str_eq(op->standard, PCMK_RESOURCE_CLASS_OCF) == FALSE) {
-        return;
+    void (*env_setter)(gpointer, gpointer, gpointer) = NULL;
+    if (op->agent == NULL) {
+        env_setter = set_alert_env;  /* we deal with alert handler */
+
+    } else if (safe_str_eq(op->standard, PCMK_RESOURCE_CLASS_OCF)) {
+        env_setter = set_ocf_env_with_prefix;
     }
 
-    if (op->params) {
-        g_hash_table_foreach(op->params, set_ocf_env_with_prefix, NULL);
+    if (env_setter != NULL && op->params != NULL) {
+        g_hash_table_foreach(op->params, env_setter, NULL);
+    }
+
+    if (env_setter == NULL || env_setter == set_alert_env) {
+        return;
     }
 
     set_ocf_env("OCF_RA_VERSION_MAJOR", "1", NULL);
-- 
2.16.4

