mirror of
https://github.com/valitydev/osquery-1.git
synced 2024-11-07 18:08:53 +00:00
IOKit HID events and OSX hardware_events table
This commit is contained in:
parent
7b56fa605d
commit
acccfa94e2
@ -6,6 +6,7 @@ if(APPLE)
|
||||
|
||||
ADD_OSQUERY_LIBRARY(osquery_events_darwin
|
||||
darwin/fsevents.cpp
|
||||
darwin/iokit_hid.cpp
|
||||
darwin/scnetwork.cpp
|
||||
)
|
||||
elseif(FREEBSD)
|
||||
|
181
osquery/events/darwin/iokit_hid.cpp
Normal file
181
osquery/events/darwin/iokit_hid.cpp
Normal file
@ -0,0 +1,181 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#include <osquery/logger.h>
|
||||
#include <osquery/tables.h>
|
||||
|
||||
#include "osquery/core/conversions.h"
|
||||
#include "osquery/events/darwin/iokit_hid.h"
|
||||
|
||||
namespace osquery {
|
||||
|
||||
REGISTER_EVENTPUBLISHER(IOKitHIDEventPublisher);
|
||||
|
||||
size_t IOKitHIDEventPublisher::initial_device_count_ = 0;
|
||||
size_t IOKitHIDEventPublisher::initial_device_evented_count_ = 0;
|
||||
boost::mutex IOKitHIDEventPublisher::iokit_match_lock_;
|
||||
|
||||
std::string IOKitHIDEventPublisher::getProperty(const IOHIDDeviceRef &device,
|
||||
const CFStringRef &property) {
|
||||
CFTypeRef value = IOHIDDeviceGetProperty(device, property);
|
||||
if (value == NULL) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Only support CFNumber and CFString types.
|
||||
if (CFGetTypeID(value) == CFNumberGetTypeID()) {
|
||||
return stringFromCFNumber((CFDataRef)value);
|
||||
} else if (CFGetTypeID(value) == CFStringGetTypeID()) {
|
||||
return stringFromCFString((CFStringRef)value);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void IOKitHIDEventPublisher::restart() {
|
||||
if (run_loop_ == nullptr) {
|
||||
// There is no run loop to restart.
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove any existing stream.
|
||||
stop();
|
||||
|
||||
if (manager_ == nullptr) {
|
||||
manager_ = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
|
||||
}
|
||||
|
||||
// Match anything.
|
||||
IOHIDManagerSetDeviceMatching(manager_, NULL);
|
||||
|
||||
auto status = IOHIDManagerOpen(manager_, kIOHIDOptionsTypeNone);
|
||||
if (status != kIOReturnSuccess) {
|
||||
LOG(ERROR) << "Cannot open IOKit HID Manager";
|
||||
return;
|
||||
}
|
||||
|
||||
// Enumerate initial set of devices matched before time=0.
|
||||
CFSetRef devices = IOHIDManagerCopyDevices(manager_);
|
||||
initial_device_count_ = devices == NULL ? 0 : CFSetGetCount(devices);
|
||||
CFRelease(devices);
|
||||
|
||||
// Register callbacks.
|
||||
IOHIDManagerRegisterDeviceMatchingCallback(
|
||||
manager_, IOKitHIDEventPublisher::MatchingCallback, NULL);
|
||||
IOHIDManagerRegisterDeviceRemovalCallback(
|
||||
manager_, IOKitHIDEventPublisher::RemovalCallback, NULL);
|
||||
|
||||
IOHIDManagerScheduleWithRunLoop(manager_, run_loop_, kCFRunLoopDefaultMode);
|
||||
manager_started_ = true;
|
||||
}
|
||||
|
||||
void IOKitHIDEventPublisher::MatchingCallback(void *context,
|
||||
IOReturn result,
|
||||
void *sender,
|
||||
IOHIDDeviceRef device) {
|
||||
{
|
||||
// Must not event on initial list of matches.
|
||||
boost::lock_guard<boost::mutex> lock(iokit_match_lock_);
|
||||
if (initial_device_count_ > initial_device_evented_count_) {
|
||||
initial_device_evented_count_++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fire(device, "add");
|
||||
}
|
||||
|
||||
void IOKitHIDEventPublisher::fire(IOHIDDeviceRef &device,
|
||||
const std::string &action) {
|
||||
auto ec = createEventContext();
|
||||
ec->device = device;
|
||||
ec->action = action;
|
||||
|
||||
// Fill in more-useful fields.
|
||||
ec->vendor_id = getProperty(device, CFSTR(kIOHIDVendorIDKey));
|
||||
ec->model_id = getProperty(device, CFSTR(kIOHIDProductIDKey));
|
||||
ec->vendor = getProperty(device, CFSTR(kIOHIDManufacturerKey));
|
||||
ec->model = getProperty(device, CFSTR(kIOHIDProductKey));
|
||||
ec->transport = getProperty(device, CFSTR(kIOHIDTransportKey));
|
||||
ec->primary_usage = getProperty(device, CFSTR(kIOHIDPrimaryUsageKey));
|
||||
ec->device_usage = getProperty(device, CFSTR(kIOHIDDeviceUsageKey));
|
||||
|
||||
// Fill in more esoteric properties.
|
||||
ec->version = getProperty(device, CFSTR(kIOHIDVersionNumberKey));
|
||||
ec->location = getProperty(device, CFSTR(kIOHIDLocationIDKey));
|
||||
ec->serial = getProperty(device, CFSTR(kIOHIDSerialNumberKey));
|
||||
ec->country_code = getProperty(device, CFSTR(kIOHIDCountryCodeKey));
|
||||
|
||||
EventFactory::fire<IOKitHIDEventPublisher>(ec);
|
||||
}
|
||||
|
||||
void IOKitHIDEventPublisher::RemovalCallback(void *context,
|
||||
IOReturn result,
|
||||
void *sender,
|
||||
IOHIDDeviceRef device) {
|
||||
|
||||
fire(device, "remove");
|
||||
}
|
||||
|
||||
void IOKitHIDEventPublisher::InputValueCallback(void *context,
|
||||
IOReturn result,
|
||||
void *sender,
|
||||
IOHIDValueRef value) {
|
||||
// Nothing yet.
|
||||
printf("value\n");
|
||||
}
|
||||
|
||||
bool IOKitHIDEventPublisher::shouldFire(const IOKitHIDSubscriptionContextRef sc,
|
||||
const IOKitHIDEventContextRef ec) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Status IOKitHIDEventPublisher::run() {
|
||||
// The run entrypoint executes in a dedicated thread.
|
||||
if (run_loop_ == nullptr) {
|
||||
run_loop_ = CFRunLoopGetCurrent();
|
||||
// Restart the stream creation.
|
||||
restart();
|
||||
}
|
||||
|
||||
// Start the run loop, it may be removed with a tearDown.
|
||||
CFRunLoopRun();
|
||||
|
||||
// Add artificial latency to run loop.
|
||||
::sleep(1);
|
||||
return Status(0, "OK");
|
||||
}
|
||||
|
||||
void IOKitHIDEventPublisher::stop() {
|
||||
// Stop the manager.
|
||||
if (manager_ != nullptr) {
|
||||
IOHIDManagerUnscheduleFromRunLoop(
|
||||
manager_, run_loop_, kCFRunLoopDefaultMode);
|
||||
IOHIDManagerClose(manager_, kIOHIDOptionsTypeNone);
|
||||
manager_started_ = false;
|
||||
manager_ = nullptr;
|
||||
}
|
||||
|
||||
// Stop the run loop.
|
||||
if (run_loop_ != nullptr) {
|
||||
CFRunLoopStop(run_loop_);
|
||||
}
|
||||
}
|
||||
|
||||
void IOKitHIDEventPublisher::tearDown() {
|
||||
stop();
|
||||
|
||||
// Do not keep a reference to the run loop.
|
||||
run_loop_ = nullptr;
|
||||
}
|
||||
|
||||
bool IOKitHIDEventPublisher::isManagerRunning() {
|
||||
if (manager_ == nullptr || !manager_started_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (run_loop_ == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return CFRunLoopIsWaiting(run_loop_);
|
||||
}
|
||||
}
|
136
osquery/events/darwin/iokit_hid.h
Normal file
136
osquery/events/darwin/iokit_hid.h
Normal file
@ -0,0 +1,136 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#include <IOKit/hid/IOHIDLib.h>
|
||||
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
#include <osquery/events.h>
|
||||
#include <osquery/status.h>
|
||||
|
||||
namespace osquery {
|
||||
|
||||
struct IOKitHIDSubscriptionContext : public SubscriptionContext {
|
||||
// Bus type, e.g., USB.
|
||||
std::string transport;
|
||||
// Product name
|
||||
std::string product;
|
||||
std::string vendor;
|
||||
|
||||
// Usage types.
|
||||
std::string primary_usage;
|
||||
std::string device_usage;
|
||||
|
||||
// Get values from HID events.
|
||||
bool values;
|
||||
|
||||
// Do not request values by default.
|
||||
IOKitHIDSubscriptionContext() : values(false) {}
|
||||
};
|
||||
|
||||
struct IOKitHIDEventContext : public EventContext {
|
||||
// The native IOKit device reference.
|
||||
IOHIDDeviceRef device;
|
||||
|
||||
// The event action: add, remove, value change.
|
||||
std::string action;
|
||||
// If a value was changed, include the result (optional).
|
||||
std::string result;
|
||||
|
||||
// The publisher pre-populates several fields.
|
||||
std::string vendor_id;
|
||||
std::string model_id;
|
||||
std::string vendor;
|
||||
std::string model;
|
||||
std::string transport;
|
||||
std::string primary_usage;
|
||||
std::string device_usage;
|
||||
|
||||
// More esoteric properties.
|
||||
std::string version;
|
||||
std::string location;
|
||||
std::string serial;
|
||||
std::string country_code;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<IOKitHIDEventContext> IOKitHIDEventContextRef;
|
||||
typedef std::shared_ptr<IOKitHIDSubscriptionContext>
|
||||
IOKitHIDSubscriptionContextRef;
|
||||
|
||||
/**
|
||||
* @brief An osquery EventPublisher for the Apple IOKit HID notification API.
|
||||
*
|
||||
*/
|
||||
class IOKitHIDEventPublisher : public EventPublisher {
|
||||
DECLARE_EVENTPUBLISHER(IOKitHIDEventPublisher,
|
||||
IOKitHIDSubscriptionContext,
|
||||
IOKitHIDEventContext)
|
||||
|
||||
public:
|
||||
void configure() {}
|
||||
void tearDown();
|
||||
|
||||
// Entrypoint to the run loop
|
||||
Status run();
|
||||
|
||||
public:
|
||||
/// IOKit HID hotplugged event.
|
||||
static void MatchingCallback(void *context,
|
||||
IOReturn result,
|
||||
void *sender,
|
||||
IOHIDDeviceRef device);
|
||||
|
||||
/// IOKit HID device removed.
|
||||
static void RemovalCallback(void *context,
|
||||
IOReturn result,
|
||||
void *sender,
|
||||
IOHIDDeviceRef device);
|
||||
|
||||
/// IOKit HID device value changed.
|
||||
static void InputValueCallback(void *context,
|
||||
IOReturn result,
|
||||
void *sender,
|
||||
IOHIDValueRef value);
|
||||
|
||||
private:
|
||||
/// Helper fire fuction to parse properties/actions.
|
||||
static void fire(IOHIDDeviceRef &device, const std::string &action);
|
||||
|
||||
public:
|
||||
IOKitHIDEventPublisher()
|
||||
: EventPublisher(), manager_(nullptr), run_loop_(nullptr) {}
|
||||
bool shouldFire(const IOKitHIDSubscriptionContextRef mc,
|
||||
const IOKitHIDEventContextRef ec);
|
||||
|
||||
public:
|
||||
/// Provide some API usage for IOKitHID parsing.
|
||||
static std::string getProperty(const IOHIDDeviceRef &device,
|
||||
const CFStringRef &property);
|
||||
|
||||
private:
|
||||
// Restart the run loop.
|
||||
void restart();
|
||||
// Stop the manager and the run loop.
|
||||
void stop();
|
||||
void schedule();
|
||||
|
||||
private:
|
||||
// Check if the manager (and run loop) are running.
|
||||
bool isManagerRunning();
|
||||
|
||||
private:
|
||||
IOHIDManagerRef manager_;
|
||||
bool manager_started_;
|
||||
|
||||
private:
|
||||
CFRunLoopRef run_loop_;
|
||||
|
||||
private:
|
||||
static size_t initial_device_count_;
|
||||
static size_t initial_device_evented_count_;
|
||||
static boost::mutex iokit_match_lock_;
|
||||
};
|
||||
}
|
@ -10,6 +10,7 @@ if(APPLE)
|
||||
|
||||
ADD_OSQUERY_LIBRARY(osquery_tables_darwin
|
||||
events/darwin/passwd_changes.cpp
|
||||
events/darwin/hardware_events.cpp
|
||||
networking/darwin/interfaces.cpp
|
||||
networking/darwin/listening_ports.cpp
|
||||
networking/darwin/routes.cpp
|
||||
|
58
osquery/tables/events/darwin/hardware_events.cpp
Normal file
58
osquery/tables/events/darwin/hardware_events.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#include <osquery/core.h>
|
||||
#include <osquery/logger.h>
|
||||
#include <osquery/tables.h>
|
||||
|
||||
#include "osquery/events/darwin/iokit_hid.h"
|
||||
|
||||
namespace osquery {
|
||||
namespace tables {
|
||||
|
||||
/**
|
||||
* @brief Track IOKit HID events.
|
||||
*/
|
||||
class HardwareEventSubscriber : public EventSubscriber {
|
||||
DECLARE_EVENTSUBSCRIBER(HardwareEventSubscriber, IOKitHIDEventPublisher);
|
||||
DECLARE_CALLBACK(Callback, IOKitHIDEventContext);
|
||||
|
||||
public:
|
||||
void init();
|
||||
|
||||
Status Callback(const IOKitHIDEventContextRef ec);
|
||||
};
|
||||
|
||||
REGISTER_EVENTSUBSCRIBER(HardwareEventSubscriber);
|
||||
|
||||
void HardwareEventSubscriber::init() {
|
||||
auto subscription = IOKitHIDEventPublisher::createSubscriptionContext();
|
||||
// We don't want hardware value changes.
|
||||
subscription->values = false;
|
||||
|
||||
BIND_CALLBACK(Callback, subscription);
|
||||
}
|
||||
|
||||
Status HardwareEventSubscriber::Callback(const IOKitHIDEventContextRef ec) {
|
||||
Row r;
|
||||
|
||||
r["action"] = ec->action;
|
||||
// There is no path in IOKit, there's a location ID (may be useful).
|
||||
r["path"] = ec->location;
|
||||
|
||||
// Type and driver are the name in IOKit
|
||||
r["type"] = "hid";
|
||||
r["driver"] = ec->transport;
|
||||
|
||||
r["model_id"] = ec->model_id;
|
||||
r["model"] = ec->model;
|
||||
r["vendor_id"] = ec->vendor_id;
|
||||
r["vendor"] = ec->vendor;
|
||||
r["serial"] = ec->serial; // Not always filled in.
|
||||
r["revision"] = ec->version;
|
||||
|
||||
r["time"] = INTEGER(ec->time);
|
||||
add(r, ec->time);
|
||||
return Status(0, "OK");
|
||||
}
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ schema([
|
||||
Column("model_id", INTEGER),
|
||||
Column("vendor", TEXT),
|
||||
Column("vendor_id", INTEGER),
|
||||
Column("serial", INTEGER),
|
||||
Column("serial", TEXT),
|
||||
Column("revision", INTEGER),
|
||||
Column("time", INTEGER),
|
||||
])
|
Loading…
Reference in New Issue
Block a user