mirror of
https://github.com/valitydev/osquery-1.git
synced 2024-11-07 18:08:53 +00:00
commit
8d1966f7ff
@ -47,6 +47,7 @@ std::string stringFromCFString(const CFStringRef& cf_string);
|
||||
* @brief Convert a CFNumberRef to a std::string.
|
||||
*/
|
||||
std::string stringFromCFNumber(const CFDataRef& cf_number);
|
||||
std::string stringFromCFData(const CFDataRef& cf_data);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
@ -7,12 +7,9 @@
|
||||
namespace osquery {
|
||||
|
||||
std::string stringFromCFString(const CFStringRef& cf_string) {
|
||||
CFIndex length;
|
||||
char *buffer;
|
||||
|
||||
// Access, then convert the CFString. CFStringGetCStringPtr is less-safe.
|
||||
length = CFStringGetLength(cf_string);
|
||||
buffer = (char *)malloc(length + 1);
|
||||
CFIndex length = CFStringGetLength(cf_string);
|
||||
char* buffer = (char*)malloc(length + 1);
|
||||
if (!CFStringGetCString(
|
||||
cf_string, buffer, length + 1, kCFStringEncodingASCII)) {
|
||||
free(buffer);
|
||||
@ -25,6 +22,24 @@ std::string stringFromCFString(const CFStringRef& cf_string) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string stringFromCFData(const CFDataRef& cf_data) {
|
||||
CFRange range = CFRangeMake(0, CFDataGetLength(cf_data));
|
||||
char* buffer = (char*)malloc(range.length + 1);
|
||||
memset(buffer, 0, range.length + 1);
|
||||
|
||||
CFDataGetBytes(cf_data, range, (UInt8*)buffer);
|
||||
for (CFIndex i = 0; i < range.length; ++i) {
|
||||
if (buffer[i] == 0) {
|
||||
buffer[i] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup allocations.
|
||||
std::string result(buffer);
|
||||
free(buffer);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string stringFromCFNumber(const CFDataRef& cf_number) {
|
||||
unsigned int value;
|
||||
if (CFGetTypeID(cf_number) != CFNumberGetTypeID() ||
|
||||
|
@ -70,8 +70,16 @@ Status UdevEventPublisher::run() {
|
||||
|
||||
std::string UdevEventPublisher::getValue(struct udev_device* device,
|
||||
const std::string& property) {
|
||||
auto value = udev_device_get_property_value(
|
||||
device, std::string("ID_" + property).c_str());
|
||||
auto value = udev_device_get_property_value(device, property.c_str());
|
||||
if (value != nullptr) {
|
||||
return std::string(value);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string UdevEventPublisher::getAttr(struct udev_device* device,
|
||||
const std::string& attr) {
|
||||
auto value = udev_device_get_sysattr_value(device, attr.c_str());
|
||||
if (value != nullptr) {
|
||||
return std::string(value);
|
||||
}
|
||||
|
@ -79,12 +79,22 @@ class UdevEventPublisher : public EventPublisher {
|
||||
* @brief Return a string representation of a udev property.
|
||||
*
|
||||
* @param device the udev device pointer.
|
||||
* @param property the udev property without the "ID_" prefix.
|
||||
* @param property the udev property identifier string.
|
||||
* @return string representation of the property or empty if null.
|
||||
*/
|
||||
static std::string getValue(struct udev_device* device,
|
||||
const std::string& property);
|
||||
|
||||
/**
|
||||
* @brief Return a string representation of a udev system attribute.
|
||||
*
|
||||
* @param device the udev device pointer.
|
||||
* @param property the udev system attribute identifier string.
|
||||
* @return string representation of the attribute or empty if null.
|
||||
*/
|
||||
static std::string getAttr(struct udev_device* device,
|
||||
const std::string& attr);
|
||||
|
||||
private:
|
||||
/// udev handle (socket descriptor contained within).
|
||||
struct udev *handle_;
|
||||
|
@ -25,6 +25,7 @@ if(APPLE)
|
||||
system/darwin/processes.cpp
|
||||
system/darwin/process_open_files.cpp
|
||||
system/darwin/quarantine.cpp
|
||||
system/darwin/pci_devices.cpp
|
||||
system/darwin/usb_devices.cpp
|
||||
system/darwin/startup_items.cpp
|
||||
)
|
||||
@ -56,6 +57,7 @@ else()
|
||||
system/linux/groups.cpp
|
||||
system/linux/mounts.cpp
|
||||
system/linux/pci_devices.cpp
|
||||
system/linux/usb_devices.cpp
|
||||
system/linux/block_devices.cpp
|
||||
)
|
||||
|
||||
|
@ -51,17 +51,19 @@ Status HardwareEventSubscriber::Callback(const UdevEventContextRef ec) {
|
||||
r["driver"] = ec->driver;
|
||||
|
||||
// UDEV properties.
|
||||
r["model"] = UdevEventPublisher::getValue(device, "MODEL");
|
||||
r["model"] = UdevEventPublisher::getValue(device, "ID_MODEL_FROM_DATABASE");
|
||||
if (r["path"].empty() && r["model"].empty()) {
|
||||
// Don't emit mising path/model combos.
|
||||
return Status(0, "Missing path and model.");
|
||||
}
|
||||
|
||||
r["model_id"] = INTEGER(UdevEventPublisher::getValue(device, "MODEL_ID"));
|
||||
r["vendor"] = UdevEventPublisher::getValue(device, "VENDOR");
|
||||
r["vendor_id"] = INTEGER(UdevEventPublisher::getValue(device, "VENDOR_ID"));
|
||||
r["serial"] = INTEGER(UdevEventPublisher::getValue(device, "SERIAL_SHORT"));
|
||||
r["revision"] = INTEGER(UdevEventPublisher::getValue(device, "REVISION"));
|
||||
r["model_id"] = INTEGER(UdevEventPublisher::getValue(device, "ID_MODEL_ID"));
|
||||
r["vendor"] = UdevEventPublisher::getValue(device, "ID_VENDOR_FROM_DATABASE");
|
||||
r["vendor_id"] =
|
||||
INTEGER(UdevEventPublisher::getValue(device, "ID_VENDOR_ID"));
|
||||
r["serial"] =
|
||||
INTEGER(UdevEventPublisher::getValue(device, "ID_SERIAL_SHORT"));
|
||||
r["revision"] = INTEGER(UdevEventPublisher::getValue(device, "ID_REVISION"));
|
||||
|
||||
r["time"] = INTEGER(ec->time);
|
||||
add(r, ec->time);
|
||||
|
@ -1,8 +0,0 @@
|
||||
table_name("pci_devices")
|
||||
schema([
|
||||
Column("slot", TEXT),
|
||||
Column("device_class", TEXT),
|
||||
Column("vendor", TEXT),
|
||||
Column("model", TEXT),
|
||||
])
|
||||
implementation("pci_devices@genPCIDevices")
|
17
osquery/tables/specs/x/pci_devices.table
Normal file
17
osquery/tables/specs/x/pci_devices.table
Normal file
@ -0,0 +1,17 @@
|
||||
table_name("pci_devices")
|
||||
schema([
|
||||
Column("pci_slot", TEXT),
|
||||
Column("pci_class", TEXT),
|
||||
Column("driver", TEXT),
|
||||
Column("vendor", TEXT),
|
||||
Column("vendor_id", TEXT),
|
||||
Column("model", TEXT),
|
||||
Column("model_id", TEXT),
|
||||
|
||||
# Optional columns
|
||||
#Column("subsystem", TEXT),
|
||||
#Column("express", INTEGER),
|
||||
#Column("thunderbolt", INTEGER),
|
||||
#Column("removable", INTEGER),
|
||||
])
|
||||
implementation("pci_devices@genPCIDevices")
|
@ -3,10 +3,10 @@ schema([
|
||||
Column("usb_address", INTEGER),
|
||||
Column("usb_port", INTEGER),
|
||||
Column("vendor", TEXT),
|
||||
Column("vendor_id", INTEGER),
|
||||
Column("vendor_id", TEXT),
|
||||
Column("model", TEXT),
|
||||
Column("model_id", INTEGER),
|
||||
Column("serial", INTEGER),
|
||||
Column("model_id", TEXT),
|
||||
Column("serial", TEXT),
|
||||
Column("removable", INTEGER),
|
||||
])
|
||||
implementation("usb_devices@genUsbDevices")
|
||||
implementation("usb_devices@genUSBDevices")
|
118
osquery/tables/system/darwin/pci_devices.cpp
Normal file
118
osquery/tables/system/darwin/pci_devices.cpp
Normal file
@ -0,0 +1,118 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/usb/IOUSBLib.h>
|
||||
|
||||
#include <osquery/core.h>
|
||||
#include <osquery/logger.h>
|
||||
#include <osquery/tables.h>
|
||||
#include <osquery/filesystem.h>
|
||||
|
||||
#include "osquery/core/conversions.h"
|
||||
|
||||
namespace osquery {
|
||||
namespace tables {
|
||||
|
||||
#define kIOPCIDeviceClassName_ "IOPCIDevice"
|
||||
|
||||
std::string getPCIProperty(const CFMutableDictionaryRef& details,
|
||||
const std::string& key) {
|
||||
std::string value;
|
||||
|
||||
// Get a property from the device.
|
||||
auto cfkey = CFStringCreateWithCString(
|
||||
kCFAllocatorDefault, key.c_str(), kCFStringEncodingUTF8);
|
||||
auto property = CFDictionaryGetValue(details, cfkey);
|
||||
CFRelease(cfkey);
|
||||
|
||||
// Several supported ways of parsing IOKit-encoded data.
|
||||
if (property) {
|
||||
if (CFGetTypeID(property) == CFNumberGetTypeID()) {
|
||||
value = stringFromCFNumber((CFDataRef)property);
|
||||
} else if (CFGetTypeID(property) == CFStringGetTypeID()) {
|
||||
value = stringFromCFString((CFStringRef)property);
|
||||
} else if (CFGetTypeID(property) == CFDataGetTypeID()) {
|
||||
value = stringFromCFData((CFDataRef)property);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void genPCIDevice(const io_service_t& device, QueryData& results) {
|
||||
Row r;
|
||||
|
||||
// Get the device details
|
||||
CFMutableDictionaryRef details;
|
||||
IORegistryEntryCreateCFProperties(
|
||||
device, &details, kCFAllocatorDefault, kNilOptions);
|
||||
|
||||
r["pci_slot"] = getPCIProperty(details, "pcidebug");
|
||||
|
||||
std::vector<std::string> properties;
|
||||
auto compatible = getPCIProperty(details, "compatible");
|
||||
boost::trim(compatible);
|
||||
boost::split(properties, compatible, boost::is_any_of(" "));
|
||||
|
||||
if (properties.size() < 2) {
|
||||
VLOG(1) << "Error parsing IOKit compatible properties";
|
||||
return;
|
||||
}
|
||||
|
||||
size_t prop_index = 0;
|
||||
if (properties[1].find("pci") == 0 && properties[1].find("pciclass") != 0) {
|
||||
// There are two sets of PCI definitions.
|
||||
prop_index = 1;
|
||||
} else if (properties[0].find("pci") != 0) {
|
||||
VLOG(1) << "No vendor/model found";
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> vendor;
|
||||
boost::split(vendor, properties[prop_index++], boost::is_any_of(","));
|
||||
r["vendor_id"] = vendor[0].substr(3);
|
||||
r["model_id"] = (vendor[1].size() == 3) ? "0" + vendor[1] : vendor[1];
|
||||
|
||||
if (properties[prop_index].find("pciclass") == 0) {
|
||||
// There is a class definition.
|
||||
r["pci_class"] = properties[prop_index++].substr(9);
|
||||
}
|
||||
|
||||
if (properties.size() > prop_index) {
|
||||
// There is a driver/ID.
|
||||
r["driver"] = properties[prop_index];
|
||||
}
|
||||
|
||||
results.push_back(r);
|
||||
CFRelease(details);
|
||||
}
|
||||
|
||||
QueryData genPCIDevices(QueryContext& context) {
|
||||
QueryData results;
|
||||
|
||||
auto matching = IOServiceMatching(kIOPCIDeviceClassName_);
|
||||
if (matching == nullptr) {
|
||||
// No devices matched USB, very odd.
|
||||
return results;
|
||||
}
|
||||
|
||||
io_iterator_t it;
|
||||
auto kr = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &it);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
return results;
|
||||
}
|
||||
|
||||
io_service_t device;
|
||||
while ((device = IOIteratorNext(it))) {
|
||||
genPCIDevice(device, results);
|
||||
IOObjectRelease(device);
|
||||
}
|
||||
|
||||
IOObjectRelease(it);
|
||||
return results;
|
||||
}
|
||||
}
|
||||
}
|
@ -53,7 +53,7 @@ void genUSBDevice(const io_service_t& device, QueryData& results) {
|
||||
CFRelease(details);
|
||||
}
|
||||
|
||||
QueryData genUsbDevices(QueryContext& context) {
|
||||
QueryData genUSBDevices(QueryContext& context) {
|
||||
QueryData results;
|
||||
|
||||
auto matching = IOServiceMatching(kIOUSBDeviceClassName);
|
||||
|
@ -1,71 +1,79 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#include <libudev.h>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
|
||||
#include <osquery/core.h>
|
||||
#include <osquery/logger.h>
|
||||
#include <osquery/tables.h>
|
||||
|
||||
#include "osquery/events/linux/udev.h"
|
||||
|
||||
namespace osquery {
|
||||
namespace tables {
|
||||
|
||||
const std::string kSlot = "PCI_SLOT_NAME";
|
||||
const std::string kClass = "ID_PCI_CLASS_FROM_DATABASE";
|
||||
const std::string kVendor = "ID_VENDOR_FROM_DATABASE";
|
||||
const std::string kModel = "ID_MODEL_FROM_DATABASE";
|
||||
|
||||
struct udev *udev;
|
||||
struct udev_enumerate *enumerate;
|
||||
struct udev_list_entry *devices, *dev_list_entry;
|
||||
struct udev_device *dev;
|
||||
const std::string kPCIKeySlot = "PCI_SLOT_NAME";
|
||||
const std::string kPCIKeyClass = "ID_PCI_CLASS_FROM_DATABASE";
|
||||
const std::string kPCIKeyVendor = "ID_VENDOR_FROM_DATABASE";
|
||||
const std::string kPCIKeyModel = "ID_MODEL_FROM_DATABASE";
|
||||
const std::string kPCIKeyID = "PCI_ID";
|
||||
const std::string kPCIKeyDriver = "DRIVER";
|
||||
|
||||
QueryData genPCIDevices(QueryContext &context) {
|
||||
QueryData results;
|
||||
|
||||
// Create the udev object
|
||||
udev = udev_new();
|
||||
if (!udev) {
|
||||
LOG(ERROR) << "Can't create udev object";
|
||||
auto udev_handle = udev_new();
|
||||
if (udev_handle == nullptr) {
|
||||
VLOG(1) << "Could not get udev handle.";
|
||||
return results;
|
||||
}
|
||||
|
||||
// Enumerate the list of all PCI devices
|
||||
enumerate = udev_enumerate_new(udev);
|
||||
// Perform enumeration/search.
|
||||
auto enumerate = udev_enumerate_new(udev_handle);
|
||||
udev_enumerate_add_match_subsystem(enumerate, "pci");
|
||||
udev_enumerate_scan_devices(enumerate);
|
||||
devices = udev_enumerate_get_list_entry(enumerate);
|
||||
|
||||
// udev_list_entry_foreach is a macro which expands to
|
||||
// a loop. The loop will be executed for each member in
|
||||
// devices, setting dev_list_entry to a list entry
|
||||
// which contains the device's path in /sys.
|
||||
// Get list entries and iterate over entries.
|
||||
struct udev_list_entry *device_entries, *entry;
|
||||
device_entries = udev_enumerate_get_list_entry(enumerate);
|
||||
|
||||
udev_list_entry_foreach(dev_list_entry, devices) {
|
||||
const char *path, *tmp;
|
||||
|
||||
// Get the filename of the /sys entry for the PCI device
|
||||
// and create a udev_device object (dev) representing it
|
||||
path = udev_list_entry_get_name(dev_list_entry);
|
||||
dev = udev_device_new_from_syspath(udev, path);
|
||||
udev_list_entry_foreach(entry, device_entries) {
|
||||
const char *path = udev_list_entry_get_name(entry);
|
||||
auto device = udev_device_new_from_syspath(udev_handle, path);
|
||||
|
||||
Row r;
|
||||
if ((tmp = udev_device_get_property_value(dev, kSlot.c_str()))) {
|
||||
r["slot"] = TEXT(tmp);
|
||||
r["pci_slot"] = UdevEventPublisher::getValue(device, kPCIKeySlot);
|
||||
r["pci_class"] = UdevEventPublisher::getValue(device, kPCIKeyClass);
|
||||
r["driver"] = UdevEventPublisher::getValue(device, kPCIKeyDriver);
|
||||
r["vendor"] = UdevEventPublisher::getValue(device, kPCIKeyVendor);
|
||||
r["model"] = UdevEventPublisher::getValue(device, kPCIKeyModel);
|
||||
|
||||
// VENDOR:MODEL ID is in the form of HHHH:HHHH.
|
||||
std::vector<std::string> ids;
|
||||
auto device_id = UdevEventPublisher::getValue(device, kPCIKeyID);
|
||||
boost::split(ids, device_id, boost::is_any_of(":"));
|
||||
if (ids.size() == 2) {
|
||||
r["vendor_id"] = ids[0];
|
||||
r["model_id"] = ids[1];
|
||||
}
|
||||
if ((tmp = udev_device_get_property_value(dev, kClass.c_str()))) {
|
||||
r["device_class"] = TEXT(tmp);
|
||||
|
||||
// Set invalid vendor/model IDs to 0.
|
||||
if (r["vendor_id"].size() == 0) {
|
||||
r["vendor_id"] = "0";
|
||||
}
|
||||
if ((tmp = udev_device_get_property_value(dev, kVendor.c_str()))) {
|
||||
r["vendor"] = TEXT(tmp);
|
||||
}
|
||||
if ((tmp = udev_device_get_property_value(dev, kModel.c_str()))) {
|
||||
r["model"] = TEXT(tmp);
|
||||
|
||||
if (r["model_id"].size() == 0) {
|
||||
r["model_id"] = "0";
|
||||
}
|
||||
|
||||
results.push_back(r);
|
||||
udev_device_unref(dev);
|
||||
udev_device_unref(device);
|
||||
}
|
||||
|
||||
// Drop references to udev structs.
|
||||
udev_enumerate_unref(enumerate);
|
||||
udev_unref(udev);
|
||||
udev_unref(udev_handle);
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
79
osquery/tables/system/linux/usb_devices.cpp
Normal file
79
osquery/tables/system/linux/usb_devices.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#include <osquery/core.h>
|
||||
#include <osquery/logger.h>
|
||||
#include <osquery/tables.h>
|
||||
|
||||
#include "osquery/events/linux/udev.h"
|
||||
|
||||
namespace osquery {
|
||||
namespace tables {
|
||||
|
||||
const std::string kUSBKeyVendorID = "ID_VENDOR_ID";
|
||||
const std::string kUSBKeyVendor = "ID_VENDOR_FROM_DATABASE";
|
||||
const std::string kUSBKeyModelID = "ID_MODEL_ID";
|
||||
const std::string kUSBKeyModel = "ID_MODEL_FROM_DATABASE";
|
||||
const std::string kUSBKeyDriver = "ID_USB_DRIVER";
|
||||
const std::string kUSBKeySubsystem = "SUBSYSTEM";
|
||||
const std::string kUSBKeySerial = "ID_SERIAL_SHORT";
|
||||
const std::string kUSBKeyAddress = "BUSNUM";
|
||||
const std::string kUSBKeyPort = "DEVNUM";
|
||||
|
||||
QueryData genUSBDevices(QueryContext &context) {
|
||||
QueryData results;
|
||||
|
||||
auto udev_handle = udev_new();
|
||||
if (udev_handle == nullptr) {
|
||||
VLOG(1) << "Could not get udev handle.";
|
||||
return results;
|
||||
}
|
||||
|
||||
// Perform enumeration/search.
|
||||
auto enumerate = udev_enumerate_new(udev_handle);
|
||||
udev_enumerate_add_match_subsystem(enumerate, "usb");
|
||||
udev_enumerate_scan_devices(enumerate);
|
||||
|
||||
// Get list entries and iterate over entries.
|
||||
struct udev_list_entry *device_entries, *entry;
|
||||
device_entries = udev_enumerate_get_list_entry(enumerate);
|
||||
|
||||
udev_list_entry_foreach(entry, device_entries) {
|
||||
const char *path = udev_list_entry_get_name(entry);
|
||||
auto device = udev_device_new_from_syspath(udev_handle, path);
|
||||
|
||||
Row r;
|
||||
// r["driver"] = UdevEventPublisher::getValue(device, kUSBKeyDriver);
|
||||
r["vendor"] = UdevEventPublisher::getValue(device, kUSBKeyVendor);
|
||||
r["model"] = UdevEventPublisher::getValue(device, kUSBKeyModel);
|
||||
|
||||
// USB-specific vendor/model ID properties.
|
||||
r["model_id"] = UdevEventPublisher::getValue(device, kUSBKeyModelID);
|
||||
r["vendor_id"] = UdevEventPublisher::getValue(device, kUSBKeyVendorID);
|
||||
r["serial"] = UdevEventPublisher::getValue(device, kUSBKeySerial);
|
||||
|
||||
// Address/port accessors.
|
||||
r["usb_address"] = UdevEventPublisher::getValue(device, kUSBKeyAddress);
|
||||
r["usb_port"] = UdevEventPublisher::getValue(device, kUSBKeyPort);
|
||||
|
||||
// Removable detection.
|
||||
auto removable = UdevEventPublisher::getAttr(device, "removable");
|
||||
if (removable == "unknown") {
|
||||
r["removable"] = "-1";
|
||||
} else {
|
||||
r["removable"] = "1";
|
||||
}
|
||||
|
||||
if (r["usb_address"].size() > 0 && r["usb_port"].size() > 0) {
|
||||
results.push_back(r);
|
||||
}
|
||||
udev_device_unref(device);
|
||||
}
|
||||
|
||||
// Drop references to udev structs.
|
||||
udev_enumerate_unref(enumerate);
|
||||
udev_unref(udev_handle);
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user