Config MD5 a bit more deterministic

```
$ ./build/darwin/osquery/osqueryi --config_path=/asdfasdfadfs
E0903 11:45:02.050308 1990836992 init.cpp:370] Error reading config: config file does not exist
Using a virtual database. Need help, type '.help'
osquery> .mode line
osquery> .all osquery_info
           pid = 33700
       version = 1.5.2-43-gb06fa92
    config_md5 =
  config_valid = 0
   config_path = /asdfasdfadfs
    extensions = active
build_platform = darwin
  build_distro = 10.10
osquery> .exit

$ ./build/darwin/osquery/osqueryi
osquery> .mode line
osquery> .all osquery_info
           pid = 33781
       version = 1.5.2-43-gb06fa92
    config_md5 = 8a432ac93d3de080c62d77ba99b89783
  config_valid = 1
   config_path = /var/osquery/osquery.conf
    extensions = active
build_platform = darwin
  build_distro = 10.10
osquery> .exit
```
This commit is contained in:
Mike Arpaia 2015-09-03 11:43:36 -07:00
parent b06fa92e76
commit de58353131
5 changed files with 56 additions and 53 deletions

View File

@ -91,7 +91,7 @@ class Schedule {
*/
class Config {
private:
Config() : schedule_(Schedule()){};
Config() : schedule_(Schedule()), valid_(false){};
protected:
typedef boost::unique_lock<boost::shared_mutex> WriteLock;
@ -172,6 +172,17 @@ class Config {
*/
Status getMD5(std::string& hash);
/**
* @brief Hash a source's config data
*
* @param source is the place where the config content came from
* @param content is the content of the config data for a given source
*/
void hashSource(const std::string& source, const std::string& content);
/// Whether or not the last loaded config was valid
bool isValid();
/**
* @brief Add a pack to the osquery schedule
*/
@ -270,7 +281,8 @@ class Config {
Schedule schedule_;
std::map<std::string, QueryPerformance> performance_;
std::map<std::string, std::vector<std::string> > files_;
std::string hash_;
std::map<std::string, std::string> hash_;
bool valid_;
private:
friend class ConfigTests;

View File

@ -34,6 +34,7 @@ boost::shared_mutex config_schedule_mutex_;
boost::shared_mutex config_performance_mutex_;
boost::shared_mutex config_files_mutex_;
boost::shared_mutex config_hash_mutex_;
boost::shared_mutex config_valid_mutex_;
void Config::addPack(const Pack& pack) {
WriteLock wlock(config_schedule_mutex_);
@ -78,7 +79,7 @@ void Config::clearSchedule() {
void Config::clearHash() {
WriteLock wlock(config_hash_mutex_);
std::string().swap(hash_);
hash_.erase(hash_.begin(), hash_.end());
}
void Config::clearFiles() {
@ -86,7 +87,13 @@ void Config::clearFiles() {
files_.erase(files_.begin(), files_.end());
}
bool Config::isValid() {
ReadLock rlock(config_valid_mutex_);
return valid_;
}
Status Config::load() {
valid_ = false;
auto& config_plugin = Registry::getActive("config");
if (!Registry::exists("config", config_plugin)) {
return Status(1, "Missing config plugin " + config_plugin);
@ -102,6 +109,7 @@ Status Config::load() {
clearSchedule();
clearHash();
clearFiles();
valid_ = true;
// if there was a response, parse it and update internal state
if (response.size() > 0) {
@ -130,6 +138,8 @@ Status Config::update(const std::map<std::string, std::string>& config) {
}
for (const auto& source : config) {
hashSource(source.first, source.second);
// load the config (source.second) into a pt::ptree
std::stringstream json;
json << source.second;
@ -270,53 +280,30 @@ void Config::getPerformanceStats(
}
}
void Config::hashSource(const std::string& source, const std::string& content) {
WriteLock wlock(config_hash_mutex_);
hash_[source] =
hashFromBuffer(HASH_TYPE_MD5, &(content.c_str())[0], content.size());
}
Status Config::getMD5(std::string& hash) {
if (hash_.empty()) {
std::vector<char> buffer;
auto add = [&buffer](const std::string& text) {
for (const auto& c : text) {
buffer.push_back(c);
}
};
scheduledQueries(
[&add, &buffer](const std::string& name, const ScheduledQuery& query) {
add(name);
add(query.query);
add(std::to_string(query.interval));
for (const auto& it : query.options) {
add(it.first);
add(it.second ? "true" : "false");
}
});
auto parsers = Registry::all("config_parser");
for (const auto& parser : parsers) {
add(parser.first);
try {
if (parser.second == nullptr || parser.second.get() == nullptr) {
continue;
}
auto plugin =
std::static_pointer_cast<ConfigParserPlugin>(parser.second);
if (plugin == nullptr || plugin.get() == nullptr) {
continue;
}
std::stringstream ss;
pt::write_json(ss, plugin->getData());
add(ss.str());
} catch (const std::bad_cast& e) {
LOG(ERROR) << "Error casting config parser plugin: " << e.what();
} catch (const pt::ptree_error& e) {
LOG(ERROR)
<< "Error writing config parser content to JSON: " << e.what();
}
}
std::sort(buffer.begin(), buffer.end());
hash_ = hashFromBuffer(HASH_TYPE_MD5, &buffer[0], buffer.size());
if (valid_) {
return Status(1, "Current config is not valid");
}
hash = hash_;
ReadLock rlock(config_hash_mutex_);
std::vector<char> buffer;
buffer.reserve(hash_.size() * 32);
auto add = [&buffer](const std::string& text) {
for (const auto& c : text) {
buffer.push_back(c);
}
};
for (const auto it : hash_) {
add(it.second);
}
hash = hashFromBuffer(HASH_TYPE_MD5, &buffer[0], buffer.size());
return Status(0, "OK");
}

View File

@ -365,7 +365,10 @@ void Initializer::start() {
}
// Load the osquery config using the default/active config plugin.
Config::getInstance().load();
auto s = Config::getInstance().load();
if (!s.ok()) {
LOG(ERROR) << "Error reading config: " << s.toString();
}
// Initialize the status and result plugin logger.
initActivePlugin("logger", FLAGS_logger_plugin);

View File

@ -144,6 +144,8 @@ QueryData genOsqueryInfo(QueryContext& context) {
VLOG(1) << "Could not retrieve config hash: " << s.toString();
}
r["config_valid"] = Config::getInstance().isValid() ? INTEGER(1) : INTEGER(0);
r["config_path"] = Flag::getValue("config_path");
r["extensions"] =
(pingExtension(FLAGS_extensions_socket).ok()) ? "active" : "inactive";

View File

@ -3,13 +3,12 @@ description("Top level information about the running version of osquery.")
schema([
Column("pid", INTEGER, "Process (or thread) ID"),
Column("version", TEXT, "osquery toolkit version"),
Column("config_md5", TEXT, "md5 hash of the working configuration"),
Column("config_path", TEXT,
"Optional: path to filesystem config plugin content"),
Column("config_md5", TEXT, "md5 hash of the working configuration state"),
Column("config_valid", INTEGER, "1 if the config was loaded and considered valid, else 0"),
Column("config_path", TEXT, "Optional: path to filesystem config plugin content"),
Column("extensions", TEXT, "osquery extensions status"),
Column("build_platform", TEXT, "osquery toolkit build platform"),
Column("build_distro", TEXT,
"osquery toolkit platform distribution name (os version)"),
Column("build_distro", TEXT, "osquery toolkit platform distribution name (os version)"),
])
attributes(utility=True)
implementation("osquery@genOsqueryInfo")