bool isLauncherProcessDead(PlatformProcess& launcher) { if (!launcher.isValid()) { return true; } return (::getppid() != launcher.nativeHandle()); }
bool WatcherRunner::watch(const PlatformProcess& child) const { int status = 0; ProcessState result = checkChildProcessStatus(child, status); if (Watcher::fatesBound()) { // A signal was handled while the watcher was watching. return false; } if (!child.isValid() || result == PROCESS_ERROR) { // Worker does not exist or never existed. return false; } else if (result == PROCESS_STILL_ALIVE) { // If the inspect finds problems it will stop/restart the worker. if (!isChildSane(child)) { stopChild(child); return false; } return true; } if (result == PROCESS_EXITED) { // If the worker process existed, store the exit code. Watcher::instance().worker_status_ = status; } return true; }
bool isLauncherProcessDead(PlatformProcess &launcher) { DWORD code = 0; if (!::GetExitCodeProcess(launcher.nativeHandle(), &code)) { // TODO(#1991): If an error occurs with GetExitCodeProcess, do we want to // return a Status object to describe the error with more granularity? return false; } return (code != STILL_ACTIVE); }
ProcessState checkChildProcessStatus(const PlatformProcess &process, int &status) { DWORD exit_code = 0; if (!::GetExitCodeProcess(process.nativeHandle(), &exit_code)) { return PROCESS_ERROR; } if (exit_code == STILL_ACTIVE) { return PROCESS_STILL_ALIVE; } status = exit_code; return PROCESS_EXITED; }
bool PlatformProcess::operator!=(const PlatformProcess& process) const { return (nativeHandle() != process.nativeHandle()); }
bool WatcherRunner::isChildSane(const PlatformProcess& child) const { auto rows = SQL::selectAllFrom("processes", "pid", EQUALS, INTEGER(child.pid())); if (rows.size() == 0) { // Could not find worker process? return false; } // Get the performance state for the worker or extension. size_t sustained_latency = 0; // Compare CPU utilization since last check. size_t footprint = 0; pid_t parent = 0; // IV is the check interval in seconds, and utilization is set per-second. auto iv = std::max(getWorkerLimit(INTERVAL), (size_t)1); { WatcherLocker locker; auto& state = Watcher::getState(child); UNSIGNED_BIGINT_LITERAL user_time = 0, system_time = 0; try { parent = AS_LITERAL(BIGINT_LITERAL, rows[0].at("parent")); user_time = AS_LITERAL(BIGINT_LITERAL, rows[0].at("user_time")) / iv; system_time = AS_LITERAL(BIGINT_LITERAL, rows[0].at("system_time")) / iv; footprint = AS_LITERAL(BIGINT_LITERAL, rows[0].at("resident_size")); } catch (const std::exception& e) { state.sustained_latency = 0; } // Check the difference of CPU time used since last check. if (user_time - state.user_time > getWorkerLimit(UTILIZATION_LIMIT) || system_time - state.system_time > getWorkerLimit(UTILIZATION_LIMIT)) { state.sustained_latency++; } else { state.sustained_latency = 0; } // Update the current CPU time. state.user_time = user_time; state.system_time = system_time; // Check if the sustained difference exceeded the acceptable latency limit. sustained_latency = state.sustained_latency; // Set the memory footprint as the amount of resident bytes allocated // since the process image was created (estimate). // A more-meaningful check would limit this to writable regions. if (state.initial_footprint == 0) { state.initial_footprint = footprint; } // Set the measured/limit-applied footprint to the post-launch allocations. if (footprint < state.initial_footprint) { footprint = 0; } else { footprint = footprint - state.initial_footprint; } } // Only make a decision about the child sanity if it is still the watcher's // child. It's possible for the child to die, and its pid reused. if (parent != PlatformProcess::getCurrentProcess()->pid()) { // The child's parent is not the watcher. Watcher::reset(child); // Do not stop or call the child insane, since it is not our child. return true; } if (sustained_latency > 0 && sustained_latency * iv >= getWorkerLimit(LATENCY_LIMIT)) { LOG(WARNING) << "osqueryd worker (" << child.pid() << ") system performance limits exceeded"; return false; } // Check if the private memory exceeds a memory limit. if (footprint > 0 && footprint > getWorkerLimit(MEMORY_LIMIT) * 1024 * 1024) { LOG(WARNING) << "osqueryd worker (" << child.pid() << ") memory limits exceeded: " << footprint; return false; } // The worker is sane, no action needed. // Attempt to flush status logs to the well-behaved worker. if (use_worker_) { relayStatusLogs(); } return true; }
void WatcherRunner::stopChild(const PlatformProcess& child) const { child.kill(); // Clean up the defunct (zombie) process. cleanupDefunctProcesses(); }
bool PlatformProcess::operator!=(const PlatformProcess &process) const { return (::GetProcessId(nativeHandle()) != ::GetProcessId(process.nativeHandle())); }