From 643f7f2b7ef6fba389ffb6467d48742e83740fcd Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Fri, 3 Mar 2023 13:16:16 +0100 Subject: [PATCH] ProcessSpawnImpl(): use POSIX execvp(3), not GNU/OpenBSD-only execvpe(3) Modify the fork(2)ed process' env in-place, then call execvp(3). --- doc/22-selinux.md | 4 +-- lib/base/process.cpp | 72 ++++++++++++++++---------------------------- 2 files changed, 28 insertions(+), 48 deletions(-) diff --git a/doc/22-selinux.md b/doc/22-selinux.md index 0eb337345..1307a280e 100644 --- a/doc/22-selinux.md +++ b/doc/22-selinux.md @@ -122,7 +122,7 @@ Having this boolean enabled allows icinga2 to connect to all ports. This can be **icinga2_run_sudo** -To allow Icinga 2 executing plugins via sudo you can toggle this boolean. It is disabled by default, resulting in error messages like `execvpe(sudo) failed: Permission denied`. +To allow Icinga 2 executing plugins via sudo you can toggle this boolean. It is disabled by default, resulting in error messages like `execvp(sudo) failed: Permission denied`. **httpd_can_write_icinga2_command** @@ -219,7 +219,7 @@ In this case it is the CheckCommand [running_kernel](10-icinga-template-library. assign where host.name == NodeName } -Having this Service defined will result in a UNKNOWN state and the error message `execvpe(sudo) failed: Permission denied` because SELinux denying the execution. +Having this Service defined will result in a UNKNOWN state and the error message `execvp(sudo) failed: Permission denied` because SELinux denying the execution. Switching the boolean `icinga2_run_sudo` to allow the execution will result in the check executed successfully. diff --git a/lib/base/process.cpp b/lib/base/process.cpp index aa6a0259e..965b92864 100644 --- a/lib/base/process.cpp +++ b/lib/base/process.cpp @@ -15,19 +15,14 @@ #include #include #include +#include +#include #ifndef _WIN32 -# include # include # include # include - -# ifndef __APPLE__ -extern char **environ; -# else /* __APPLE__ */ -# include -# define environ (*_NSGetEnviron()) -# endif /* __APPLE__ */ +# include #endif /* _WIN32 */ using namespace icinga; @@ -97,44 +92,18 @@ static Value ProcessSpawnImpl(struct msghdr *msgh, const Dictionary::Ptr& reques argv[arguments->GetLength()] = nullptr; - // build envp - int envc = 0; - - /* count existing environment variables */ - while (environ[envc]) - envc++; - - auto **envp = new char *[envc + (extraEnvironment ? extraEnvironment->GetLength() : 0) + 2]; - const char* lcnumeric = "LC_NUMERIC="; - const char* notifySocket = "NOTIFY_SOCKET="; - int j = 0; - - for (int i = 0; i < envc; i++) { - if (strncmp(environ[i], lcnumeric, strlen(lcnumeric)) == 0) { - continue; - } - - if (strncmp(environ[i], notifySocket, strlen(notifySocket)) == 0) { - continue; - } - - envp[j] = strdup(environ[i]); - ++j; - } + std::vector> extraEnv; if (extraEnvironment) { ObjectLock olock(extraEnvironment); + extraEnv.reserve(extraEnvironment->GetLength()); + for (const Dictionary::Pair& kv : extraEnvironment) { - String skv = kv.first + "=" + Convert::ToString(kv.second); - envp[j] = strdup(skv.CStr()); - j++; + extraEnv.emplace_back(kv.first, Convert::ToString(kv.second)); } } - envp[j] = strdup("LC_NUMERIC=C"); - envp[j + 1] = nullptr; - extraEnvironment.reset(); pid_t pid = fork(); @@ -163,6 +132,23 @@ static Value ProcessSpawnImpl(struct msghdr *msgh, const Dictionary::Ptr& reques (void)close(fds[1]); (void)close(fds[2]); + if (unsetenv("NOTIFY_SOCKET")) { + perror("unsetenv() failed"); + _exit(128); + } + + if (setenv("LC_NUMERIC", "C", 1)) { + perror("setenv() failed"); + _exit(128); + } + + for (auto& kv : extraEnv) { + if (setenv(kv.first.CStr(), kv.second.CStr(), 1)) { + perror("setenv() failed"); + _exit(128); + } + } + #ifdef HAVE_NICE if (adjustPriority) { // Cheating the compiler on "warning: ignoring return value of 'int nice(int)', declared with attribute warn_unused_result [-Wunused-result]". @@ -186,9 +172,9 @@ static Value ProcessSpawnImpl(struct msghdr *msgh, const Dictionary::Ptr& reques sigemptyset(&mask); sigprocmask(SIG_SETMASK, &mask, nullptr); - if (icinga2_execvpe(argv[0], argv, envp) < 0) { + if (execvp(argv[0], argv) < 0) { char errmsg[512]; - strcpy(errmsg, "execvpe("); + strcpy(errmsg, "execvp("); strncat(errmsg, argv[0], sizeof(errmsg) - strlen(errmsg) - 1); strncat(errmsg, ") failed", sizeof(errmsg) - strlen(errmsg) - 1); errmsg[sizeof(errmsg) - 1] = '\0'; @@ -208,12 +194,6 @@ static Value ProcessSpawnImpl(struct msghdr *msgh, const Dictionary::Ptr& reques delete[] argv; - // free environment - for (int i = 0; envp[i]; i++) - free(envp[i]); - - delete[] envp; - Dictionary::Ptr response = new Dictionary({ { "rc", pid }, { "errno", errorCode }