diff --git a/0001-Revert-Fix-service-lib-avoid-call-pattern-leading-to.patch b/0001-Revert-Fix-service-lib-avoid-call-pattern-leading-to.patch new file mode 100644 index 0000000..aa6054d --- /dev/null +++ b/0001-Revert-Fix-service-lib-avoid-call-pattern-leading-to.patch @@ -0,0 +1,144 @@ +From 60c3bcbcebd8b619b2124dfed9585182b97eb385 Mon Sep 17 00:00:00 2001 +From: "Gao,Yan" +Date: Thu, 11 Apr 2019 17:08:41 +0200 +Subject: [PATCH 1/2] Revert "Fix: service-lib: avoid call-pattern leading to + use-after-free" + +This reverts commit e5a1d5dd751effe674e57a2f834e75650ad210c1. +--- + include/crm/services.h | 8 +------- + lib/fencing/st_client.c | 18 +++--------------- + lib/services/services.c | 13 +------------ + lib/services/services_linux.c | 5 ----- + lib/services/services_private.h | 1 - + 5 files changed, 5 insertions(+), 40 deletions(-) + +diff --git a/include/crm/services.h b/include/crm/services.h +index 4bdd21a34..c13fc0f04 100644 +--- a/include/crm/services.h ++++ b/include/crm/services.h +@@ -305,17 +305,11 @@ gboolean services_action_kick(const char *name, const char *action, + * + * \param[in] op services action data + * \param[in] action_callback callback for when the action completes +- * \param[in] action_fork_callback callback for when action forked successfully + * + * \retval TRUE succesfully started execution + * \retval FALSE failed to start execution, no callback will be received + */ +- gboolean services_action_async_fork_notify(svc_action_t * op, +- void (*action_callback) (svc_action_t *), +- void (*action_fork_callback) (svc_action_t *)); +- +- gboolean services_action_async(svc_action_t * op, +- void (*action_callback) (svc_action_t *)); ++ gboolean services_action_async(svc_action_t * op, void (*action_callback) (svc_action_t *)); + + gboolean services_action_cancel(const char *name, const char *action, + guint interval_ms); +diff --git a/lib/fencing/st_client.c b/lib/fencing/st_client.c +index f4b7addc2..0f2c33012 100644 +--- a/lib/fencing/st_client.c ++++ b/lib/fencing/st_client.c +@@ -720,18 +720,6 @@ stonith_action_async_done(svc_action_t *svc_action) + stonith__destroy_action(action); + } + +-static void +-stonith_action_async_forked(svc_action_t *svc_action) +-{ +- stonith_action_t *action = (stonith_action_t *) svc_action->cb_data; +- +- action->pid = svc_action->pid; +- action->svc_action = svc_action; +- +- crm_trace("Child process %d performing action '%s' successfully forked", +- action->pid, action->action); +-} +- + static int + internal_stonith_action_execute(stonith_action_t * action) + { +@@ -778,12 +766,12 @@ internal_stonith_action_execute(stonith_action_t * action) + + if (action->async) { + /* async */ +- if(services_action_async_fork_notify(svc_action, +- &stonith_action_async_done, +- &stonith_action_async_forked) == FALSE) { ++ if(services_action_async(svc_action, &stonith_action_async_done) == FALSE) { + services_action_free(svc_action); + svc_action = NULL; + } else { ++ action->pid = svc_action->pid; ++ action->svc_action = svc_action; + rc = 0; + } + +diff --git a/lib/services/services.c b/lib/services/services.c +index 313567f58..fa1e0dbe8 100644 +--- a/lib/services/services.c ++++ b/lib/services/services.c +@@ -766,17 +766,12 @@ services_untrack_op(svc_action_t *op) + } + + gboolean +-services_action_async_fork_notify(svc_action_t * op, +- void (*action_callback) (svc_action_t *), +- void (*action_fork_callback) (svc_action_t *)) ++services_action_async(svc_action_t * op, void (*action_callback) (svc_action_t *)) + { + op->synchronous = false; + if (action_callback) { + op->opaque->callback = action_callback; + } +- if (action_fork_callback) { +- op->opaque->fork_callback = action_fork_callback; +- } + + if (op->interval_ms > 0) { + init_recurring_actions(); +@@ -796,12 +791,6 @@ services_action_async_fork_notify(svc_action_t * op, + return action_exec_helper(op); + } + +-gboolean +-services_action_async(svc_action_t * op, +- void (*action_callback) (svc_action_t *)) +-{ +- return services_action_async_fork_notify(op, action_callback, NULL); +-} + + static gboolean processing_blocked_ops = FALSE; + +diff --git a/lib/services/services_linux.c b/lib/services/services_linux.c +index 8686f2947..66f0fbfc7 100644 +--- a/lib/services/services_linux.c ++++ b/lib/services/services_linux.c +@@ -888,11 +888,6 @@ services_os_action_execute(svc_action_t * op) + op->opaque->stdin_fd = -1; + } + +- // after fds are setup properly and before we plug anything into mainloop +- if (op->opaque->fork_callback) { +- op->opaque->fork_callback(op); +- } +- + if (op->synchronous) { + action_synced_wait(op, pmask); + sigchld_cleanup(); +diff --git a/lib/services/services_private.h b/lib/services/services_private.h +index 660a35b67..bb4a7b6a3 100644 +--- a/lib/services/services_private.h ++++ b/lib/services/services_private.h +@@ -25,7 +25,6 @@ struct svc_action_private_s { + + guint repeat_timer; + void (*callback) (svc_action_t * op); +- void (*fork_callback) (svc_action_t * op); + + int stderr_fd; + mainloop_io_t *stderr_gsource; +-- +2.16.4 + diff --git a/0002-Revert-use-common-service-interface-for-fence-agents.patch b/0002-Revert-use-common-service-interface-for-fence-agents.patch new file mode 100644 index 0000000..c491f39 --- /dev/null +++ b/0002-Revert-use-common-service-interface-for-fence-agents.patch @@ -0,0 +1,817 @@ +From 5e862acfe98fa659095c651b6e7d97fd2ed39a07 Mon Sep 17 00:00:00 2001 +From: "Gao,Yan" +Date: Thu, 11 Apr 2019 17:20:33 +0200 +Subject: [PATCH 2/2] Revert "use common service interface for fence-agents and + RAs" + +This reverts commit 18c321e792a279d81008cbd99cb5ec7f81db096f. +--- + include/crm/services.h | 5 +- + lib/fencing/Makefile.am | 1 - + lib/fencing/st_client.c | 453 +++++++++++++++++++++++++++++++--------- + lib/services/services_linux.c | 93 --------- + lib/services/services_private.h | 2 - + 5 files changed, 355 insertions(+), 199 deletions(-) + +diff --git a/include/crm/services.h b/include/crm/services.h +index c13fc0f04..013f0b851 100644 +--- a/include/crm/services.h ++++ b/include/crm/services.h +@@ -156,10 +156,7 @@ typedef struct svc_action_s { + char *agent; + + int timeout; +- GHashTable *params; /* used for setting up environment for ocf-ra & +- alert agents +- and to be sent via stdin for fence-agents +- */ ++ GHashTable *params; /* used by OCF agents and alert agents */ + + int rc; + int pid; +diff --git a/lib/fencing/Makefile.am b/lib/fencing/Makefile.am +index 6191cb9e2..486dd7d7a 100644 +--- a/lib/fencing/Makefile.am ++++ b/lib/fencing/Makefile.am +@@ -15,7 +15,6 @@ libstonithd_la_CFLAGS = $(CFLAGS_HARDENED_LIB) + libstonithd_la_LDFLAGS += $(LDFLAGS_HARDENED_LIB) + + libstonithd_la_LIBADD = $(top_builddir)/lib/common/libcrmcommon.la +-libstonithd_la_LIBADD += $(top_builddir)/lib/services/libcrmservice.la + + libstonithd_la_SOURCES = st_client.c st_rhcs.c + if BUILD_LHA_SUPPORT +diff --git a/lib/fencing/st_client.c b/lib/fencing/st_client.c +index 0f2c33012..8f6734d33 100644 +--- a/lib/fencing/st_client.c ++++ b/lib/fencing/st_client.c +@@ -11,7 +11,6 @@ + #include + #include + #include +-#include + + #include + #include +@@ -38,18 +37,23 @@ struct stonith_action_s { + char *agent; + char *action; + char *victim; +- GHashTable *args; ++ char *args; + int timeout; + int async; + void *userdata; + void (*done_cb) (GPid pid, gint status, const char *output, gpointer user_data); + +- svc_action_t *svc_action; ++ /*! internal async track data */ ++ int fd_stdout; ++ int fd_stderr; ++ int last_timeout_signo; + + /*! internal timing information */ + time_t initial_start_time; + int tries; + int remaining_timeout; ++ guint timer_sigterm; ++ guint timer_sigkill; + int max_retries; + + /* device output data */ +@@ -431,11 +435,13 @@ stonith_api_register_level(stonith_t * st, int options, const char *node, int le + } + + static void +-append_arg(const char *key, const char *value, GHashTable **args) ++append_arg(const char *key, const char *value, char **args) + { ++ int len = 3; /* =, \n, \0 */ ++ int last = 0; ++ + CRM_CHECK(key != NULL, return); + CRM_CHECK(value != NULL, return); +- CRM_CHECK(args != NULL, return); + + if (strstr(key, "pcmk_")) { + return; +@@ -445,13 +451,15 @@ append_arg(const char *key, const char *value, GHashTable **args) + return; + } + +- if (!*args) { +- *args = crm_str_table_new(); ++ len += strlen(key); ++ len += strlen(value); ++ if (*args != NULL) { ++ last = strlen(*args); + } + +- CRM_CHECK(*args != NULL, return); ++ *args = realloc_safe(*args, last + len); + crm_trace("Appending: %s=%s", key, value); +- g_hash_table_replace(*args, strdup(key), strdup(value)); ++ sprintf((*args) + last, "%s=%s\n", key, value); + } + + static void +@@ -467,12 +475,12 @@ append_config_arg(gpointer key, gpointer value, gpointer user_data) + } + } + +-static GHashTable * ++static char * + make_args(const char *agent, const char *action, const char *victim, uint32_t victim_nodeid, GHashTable * device_args, + GHashTable * port_map) + { + char buffer[512]; +- GHashTable *arg_list = NULL; ++ char *arg_list = NULL; + const char *value = NULL; + + CRM_CHECK(action != NULL, return NULL); +@@ -538,6 +546,66 @@ make_args(const char *agent, const char *action, const char *victim, uint32_t vi + return arg_list; + } + ++static gboolean ++st_child_term(gpointer data) ++{ ++ int rc = 0; ++ stonith_action_t *track = data; ++ ++ crm_info("Child %d timed out, sending SIGTERM", track->pid); ++ track->timer_sigterm = 0; ++ track->last_timeout_signo = SIGTERM; ++ rc = kill(-track->pid, SIGTERM); ++ if (rc < 0) { ++ crm_perror(LOG_ERR, "Couldn't send SIGTERM to %d", track->pid); ++ } ++ return FALSE; ++} ++ ++static gboolean ++st_child_kill(gpointer data) ++{ ++ int rc = 0; ++ stonith_action_t *track = data; ++ ++ crm_info("Child %d timed out, sending SIGKILL", track->pid); ++ track->timer_sigkill = 0; ++ track->last_timeout_signo = SIGKILL; ++ rc = kill(-track->pid, SIGKILL); ++ if (rc < 0) { ++ crm_perror(LOG_ERR, "Couldn't send SIGKILL to %d", track->pid); ++ } ++ return FALSE; ++} ++ ++static void ++stonith_action_clear_tracking_data(stonith_action_t * action) ++{ ++ if (action->timer_sigterm > 0) { ++ g_source_remove(action->timer_sigterm); ++ action->timer_sigterm = 0; ++ } ++ if (action->timer_sigkill > 0) { ++ g_source_remove(action->timer_sigkill); ++ action->timer_sigkill = 0; ++ } ++ if (action->fd_stdout) { ++ close(action->fd_stdout); ++ action->fd_stdout = 0; ++ } ++ if (action->fd_stderr) { ++ close(action->fd_stderr); ++ action->fd_stderr = 0; ++ } ++ free(action->output); ++ action->output = NULL; ++ free(action->error); ++ action->error = NULL; ++ action->rc = 0; ++ action->pid = 0; ++ action->last_timeout_signo = 0; ++} ++ + /*! + * \internal + * \brief Free all memory used by a stonith action +@@ -548,17 +616,11 @@ void + stonith__destroy_action(stonith_action_t *action) + { + if (action) { ++ stonith_action_clear_tracking_data(action); + free(action->agent); +- if (action->args) { +- g_hash_table_destroy(action->args); +- } ++ free(action->args); + free(action->action); + free(action->victim); +- if (action->svc_action) { +- services_action_free(action->svc_action); +- } +- free(action->output); +- free(action->error); + free(action); + } + } +@@ -640,6 +702,38 @@ stonith_action_create(const char *agent, + return action; + } + ++#define READ_MAX 500 ++static char * ++read_output(int fd) ++{ ++ char buffer[READ_MAX]; ++ char *output = NULL; ++ int len = 0; ++ int more = 0; ++ ++ if (!fd) { ++ return NULL; ++ } ++ ++ do { ++ errno = 0; ++ memset(&buffer, 0, READ_MAX); ++ more = read(fd, buffer, READ_MAX - 1); ++ ++ if (more > 0) { ++ buffer[more] = 0; /* Make sure it's nul-terminated for logging ++ * 'more' is always less than our buffer size ++ */ ++ output = realloc_safe(output, len + more + 1); ++ snprintf(output + len, more + 1, "%s", buffer); ++ len += more; ++ } ++ ++ } while (more == (READ_MAX - 1) || (more < 0 && errno == EINTR)); ++ ++ return output; ++} ++ + static gboolean + update_remaining_timeout(stonith_action_t * action) + { +@@ -659,51 +753,58 @@ update_remaining_timeout(stonith_action_t * action) + return action->remaining_timeout ? TRUE : FALSE; + } + +-static int +-svc_action_to_errno(svc_action_t *svc_action) { +- int rv = pcmk_ok; ++static void ++stonith_action_async_done(mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode) ++{ ++ stonith_action_t *action = mainloop_child_userdata(p); + +- if (svc_action->rc > 0) { +- /* Try to provide a useful error code based on the fence agent's +- * error output. +- */ +- if (svc_action->rc == PCMK_OCF_TIMEOUT) { +- rv = -ETIME; ++ if (action->timer_sigterm > 0) { ++ g_source_remove(action->timer_sigterm); ++ action->timer_sigterm = 0; ++ } ++ if (action->timer_sigkill > 0) { ++ g_source_remove(action->timer_sigkill); ++ action->timer_sigkill = 0; ++ } + +- } else if (svc_action->stderr_data == NULL) { +- rv = -ENODATA; ++ action->output = read_output(action->fd_stdout); ++ action->error = read_output(action->fd_stderr); + +- } else if (strstr(svc_action->stderr_data, "imed out")) { +- /* Some agents have their own internal timeouts */ +- rv = -ETIME; ++ if (action->last_timeout_signo) { ++ action->rc = -ETIME; ++ crm_notice("Child process %d performing action '%s' timed out with signal %d", ++ pid, action->action, action->last_timeout_signo); + +- } else if (strstr(svc_action->stderr_data, "Unrecognised action")) { +- rv = -EOPNOTSUPP; ++ } else if (signo) { ++ action->rc = -ECONNABORTED; ++ crm_notice("Child process %d performing action '%s' timed out with signal %d", ++ pid, action->action, signo); + +- } else { +- rv = -pcmk_err_generic; ++ } else { ++ crm_debug("Child process %d performing action '%s' exited with rc %d", ++ pid, action->action, exitcode); ++ if (exitcode > 0) { ++ /* Try to provide a useful error code based on the fence agent's ++ * error output. ++ */ ++ if (action->error == NULL) { ++ exitcode = -ENODATA; ++ ++ } else if (strstr(action->error, "imed out")) { ++ /* Some agents have their own internal timeouts */ ++ exitcode = -ETIMEDOUT; ++ ++ } else if (strstr(action->error, "Unrecognised action")) { ++ exitcode = -EOPNOTSUPP; ++ ++ } else { ++ exitcode = -pcmk_err_generic; ++ } + } ++ action->rc = exitcode; + } +- return rv; +-} +- +-static void +-stonith_action_async_done(svc_action_t *svc_action) +-{ +- stonith_action_t *action = (stonith_action_t *) svc_action->cb_data; +- +- action->rc = svc_action_to_errno(svc_action); +- action->output = svc_action->stdout_data; +- svc_action->stdout_data = NULL; +- action->error = svc_action->stderr_data; +- svc_action->stderr_data = NULL; +- +- svc_action->params = NULL; +- +- crm_debug("Child process %d performing action '%s' exited with rc %d", +- action->pid, action->action, svc_action->rc); + +- log_action(action, action->pid); ++ log_action(action, pid); + + if (action->rc != pcmk_ok && update_remaining_timeout(action)) { + int rc = internal_stonith_action_execute(action); +@@ -713,21 +814,28 @@ stonith_action_async_done(svc_action_t *svc_action) + } + + if (action->done_cb) { +- action->done_cb(action->pid, action->rc, action->output, action->userdata); ++ action->done_cb(pid, action->rc, action->output, action->userdata); + } + +- action->svc_action = NULL; // don't remove our caller + stonith__destroy_action(action); + } + + static int + internal_stonith_action_execute(stonith_action_t * action) + { +- int rc = -EPROTO; ++ int pid, status = 0, len, rc = -EPROTO; ++ int ret; ++ int total = 0; ++ int p_read_fd, p_write_fd; /* parent read/write file descriptors */ ++ int c_read_fd, c_write_fd; /* child read/write file descriptors */ ++ int c_stderr_fd, p_stderr_fd; /* parent/child side file descriptors for stderr */ ++ int fd1[2]; ++ int fd2[2]; ++ int fd3[2]; + int is_retry = 0; +- svc_action_t *svc_action = NULL; +- static int stonith_sequence = 0; +- char *buffer = NULL; ++ ++ /* clear any previous tracking data */ ++ stonith_action_clear_tracking_data(action); + + if (!action->tries) { + action->initial_start_time = time(NULL); +@@ -740,60 +848,207 @@ internal_stonith_action_execute(stonith_action_t * action) + is_retry = 1; + } + ++ c_read_fd = c_write_fd = p_read_fd = p_write_fd = c_stderr_fd = p_stderr_fd = -1; ++ + if (action->args == NULL || action->agent == NULL) + goto fail; ++ len = strlen(action->args); ++ ++ if (pipe(fd1)) ++ goto fail; ++ p_read_fd = fd1[0]; ++ c_write_fd = fd1[1]; ++ ++ if (pipe(fd2)) ++ goto fail; ++ c_read_fd = fd2[0]; ++ p_write_fd = fd2[1]; ++ ++ if (pipe(fd3)) ++ goto fail; ++ p_stderr_fd = fd3[0]; ++ c_stderr_fd = fd3[1]; ++ ++ crm_debug("forking"); ++ pid = fork(); ++ if (pid < 0) { ++ rc = -ECHILD; ++ goto fail; ++ } ++ ++ if (!pid) { ++ /* child */ ++ setpgid(0, 0); ++ ++ close(1); ++ /* coverity[leaked_handle] False positive */ ++ if (dup(c_write_fd) < 0) ++ goto fail; ++ close(2); ++ /* coverity[leaked_handle] False positive */ ++ if (dup(c_stderr_fd) < 0) ++ goto fail; ++ close(0); ++ /* coverity[leaked_handle] False positive */ ++ if (dup(c_read_fd) < 0) ++ goto fail; ++ ++ /* keep c_stderr_fd open so parent can report all errors. */ ++ /* keep c_write_fd open so hostlist can be sent to parent. */ ++ close(c_read_fd); ++ close(p_read_fd); ++ close(p_write_fd); ++ close(p_stderr_fd); ++ ++ /* keep retries from executing out of control */ ++ if (is_retry) { ++ sleep(1); ++ } ++ execlp(action->agent, action->agent, NULL); ++ exit(CRM_EX_ERROR); ++ } ++ ++ /* parent */ ++ action->pid = pid; ++ ret = crm_set_nonblocking(p_read_fd); ++ if (ret < 0) { ++ crm_notice("Could not set output of %s to be non-blocking: %s " ++ CRM_XS " rc=%d", ++ action->agent, pcmk_strerror(rc), rc); ++ } ++ ret = crm_set_nonblocking(p_stderr_fd); ++ if (ret < 0) { ++ crm_notice("Could not set error output of %s to be non-blocking: %s " ++ CRM_XS " rc=%d", ++ action->agent, pcmk_strerror(rc), rc); ++ } ++ ++ errno = 0; ++ do { ++ crm_debug("sending args"); ++ ret = write(p_write_fd, action->args + total, len - total); ++ if (ret > 0) { ++ total += ret; ++ } + +- buffer = crm_strdup_printf(RH_STONITH_DIR "/%s", basename(action->agent)); +- svc_action = services_action_create_generic(buffer, NULL); +- free(buffer); +- svc_action->timeout = 1000 * action->remaining_timeout; +- svc_action->standard = strdup(PCMK_RESOURCE_CLASS_STONITH); +- svc_action->id = crm_strdup_printf("%s_%s_%d", basename(action->agent), +- action->action, action->tries); +- svc_action->agent = strdup(action->agent); +- svc_action->sequence = stonith_sequence++; +- svc_action->params = action->args; +- svc_action->cb_data = (void *) action; +- +- /* keep retries from executing out of control and free previous results */ +- if (is_retry) { +- free(action->output); +- action->output = NULL; +- free(action->error); +- action->error = NULL; +- sleep(1); ++ } while (errno == EINTR && total < len); ++ ++ if (total != len) { ++ crm_perror(LOG_ERR, "Sent %d not %d bytes", total, len); ++ if (ret >= 0) { ++ rc = -ECOMM; ++ } ++ goto fail; + } + ++ close(p_write_fd); p_write_fd = -1; ++ ++ /* async */ + if (action->async) { +- /* async */ +- if(services_action_async(svc_action, &stonith_action_async_done) == FALSE) { +- services_action_free(svc_action); +- svc_action = NULL; ++ action->fd_stdout = p_read_fd; ++ action->fd_stderr = p_stderr_fd; ++ mainloop_child_add(pid, 0/* Move the timeout here? */, action->action, action, stonith_action_async_done); ++ crm_trace("Op: %s on %s, pid: %d, timeout: %ds", action->action, action->agent, pid, ++ action->remaining_timeout); ++ action->last_timeout_signo = 0; ++ if (action->remaining_timeout) { ++ action->timer_sigterm = ++ g_timeout_add(1000 * action->remaining_timeout, st_child_term, action); ++ action->timer_sigkill = ++ g_timeout_add(1000 * (action->remaining_timeout + 5), st_child_kill, action); + } else { +- action->pid = svc_action->pid; +- action->svc_action = svc_action; +- rc = 0; ++ crm_err("No timeout set for stonith operation %s with device %s", ++ action->action, action->agent); + } + ++ close(c_write_fd); ++ close(c_read_fd); ++ close(c_stderr_fd); ++ return 0; ++ + } else { + /* sync */ +- if (services_action_sync(svc_action)) { ++ int timeout = action->remaining_timeout + 1; ++ pid_t p = 0; ++ ++ while (action->remaining_timeout < 0 || timeout > 0) { ++ p = waitpid(pid, &status, WNOHANG); ++ if (p > 0) { ++ break; ++ } ++ sleep(1); ++ timeout--; ++ } ++ ++ if (timeout == 0) { ++ int killrc = kill(-pid, SIGKILL); ++ ++ if (killrc && errno != ESRCH) { ++ crm_err("kill(%d, KILL) failed: %s (%d)", pid, pcmk_strerror(errno), errno); ++ } ++ /* ++ * From sigprocmask(2): ++ * It is not possible to block SIGKILL or SIGSTOP. Attempts to do so are silently ignored. ++ * ++ * This makes it safe to skip WNOHANG here ++ */ ++ p = waitpid(pid, &status, 0); ++ } ++ ++ if (p <= 0) { ++ crm_perror(LOG_ERR, "waitpid(%d)", pid); ++ ++ } else if (p != pid) { ++ crm_err("Waited for %d, got %d", pid, p); ++ } ++ ++ action->output = read_output(p_read_fd); ++ action->error = read_output(p_stderr_fd); ++ ++ action->rc = -ECONNABORTED; ++ ++ log_action(action, pid); ++ ++ rc = action->rc; ++ if (timeout == 0) { ++ action->rc = -ETIME; ++ } else if (WIFEXITED(status)) { ++ crm_debug("result = %d", WEXITSTATUS(status)); ++ action->rc = -WEXITSTATUS(status); + rc = 0; +- action->rc = svc_action_to_errno(svc_action); +- action->output = svc_action->stdout_data; +- svc_action->stdout_data = NULL; +- action->error = svc_action->stderr_data; +- svc_action->stderr_data = NULL; ++ ++ } else if (WIFSIGNALED(status)) { ++ crm_err("call %s for %s exited due to signal %d", action->action, action->agent, ++ WTERMSIG(status)); ++ + } else { +- action->rc = -ECONNABORTED; +- rc = action->rc; ++ crm_err("call %s for %s returned unexpected status %#x", ++ action->action, action->agent, status); + } +- +- svc_action->params = NULL; +- services_action_free(svc_action); + } + + fail: ++ ++ if (p_read_fd >= 0) { ++ close(p_read_fd); ++ } ++ if (p_write_fd >= 0) { ++ close(p_write_fd); ++ } ++ if (p_stderr_fd >= 0) { ++ close(p_stderr_fd); ++ } ++ ++ if (c_read_fd >= 0) { ++ close(c_read_fd); ++ } ++ if (c_write_fd >= 0) { ++ close(c_write_fd); ++ } ++ if (c_stderr_fd >= 0) { ++ close(c_stderr_fd); ++ } ++ + return rc; + } + +diff --git a/lib/services/services_linux.c b/lib/services/services_linux.c +index 66f0fbfc7..23428a828 100644 +--- a/lib/services/services_linux.c ++++ b/lib/services/services_linux.c +@@ -196,39 +196,6 @@ add_action_env_vars(const svc_action_t *op) + } + } + +-static void +-pipe_in_single_parameter(gpointer key, gpointer value, gpointer user_data) +-{ +- svc_action_t *op = user_data; +- char *buffer = crm_strdup_printf("%s=%s\n", (char *)key, (char *) value); +- int ret, total = 0, len = strlen(buffer); +- +- do { +- errno = 0; +- ret = write(op->opaque->stdin_fd, buffer + total, len - total); +- if (ret > 0) { +- total += ret; +- } +- +- } while ((errno == EINTR) && (total < len)); +- free(buffer); +-} +- +-/*! +- * \internal +- * \brief Pipe parameters in via stdin for action +- * +- * \param[in] op Action to use +- */ +-static void +-pipe_in_action_stdin_parameters(const svc_action_t *op) +-{ +- crm_debug("sending args"); +- if (op->params) { +- g_hash_table_foreach(op->params, pipe_in_single_parameter, (gpointer) op); +- } +-} +- + gboolean + recurring_action_timer(gpointer data) + { +@@ -318,10 +285,6 @@ operation_finished(mainloop_child_t * p, pid_t pid, int core, int signo, int exi + op->opaque->stdout_gsource = NULL; + } + +- if (op->opaque->stdin_fd >= 0) { +- close(op->opaque->stdin_fd); +- } +- + if (signo) { + if (mainloop_child_timeout(p)) { + crm_warn("%s - timed out after %dms", prefix, op->timeout); +@@ -653,9 +616,6 @@ action_synced_wait(svc_action_t * op, sigset_t *mask) + + close(op->opaque->stdout_fd); + close(op->opaque->stderr_fd); +- if (op->opaque->stdin_fd >= 0) { +- close(op->opaque->stdin_fd); +- } + + #ifdef HAVE_SYS_SIGNALFD_H + close(sfd); +@@ -669,7 +629,6 @@ services_os_action_execute(svc_action_t * op) + { + int stdout_fd[2]; + int stderr_fd[2]; +- int stdin_fd[2] = {-1, -1}; + int rc; + struct stat st; + sigset_t *pmask; +@@ -735,25 +694,6 @@ services_os_action_execute(svc_action_t * op) + return FALSE; + } + +- if (safe_str_eq(op->standard, PCMK_RESOURCE_CLASS_STONITH)) { +- if (pipe(stdin_fd) < 0) { +- rc = errno; +- +- close(stdout_fd[0]); +- close(stdout_fd[1]); +- close(stderr_fd[0]); +- close(stderr_fd[1]); +- +- crm_err("pipe(stdin_fd) failed. '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc); +- +- services_handle_exec_error(op, rc); +- if (!op->synchronous) { +- return operation_finalize(op); +- } +- return FALSE; +- } +- } +- + if (op->synchronous) { + #ifdef HAVE_SYS_SIGNALFD_H + sigemptyset(&mask); +@@ -801,10 +741,6 @@ services_os_action_execute(svc_action_t * op) + close(stdout_fd[1]); + close(stderr_fd[0]); + close(stderr_fd[1]); +- if (stdin_fd[0] >= 0) { +- close(stdin_fd[0]); +- close(stdin_fd[1]); +- } + + crm_err("Could not execute '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc); + services_handle_exec_error(op, rc); +@@ -818,9 +754,6 @@ services_os_action_execute(svc_action_t * op) + case 0: /* Child */ + close(stdout_fd[0]); + close(stderr_fd[0]); +- if (stdin_fd[1] >= 0) { +- close(stdin_fd[1]); +- } + if (STDOUT_FILENO != stdout_fd[1]) { + if (dup2(stdout_fd[1], STDOUT_FILENO) != STDOUT_FILENO) { + crm_err("dup2() failed (stdout)"); +@@ -833,13 +766,6 @@ services_os_action_execute(svc_action_t * op) + } + close(stderr_fd[1]); + } +- if ((stdin_fd[0] >= 0) && +- (STDIN_FILENO != stdin_fd[0])) { +- if (dup2(stdin_fd[0], STDIN_FILENO) != STDIN_FILENO) { +- crm_err("dup2() failed (stdin)"); +- } +- close(stdin_fd[0]); +- } + + if (op->synchronous) { + sigchld_cleanup(); +@@ -852,9 +778,6 @@ services_os_action_execute(svc_action_t * op) + /* Only the parent reaches here */ + close(stdout_fd[1]); + close(stderr_fd[1]); +- if (stdin_fd[0] >= 0) { +- close(stdin_fd[0]); +- } + + op->opaque->stdout_fd = stdout_fd[0]; + rc = crm_set_nonblocking(op->opaque->stdout_fd); +@@ -872,22 +795,6 @@ services_os_action_execute(svc_action_t * op) + pcmk_strerror(rc), rc); + } + +- op->opaque->stdin_fd = stdin_fd[1]; +- if (op->opaque->stdin_fd >= 0) { +- // using buffer behind non-blocking-fd here - that could be improved +- // as long as no other standard uses stdin_fd assume stonith +- rc = crm_set_nonblocking(op->opaque->stdin_fd); +- if (rc < 0) { +- crm_warn("Could not set child input non-blocking: %s " +- CRM_XS " fd=%d,rc=%d", +- pcmk_strerror(rc), op->opaque->stdin_fd, rc); +- } +- pipe_in_action_stdin_parameters(op); +- // as long as we are handling parameters directly in here just close +- close(op->opaque->stdin_fd); +- op->opaque->stdin_fd = -1; +- } +- + if (op->synchronous) { + action_synced_wait(op, pmask); + sigchld_cleanup(); +diff --git a/lib/services/services_private.h b/lib/services/services_private.h +index bb4a7b6a3..23395e20e 100644 +--- a/lib/services/services_private.h ++++ b/lib/services/services_private.h +@@ -31,8 +31,6 @@ struct svc_action_private_s { + + int stdout_fd; + mainloop_io_t *stdout_gsource; +- +- int stdin_fd; + #if SUPPORT_DBUS + DBusPendingCall* pending; + unsigned timerid; +-- +2.16.4 + diff --git a/_servicedata b/_servicedata index 522c9a9..e95af59 100644 --- a/_servicedata +++ b/_servicedata @@ -1,6 +1,6 @@ git://github.com/ClusterLabs/pacemaker.git - 9bf0fcf37d50854b087a28003f2d9f7ca94601e0 + 1b68da8e8994330a9034280221357abdb02084f4 \ No newline at end of file diff --git a/bug-728579_pacemaker-stonith-dev-id.patch b/bug-728579_pacemaker-stonith-dev-id.patch index 6cd5cfb..b7a526d 100644 --- a/bug-728579_pacemaker-stonith-dev-id.patch +++ b/bug-728579_pacemaker-stonith-dev-id.patch @@ -4,11 +4,11 @@ Date: Thu Sep 6 15:14:58 2012 +0800 Medium: stonith: Expose IDs of stonith resources to stonith agents through "$CRM_meta_st_device_id" environment variable -Index: pacemaker-2.0.1+20190402.e091f4f0c/daemons/fenced/fenced_commands.c +Index: pacemaker-2.0.0+20180726.3d81c89b8/daemons/fenced/fenced_commands.c =================================================================== ---- pacemaker-2.0.1+20190402.e091f4f0c.orig/daemons/fenced/fenced_commands.c -+++ pacemaker-2.0.1+20190402.e091f4f0c/daemons/fenced/fenced_commands.c -@@ -946,6 +946,7 @@ build_device_from_xml(xmlNode * msg) +--- pacemaker-2.0.0+20180726.3d81c89b8.orig/daemons/fenced/fenced_commands.c ++++ pacemaker-2.0.0+20180726.3d81c89b8/daemons/fenced/fenced_commands.c +@@ -940,6 +940,7 @@ build_device_from_xml(xmlNode * msg) device->id, device->on_target_actions); } @@ -16,27 +16,27 @@ Index: pacemaker-2.0.1+20190402.e091f4f0c/daemons/fenced/fenced_commands.c device->work = mainloop_add_trigger(G_PRIORITY_HIGH, stonith_device_dispatch, device); /* TODO: Hook up priority */ -Index: pacemaker-2.0.1+20190402.e091f4f0c/lib/fencing/st_client.c +Index: pacemaker-2.0.0+20180726.3d81c89b8/lib/fencing/st_client.c =================================================================== ---- pacemaker-2.0.1+20190402.e091f4f0c.orig/lib/fencing/st_client.c -+++ pacemaker-2.0.1+20190402.e091f4f0c/lib/fencing/st_client.c -@@ -39,6 +39,7 @@ struct stonith_action_s { +--- pacemaker-2.0.0+20180726.3d81c89b8.orig/lib/fencing/st_client.c ++++ pacemaker-2.0.0+20180726.3d81c89b8/lib/fencing/st_client.c +@@ -38,6 +38,7 @@ struct stonith_action_s { char *action; char *victim; - GHashTable *args; + char *args; + char *dev_id; int timeout; int async; void *userdata; -@@ -559,6 +560,7 @@ stonith__destroy_action(stonith_action_t - } - free(action->output); - free(action->error); +@@ -621,6 +622,7 @@ stonith__destroy_action(stonith_action_t + free(action->args); + free(action->action); + free(action->victim); + free(action->dev_id); free(action); } } -@@ -628,6 +630,8 @@ stonith_action_create(const char *agent, +@@ -690,6 +692,8 @@ stonith_action_create(const char *agent, if (device_args) { char buffer[512]; const char *value = NULL; @@ -45,7 +45,7 @@ Index: pacemaker-2.0.1+20190402.e091f4f0c/lib/fencing/st_client.c snprintf(buffer, sizeof(buffer), "pcmk_%s_retries", _action); value = g_hash_table_lookup(device_args, buffer); -@@ -635,6 +639,11 @@ stonith_action_create(const char *agent, +@@ -697,6 +701,11 @@ stonith_action_create(const char *agent, if (value) { action->max_retries = atoi(value); } @@ -57,43 +57,23 @@ Index: pacemaker-2.0.1+20190402.e091f4f0c/lib/fencing/st_client.c } return action; -@@ -755,6 +764,10 @@ internal_stonith_action_execute(stonith_ - svc_action->params = action->args; - svc_action->cb_data = (void *) action; +@@ -878,6 +887,8 @@ internal_stonith_action_execute(stonith_ -+ if (action->dev_id) { -+ svc_action->rsc = strdup(action->dev_id); -+ } -+ - /* keep retries from executing out of control and free previous results */ - if (is_retry) { - free(action->output); -Index: pacemaker-2.0.1+20190402.e091f4f0c/lib/services/services_linux.c -=================================================================== ---- pacemaker-2.0.1+20190402.e091f4f0c.orig/lib/services/services_linux.c -+++ pacemaker-2.0.1+20190402.e091f4f0c/lib/services/services_linux.c -@@ -30,6 +30,9 @@ - #include "crm/common/mainloop.h" - #include "crm/services.h" - -+#include "crm/stonith-ng.h" -+#include "crm/fencing/internal.h" -+ - #include "services_private.h" - - #if SUPPORT_CIBSECRETS -@@ -169,6 +172,14 @@ set_ocf_env_with_prefix(gpointer key, gp - static void - add_action_env_vars(const svc_action_t *op) - { -+ if (safe_str_eq(op->standard, PCMK_RESOURCE_CLASS_STONITH) -+ && safe_str_eq(op->agent, "fence_legacy") -+ && op->rsc) { + if (!pid) { + /* child */ + const char *st_dev_id_key = CRM_META "_" F_STONITH_DEVICE; + -+ setenv(st_dev_id_key, op->rsc, 1); -+ } + setpgid(0, 0); + + close(1); +@@ -900,6 +911,10 @@ internal_stonith_action_execute(stonith_ + close(p_write_fd); + close(p_stderr_fd); + ++ if (action->dev_id) { ++ setenv(st_dev_id_key, action->dev_id, 1); ++ } + - if (safe_str_eq(op->standard, PCMK_RESOURCE_CLASS_OCF) == FALSE) { - return; - } + /* keep retries from executing out of control */ + if (is_retry) { + sleep(1); diff --git a/pacemaker-2.0.1+20190402.e091f4f0c.tar.xz b/pacemaker-2.0.1+20190402.e091f4f0c.tar.xz deleted file mode 100644 index e8506a6..0000000 --- a/pacemaker-2.0.1+20190402.e091f4f0c.tar.xz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9940f6c3f693538e61f32e18fe643d0a4c20c589b4e859e659bd3171daf2432b -size 3427304 diff --git a/pacemaker-2.0.1+20190408.1b68da8e8.tar.xz b/pacemaker-2.0.1+20190408.1b68da8e8.tar.xz new file mode 100644 index 0000000..e94755c --- /dev/null +++ b/pacemaker-2.0.1+20190408.1b68da8e8.tar.xz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d1d94399165c8dacebd71226f59fde5fa4fa3d980140ebc5f137fdafe8f342c0 +size 3427476 diff --git a/pacemaker.changes b/pacemaker.changes index dbced39..b9470bc 100644 --- a/pacemaker.changes +++ b/pacemaker.changes @@ -1,3 +1,24 @@ +------------------------------------------------------------------- +Thu Apr 11 15:32:23 UTC 2019 - Yan Gao + +- Rebase: + bug-728579_pacemaker-stonith-dev-id.patch + +- Revert "use common service interface for fence-agents and RAs" (bsc#1132123) + * 0002-Revert-use-common-service-interface-for-fence-agents.patch + +- Revert "service-lib: avoid call-pattern leading to use-after-free" + * 0001-Revert-Fix-service-lib-avoid-call-pattern-leading-to.patch + +------------------------------------------------------------------- +Tue Apr 9 10:00:32 UTC 2019 - Yan Gao + +- Update to version 2.0.1+20190408.1b68da8e8: +- scheduler: avoid error log in harmless situation +- libcrmcommon: use INT_MIN/INT_MAX instead of -1 for out-of-range integers +- service-lib: avoid call-pattern leading to use-after-free +- libp-i: Renamed to libpacemaker. + ------------------------------------------------------------------- Thu Apr 4 11:13:13 UTC 2019 - Jan Engelhardt @@ -565,7 +586,7 @@ Thu Apr 12 08:30:58 UTC 2018 - ygao@suse.com - libcrmcommon: fix memory leak in schema workaround - fencing: avoid memory leaks when freeing remote operation - fencing: free dynamic memory at stonithd shutdown -- crmd: delete resource from lrmd when appropriate +- crmd: delete resource from lrmd when appropriate (bsc#1117381) - Test: rhbz#1565187 - Ensure failures that cause fencing are not removed until after fencing completes - rhbz#1565187 - Ensure failures that cause fencing are not removed until after fencing completes diff --git a/pacemaker.spec b/pacemaker.spec index 7b09959..a06dfac 100644 --- a/pacemaker.spec +++ b/pacemaker.spec @@ -12,7 +12,7 @@ # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. -# Please submit bugfixes or comments via https://bugs.opensuse.org/ +# Please submit bugfixes or comments via http://bugs.opensuse.org/ # @@ -74,7 +74,7 @@ %endif Name: pacemaker -Version: 2.0.1+20190402.e091f4f0c +Version: 2.0.1+20190408.1b68da8e8 Release: 0 Summary: Scalable High-Availability cluster resource manager # AGPL-3.0 licensed extra/clustermon.sh is not present in the binary @@ -87,7 +87,6 @@ Source0: %{name}-%{version}.tar.xz Source1: crm_report.in Source100: pacemaker.rpmlintrc Patch1: bug-806256_pacemaker-log-level-notice.patch -Patch2: bug-728579_pacemaker-stonith-dev-id.patch Patch3: pacemaker-nagios-plugin-dir.patch Patch4: bug-812269_pacemaker-fencing-device-register-messages.patch Patch5: pacemaker-Wno-format-signedness.patch @@ -95,6 +94,9 @@ Patch6: bug-943295_pacemaker-lrmd-log-notice.patch Patch7: bug-977201_pacemaker-controld-self-fencing.patch Patch8: bug-995365_pacemaker-cts-restart-systemd-journald.patch Patch9: pacemaker-cts-StartCmd.patch +Patch10: 0001-Revert-Fix-service-lib-avoid-call-pattern-leading-to.patch +Patch11: 0002-Revert-use-common-service-interface-for-fence-agents.patch +Patch12: bug-728579_pacemaker-stonith-dev-id.patch # Required for core functionality BuildRequires: autoconf BuildRequires: automake @@ -302,7 +304,6 @@ manager. %prep %setup -q -n %{name}-%{version} %patch1 -p1 -%patch2 -p1 %patch3 -p1 %patch4 -p1 %patch5 -p1 @@ -310,6 +311,9 @@ manager. %patch7 -p1 %patch8 -p1 %patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 %build @@ -592,9 +596,8 @@ fi %{_libdir}/libcrmcommon.so.* %{_libdir}/libpe_status.so.* %{_libdir}/libpe_rules.so.* -%{_libdir}/libpacemaker-internal.so.* +%{_libdir}/libpacemaker.so.* %{_libdir}/libstonithd.so.* -%{_libdir}/libtransitioner.so.* #%license licenses/LGPLv2.1 %doc COPYING ChangeLog %{_libdir}/libcrmcluster.so.*