darwin: Improve disk_events add detection (#3332)

This commit is contained in:
Teddy Reed 2017-05-26 10:38:26 -07:00 committed by Mitchell Grenier
parent bf2457ffcd
commit 9ba0edb4bb
4 changed files with 48 additions and 36 deletions

View File

@ -22,10 +22,11 @@
#include "osquery/events/darwin/diskarbitration.h" #include "osquery/events/darwin/diskarbitration.h"
namespace fs = boost::filesystem; namespace fs = boost::filesystem;
namespace errc = boost::system::errc;
namespace osquery { namespace osquery {
const std::string kIOHIDXClassPath = "IOService:/IOResources/IOHDIXController/"; const std::string kIOHIDXClassPath{"IOService:/IOResources/IOHDIXController/"};
REGISTER(DiskArbitrationEventPublisher, "event_publisher", "diskarbitration"); REGISTER(DiskArbitrationEventPublisher, "event_publisher", "diskarbitration");
@ -83,7 +84,7 @@ void DiskArbitrationEventPublisher::tearDown() {
} }
void DiskArbitrationEventPublisher::DiskAppearedCallback(DADiskRef disk, void DiskArbitrationEventPublisher::DiskAppearedCallback(DADiskRef disk,
void *context) { void* context) {
auto ec = createEventContext(); auto ec = createEventContext();
CFDictionaryRef disk_properties = DADiskCopyDescription(disk); CFDictionaryRef disk_properties = DADiskCopyDescription(disk);
@ -120,38 +121,43 @@ void DiskArbitrationEventPublisher::DiskAppearedCallback(DADiskRef disk,
disk_properties, kDADiskDescriptionMediaWholeKey))) { disk_properties, kDADiskDescriptionMediaWholeKey))) {
ec->checksum = extractUdifChecksum(ec->path); ec->checksum = extractUdifChecksum(ec->path);
} }
} else {
// There was no interface location.
ec->path = getProperty(kDADiskDescriptionDevicePathKey, disk_properties);
} }
CFRelease(protocol_properties); CFRelease(protocol_properties);
} else { } else {
ec->path = ""; ec->path = "";
} }
fire("add", ec, disk_properties); if (ec->path.find("/SSD0@0") == std::string::npos) {
// This is not an internal SSD.
fire("add", ec, disk_properties);
}
CFRelease(disk_properties); CFRelease(disk_properties);
IOObjectRelease(entry); IOObjectRelease(entry);
} }
void DiskArbitrationEventPublisher::DiskDisappearedCallback(DADiskRef disk, void DiskArbitrationEventPublisher::DiskDisappearedCallback(DADiskRef disk,
void *context) { void* context) {
CFDictionaryRef disk_properties = DADiskCopyDescription(disk); CFDictionaryRef disk_properties = DADiskCopyDescription(disk);
fire("remove", createEventContext(), disk_properties); fire("remove", createEventContext(), disk_properties);
CFRelease(disk_properties); CFRelease(disk_properties);
} }
bool DiskArbitrationEventPublisher::shouldFire( bool DiskArbitrationEventPublisher::shouldFire(
const DiskArbitrationSubscriptionContextRef &sc, const DiskArbitrationSubscriptionContextRef& sc,
const DiskArbitrationEventContextRef &ec) const { const DiskArbitrationEventContextRef& ec) const {
// We want events for physical disks as well // We want events for physical disks as well
if (sc->physical_disks) { if (sc->physical_disks) {
return true; return true;
} else { } else {
// We want only virtual disk (DMG) events // We 'could' only want only virtual disk (DMG) events
if (ec->action == "add") { if (ec->action == "add") {
// Filter events by matching on Virtual Interface based on IO device path // Filter events by matching on Virtual Interface based on IO device path
return (boost::starts_with(ec->device_path, kIOHIDXClassPath)); // return (boost::starts_with(ec->device_path, kIOHIDXClassPath));
return true;
} else { } else {
return true; return true;
} }
@ -159,14 +165,17 @@ bool DiskArbitrationEventPublisher::shouldFire(
} }
std::string DiskArbitrationEventPublisher::extractUdifChecksum( std::string DiskArbitrationEventPublisher::extractUdifChecksum(
const std::string &path_str) { const std::string& path_str) {
fs::path path = path_str; fs::path path = path_str;
if (!pathExists(path).ok() || !isReadable(path).ok()) { if (!pathExists(path).ok() || !isReadable(path).ok()) {
return ""; return "";
} }
if (!fs::is_regular_file(path)) {
boost::system::error_code ec;
if (!fs::is_regular_file(path, ec) || ec.value() != errc::success) {
return ""; return "";
} }
// The koly trailer (footer) is 512 bytes // The koly trailer (footer) is 512 bytes
// http://newosxbook.com/DMG.html // http://newosxbook.com/DMG.html
if (fs::file_size(path) < 512) { if (fs::file_size(path) < 512) {
@ -177,7 +186,7 @@ std::string DiskArbitrationEventPublisher::extractUdifChecksum(
if (dmg_file.is_open()) { if (dmg_file.is_open()) {
dmg_file.seekg(-512L, std::ios::end); dmg_file.seekg(-512L, std::ios::end);
char *buffer = new char[4]; char* buffer = new char[4];
dmg_file.read(buffer, 4); dmg_file.read(buffer, 4);
std::string koly_signature; std::string koly_signature;
koly_signature.assign(buffer, 4); koly_signature.assign(buffer, 4);
@ -191,13 +200,13 @@ std::string DiskArbitrationEventPublisher::extractUdifChecksum(
uint32_t checksum_size; uint32_t checksum_size;
dmg_file.seekg(-156L, std::ios::end); dmg_file.seekg(-156L, std::ios::end);
dmg_file.read((char *)&checksum_size, sizeof(checksum_size)); dmg_file.read((char*)&checksum_size, sizeof(checksum_size));
// checksum_size is in big endian and we need to byte swap // checksum_size is in big endian and we need to byte swap
checksum_size = CFSwapInt32(checksum_size); checksum_size = CFSwapInt32(checksum_size);
dmg_file.seekg(-152L, std::ios::end); // checksum offset dmg_file.seekg(-152L, std::ios::end); // checksum offset
unsigned char *u_buffer = new unsigned char[checksum_size]; unsigned char* u_buffer = new unsigned char[checksum_size];
dmg_file.read((char *)u_buffer, checksum_size); dmg_file.read((char*)u_buffer, checksum_size);
// we don't want to byte swap checksum as disk utility/hdiutil doesn't // we don't want to byte swap checksum as disk utility/hdiutil doesn't
std::stringstream checksum; std::stringstream checksum;
for (size_t i = 0; i < checksum_size; i++) { for (size_t i = 0; i < checksum_size; i++) {
@ -214,16 +223,15 @@ std::string DiskArbitrationEventPublisher::extractUdifChecksum(
} }
void DiskArbitrationEventPublisher::fire( void DiskArbitrationEventPublisher::fire(
const std::string &action, const std::string& action,
const DiskArbitrationEventContextRef &ec, const DiskArbitrationEventContextRef& ec,
const CFDictionaryRef &dict) { const CFDictionaryRef& dict) {
ec->action = action; ec->action = action;
ec->name = getProperty(kDADiskDescriptionMediaNameKey, dict); ec->name = getProperty(kDADiskDescriptionMediaNameKey, dict);
ec->bsd_name = getProperty(kDADiskDescriptionMediaBSDNameKey, dict); ec->device = "/dev/" + getProperty(kDADiskDescriptionMediaBSDNameKey, dict);
ec->uuid = getProperty(kDADiskDescriptionVolumeUUIDKey, dict); ec->uuid = getProperty(kDADiskDescriptionVolumeUUIDKey, dict);
ec->size = getProperty(kDADiskDescriptionMediaSizeKey, dict); ec->size = getProperty(kDADiskDescriptionMediaSizeKey, dict);
ec->ejectable = getProperty(kDADiskDescriptionMediaEjectableKey, dict); ec->ejectable = getProperty(kDADiskDescriptionMediaRemovableKey, dict);
ec->mountable = getProperty(kDADiskDescriptionVolumeMountableKey, dict); ec->mountable = getProperty(kDADiskDescriptionVolumeMountableKey, dict);
ec->writable = getProperty(kDADiskDescriptionMediaWritableKey, dict); ec->writable = getProperty(kDADiskDescriptionMediaWritableKey, dict);
ec->content = getProperty(kDADiskDescriptionMediaContentKey, dict); ec->content = getProperty(kDADiskDescriptionMediaContentKey, dict);
@ -231,12 +239,15 @@ void DiskArbitrationEventPublisher::fire(
ec->vendor = getProperty(kDADiskDescriptionDeviceVendorKey, dict); ec->vendor = getProperty(kDADiskDescriptionDeviceVendorKey, dict);
ec->filesystem = getProperty(kDADiskDescriptionVolumeKindKey, dict); ec->filesystem = getProperty(kDADiskDescriptionVolumeKindKey, dict);
ec->disk_appearance_time = getProperty(CFSTR(kDAAppearanceTime_), dict); ec->disk_appearance_time = getProperty(CFSTR(kDAAppearanceTime_), dict);
if (ec->path.find("IOService:/") == 0) {
ec->path = ec->device;
}
EventFactory::fire<DiskArbitrationEventPublisher>(ec); EventFactory::fire<DiskArbitrationEventPublisher>(ec);
} }
std::string DiskArbitrationEventPublisher::getProperty( std::string DiskArbitrationEventPublisher::getProperty(
const CFStringRef &property, const CFDictionaryRef &dict) { const CFStringRef& property, const CFDictionaryRef& dict) {
CFTypeRef value = (CFTypeRef)CFDictionaryGetValue(dict, property); CFTypeRef value = (CFTypeRef)CFDictionaryGetValue(dict, property);
if (value == nullptr) { if (value == nullptr) {
return ""; return "";

View File

@ -34,7 +34,7 @@ struct DiskArbitrationEventContext : public EventContext {
std::string path; std::string path;
std::string device_path; std::string device_path;
std::string name; std::string name;
std::string bsd_name; std::string device;
std::string uuid; std::string uuid;
std::string size; std::string size;
std::string ejectable; std::string ejectable;
@ -63,28 +63,28 @@ class DiskArbitrationEventPublisher
void tearDown() override; void tearDown() override;
bool shouldFire(const DiskArbitrationSubscriptionContextRef &sc, bool shouldFire(const DiskArbitrationSubscriptionContextRef& sc,
const DiskArbitrationEventContextRef &ec) const override; const DiskArbitrationEventContextRef& ec) const override;
Status run() override; Status run() override;
static void DiskAppearedCallback(DADiskRef disk, void *context); static void DiskAppearedCallback(DADiskRef disk, void* context);
static void DiskDisappearedCallback(DADiskRef disk, void *context); static void DiskDisappearedCallback(DADiskRef disk, void* context);
private: private:
void restart(); void restart();
void stop() override; void stop() override;
static std::string getProperty(const CFStringRef &property, static std::string getProperty(const CFStringRef& property,
const CFDictionaryRef &dict); const CFDictionaryRef& dict);
static std::string extractUdifChecksum(const std::string &path); static std::string extractUdifChecksum(const std::string& path);
static void fire(const std::string &action, static void fire(const std::string& action,
const DiskArbitrationEventContextRef &ec, const DiskArbitrationEventContextRef& ec,
const CFDictionaryRef &dict); const CFDictionaryRef& dict);
private: private:
/// Disk arbitration session. /// Disk arbitration session.

View File

@ -41,7 +41,7 @@ Status DiskEventSubscriber::Callback(const ECRef& ec, const SCRef& sc) {
r["action"] = ec->action; r["action"] = ec->action;
r["path"] = ec->path; r["path"] = ec->path;
r["name"] = ec->name; r["name"] = ec->name;
r["bsd_name"] = "/dev/" + ec->bsd_name; r["device"] = ec->device;
r["uuid"] = ec->uuid; r["uuid"] = ec->uuid;
r["size"] = ec->size; r["size"] = ec->size;
r["ejectable"] = ec->ejectable; r["ejectable"] = ec->ejectable;

View File

@ -4,7 +4,8 @@ schema([
Column("action", TEXT, "Appear or disappear"), Column("action", TEXT, "Appear or disappear"),
Column("path", TEXT, "Path of the DMG file accessed"), Column("path", TEXT, "Path of the DMG file accessed"),
Column("name", TEXT, "Disk event name"), Column("name", TEXT, "Disk event name"),
Column("bsd_name", TEXT, "Disk event BSD name"), Column("device", TEXT, "Disk event BSD name",
aliases=["bsd_name"]),
Column("uuid", TEXT, "UUID of the volume inside DMG if available"), Column("uuid", TEXT, "UUID of the volume inside DMG if available"),
Column("size", BIGINT, "Size of partition in bytes"), Column("size", BIGINT, "Size of partition in bytes"),
Column("ejectable", INTEGER, "1 if ejectable, 0 if not"), Column("ejectable", INTEGER, "1 if ejectable, 0 if not"),