Skip to content

Commit

Permalink
Augeas Table: Fix like queries
Browse files Browse the repository at this point in the history
Add querying by LIKE to the augeas table. This fixes querying the
`/augeas` part of the tree, and should additionally improve the behavior
around file paths.

Prior, there is implicit magic that makes the path part work -- we
append `//*` the augeas recursive wildcard. This combined with sqlite
filtering made it appear to work for simple trailing wildcards. But, it
would fail for leading or infix wildcards.

This replaces that with some additional routines to allow wildcard
conversion. The UX is a bit weird, in that `path` should _not_ have a
trailing wildcard, and the behavior of `%` vs `%%` is different. But
this feels like the simplest bridge between osquery and augeas.

This is mostly clearly visible with `select * from augeas where node like "/augeas/load/%";` returning zero results.

We could consider whether to keep using `/files//*` as the default
pattern or not.
  • Loading branch information
directionless committed Mar 3, 2021
1 parent dcef5d5 commit d6f66ff
Showing 1 changed file with 59 additions and 0 deletions.
59 changes: 59 additions & 0 deletions osquery/tables/system/posix/augeas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,20 @@ class AugeasHandle {

static AugeasHandle kAugeasHandle;

// Augeas presents data as a slash seperated tree. It uses `/*` as a
// single level wildcard, and `//*` as a recursive wildcard. However,
// sqlite uses % as a wildcard. To allow for LIKE expressions, we need
// to convert.
void convertWildcards(std::string& str) {
size_t pos;
while ((pos = str.find("%%")) != std::string::npos) {
str.replace(pos, 2, "/*");
}
while ((pos = str.find("%")) != std::string::npos) {
str.replace(pos, 1, "*");
}
}

QueryData genAugeas(QueryContext& context) {
// Strategy for handling augeas
// (As informed by forensic examination of the underlying code)
Expand Down Expand Up @@ -202,12 +216,27 @@ QueryData genAugeas(QueryContext& context) {
patterns.insert(nodes.begin(), nodes.end());
}

if (context.hasConstraint("node", LIKE)) {
auto nodes = context.constraints["node"].getAll(LIKE);
for (std::string node : nodes) {
if (node.empty()) {
continue;
}
convertWildcards(node);
patterns.insert(node);
}
}

if (context.hasConstraint("path", EQUALS)) {
// Allow requests via filesystem path.
auto paths = context.constraints["path"].getAll(EQUALS);
std::ostringstream pattern;

for (const auto& path : paths) {
if (path.empty()) {
continue;
}

pattern << "/files" << path;
patterns.insert(pattern.str());

Expand All @@ -222,6 +251,36 @@ QueryData genAugeas(QueryContext& context) {
}
}

// This LIKE strategy only works because we've loaded the entire
// augeas system. If we ever move to loading by explicit files, this
// will break.
if (context.hasConstraint("path", LIKE)) {
auto paths = context.constraints["path"].getAll(LIKE);
std::ostringstream pattern;

for (std::string path : paths) {
if (path.empty()) {
continue;
}

convertWildcards(path);

pattern << "/files" << path;
patterns.insert(pattern.str());

pattern.clear();
pattern.str(std::string());

if (!strncmp(&path.back(), "*", 1)) {
pattern << "/files" << path << "//*";
patterns.insert(pattern.str());
}

pattern.clear();
pattern.str(std::string());
}
}

if (patterns.empty()) {
matchAugeasPattern(aug, "/files//*", results, context);
} else {
Expand Down

0 comments on commit d6f66ff

Please sign in to comment.