From 3ffe130d24b4c4dc639517d72434b19c5f9206c0 Mon Sep 17 00:00:00 2001 From: David Nichols Date: Sat, 3 Feb 2024 10:13:06 +0100 Subject: [PATCH] refs #4793 do not clear signal mask before execl() after fork() in system() to avoid crashes when the child is terminated by a signal --- command-line.cpp | 2 +- lib/ql_lib.qpp | 67 +++++++++++++++++++++++++----------------------- 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/command-line.cpp b/command-line.cpp index cb0bffb52d..ad0cdb99ac 100644 --- a/command-line.cpp +++ b/command-line.cpp @@ -1,4 +1,4 @@ -/* + /* command-line.cpp Qore Programming Language diff --git a/lib/ql_lib.qpp b/lib/ql_lib.qpp index e3fd8a32c8..4d4ed5ffa5 100644 --- a/lib/ql_lib.qpp +++ b/lib/ql_lib.qpp @@ -91,7 +91,7 @@ extern bool threads_initialized; AbstractQoreNode* missing_function_error(const char* func, ExceptionSink* xsink) { QoreString have(func); have.toupr(); - return xsink->raiseException("MISSING-FEATURE-ERROR", "this system does not implement %s(); for maximum portability use the constant Option::HAVE_%s to check if this function is implemented before calling", func, have.getBuffer()); + return xsink->raiseException("MISSING-FEATURE-ERROR", "this system does not implement %s(); for maximum portability use the constant Option::HAVE_%s to check if this function is implemented before calling", func, have.c_str()); } AbstractQoreNode* missing_function_error(const char* func, const char* opt, ExceptionSink* xsink) { @@ -285,7 +285,7 @@ exec("/usr/bin/xterm -bg black -fg white -sb -sl 2000"); @endcode */ nothing exec(string command) [dom=EXTERNAL_PROCESS,PROCESS] { - ExecArgList exec_args(command->getBuffer()); + ExecArgList exec_args(command->c_str()); execvp(exec_args.getFile(), exec_args.getArgs()); xsink->raiseErrnoException("EXEC-ERROR", errno, "execvp() failed in child process for target '%s'", exec_args.getFile()); @@ -310,31 +310,34 @@ int rc = system("ls -l"); */ int system(string command) [dom=EXTERNAL_PROCESS] { #if defined(HAVE_FORK) && defined(HAVE_SIGNAL_HANDLING) - // on platforms with fork(2) and signal handling, we need to fork, enable all signals, then execvp() - pid_t pid; - if (!(pid = fork())) { - // enable all signals - sigset_t mask; - sigemptyset(&mask); - sigprocmask(SIG_SETMASK, &mask, 0); - - // exec pgm like system(): sh -c "command" - execl("/bin/sh", "sh", "-c", command->getBuffer(), NULL); - fprintf(stderr, "execvp() failed in child process for target '/bin/sh' with error code %d: %s\n", errno, strerror(errno)); - _Exit(-1); - //qore_exit_process(-1); - } - if (pid == -1) - return -1; - - // wait for child to exit - int status; - wait(&status); - return WIFEXITED(status) ? WEXITSTATUS(status) : -1; + // on platforms with fork(2) and signal handling, we need to fork, enable all signals, then execl() + pid_t pid; + if (!(pid = fork())) { + // exec pgm like system(): sh -c "command" + execl("/bin/sh", "sh", "-c", command->c_str(), NULL); + fprintf(stderr, "execl() failed in child process for target '/bin/sh' with error code %d: %s\n", errno, + strerror(errno)); + _Exit(-1); + //qore_exit_process(-1); + } + if (pid == -1) + return -1; + + // wait for child to exit + int status; + //wait(&status); + while (true) { + int rc = waitpid(pid, &status, WUNTRACED); + if (rc == -1 && errno == EINTR) { + continue; + } + break; + } + return WIFEXITED(status) ? WEXITSTATUS(status) : -1; #elif defined(HAVE_SYSTEM) - return system(command->getBuffer()); + return system(command->c_str()); #else - return missing_function_error("system", xsink); + return missing_function_error("system", xsink); #endif } @@ -807,7 +810,7 @@ string fn = basename("/usr/local/bin/file_name"); @see dirname() */ string basename(string path) [flags=CONSTANT] { - char* p = q_basename(path->getBuffer()); + char* p = q_basename(path->c_str()); int len = strlen(p); return new QoreStringNode(p, len, len + 1, path->getEncoding()); } @@ -831,7 +834,7 @@ string dir = dirname("/usr/local/bin/file_name"); @see basename() */ string dirname(string path) [flags=CONSTANT] { - char* p = q_dirname(path->getBuffer()); + char* p = q_dirname(path->c_str()); int len = strlen(p); return new QoreStringNode(p, len, len + 1, path->getEncoding()); } @@ -964,7 +967,7 @@ if (!exists host) @see gethostbyname_long() for a version of this function that returns all host information, including all hostname aliases and all addresses */ *string gethostbyname(string name) [flags=CONSTANT;dom=EXTERNAL_INFO] { - return q_gethostbyname_to_string(name->getBuffer()); + return q_gethostbyname_to_string(name->c_str()); } //! This function variant does nothing at all; it is only included for backwards-compatibility with qore prior to version 0.8.0 for functions that would ignore type errors in arguments @@ -993,7 +996,7 @@ if (!exists hostname) @see gethostbyaddr_long() for a version of this function that returns all host information, including all hostname aliases and all addresses */ *string gethostbyaddr(string addr, softint type = AF_INET) [flags=CONSTANT;dom=EXTERNAL_INFO] { - return q_gethostbyaddr_to_string(xsink, addr->getBuffer(), type); + return q_gethostbyaddr_to_string(xsink, addr->c_str(), type); } //! This function variant does nothing at all; it is only included for backwards-compatibility with qore prior to version 0.8.0 for functions that would ignore type errors in arguments @@ -1018,7 +1021,7 @@ if (!ah) @see gethostbyname() for a version of this function that returns just the first network address corresponding to the hostname */ *hash gethostbyname_long(string name) [flags=CONSTANT;dom=EXTERNAL_INFO] { - return q_gethostbyname_to_hash(name->getBuffer()); + return q_gethostbyname_to_hash(name->c_str()); } //! This function variant does nothing at all; it is only included for backwards-compatibility with qore prior to version 0.8.0 for functions that would ignore type errors in arguments @@ -1047,7 +1050,7 @@ if (!ah) @see gethostbyaddr() for a simpler version of this function that returns just a single hostname for the address */ *hash gethostbyaddr_long(string addr, softint type = AF_INET) [flags=CONSTANT;dom=EXTERNAL_INFO] { - return q_gethostbyaddr_to_hash(xsink, addr->getBuffer(), type); + return q_gethostbyaddr_to_hash(xsink, addr->c_str(), type); } //! This function variant does nothing at all; it is only included for backwards-compatibility with qore prior to version 0.8.0 for functions that would ignore type errors in arguments @@ -1074,7 +1077,7 @@ list> l = getaddrinfo("localhost"); @throw QOREADDRINFO-GETINFO-ERROR nodename nor servname provided, or not known */ list> getaddrinfo(*string node, *softstring service, softint family = AF_UNSPEC, softint flags = 0) [flags=RET_VALUE_ONLY;dom=EXTERNAL_INFO] { - return q_getaddrinfo_to_list(xsink, node ? node->getBuffer() : 0, service ? service->getBuffer() : 0, (int)family, (int)flags); + return q_getaddrinfo_to_list(xsink, node ? node->c_str() : 0, service ? service->c_str() : 0, (int)family, (int)flags); } //! closes all possible file descriptors; useful in "daemon" processes that may have inherited open file descriptors