diff --git a/include/osquery/filesystem.h b/include/osquery/filesystem.h index 5a3de6f6b8c..f2ec85512ea 100644 --- a/include/osquery/filesystem.h +++ b/include/osquery/filesystem.h @@ -26,6 +26,13 @@ namespace osquery { * this many wildcards. */ const unsigned int kMaxDirectoryTraversalDepth = 40; +typedef unsigned int ReturnSetting; +enum { + REC_LIST_FILES = 0x1, // Return only files + REC_LIST_FOLDERS = 0x2, // Return only folders + REC_EVENT_OPT = 0x4, // Enable optimizations for file event resolutions + REC_LIST_ALL = REC_LIST_FILES | REC_LIST_FOLDERS +}; const std::string kWildcardCharacter = "%"; const std::string kWildcardCharacterRecursive = @@ -125,6 +132,30 @@ Status listDirectoriesInDirectory(const boost::filesystem::path& path, Status resolveFilePattern(const boost::filesystem::path& fs_path, std::vector& results); +/** + * @brief Given a wildcard filesystem patten, resolve all possible paths + * + * @code{.cpp} + * std::vector results; + * auto s = resolveFilePattern("/Users/marpaia/Downloads/%", results); + * if (s.ok()) { + * for (const auto& result : results) { + * LOG(INFO) << result; + * } + * } + * @endcode + * + * @param fs_path The filesystem pattern + * @param results The vector in which all results will be returned + * @param setting Do you want files returned, folders or both? + * + * @return An instance of osquery::Status which indicates the success or + * failure of the operation + */ +Status resolveFilePattern(const boost::filesystem::path& fs_path, + std::vector& results, + ReturnSetting setting); + /** * @brief Get directory portion of a path. * diff --git a/osquery/config/config.cpp b/osquery/config/config.cpp index 5a2c3f894b4..e4925f7d1a6 100644 --- a/osquery/config/config.cpp +++ b/osquery/config/config.cpp @@ -105,13 +105,15 @@ Status Config::genConfig(OsqueryConfig& conf) { } if (tree.count("additional_monitoring") > 0) { + ReturnSetting settings = REC_LIST_FOLDERS | REC_EVENT_OPT; for (const pt::ptree::value_type& v : tree.get_child("additional_monitoring")) { if (v.first == "file_paths") { for (const pt::ptree::value_type& file_cat : v.second) { for (const pt::ptree::value_type& file : file_cat.second) { osquery::resolveFilePattern(file.second.get_value(), - conf.eventFiles[file_cat.first]); + conf.eventFiles[file_cat.first], + settings); } } } diff --git a/osquery/config/config_tests.cpp b/osquery/config/config_tests.cpp index 3b445387dfa..baad3e1a92a 100644 --- a/osquery/config/config_tests.cpp +++ b/osquery/config/config_tests.cpp @@ -71,8 +71,8 @@ TEST_F(ConfigTests, test_threatfiles_execute) { auto files = Config::getInstance().getWatchedFiles(); EXPECT_EQ(files.size(), 2); - EXPECT_EQ(files["downloads"].size(), 9); - EXPECT_EQ(files["system_binaries"].size(), 5); + EXPECT_EQ(files["downloads"].size(), 1); + EXPECT_EQ(files["system_binaries"].size(), 2); } } diff --git a/osquery/core/test_util.cpp b/osquery/core/test_util.cpp index d148631bae4..3d83ae39126 100644 --- a/osquery/core/test_util.cpp +++ b/osquery/core/test_util.cpp @@ -254,7 +254,7 @@ void createMockFileStructure() { "/deep11/deep2/deep3/"); boost::filesystem::create_directories(kFakeDirectory + "/deep1/deep2/"); writeTextFile(kFakeDirectory + "/root.txt", "root"); - writeTextFile(kFakeDirectory + "/toor.txt", "toor"); + writeTextFile(kFakeDirectory + "/door.txt", "toor"); writeTextFile(kFakeDirectory + "/roto.txt", "roto"); writeTextFile(kFakeDirectory + "/deep1/level1.txt", "l1"); writeTextFile(kFakeDirectory + "/deep11/not_bash", "l1"); diff --git a/osquery/events/darwin/fsevents.cpp b/osquery/events/darwin/fsevents.cpp index fb96df3dc9e..dc7e99eb7da 100644 --- a/osquery/events/darwin/fsevents.cpp +++ b/osquery/events/darwin/fsevents.cpp @@ -3,7 +3,7 @@ * All rights reserved. * * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant + * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * */ @@ -20,6 +20,7 @@ namespace osquery { std::map kMaskActions = { {kFSEventStreamEventFlagItemChangeOwner, "ATTRIBUTES_MODIFIED"}, {kFSEventStreamEventFlagItemXattrMod, "ATTRIBUTES_MODIFIED"}, + {kFSEventStreamEventFlagItemInodeMetaMod, "ATTRIBUTES_MODIFIED"}, {kFSEventStreamEventFlagItemCreated, "CREATED"}, {kFSEventStreamEventFlagItemRemoved, "DELETED"}, {kFSEventStreamEventFlagItemModified, "UPDATED"}, @@ -156,7 +157,6 @@ void FSEventsEventPublisher::Callback( break; } } - ec->path = std::string(((char**)event_paths)[i]); EventFactory::fire(ec); } @@ -165,6 +165,9 @@ void FSEventsEventPublisher::Callback( bool FSEventsEventPublisher::shouldFire( const FSEventsSubscriptionContextRef& mc, const FSEventsEventContextRef& ec) const { + // This is stopping us from getting events on links. + // If we need this feature later, this line will have to be updated to + // understand links. ssize_t found = ec->path.find(mc->path); if (found != 0) { return false; diff --git a/osquery/events/darwin/fsevents_tests.cpp b/osquery/events/darwin/fsevents_tests.cpp index 222793ced2b..b57a4c97759 100644 --- a/osquery/events/darwin/fsevents_tests.cpp +++ b/osquery/events/darwin/fsevents_tests.cpp @@ -3,7 +3,7 @@ * All rights reserved. * * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant + * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * */ @@ -29,9 +29,7 @@ int kMaxEventLatency = 3000; class FSEventsTests : public testing::Test { protected: - void TearDown() { - boost::filesystem::remove_all(kRealTestPath); - } + void TearDown() { boost::filesystem::remove_all(kRealTestPath); } void StartEventLoop() { event_pub_ = std::make_shared(); diff --git a/osquery/events/events.cpp b/osquery/events/events.cpp index bb273fecb18..afeeeed4f0c 100644 --- a/osquery/events/events.cpp +++ b/osquery/events/events.cpp @@ -3,7 +3,7 @@ * All rights reserved. * * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant + * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * */ @@ -401,8 +401,7 @@ Status EventFactory::run(EventPublisherID& type_id) { EventPublisherRef publisher; try { publisher = EventFactory::getInstance().getEventPublisher(type_id); - } - catch (std::out_of_range& e) { + } catch (std::out_of_range& e) { return Status(1, "No event type found"); } @@ -418,7 +417,8 @@ Status EventFactory::run(EventPublisherID& type_id) { // The runloop status is not reflective of the event type's. publisher->tearDown(); - VLOG(1) << "Event publisher " << publisher->type() << " runloop terminated"; + VLOG(1) << "Event publisher " << publisher->type() + << " runloop terminated for reason: " << status.getMessage(); return Status(0, "OK"); } @@ -493,8 +493,7 @@ Status EventFactory::addSubscription(EventPublisherID& type_id, EventPublisherRef publisher; try { publisher = getInstance().getEventPublisher(type_id); - } - catch (std::out_of_range& e) { + } catch (std::out_of_range& e) { return Status(1, "No event type found"); } @@ -508,8 +507,7 @@ size_t EventFactory::numSubscriptions(EventPublisherID& type_id) { EventPublisherRef publisher; try { publisher = EventFactory::getInstance().getEventPublisher(type_id); - } - catch (std::out_of_range& e) { + } catch (std::out_of_range& e) { return 0; } return publisher->numSubscriptions(); @@ -539,8 +537,7 @@ Status EventFactory::deregisterEventPublisher(EventPublisherID& type_id) { EventPublisherRef publisher; try { publisher = ef.getEventPublisher(type_id); - } - catch (std::out_of_range& e) { + } catch (std::out_of_range& e) { return Status(1, "No event publisher to deregister"); } diff --git a/osquery/events/events_tests.cpp b/osquery/events/events_tests.cpp index f5712873741..73c5c71e791 100644 --- a/osquery/events/events_tests.cpp +++ b/osquery/events/events_tests.cpp @@ -3,7 +3,7 @@ * All rights reserved. * * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant + * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * */ diff --git a/osquery/events/linux/inotify.cpp b/osquery/events/linux/inotify.cpp index 12ff6724a2b..9e6e0261e1a 100644 --- a/osquery/events/linux/inotify.cpp +++ b/osquery/events/linux/inotify.cpp @@ -63,6 +63,21 @@ void INotifyEventPublisher::tearDown() { inotify_handle_ = -1; } +Status INotifyEventPublisher::restartMonitoring(){ + if (last_restart_ != 0 && getUnixTime() - last_restart_ < 10) { + return Status(1, "Overflow"); + } + last_restart_ = getUnixTime(); + VLOG(1) << "Got an overflow, trying to restart..."; + for(const auto& desc : descriptors_){ + removeMonitor(desc, 1); + } + path_descriptors_.clear(); + descriptor_paths_.clear(); + configure(); + return Status(0, "OK"); +} + Status INotifyEventPublisher::run() { // Get a while wrapper for free. char buffer[BUFFER_SIZE]; @@ -92,7 +107,10 @@ Status INotifyEventPublisher::run() { auto event = reinterpret_cast(p); if (event->mask & IN_Q_OVERFLOW) { // The inotify queue was overflown (remove all paths). - return Status(1, "Overflow"); + Status stat = restartMonitoring(); + if(!stat.ok()){ + return stat; + } } if (event->mask & IN_IGNORED) { @@ -106,6 +124,9 @@ Status INotifyEventPublisher::run() { removeMonitor(event->wd, false); } else { auto ec = createEventContextFrom(event); + if(event->mask & IN_CREATE && isDirectory(ec->path).ok()){ + addMonitor(ec->path, 1); + } fire(ec); } // Continue to iterate @@ -129,8 +150,6 @@ INotifyEventContextRef INotifyEventPublisher::createEventContextFrom( path << "/" << event->name; } ec->path = path.str(); - - // Set the action (may be multiple) for (const auto& action : kMaskActions) { if (event->mask & action.first) { ec->action = action.second; @@ -179,15 +198,10 @@ bool INotifyEventPublisher::addMonitor(const std::string& path, if (recursive && isDirectory(path).ok()) { std::vector children; // Get a list of children of this directory (requesed recursive watches). - if (!listFilesInDirectory(path, children).ok()) { - return false; - } + listDirectoriesInDirectory(path, children); for (const auto& child : children) { - // Only watch child directories, a watch on the directory implies files. - if (isDirectory(child).ok()) { - addMonitor(child, recursive); - } + addMonitor(child, recursive); } } diff --git a/osquery/events/linux/inotify.h b/osquery/events/linux/inotify.h index 7325687fbfd..7d5a0d07f41 100644 --- a/osquery/events/linux/inotify.h +++ b/osquery/events/linux/inotify.h @@ -127,12 +127,15 @@ class INotifyEventPublisher int getHandle() { return inotify_handle_; } /// Get the number of actual INotify active descriptors. int numDescriptors() { return descriptors_.size(); } + /// If we overflow, try and restart the monitor + Status restartMonitoring(); // Consider an event queue if separating buffering from firing/servicing. DescriptorVector descriptors_; PathDescriptorMap path_descriptors_; DescriptorPathMap descriptor_paths_; int inotify_handle_; + int last_restart_; public: FRIEND_TEST(INotifyTests, test_inotify_optimization); diff --git a/osquery/filesystem/filesystem.cpp b/osquery/filesystem/filesystem.cpp index 0719738f86c..b0af93f61b3 100644 --- a/osquery/filesystem/filesystem.cpp +++ b/osquery/filesystem/filesystem.cpp @@ -10,7 +10,6 @@ #include #include -#include #include #include @@ -198,27 +197,33 @@ Status listDirectoriesInDirectory(const boost::filesystem::path& path, */ Status doubleStarTraversal(const boost::filesystem::path& fs_path, std::vector& results, + ReturnSetting setting, unsigned int rec_depth) { if (rec_depth >= kMaxDirectoryTraversalDepth) { return Status(2, fs_path.string().c_str()); } // List files first - Status stat = listFilesInDirectory(fs_path, results); - if (!stat.ok()) { - return Status(0, "OK"); + if (setting & REC_LIST_FILES) { + Status stat = listFilesInDirectory(fs_path, results); + if (!stat.ok()) { + return Status(0, "OK"); + } } std::vector folders; - stat = listDirectoriesInDirectory(fs_path, folders); + Status stat = listDirectoriesInDirectory(fs_path, folders); if (!stat.ok()) { return Status(0, "OK"); } - + if (setting & REC_LIST_FOLDERS) { + results.push_back(fs_path.string()); + } for (const auto& folder : folders) { boost::filesystem::path p(folder); if (boost::filesystem::is_symlink(p)) { continue; } - stat = doubleStarTraversal(folder, results, rec_depth + 1); + + stat = doubleStarTraversal(folder, results, setting, rec_depth + 1); if (!stat.ok() && stat.getCode() == 2) { return stat; } @@ -245,18 +250,25 @@ Status doubleStarTraversal(const boost::filesystem::path& fs_path, */ Status resolveLastPathComponent(const boost::filesystem::path& fs_path, std::vector& results, + ReturnSetting setting, const std::vector& components, unsigned int rec_depth) { // Is the last component a double star? if (components[components.size() - 1] == kWildcardCharacterRecursive) { - Status stat = - doubleStarTraversal(fs_path.parent_path(), results, rec_depth); - return stat; + if (setting & REC_EVENT_OPT) { + results.push_back(fs_path.parent_path().string()); + return Status(0, "OK"); + } else { + Status stat = doubleStarTraversal( + fs_path.parent_path(), results, setting, rec_depth); + return stat; + } } // Is the path a file try { - if (boost::filesystem::is_regular_file(fs_path)) { + if (setting == REC_LIST_FILES && + boost::filesystem::is_regular_file(fs_path)) { results.push_back(fs_path.string()); return Status(0, "OK"); } @@ -266,15 +278,33 @@ Status resolveLastPathComponent(const boost::filesystem::path& fs_path, } std::vector files; - Status stat = listFilesInDirectory(fs_path.parent_path(), files); - if (!stat.ok()) { - return stat; + std::vector folders; + Status stat_file = listFilesInDirectory(fs_path.parent_path(), files); + Status stat_fold = listDirectoriesInDirectory(fs_path.parent_path(), folders); + + if (!stat_file.ok()) { + return stat_file; + } + if (!stat_fold.ok()) { + return stat_fold; } // Is the last component a wildcard? if (components[components.size() - 1] == kWildcardCharacter) { - for (const auto& file : files) { - results.push_back(file); + if (setting & REC_EVENT_OPT) { + results.push_back(fs_path.parent_path().string()); + return Status(0, "OK"); + } + if (setting & REC_LIST_FOLDERS) { + results.push_back(fs_path.parent_path().string()); + for (const auto& fold : folders) { + results.push_back(fold); + } + } + if (setting & REC_LIST_FILES) { + for (const auto& file : files) { + results.push_back(file); + } } return Status(0, "OK"); } @@ -285,7 +315,7 @@ Status resolveLastPathComponent(const boost::filesystem::path& fs_path, std::vector(components.begin(), components.end() - 1), "/"); - // Is this a .*% type file match + // Is this a (.*)% type file match if (components[components.size() - 1].find(kWildcardCharacter, 1) != std::string::npos && components[components.size() - 1][0] != kWildcardCharacter[0]) { @@ -294,25 +324,49 @@ Status resolveLastPathComponent(const boost::filesystem::path& fs_path, processed_path + "/" + components[components.size() - 1].substr( 0, components[components.size() - 1].find(kWildcardCharacter, 1)); - for (const auto& file : files) { - if (file.find(prefix, 0) != 0) { - continue; + if (setting & REC_LIST_FOLDERS) { + for (const auto& fold : folders) { + if (fold.find(prefix, 0) != 0) { + continue; + } + results.push_back(fold); } - results.push_back(file); } + if (setting & REC_LIST_FILES || setting & REC_EVENT_OPT) { + for (const auto& file : files) { + if (file.find(prefix, 0) != 0) { + continue; + } + results.push_back(file); + } + } + // Should be a return here? + return Status(0, "OK"); } // Is this a %(.*) type file match if (components[components.size() - 1][0] == kWildcardCharacter[0]) { std::string suffix = components[components.size() - 1].substr(1); - - for (const auto& file : files) { - boost::filesystem::path p(file); - std::string file_name = p.filename().string(); - size_t pos = file_name.find(suffix); - if (pos != std::string::npos && - pos + suffix.length() == file_name.length()) { - results.push_back(file); + if (setting & REC_LIST_FOLDERS) { + for (const auto& fold : folders) { + std::string file_name = + boost::filesystem::path(fold).filename().string(); + size_t pos = file_name.find(suffix); + if (pos != std::string::npos && + pos + suffix.length() == file_name.length()) { + results.push_back(fold); + } + } + } + if (setting & REC_LIST_FILES || setting & REC_EVENT_OPT) { + for (const auto& file : files) { + boost::filesystem::path p(file); + std::string file_name = p.filename().string(); + size_t pos = file_name.find(suffix); + if (pos != std::string::npos && + pos + suffix.length() == file_name.length()) { + results.push_back(file); + } } } return Status(0, "OK"); @@ -325,9 +379,7 @@ Status resolveLastPathComponent(const boost::filesystem::path& fs_path, // Is the path a directory if (boost::filesystem::is_directory(fs_path)) { - for (auto& file : files) { - results.push_back(file); - } + results.push_back(fs_path.string()); return Status(0, "OK"); } @@ -351,6 +403,7 @@ Status resolveLastPathComponent(const boost::filesystem::path& fs_path, */ Status resolveFilePattern(std::vector components, std::vector& results, + ReturnSetting setting = REC_LIST_FILES, unsigned int processed_index = 0, unsigned int rec_depth = 0) { @@ -391,8 +444,8 @@ Status resolveFilePattern(std::vector components, for (const auto& dir : folders) { boost::filesystem::path p(dir); components[i] = p.filename().string(); - Status stat = - resolveFilePattern(components, results, i + 1, rec_depth + 1); + Status stat = resolveFilePattern( + components, results, setting, i + 1, rec_depth + 1); if (!stat.ok() && stat.getCode() == 2) { return stat; } @@ -412,8 +465,8 @@ Status resolveFilePattern(std::vector components, } boost::filesystem::path p(dir); components[i] = p.filename().string(); - Status stat = - resolveFilePattern(components, results, i + 1, rec_depth + 1); + Status stat = resolveFilePattern( + components, results, setting, i + 1, rec_depth + 1); if (!stat.ok() && stat.getCode() == 2) { return stat; } @@ -429,8 +482,8 @@ Status resolveFilePattern(std::vector components, if (pos != std::string::npos && pos + suffix.length() == folder_name.length()) { components[i] = p.filename().string(); - Status stat = - resolveFilePattern(components, results, i + 1, rec_depth + 1); + Status stat = resolveFilePattern( + components, results, setting, i + 1, rec_depth + 1); if (!stat.ok() && stat.getCode() == 2) { return stat; } @@ -445,6 +498,7 @@ Status resolveFilePattern(std::vector components, // list the files at this point or do our ** traversal return resolveLastPathComponent("/" + boost::algorithm::join(components, "/"), results, + setting, components, rec_depth); } @@ -454,6 +508,12 @@ Status resolveFilePattern(const boost::filesystem::path& fs_path, return resolveFilePattern(split(fs_path.string(), "/"), results); } +Status resolveFilePattern(const boost::filesystem::path& fs_path, + std::vector& results, + ReturnSetting setting) { + return resolveFilePattern(split(fs_path.string(), "/"), results, setting); +} + Status getDirectory(const boost::filesystem::path& path, boost::filesystem::path& dirpath) { if (!isDirectory(path).ok()) { diff --git a/osquery/filesystem/filesystem_tests.cpp b/osquery/filesystem/filesystem_tests.cpp index cde162a4693..76078779e68 100644 --- a/osquery/filesystem/filesystem_tests.cpp +++ b/osquery/filesystem/filesystem_tests.cpp @@ -53,10 +53,16 @@ TEST_F(FilesystemTests, test_list_files_in_directory_not_found) { EXPECT_FALSE(not_found.ok()); EXPECT_EQ(not_found.toString(), "Directory not found: /foo/bar"); } -TEST_F(FilesystemTests, test_wildcard_single_folder_list) { + +TEST_F(FilesystemTests, test_wildcard_single_file_list) { std::vector files; + std::vector files_flag; auto status = resolveFilePattern(kFakeDirectory + "/%", files); + auto status2 = + resolveFilePattern(kFakeDirectory + "/%", files_flag, REC_LIST_FILES); EXPECT_TRUE(status.ok()); + EXPECT_EQ(files.size(), 3); + EXPECT_EQ(files.size(), files_flag.size()); EXPECT_NE( std::find(files.begin(), files.end(), kFakeDirectory + "/roto.txt"), files.end()); @@ -132,6 +138,72 @@ TEST_F(FilesystemTests, test_list_files_in_directorty) { EXPECT_NE(std::find(results.begin(), results.end(), "/etc/hosts"), results.end()); } + +TEST_F(FilesystemTests, test_wildcard_single_folder_list) { + std::vector folders; + auto status = + resolveFilePattern(kFakeDirectory + "/%", folders, REC_LIST_FOLDERS); + EXPECT_TRUE(status.ok()); + EXPECT_EQ(folders.size(), 3); + EXPECT_NE( + std::find(folders.begin(), folders.end(), kFakeDirectory + "/deep11"), + folders.end()); +} + +TEST_F(FilesystemTests, test_wildcard_single_all_list) { + std::vector all; + auto status = resolveFilePattern(kFakeDirectory + "/%", all, REC_LIST_ALL); + EXPECT_TRUE(status.ok()); + EXPECT_EQ(all.size(), 6); + EXPECT_NE(std::find(all.begin(), all.end(), kFakeDirectory + "/roto.txt"), + all.end()); + EXPECT_NE(std::find(all.begin(), all.end(), kFakeDirectory + "/deep11"), + all.end()); +} + +TEST_F(FilesystemTests, test_wildcard_double_folders) { + std::vector all; + auto status = + resolveFilePattern(kFakeDirectory + "/%%", all, REC_LIST_FOLDERS); + EXPECT_TRUE(status.ok()); + EXPECT_EQ(all.size(), 6); + EXPECT_NE(std::find(all.begin(), all.end(), kFakeDirectory), all.end()); + EXPECT_NE( + std::find(all.begin(), all.end(), kFakeDirectory + "/deep11/deep2/deep3"), + all.end()); +} + +TEST_F(FilesystemTests, test_wildcard_double_all) { + std::vector all; + auto status = resolveFilePattern(kFakeDirectory + "/%%", all, REC_LIST_ALL); + EXPECT_TRUE(status.ok()); + EXPECT_EQ(all.size(), 15); + EXPECT_NE(std::find(all.begin(), all.end(), kFakeDirectory + "/roto.txt"), + all.end()); + EXPECT_NE( + std::find(all.begin(), all.end(), kFakeDirectory + "/deep11/deep2/deep3"), + all.end()); +} +TEST_F(FilesystemTests, test_double_wild_event_opt) { + std::vector all; + auto status = resolveFilePattern(kFakeDirectory + "/%%", all, + REC_LIST_FOLDERS | REC_EVENT_OPT); + EXPECT_TRUE(status.ok()); + EXPECT_EQ(all.size(), 1); + EXPECT_NE(std::find(all.begin(), all.end(), kFakeDirectory), all.end()); +} + +TEST_F(FilesystemTests, test_letter_wild_opt) { + std::vector all; + auto status = resolveFilePattern(kFakeDirectory + "/d%", all, + REC_LIST_FOLDERS | REC_EVENT_OPT); + EXPECT_TRUE(status.ok()); + EXPECT_EQ(all.size(), 3); + EXPECT_NE(std::find(all.begin(), all.end(), kFakeDirectory + "/deep1"), + all.end()); + EXPECT_NE(std::find(all.begin(), all.end(), kFakeDirectory + "/door.txt"), + all.end()); +} } int main(int argc, char* argv[]) { diff --git a/osquery/tables/events/darwin/file_changes.cpp b/osquery/tables/events/darwin/file_changes.cpp index 5904b168e1e..a8ef0cfab70 100644 --- a/osquery/tables/events/darwin/file_changes.cpp +++ b/osquery/tables/events/darwin/file_changes.cpp @@ -58,6 +58,7 @@ void FileChangesEventSubscriber::init() { const auto& file_map = Config::getInstance().getWatchedFiles(); for (const auto& element_kv : file_map) { for (const auto& file : element_kv.second) { + VLOG(1) << "Added listener to: " << file; auto mc = createSubscriptionContext(); mc->path = file; subscribe(&FileChangesEventSubscriber::Callback, mc, @@ -72,7 +73,11 @@ Status FileChangesEventSubscriber::Callback(const FSEventsEventContextRef& ec, r["action"] = ec->action; r["time"] = ec->time_string; r["target_path"] = ec->path; - r["category"] = *(std::string*)user_data; + if (user_data != nullptr) { + r["category"] = *(std::string*)user_data; + } else { + r["category"] = "Undefined"; + } r["transaction_id"] = INTEGER(ec->fsevent_id); r["md5"] = hashFromFile(HASH_TYPE_MD5, ec->path); r["sha1"] = hashFromFile(HASH_TYPE_SHA1, ec->path); diff --git a/osquery/tables/events/linux/file_changes.cpp b/osquery/tables/events/linux/file_changes.cpp index f3dc82b5393..601c4f80bad 100644 --- a/osquery/tables/events/linux/file_changes.cpp +++ b/osquery/tables/events/linux/file_changes.cpp @@ -59,11 +59,13 @@ void FileChangesEventSubscriber::init() { for (const auto& element_kv : file_map) { for (const auto& file : element_kv.second) { + VLOG(1) << "Added listener to: " << file; auto mc = createSubscriptionContext(); + mc->recursive = 1; mc->path = file; mc->mask = IN_ATTRIB | IN_MODIFY | IN_DELETE | IN_CREATE; subscribe(&FileChangesEventSubscriber::Callback, mc, - (void*)(&element_kv.first)); + (void*)(&element_kv.first)); } } } @@ -74,7 +76,11 @@ Status FileChangesEventSubscriber::Callback(const INotifyEventContextRef& ec, r["action"] = ec->action; r["time"] = ec->time_string; r["target_path"] = ec->path; - r["category"] = *(std::string*)user_data; + if (user_data != nullptr) { + r["category"] = *(std::string*)user_data; + } else { + r["category"] = "Undefined"; + } r["transaction_id"] = INTEGER(ec->event->cookie); r["md5"] = hashFromFile(HASH_TYPE_MD5, ec->path); r["sha1"] = hashFromFile(HASH_TYPE_SHA1, ec->path);