From 2b3e2b622ef49ad012a981a2214f2284c144ad80 Mon Sep 17 00:00:00 2001 From: Jack Rann Date: Fri, 20 Sep 2024 15:19:35 -0700 Subject: [PATCH 1/4] Resort to finding bash along PATH --- src/configuration.cc | 2 +- src/engines/bash-engine.cc | 10 +++++----- src/include/utils.hh | 2 ++ src/utils.cc | 12 +++++++++--- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/configuration.cc b/src/configuration.cc index d81126f1..7429e684 100644 --- a/src/configuration.cc +++ b/src/configuration.cc @@ -572,7 +572,7 @@ class Configuration : public IConfiguration #ifdef __FreeBSD__ setKey("bash-command", "/usr/local/bin/bash"); #else - setKey("bash-command", "/bin/bash"); + setKey("bash-command", "bash"); #endif setKey("kernel-coverage-path", "/sys/kernel/debug/kprobe-coverage"); setKey("path-strip-level", 2); diff --git a/src/engines/bash-engine.cc b/src/engines/bash-engine.cc index 693171f2..c718b91e 100644 --- a/src/engines/bash-engine.cc +++ b/src/engines/bash-engine.cc @@ -78,7 +78,8 @@ class BashEngine : public ScriptEngineBase return false; } - m_bashSupportsXtraceFd = bashCanHandleXtraceFd(); + const std::string command = path_to_executable(conf.keyAsString("bash-command")); + m_bashSupportsXtraceFd = bashCanHandleXtraceFd(command); std::string helperPath = IOutputHandler::getInstance().getBaseDirectory() + "bash-helper.sh"; std::string helperDebugTrapPath = IOutputHandler::getInstance().getBaseDirectory() + "bash-helper-debug-trap.sh"; @@ -165,7 +166,6 @@ class BashEngine : public ScriptEngineBase xtraceFd = rlim.rlim_cur / 4; #endif } - const std::string command = conf.keyAsString("bash-command"); bool usePS4 = conf.keyAsInt("bash-use-ps4"); // Revert to stderr if this bash version can't handle BASH_XTRACE @@ -228,7 +228,7 @@ class BashEngine : public ScriptEngineBase char **vec; int argcStart = 1; vec = (char **) xmalloc(sizeof(char *) * (argc + 3)); - vec[0] = xstrdup(conf.keyAsString("bash-command").c_str()); + vec[0] = xstrdup(command.c_str()); for (unsigned i = 0; i < argc; i++) vec[argcStart + i] = xstrdup(argv[i]); @@ -505,12 +505,12 @@ class BashEngine : public ScriptEngineBase free(curLine); } - bool bashCanHandleXtraceFd() + bool bashCanHandleXtraceFd(std::string bash_executable) { FILE *fp; bool out = false; IConfiguration &conf = IConfiguration::getInstance(); - std::string cmd = conf.keyAsString("bash-command") + " -c 'echo \"$BASH_VERSION\"'"; + std::string cmd = bash_executable + " -c 'echo \"$BASH_VERSION\"'"; /* Has input via stderr been forced regardless of bash version? * Basically for testing only diff --git a/src/include/utils.hh b/src/include/utils.hh index 33d6edb6..a09a41e9 100644 --- a/src/include/utils.hh +++ b/src/include/utils.hh @@ -115,6 +115,8 @@ extern bool file_exists(const std::string &path); extern bool executable_exists_in_path(const std::string &path); +extern std::string path_to_executable(const std::string &path); + extern uint64_t get_file_timestamp(const std::string &path); extern int concat_files(const char *dst, const char *file_a, const char *file_b); diff --git a/src/utils.cc b/src/utils.cc index 6da7f03e..4dfbb8f5 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -330,11 +330,17 @@ bool file_exists(const std::string &path) } bool executable_exists_in_path(const std::string &executableName) +{ + // Return boolean based on whether we found an executable or not + return path_to_executable(executableName) != ""; +} + +std::string path_to_executable(const std::string &executableName) { // Full path to it if (file_exists(executableName)) { - return true; + return executableName; } std::string path = getenv("PATH"); @@ -348,11 +354,11 @@ bool executable_exists_in_path(const std::string &executableName) if (file_exists(cur)) { - return true; + return cur; } } - return false; + return ""; } void mock_read_file(void *(*callback)(size_t *out_size, const char *path)) From 2fdbc5f266b259b38c8ab859dc0d705bfe7375b3 Mon Sep 17 00:00:00 2001 From: Jack Rann Date: Fri, 20 Sep 2024 17:29:00 -0700 Subject: [PATCH 2/4] Use execvp() to eliminate the need to get full path to bash executable --- src/engines/bash-engine.cc | 17 ++++++++++++----- src/include/utils.hh | 2 -- src/utils.cc | 12 +++--------- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/engines/bash-engine.cc b/src/engines/bash-engine.cc index c718b91e..a4e8125e 100644 --- a/src/engines/bash-engine.cc +++ b/src/engines/bash-engine.cc @@ -78,8 +78,15 @@ class BashEngine : public ScriptEngineBase return false; } - const std::string command = path_to_executable(conf.keyAsString("bash-command")); - m_bashSupportsXtraceFd = bashCanHandleXtraceFd(command); + const std::string command = conf.keyAsString("bash-command"); + if (!executable_exists_in_path(command)) + { + error("Cannot find Bash parser '%s'", command.c_str()); + + return false; + } + + m_bashSupportsXtraceFd = bashCanHandleXtraceFd(); std::string helperPath = IOutputHandler::getInstance().getBaseDirectory() + "bash-helper.sh"; std::string helperDebugTrapPath = IOutputHandler::getInstance().getBaseDirectory() + "bash-helper-debug-trap.sh"; @@ -234,7 +241,7 @@ class BashEngine : public ScriptEngineBase vec[argcStart + i] = xstrdup(argv[i]); /* Execute the script */ - if (execv(vec[0], vec)) + if (execvp(vec[0], vec)) { perror("Failed to execute script"); @@ -505,12 +512,12 @@ class BashEngine : public ScriptEngineBase free(curLine); } - bool bashCanHandleXtraceFd(std::string bash_executable) + bool bashCanHandleXtraceFd() { FILE *fp; bool out = false; IConfiguration &conf = IConfiguration::getInstance(); - std::string cmd = bash_executable + " -c 'echo \"$BASH_VERSION\"'"; + std::string cmd = conf.keyAsString("bash-command") + " -c 'echo \"$BASH_VERSION\"'"; /* Has input via stderr been forced regardless of bash version? * Basically for testing only diff --git a/src/include/utils.hh b/src/include/utils.hh index a09a41e9..33d6edb6 100644 --- a/src/include/utils.hh +++ b/src/include/utils.hh @@ -115,8 +115,6 @@ extern bool file_exists(const std::string &path); extern bool executable_exists_in_path(const std::string &path); -extern std::string path_to_executable(const std::string &path); - extern uint64_t get_file_timestamp(const std::string &path); extern int concat_files(const char *dst, const char *file_a, const char *file_b); diff --git a/src/utils.cc b/src/utils.cc index 4dfbb8f5..6da7f03e 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -330,17 +330,11 @@ bool file_exists(const std::string &path) } bool executable_exists_in_path(const std::string &executableName) -{ - // Return boolean based on whether we found an executable or not - return path_to_executable(executableName) != ""; -} - -std::string path_to_executable(const std::string &executableName) { // Full path to it if (file_exists(executableName)) { - return executableName; + return true; } std::string path = getenv("PATH"); @@ -354,11 +348,11 @@ std::string path_to_executable(const std::string &executableName) if (file_exists(cur)) { - return cur; + return true; } } - return ""; + return false; } void mock_read_file(void *(*callback)(size_t *out_size, const char *path)) From 065d2b49a77b3706be373e5145a2d2695737e4bb Mon Sep 17 00:00:00 2001 From: Jack Rann Date: Sat, 21 Sep 2024 13:09:50 -0700 Subject: [PATCH 3/4] Update man-page with bash parser default --- doc/kcov.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/kcov.1 b/doc/kcov.1 index e8591959..d456cc4c 100644 --- a/doc/kcov.1 +++ b/doc/kcov.1 @@ -107,7 +107,7 @@ Set the python parser to use for Python programs (the default is python). Can be run with Python 3 on systems where Python 2 is the default. .TP \fB\-\-bash\-parser\fP=\fIPARSER\fP -Set the bash parser to use for shell scripts (the default is /bin/bash). +Set the bash parser to use for shell scripts (the default is bash). .TP \fB\-\-bash\-method\fP=\fIMETHOD\fP Use collection method \fIMETHOD\fP for bash scripts. The method can be either PS4, for use of From e195cc85c1f0f2011a5b81f5215e99d527ae1eef Mon Sep 17 00:00:00 2001 From: Jack Rann Date: Mon, 23 Sep 2024 12:23:52 -0700 Subject: [PATCH 4/4] Hardcode /bin/*sh redirector to /bin/bash --- src/engines/bash-execve-redirector.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/engines/bash-execve-redirector.c b/src/engines/bash-execve-redirector.c index 8a2b444b..26ca01de 100644 --- a/src/engines/bash-execve-redirector.c +++ b/src/engines/bash-execve-redirector.c @@ -53,6 +53,7 @@ int execve(const char *filename, char * const argv[], char * const envp[]) && (strstr(startBytes, "/bin/sh") != NULL || strstr(startBytes, "/bin/bash") != NULL || strstr(startBytes, "/bin/ash") != NULL || strstr(startBytes, "/bin/dash") != NULL )) { + char *bashExec = "/bin/bash"; char **replacementArgv; unsigned i = 0; @@ -63,7 +64,7 @@ int execve(const char *filename, char * const argv[], char * const envp[]) unsigned arg = 0; replacementArgv = malloc(sizeof(char*) * (i + 4)); - replacementArgv[arg++] = strdup(kcovBash); + replacementArgv[arg++] = strdup(bashExec); if (!kcovUseDebugTrap) replacementArgv[arg++] = strdup(bashArg); replacementArgv[arg++] = strdup(filename); @@ -71,7 +72,7 @@ int execve(const char *filename, char * const argv[], char * const envp[]) replacementArgv[i + arg] = strdup(argv[i]); replacementArgv[i + arg] = NULL; - filename = strdup(kcovBash); + filename = strdup(bashExec); argv = replacementArgv; }