osquery-1/osquery/examples/example_extension.cpp
Stefano Bonicatti 62336ee8bb Fix a race condition during the shutdown of the worker process (#5943)
When a thread different from the main requests a shutdown
through Initializer::requestShutdown, it should not call
waitForShutdown; there's no reason to wait, moreover the function
doesn't only wait, but also actually stops other components and then
finally calls exit().

Since the main thread is already inside the waitForShutdown call
waiting on Dispatcher::joinServices or inside the shutdown() callable
on Windows, having a secondary thread do
the same work potentially at the same time is wrong.
Moreover calling exit() from a secondary thread is most of the time
incorrect.

The waitForShutdown function has been renamed to waitThenShutdown
to better represent what it's actually doing.
2019-10-27 17:09:50 -04:00

110 lines
3.1 KiB
C++

/**
* 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.
*/
#include <osquery/sdk.h>
#include <osquery/system.h>
using namespace osquery;
class ExampleConfigPlugin : public ConfigPlugin {
public:
Status setUp() {
LOG(WARNING) << "ExampleConfigPlugin setting up";
return Status::success();
}
Status genConfig(std::map<std::string, std::string>& config) {
config["data"] = "{\"queries\":{}}";
return Status::success();
}
};
class ExampleTable : public TablePlugin {
private:
TableColumns columns() const {
return {
std::make_tuple("example_text", TEXT_TYPE, ColumnOptions::DEFAULT),
std::make_tuple(
"example_integer", INTEGER_TYPE, ColumnOptions::DEFAULT),
};
}
TableRows generate(QueryContext& request) {
TableRows results;
auto r = make_table_row();
r["example_text"] = "example";
r["example_integer"] = INTEGER(1);
results.push_back(std::move(r));
return results;
}
};
/**
* @brief A more 'complex' example table is provided to assist with tests.
*
* This table will access options and flags known to the extension.
* An extension should not assume access to any CLI flags- rather, access is
* provided via the osquery-meta table: osquery_flags.
*
* There is no API/C++ wrapper to provide seamless use of flags yet.
* We can force an implicit query to the manager though.
*
* Database access should be mediated by the *Database functions.
* Direct use of the "database" registry will lead to undefined behavior.
*/
class ComplexExampleTable : public TablePlugin {
private:
TableColumns columns() const {
return {
std::make_tuple("flag_test", TEXT_TYPE, ColumnOptions::DEFAULT),
std::make_tuple("database_test", TEXT_TYPE, ColumnOptions::DEFAULT),
};
}
TableRows generate(QueryContext& request) {
auto r = make_table_row();
// Use the basic 'force' flag to check implicit SQL usage.
auto flags =
SQL("select default_value from osquery_flags where name = 'force'");
if (flags.rows().size() > 0) {
r["flag_test"] = flags.rows().back().at("default_value");
}
std::string content;
setDatabaseValue(kPersistentSettings, "complex_example", "1");
if (getDatabaseValue(kPersistentSettings, "complex_example", content)) {
r["database_test"] = content;
}
TableRows result;
result.push_back(std::move(r));
return result;
}
};
REGISTER_EXTERNAL(ExampleConfigPlugin, "config", "example");
REGISTER_EXTERNAL(ExampleTable, "table", "example");
REGISTER_EXTERNAL(ComplexExampleTable, "table", "complex_example");
int main(int argc, char* argv[]) {
osquery::Initializer runner(argc, argv, ToolType::EXTENSION);
auto status = startExtension("example", "0.0.1");
if (!status.ok()) {
LOG(ERROR) << status.getMessage();
runner.requestShutdown(status.getCode());
}
// Finally wait for a signal / interrupt to shutdown.
runner.waitThenShutdown();
return 0;
}