std::shared_ptr<PlatformProcess> PlatformProcess::launchExtension( const std::string& exec_path, const std::string& extension, const std::string& extensions_socket, const std::string& extensions_timeout, const std::string& extensions_interval, const std::string& verbose) { auto ext_pid = ::fork(); if (ext_pid < 0) { return std::shared_ptr<PlatformProcess>(); } else if (ext_pid == 0) { setEnvVar("OSQUERY_EXTENSION", std::to_string(::getpid()).c_str()); ::execle(exec_path.c_str(), ("osquery extension: " + extension).c_str(), "--socket", extensions_socket.c_str(), "--timeout", extensions_timeout.c_str(), "--interval", extensions_interval.c_str(), (verbose == "true") ? "--verbose" : (char*)nullptr, (char*)nullptr, ::environ); // Code should never reach this point VLOG(1) << "Could not start extension process: " << extension; Initializer::shutdown(EXIT_FAILURE); return std::shared_ptr<PlatformProcess>(); } return std::make_shared<PlatformProcess>(ext_pid); }
void WatcherRunner::createWorker() { { WatcherLocker locker; if (Watcher::getState(Watcher::getWorker()).last_respawn_time > getUnixTime() - getWorkerLimit(RESPAWN_LIMIT)) { LOG(WARNING) << "osqueryd worker respawning too quickly: " << Watcher::workerRestartCount() << " times"; Watcher::workerRestarted(); // The configured automatic delay. size_t delay = getWorkerLimit(RESPAWN_DELAY) * 1000; // Exponential back off for quickly-respawning clients. delay += pow(2, Watcher::workerRestartCount()) * 1000; pauseMilli(delay); } } // Get the path of the current process. auto qd = SQL::selectAllFrom("processes", "pid", EQUALS, INTEGER(PlatformProcess::getCurrentProcess()->pid())); if (qd.size() != 1 || qd[0].count("path") == 0 || qd[0]["path"].size() == 0) { LOG(ERROR) << "osquery watcher cannot determine process path for worker"; Initializer::requestShutdown(EXIT_FAILURE); return; } // Set an environment signaling to potential plugin-dependent workers to wait // for extensions to broadcast. if (Watcher::hasManagedExtensions()) { setEnvVar("OSQUERY_EXTENSIONS", "true"); } // Get the complete path of the osquery process binary. boost::system::error_code ec; auto exec_path = fs::system_complete(fs::path(qd[0]["path"]), ec); if (!safePermissions( exec_path.parent_path().string(), exec_path.string(), true)) { // osqueryd binary has become unsafe. LOG(ERROR) << RLOG(1382) << "osqueryd has unsafe permissions: " << exec_path.string(); Initializer::requestShutdown(EXIT_FAILURE); return; } auto worker = PlatformProcess::launchWorker(exec_path.string(), argc_, argv_); if (worker == nullptr) { // Unrecoverable error, cannot create a worker process. LOG(ERROR) << "osqueryd could not create a worker process"; Initializer::shutdown(EXIT_FAILURE); return; } Watcher::setWorker(worker); Watcher::resetWorkerCounters(getUnixTime()); VLOG(1) << "osqueryd watcher (" << PlatformProcess::getCurrentProcess()->pid() << ") executing worker (" << worker->pid() << ")"; }
RpmEnvironmentManager() : config_(getEnvVar("RPM_CONFIGDIR")) { // Honor a caller's environment if (!config_.is_initialized()) { setEnvVar("RPM_CONFIGDIR", "/usr/lib/rpm"); } callback_ = rpmlogSetCallback(&RpmEnvironmentManager::Callback, nullptr); }
std::shared_ptr<PlatformProcess> PlatformProcess::launchExtension( const std::string& exec_path, const std::string& extensions_socket, const std::string& extensions_timeout, const std::string& extensions_interval, bool verbose) { auto ext_pid = ::fork(); if (ext_pid < 0) { return std::shared_ptr<PlatformProcess>(); } else if (ext_pid == 0) { setEnvVar("OSQUERY_EXTENSION", std::to_string(::getpid()).c_str()); struct sigaction sig_action; sig_action.sa_handler = SIG_DFL; sig_action.sa_flags = 0; sigemptyset(&sig_action.sa_mask); for (auto i = NSIG; i >= 0; i--) { sigaction(i, &sig_action, nullptr); } std::vector<const char*> arguments; arguments.push_back(exec_path.c_str()); arguments.push_back(exec_path.c_str()); std::string arg_verbose("--verbose"); if (verbose) { arguments.push_back(arg_verbose.c_str()); } std::string arg_socket("--socket"); arguments.push_back(arg_socket.c_str()); arguments.push_back(extensions_socket.c_str()); std::string arg_timeout("--timeout"); arguments.push_back(arg_timeout.c_str()); arguments.push_back(extensions_timeout.c_str()); std::string arg_interval("--interval"); arguments.push_back(arg_interval.c_str()); arguments.push_back(extensions_interval.c_str()); arguments.push_back(nullptr); char* const* argv = const_cast<char* const*>(&arguments[1]); ::execve(arguments[0], argv, ::environ); // Code should never reach this point VLOG(1) << "Could not start extension process: " << exec_path; Initializer::shutdown(EXIT_FAILURE); return std::shared_ptr<PlatformProcess>(); } return std::make_shared<PlatformProcess>(ext_pid); }
std::shared_ptr<PlatformProcess> PlatformProcess::launchWorker( const std::string& exec_path, int argc /* unused */, char** argv) { auto worker_pid = ::fork(); if (worker_pid < 0) { return std::shared_ptr<PlatformProcess>(); } else if (worker_pid == 0) { setEnvVar("OSQUERY_WORKER", std::to_string(::getpid()).c_str()); ::execve(exec_path.c_str(), argv, ::environ); // Code should never reach this point LOG(ERROR) << "osqueryd could not start worker process"; Initializer::shutdown(EXIT_CATASTROPHIC); return std::shared_ptr<PlatformProcess>(); } return std::make_shared<PlatformProcess>(worker_pid); }
TEST_F(ProcessTests, test_envVar) { auto val = getEnvVar("GTEST_OSQUERY"); EXPECT_FALSE(val); EXPECT_FALSE(val.is_initialized()); EXPECT_TRUE(setEnvVar("GTEST_OSQUERY", "true")); val = getEnvVar("GTEST_OSQUERY"); EXPECT_FALSE(!val); EXPECT_TRUE(val.is_initialized()); EXPECT_EQ(*val, "true"); EXPECT_TRUE(unsetEnvVar("GTEST_OSQUERY")); val = getEnvVar("GTEST_OSQUERY"); EXPECT_FALSE(val); EXPECT_FALSE(val.is_initialized()); }
/* Takes the command struct and takes approproate action. * Will either execute a shell command, program, or output an error message. * @params: command - a struct representing the command * @return: false is the command was note found, true otherwise. */ bool processCommand(command_t* command, char* pEnv[]){ char* defaultDir = getenv("HOME"); if( strcmp(command->name, "cd") == CMP_OK) { if( command->argc == 1 ) { changeDirectory(defaultDir); } else { changeDirectory(command->argv[1]); } } else if( strcmp(command->name,"help") == CMP_OK) { help(); } else if( strcmp(command->name, "senv") == CMP_OK) { char* envName = NULL; char* envVal = NULL; if( command->argc > 1) { envName = command->argv[1]; } if( command->argc > 2) { envVal = command->argv[2]; } setEnvVar(envName,envVal); } else if( strcmp(command->name, "usenv") == CMP_OK) { char* envName = NULL; if( command->argc > 1) { envName = command->argv[1]; } unsetEnvVar(envName); } else if( strcmp(command->name, "genv") == CMP_OK) { char* envName = NULL; if( command-> argc > 1) { envName = command->argv[1]; } getEnvVar(envName); } else { char* filePath = getFilePath(command->name); if(filePath != NULL) { pid_t pid_command = fork(); if(pid_command < CHILD) { // ERROR fprintf(stderr, "Fork failure!\n"); } else if ( pid_command == CHILD) { if(command->isBg) { freopen("/dev/null","w",stdout); freopen("/dev/null","w",stderr); } execve(filePath, command->argv, pEnv); } else { if(!command->isBg) { int stat; waitpid(pid_command, &stat, 0); } else { printf("Process ID: %d\n", pid_command); } } } else if(strcmp(command->name, "quit") == CMP_OK || strcmp(command->name, "exit") == CMP_OK || strcmp(command->name, "q") == CMP_OK ) { return false; } else { printf("%s: Command not found\n", command->name); return false; } } return true; }
std::shared_ptr<PlatformProcess> PlatformProcess::launchExtension( const std::string &exec_path, const std::string &extension, const std::string &extensions_socket, const std::string &extensions_timeout, const std::string &extensions_interval, const std::string &verbose) { ::STARTUPINFOA si = {0}; ::PROCESS_INFORMATION pi = {0}; si.cb = sizeof(si); // To prevent errant double quotes from altering the intended arguments for // argv, we strip them out completely. std::stringstream argv_stream; argv_stream << "\"osquery extension: " << boost::replace_all_copy(extension, "\"", "") << "\" "; argv_stream << "--socket \"" << extensions_socket << "\" "; argv_stream << "--timeout " << extensions_timeout << " "; argv_stream << "--interval " << extensions_interval << " "; if (verbose == "true") { argv_stream << "--verbose"; } // We don't directly use argv.c_str() as the value for lpCommandLine in // CreateProcess since that argument requires a modifiable buffer. So, // instead, we off-load the contents of argv into a vector which will have its // backing memory as modifiable. std::string argv = argv_stream.str(); std::vector<char> mutable_argv(argv.begin(), argv.end()); mutable_argv.push_back('\0'); // In POSIX, this environment variable is set to the child's process ID. But // that is not easily accomplishable on Windows and provides no value since // this is never used elsewhere in the core. if (!setEnvVar("OSQUERY_EXTENSION", "1")) { return std::shared_ptr<PlatformProcess>(); } BOOL status = ::CreateProcessA(exec_path.c_str(), &mutable_argv[0], NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); unsetEnvVar("OSQUERY_EXTENSION"); if (!status) { return std::shared_ptr<PlatformProcess>(); } auto process = std::make_shared<PlatformProcess>(pi.hProcess); ::CloseHandle(pi.hThread); ::CloseHandle(pi.hProcess); return process; }
std::shared_ptr<PlatformProcess> PlatformProcess::launchWorker( const std::string &exec_path, int argc, char **argv) { ::STARTUPINFOA si = {0}; ::PROCESS_INFORMATION pi = {0}; si.cb = sizeof(si); std::stringstream argv_stream; std::stringstream handle_stream; // The HANDLE exposed to the child process is currently limited to only having // SYNCHRONIZE and PROCESS_QUERY_LIMITED_INFORMATION capabilities. The // SYNCHRONIZE permissions allows for WaitForSingleObject. // PROCESS_QUERY_LIMITED_INFORMATION allows for the ability to use the // GetProcessId and GetExitCodeProcess API functions. HANDLE hLauncherProcess = ::OpenProcess(SYNCHRONIZE | PROCESS_QUERY_LIMITED_INFORMATION, TRUE, GetCurrentProcessId()); if (hLauncherProcess == NULL) { return std::shared_ptr<PlatformProcess>(); } handle_stream << hLauncherProcess; std::string handle = handle_stream.str(); // In the POSIX version, the environment variable OSQUERY_WORKER is set to the // string form of the child process' process ID. However, this is not easily // doable on Windows. Since the value does not appear to be used by the rest // of osquery, we currently just set it to '1'. // // For the worker case, we also set another environment variable, // OSQUERY_LAUNCHER. OSQUERY_LAUNCHER stores the string form of a HANDLE to // the current process. This is mostly used for detecting the death of the // launcher process in WatcherWatcherRunner::start if (!setEnvVar("OSQUERY_WORKER", "1") || !setEnvVar("OSQUERY_LAUNCHER", handle.c_str())) { ::CloseHandle(hLauncherProcess); return std::shared_ptr<PlatformProcess>(); } // Since Windows does not accept a char * array for arguments, we have to // build one as a string. Therefore, we need to make sure that special // characters are not present that would obstruct the parsing of arguments. // For now, we strip out all double quotes. If the an entry in argv has // spaces, we will put double-quotes around the entry. // // NOTE: This is extremely naive and will break the moment complexities are // involved... Windows command line argument parsing is extremely // nitpicky and is different in behavior than POSIX argv parsing. // // We don't directly use argv.c_str() as the value for lpCommandLine in // CreateProcess since that argument requires a modifiable buffer. So, // instead, we off-load the contents of argv into a vector which will have its // backing memory as modifiable. for (size_t i = 0; i < argc; i++) { std::string component(argv[i]); if (component.find(" ") != std::string::npos) { boost::replace_all(component, "\"", "\\\""); argv_stream << "\"" << component << "\" "; } else { argv_stream << component << " "; } } std::string cmdline = argv_stream.str(); std::vector<char> mutable_argv(cmdline.begin(), cmdline.end()); mutable_argv.push_back('\0'); BOOL status = ::CreateProcessA(exec_path.c_str(), &mutable_argv[0], NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); unsetEnvVar("OSQUERY_WORKER"); unsetEnvVar("OSQUERY_LAUNCHER"); ::CloseHandle(hLauncherProcess); if (!status) { return std::shared_ptr<PlatformProcess>(); } auto process = std::make_shared<PlatformProcess>(pi.hProcess); ::CloseHandle(pi.hThread); ::CloseHandle(pi.hProcess); return process; }