void WatcherRunner::start() { // Set worker performance counters to an initial state. Watcher::resetWorkerCounters(0); // Enter the watch loop. do { if (use_worker_ && !watch(Watcher::getWorker())) { if (Watcher::fatesBound()) { // A signal has interrupted the watcher. break; } // The watcher failed, create a worker. createWorker(); } // Loop over every managed extension and check sanity. std::vector<std::string> failing_extensions; for (const auto& extension : Watcher::extensions()) { if (!watch(*extension.second)) { if (!createExtension(extension.first)) { failing_extensions.push_back(extension.first); } } } // If any extension creations failed, stop managing them. for (const auto& failed_extension : failing_extensions) { Watcher::removeExtensionPath(failed_extension); } pauseMilli(getWorkerLimit(INTERVAL) * 1000); } while (!interrupted() && ok()); }
void SchedulerRunner::start() { // Start the counter at the second. auto i = osquery::getUnixTime(); for (; (timeout_ == 0) || (i <= timeout_); ++i) { Config::get().scheduledQueries( ([&i](const std::string& name, const ScheduledQuery& query) { if (query.splayed_interval > 0 && i % query.splayed_interval == 0) { TablePlugin::kCacheInterval = query.splayed_interval; TablePlugin::kCacheStep = i; launchQuery(name, query); } })); // Configuration decorators run on 60 second intervals only. if ((i % 60) == 0) { runDecorators(DECORATE_INTERVAL, i); } if (FLAGS_schedule_reload > 0 && (i % FLAGS_schedule_reload) == 0) { if (FLAGS_schedule_reload_sql) { SQLiteDBManager::resetPrimary(); } resetDatabase(); } // GLog is not re-entrant, so logs must be flushed in a dedicated thread. if ((i % 3) == 0) { relayStatusLogs(true); } // Put the thread into an interruptible sleep without a config instance. pauseMilli(interval_ * 1000); if (interrupted()) { break; } } }
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() << ")"; }
void TLSLogForwarderRunner::start() { while (!interrupted()) { check(); // Cool off and time wait the configured period. pauseMilli(FLAGS_logger_tls_period * 1000); } }
void BufferedLogForwarder::start() { while (!interrupted()) { check(); // Cool off and time wait the configured period. pauseMilli(log_period_); } }
Status INotifyEventPublisher::run() { // Get a while wrapper for free. char buffer[kINotifyBufferSize]; fd_set set; FD_ZERO(&set); FD_SET(getHandle(), &set); struct timeval timeout = {1, 0}; int selector = ::select(getHandle() + 1, &set, nullptr, nullptr, &timeout); if (selector == -1) { LOG(WARNING) << "Could not read inotify handle"; return Status(1, "INotify handle failed"); } if (selector == 0) { // Read timeout. return Status(0, "Continue"); } ssize_t record_num = ::read(getHandle(), buffer, kINotifyBufferSize); if (record_num == 0 || record_num == -1) { return Status(1, "INotify read failed"); } for (char* p = buffer; p < buffer + record_num;) { // Cast the inotify struct, make shared pointer, and append to contexts. auto event = reinterpret_cast<struct inotify_event*>(p); if (event->mask & IN_Q_OVERFLOW) { // The inotify queue was overflown (remove all paths). Status stat = restartMonitoring(); if (!stat.ok()) { return stat; } } if (event->mask & IN_IGNORED) { // This inotify watch was removed. removeMonitor(event->wd, false); } else if (event->mask & IN_MOVE_SELF) { // This inotify path was moved, but is still watched. removeMonitor(event->wd, true); } else if (event->mask & IN_DELETE_SELF) { // A file was moved to replace the watched path. removeMonitor(event->wd, false); } else { auto ec = createEventContextFrom(event); if (!ec->action.empty()) { fire(ec); } } // Continue to iterate p += (sizeof(struct inotify_event)) + event->len; } pauseMilli(kINotifyMLatency); return Status(0, "OK"); }
void WatcherWatcherRunner::start() { while (!interrupted()) { if (isLauncherProcessDead(*watcher_)) { // Watcher died, the worker must follow. VLOG(1) << "osqueryd worker (" << PlatformProcess::getCurrentProcess()->pid() << ") detected killed watcher (" << watcher_->pid() << ")"; // The watcher watcher is a thread. Do not join services after removing. Initializer::requestShutdown(); break; } pauseMilli(getWorkerLimit(INTERVAL) * 1000); } }
Status UdevEventPublisher::run() { int fd = 0; { WriteLock lock(mutex_); if (monitor_ == nullptr) { return Status(1); } fd = udev_monitor_get_fd(monitor_); } struct pollfd fds[1]; fds[0].fd = fd; fds[0].events = POLLIN; int selector = ::poll(fds, 1, 1000); if (selector == -1 && errno != EINTR && errno != EAGAIN) { LOG(ERROR) << "Could not read udev monitor"; return Status(1, "udev monitor failed."); } if (selector == 0 || !(fds[0].revents & POLLIN)) { // Read timeout. return Status(0, "Finished"); } { WriteLock lock(mutex_); struct udev_device* device = udev_monitor_receive_device(monitor_); if (device == nullptr) { LOG(ERROR) << "udev monitor returned invalid device"; return Status(1, "udev monitor failed."); } auto ec = createEventContextFrom(device); fire(ec); udev_device_unref(device); } pauseMilli(kUdevMLatency); return Status(0, "OK"); }
void TLSConfigRefreshRunner::start() { while (!interrupted()) { // Cool off and time wait the configured period. // Apply this interruption initially as at t=0 the config was read. pauseMilli(FLAGS_config_tls_refresh * 1000); // Access the configuration. auto plugin = Registry::get("config", "tls"); if (plugin != nullptr) { auto config_plugin = std::dynamic_pointer_cast<ConfigPlugin>(plugin); // The config instance knows the TLS plugin is selected. std::map<std::string, std::string> config; if (config_plugin->genConfig(config)) { Config::getInstance().update(config); } } } }
void SchedulerRunner::start() { // Start the counter at the second. auto i = osquery::getUnixTime(); for (; (timeout_ == 0) || (i <= timeout_); ++i) { Config::getInstance().scheduledQueries( ([&i](const std::string& name, const ScheduledQuery& query) { if (query.splayed_interval > 0 && i % query.splayed_interval == 0) { TablePlugin::kCacheInterval = query.splayed_interval; TablePlugin::kCacheStep = i; launchQuery(name, query); } })); // Configuration decorators run on 60 second intervals only. if (i % 60 == 0) { runDecorators(DECORATE_INTERVAL, i); } // Put the thread into an interruptible sleep without a config instance. pauseMilli(interval_ * 1000); if (interrupted()) { break; } } }
Status KernelEventPublisher::run() { { WriteLock lock(mutex_); if (queue_ == nullptr) { return Status(1, "No kernel communication"); } } // Perform queue read min/max synchronization. try { int drops = 0; WriteLock lock(mutex_); if ((drops = queue_->kernelSync(OSQUERY_OPTIONS_NO_BLOCK)) > 0 && kToolType == ToolType::DAEMON) { LOG(WARNING) << "Dropping " << drops << " kernel events"; } } catch (const CQueueException &e) { LOG(WARNING) << "Queue synchronization error: " << e.what(); } auto dequeueEvents = [this]() { // Dequeue several events while holding the lock. int max_before_lock = kKernelEventsIterate; while (max_before_lock > 0) { // Request an event from the synchronized, safe, portion of the queue. CQueue::event *event = nullptr; auto event_type = queue_->dequeue(&event); if (event_type == OSQUERY_NULL_EVENT) { return false; } // Each event type may use a specific event type structure. KernelEventContextRef ec = nullptr; switch (event_type) { case OSQUERY_PROCESS_EVENT: ec = createEventContextFrom<osquery_process_event_t>(event_type, event); fire(ec); break; case OSQUERY_FILE_EVENT: ec = createEventContextFrom<osquery_file_event_t>(event_type, event); fire(ec); break; default: LOG(WARNING) << "Unknown kernel event received: " << event_type; break; } max_before_lock--; } return true; }; // Iterate over each event type in the queue and appropriately fire each. int max_before_sync = kKernelEventsSyncMax; while (max_before_sync > 0) { WriteLock lock(mutex_); // The kernel publisher may have been torn down. if (queue_ == nullptr) { break; } // A NULL event occurred, stop dequeuing. if (!dequeueEvents()) { break; } // Append the number of dequeue events to the synchronization counter. max_before_sync -= kKernelEventsIterate; } // Pause for a cool-off since we implement comms in a no-blocking mode. pauseMilli(1000); return Status(0, "Continue"); }