/** * Copyright (c) 2014-present, Facebook, Inc. * All rights reserved. * * This source code is licensed in accordance with the terms specified in * the LICENSE file found in the root directory of this source tree. */ #pragma once #include #include #include #include #include #include #include #include // FIXME(fmanco): env functions were split but most usages still include // process.h. Once those includes are fixed this can be removed. #include namespace osquery { /// Constant for an invalid process const auto kInvalidPid = (PlatformPidType)-1; /// Used by Windows to wait on the main execution thread extern unsigned long kLegacyThreadId; /** * @brief Categories of process states adapted to be platform agnostic * * A process can have the following states. Unfortunately, because of operating * system differences. A generic state change is not directly translatable on * Windows. Therefore, PROCESS_STATE_CHANGE will only occur on POSIX systems. */ enum ProcessState { PROCESS_ERROR = -1, PROCESS_STILL_ALIVE = 0, PROCESS_EXITED, PROCESS_STATE_CHANGE }; /** * @brief Platform-agnostic process object. * * PlatformProcess is a specialized, platform-agnostic class that handles the * process operation needs of osquery. */ class PlatformProcess : private boost::noncopyable { public: /// Default constructor marks the process as invalid explicit PlatformProcess() : id_(kInvalidPid) {} explicit PlatformProcess(PlatformPidType id); #ifdef WIN32 /* * @brief Constructor that accepts a pid_t * * Allow for the creation of a PlatformProcess object from a pid_t. On * Windows, PlatformPidType is not a pid_t because it cannot be assumed that * the PID will point to the expected process. After a process dies, the PID * can be immediately reused. Using HANDLEs (as what is done now) mitigates * this issue. */ explicit PlatformProcess(pid_t pid); #endif PlatformProcess(const PlatformProcess& src) = delete; PlatformProcess(PlatformProcess&& src) noexcept; virtual ~PlatformProcess(); PlatformProcess& operator=(const PlatformProcess& process) = delete; bool operator==(const PlatformProcess& process) const; bool operator!=(const PlatformProcess& process) const; /** * @brief Returns the process's ID * * Returns the associated process' process ID (on POSIX, pid() and * nativeHandle() do not differ). * * NOTE: In most situations, this should ideally not be used on Windows when * dealing with tracking process lifetimes. */ int pid() const; /** * @brief Returns the native "handle" object of the process. * * On Windows, this is in the of a HANDLE. For POSIX, this is just the pid_t * of the process. */ PlatformPidType nativeHandle() const { return id_; } /// Hard terminates the process bool kill() const; /** * @brief Attempt to kill a process gracefully, usually a child process. */ bool killGracefully() const; /** * @brief Wait or cleanup a process, usually a child process. * * This will wait for a process to cleanup. Use this after requesting a * graceful shutdown. * * @return true if the process was cleaned, otherwise false. */ bool cleanup() const; /// Returns whether the PlatformProcess object is valid bool isValid() const { return (id_ != kInvalidPid); } virtual ProcessState checkStatus(int& status) const; /// Returns the current process static std::shared_ptr getCurrentProcess(); /// Returns the pid of the current process static int getCurrentPid(); /// Returns the launcher process (only works for worker processes) static std::shared_ptr getLauncherProcess(); /** * @brief Creates a new worker process. * * Launches a worker process given a worker executable path, number of * arguments, and an array of arguments. All double quotes within each entry * in the array of arguments will be supplanted with a preceding blackslash. */ static std::shared_ptr launchWorker( const std::string& exec_path, int argc, char** argv); /** * @brief Creates a new extension process. * * Launches a new extension with various options. Any double quotes in the * extension name will be stripped away. */ static std::shared_ptr launchExtension( const std::string& exec_path, const std::string& extensions_socket, const std::string& extensions_timeout, const std::string& extensions_interval, bool verbose = false); /** * @brief Launches a new test Python script. * * This will launch a new Python process to run the specified script and * script arguments. This is used within the test harnesses to run example * TLS server scripts. */ static std::shared_ptr launchTestPythonScript( const std::string& args); private: /** * @brief Stores the native handle denoting the process * * "Handle" of the process. On Windows, this will be a HANDLE. On POSIX * systems, this will be a pid_t. */ PlatformPidType id_; }; #ifdef WIN32 /** * @brief Handles the resource lifetime of a PSECURITY_DESCRIPTOR * * Class to handle the scope of a PSECURITY_DESCRIPTOR from * GetSecurityInfo/GetNamedSecurityInfo class of functions (or any * PSECURITY_DESCRIPTOR pointer where the buffer is allocated via LocalAlloc) */ class SecurityDescriptor { public: explicit SecurityDescriptor(PSECURITY_DESCRIPTOR sd) : sd_(sd) {} SecurityDescriptor(SecurityDescriptor&& src) noexcept { sd_ = src.sd_; std::swap(sd_, src.sd_); } ~SecurityDescriptor() { if (sd_ != nullptr) { ::LocalFree(sd_); sd_ = nullptr; } } private: PSECURITY_DESCRIPTOR sd_{nullptr}; }; #endif /// Returns the current user's ID (UID on POSIX systems and RID for Windows) int platformGetUid(); inline void sleepFor(size_t msec) { std::chrono::milliseconds mduration(msec); std::this_thread::sleep_for(mduration); } /** * @brief Returns a handle of the specified module path * * On POSIX, this invokes dlopen with RTLD_NOW and RTLD_LOCAL flags */ ModuleHandle platformModuleOpen(const std::string& path); /** * @brief Returns a pointer of where the requested symbol exists */ void* platformModuleGetSymbol(ModuleHandle module, const std::string& symbol); /** * @brief Returns a string of the last error * * On Windows, this returns the last error message which may not necessarily be * from a module operation. It is suggested to call this immediately after a * platformModule function for best accuracy. */ std::string platformModuleGetError(); /** * @brief Closes the library handle * * On Windows, this will also try to unload the library. */ bool platformModuleClose(ModuleHandle module); /** * @brief Checks to see if the launcher process is dead * * Note, this only works on worker processes. */ bool isLauncherProcessDead(PlatformProcess& launcher); /// Sets the current process to run with background scheduling priority. void setToBackgroundPriority(); /** * @brief Returns the current processes pid * * On Windows, returns the value of GetCurrentProcessId * and on posix platforms returns getpid() */ int platformGetPid(); /** * @brief Returns the current thread id * * On Windows, returns the value of GetCurrentThreadId * and on posix platforms returns gettid() */ int platformGetTid(); /** * @brief Allows for platform specific exit logic * * On Windows this makes use of a thread specific exit APIs * to ensure that our main threads shutdown and notify the SCM * thread so we can close the service cleanly. On posix this is * just a stub to exit() */ void platformMainThreadExit(int excode); } // namespace osquery