Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix waiting for mutiple extensions to be loaded not correctly waiting for timeout #8067

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 15 additions & 12 deletions osquery/core/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -652,19 +652,22 @@ bool Initializer::isWatcher() {

void Initializer::initActivePlugin(const std::string& type,
const std::string& name) const {
auto status = applyExtensionDelay(([type, name](bool& stop) {
auto rs = RegistryFactory::get().setActive(type, name);
if (rs.ok()) {
// The plugin was found, and is now active.
return rs;
}
size_t delay = 0;
auto status = applyExtensionDelay(
([type, name](bool& stop) {
auto rs = RegistryFactory::get().setActive(type, name);
if (rs.ok()) {
// The plugin was found, and is now active.
return rs;
}

if (!Watcher::hasManagedExtensions()) {
// The plugin must be local, and is not active, problem.
stop = true;
}
return rs;
}));
if (!Watcher::hasManagedExtensions()) {
// The plugin must be local, and is not active, problem.
stop = true;
}
return rs;
}),
delay);

if (!status.ok()) {
std::string message = "Cannot activate " + name + " " + type +
Expand Down
80 changes: 43 additions & 37 deletions osquery/extensions/extensions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,8 @@ class ExtensionManagerWatcher : public ExtensionWatcher {
std::map<RouteUUID, size_t> failures_;
};

Status applyExtensionDelay(std::function<Status(bool& stop)> predicate) {
// Make sure the extension manager path exists, and is writable.
size_t delay = 0;
Status applyExtensionDelay(std::function<Status(bool& stop)> predicate,
size_t& delay) {
// The timeout is given in seconds, but checked interval is microseconds.
size_t timeout = atoi(FLAGS_extensions_timeout.c_str()) * 1000;
if (timeout < kExtensionInitializeLatency * 10) {
Expand All @@ -178,23 +177,27 @@ Status applyExtensionDelay(std::function<Status(bool& stop)> predicate) {
}

Status extensionPathActive(const std::string& path, bool use_timeout = false) {
return applyExtensionDelay(([path, &use_timeout](bool& stop) {
if (socketExists(path)) {
try {
// Create a client with a 10-second receive timeout.
ExtensionManagerClient client(path, 10);
auto status = client.ping();
return Status::success();
} catch (const std::exception& /* e */) {
// Path might exist without a connected extension or extension manager.
}
}
// Only check active once if this check does not allow a timeout.
if (!use_timeout) {
stop = true;
}
return Status(1, "Extension socket not available: " + path);
}));
size_t delay = 0;
return applyExtensionDelay(
([path, &use_timeout](bool& stop) {
if (socketExists(path)) {
try {
// Create a client with a 10-second receive timeout.
ExtensionManagerClient client(path, 10);
auto status = client.ping();
return Status::success();
} catch (const std::exception& /* e */) {
// Path might exist without a connected extension or extension
// manager.
}
}
// Only check active once if this check does not allow a timeout.
if (!use_timeout) {
stop = true;
}
return Status(1, "Extension socket not available: " + path);
}),
delay);
}

ExtensionWatcher::ExtensionWatcher(const std::string& path,
Expand Down Expand Up @@ -754,30 +757,33 @@ Status startExtensionManager(const std::string& manager_path) {

// The shell or daemon flag configuration may require an extension.
if (!FLAGS_extensions_require.empty()) {
size_t delay = 0;
bool waited = false;
auto extensions = osquery::split(FLAGS_extensions_require, ",");
for (const auto& extension : extensions) {
status = applyExtensionDelay(([extension, &waited](bool& stop) {
ExtensionList registered_extensions;
if (getExtensions(registered_extensions).ok()) {
for (const auto& existing : registered_extensions) {
if (existing.second.name == extension) {
return pingExtension(getExtensionSocket(existing.first));
status = applyExtensionDelay(
([extension, &waited](bool& stop) {
ExtensionList registered_extensions;
if (getExtensions(registered_extensions).ok()) {
for (const auto& existing : registered_extensions) {
if (existing.second.name == extension) {
return pingExtension(getExtensionSocket(existing.first));
}
}
}
}
}

if (waited) {
// If we have already waited for the timeout period, stop early.
stop = true;
}
return Status(
1, "Required extension not found or not loaded: " + extension);
}));
if (waited) {
// If we have already waited for the timeout period, stop early.
stop = true;
}
return Status(
1, "Required extension not found or not loaded: " + extension);
}),
delay);

// A required extension was not loaded.
waited = true;
if (!status.ok()) {
// A required extension was not loaded in time.
waited = true;
LOG(WARNING) << status.getMessage();
return status;
}
Expand Down
4 changes: 3 additions & 1 deletion osquery/extensions/extensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,11 @@ Status pingExtension(const std::string& path);
* loaded or broadcasted a registry.
*
* @param predicate return true or set stop to end the timeout loop.
* @param delay the value to check the timeout against.
* @return the last status from the predicate.
*/
Status applyExtensionDelay(std::function<Status(bool& stop)> predicate);
Status applyExtensionDelay(std::function<Status(bool& stop)> predicate,
size_t& delay);

/**
* @brief Read the autoload flags and return a set of autoload paths.
Expand Down
Loading