mirror of
https://github.com/valitydev/osquery-1.git
synced 2024-11-08 10:23:54 +00:00
156 lines
4.6 KiB
C++
156 lines
4.6 KiB
C++
// Copyright 2004-present Facebook. All Rights Reserved.
|
|
|
|
#include <sstream>
|
|
|
|
#include <linux/limits.h>
|
|
|
|
#include "osquery/events.h"
|
|
#include "osquery/events/linux/inotify.h"
|
|
|
|
#include <glog/logging.h>
|
|
|
|
namespace osquery {
|
|
|
|
REGISTER_EVENTTYPE(INotifyEventPublisher);
|
|
|
|
int kINotifyULatency = 200;
|
|
static const uint32_t BUFFER_SIZE =
|
|
(10 * ((sizeof(struct inotify_event)) + NAME_MAX + 1));
|
|
|
|
std::map<int, std::string> kMaskActions = {{IN_ACCESS, "ACCESSED"},
|
|
{IN_ATTRIB, "ATTRIBUTES_MODIFIED"},
|
|
{IN_CLOSE_WRITE, "UPDATED"},
|
|
{IN_CREATE, "CREATED"},
|
|
{IN_DELETE, "DELETED"},
|
|
{IN_MODIFY, "UPDATED"},
|
|
{IN_MOVED_FROM, "MOVED_FROM"},
|
|
{IN_MOVED_TO, "MOVED_TO"},
|
|
{IN_OPEN, "OPENED"}, };
|
|
|
|
void INotifyEventPublisher::setUp() {
|
|
inotify_handle_ = ::inotify_init();
|
|
// If this does not work throw an exception.
|
|
if (inotify_handle_ == -1) {
|
|
// Todo: throw exception and DO NOT register this eventtype.
|
|
}
|
|
}
|
|
|
|
void INotifyEventPublisher::configure() {
|
|
// Not optimizing on watches for now.
|
|
}
|
|
|
|
void INotifyEventPublisher::tearDown() {
|
|
::close(inotify_handle_);
|
|
inotify_handle_ = -1;
|
|
}
|
|
|
|
Status INotifyEventPublisher::run() {
|
|
// Get a while wraper for free.
|
|
char buffer[BUFFER_SIZE];
|
|
fd_set set;
|
|
|
|
FD_ZERO(&set);
|
|
FD_SET(getHandle(), &set);
|
|
|
|
struct timeval timeout = {0, kINotifyULatency};
|
|
int selector = ::select(getHandle() + 1, &set, nullptr, nullptr, &timeout);
|
|
if (selector == -1) {
|
|
LOG(ERROR) << "Could not read inotify handle";
|
|
return Status(1, "INotify handle failed");
|
|
}
|
|
|
|
if (selector == 0) {
|
|
// Read timeout.
|
|
return Status(0, "Continue");
|
|
}
|
|
ssize_t record_num = ::read(getHandle(), buffer, BUFFER_SIZE);
|
|
if (record_num == 0 || record_num == -1) {
|
|
return Status(1, "INotify read failed");
|
|
}
|
|
|
|
for (char* p = buffer; p < buffer + record_num;) {
|
|
// Cast the inotify struct, make shared pointer, and append to contexts.
|
|
auto event = reinterpret_cast<struct inotify_event*>(p);
|
|
if (event->mask & IN_Q_OVERFLOW) {
|
|
// The inotify queue was overflown.
|
|
return Status(1, "Overflow");
|
|
}
|
|
|
|
if (event->mask & IN_IGNORED) {
|
|
// This inotify watch was removed.
|
|
} else if (event->mask & IN_MOVE_SELF) {
|
|
// This inotify path was moved, but is still watched.
|
|
} else if (event->mask & IN_DELETE_SELF) {
|
|
// A file was moved to replace the watched path.
|
|
} else {
|
|
auto ec = createEventContext(event);
|
|
fire(ec);
|
|
}
|
|
// Continue to iterate
|
|
p += (sizeof(struct inotify_event)) + event->len;
|
|
}
|
|
|
|
::usleep(kINotifyULatency);
|
|
return Status(0, "Continue");
|
|
}
|
|
|
|
INotifyEventContextRef INotifyEventPublisher::createEventContext(
|
|
struct inotify_event* event) {
|
|
auto shared_event = std::make_shared<struct inotify_event>(*event);
|
|
auto ec = createEventContext();
|
|
ec->event = shared_event;
|
|
|
|
// Get the pathname the watch fired on.
|
|
std::ostringstream path;
|
|
path << descriptor_paths_[event->wd];
|
|
if (event->len > 1) {
|
|
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;
|
|
break;
|
|
}
|
|
}
|
|
return ec;
|
|
}
|
|
|
|
bool INotifyEventPublisher::shouldFire(const INotifyMonitorContextRef mc,
|
|
const INotifyEventContextRef ec) {
|
|
ssize_t found = ec->path.find(mc->path);
|
|
if (found != 0) {
|
|
return false;
|
|
}
|
|
|
|
// The monitor may supply a required event mask.
|
|
if (mc->mask != 0 && !(ec->event->mask & mc->mask)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
Status INotifyEventPublisher::addMonitor(const MonitorRef monitor) {
|
|
EventPublisher::addMonitor(monitor);
|
|
// Instead of keeping track of every path, act greedy.
|
|
const auto& mc = getMonitorContext(monitor->context);
|
|
// Add the inotify watch.
|
|
int watch = ::inotify_add_watch(getHandle(), mc->path.c_str(), IN_ALL_EVENTS);
|
|
if (watch == -1) {
|
|
LOG(ERROR) << "Could not add inotify watch on: " << mc->path;
|
|
return Status(1, "Add Watch Failed");
|
|
}
|
|
descriptors_.push_back(watch);
|
|
path_descriptors_[mc->path] = watch;
|
|
descriptor_paths_[watch] = mc->path;
|
|
|
|
return Status(0, "OK");
|
|
}
|
|
|
|
bool INotifyEventPublisher::isMonitored(const std::string& path) {
|
|
return (path_descriptors_.find(path) != path_descriptors_.end());
|
|
}
|
|
}
|