bool isLauncherProcessDead(PlatformProcess& launcher) {
  if (!launcher.isValid()) {
    return true;
  }

  return (::getppid() != launcher.nativeHandle());
}
Beispiel #2
0
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;
}
Beispiel #3
0
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);
}
Beispiel #4
0
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;
}
Beispiel #5
0
bool PlatformProcess::operator!=(const PlatformProcess& process) const {
  return (nativeHandle() != process.nativeHandle());
}
Beispiel #6
0
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;
}
Beispiel #7
0
void WatcherRunner::stopChild(const PlatformProcess& child) const {
  child.kill();

  // Clean up the defunct (zombie) process.
  cleanupDefunctProcesses();
}
Beispiel #8
0
bool PlatformProcess::operator!=(const PlatformProcess &process) const {
  return (::GetProcessId(nativeHandle()) !=
          ::GetProcessId(process.nativeHandle()));
}