Merge pull request #1605 from theopolis/linux_system_info

[#1546] Add computer_name to system_info and extend to Linux
This commit is contained in:
Teddy Reed 2015-11-04 10:54:45 -08:00
commit 501c20c284
8 changed files with 166 additions and 36 deletions

View File

@ -78,7 +78,6 @@ endif()
# Construct a set of all object files, starting with third-party and all
# of the osquery core objects (sources from ADD_CORE_LIBRARY macros).
set(OSQUERY_OBJECTS $<TARGET_OBJECTS:osquery_sqlite>)
add_compile_options(-Werror)
# Add subdirectories
add_subdirectory(config)

View File

@ -55,9 +55,14 @@ FLAG(string,
"Field used to identify the host running osquery (hostname, uuid)");
std::string getHostname() {
char hostname[256] = {0}; // Linux max should be 64.
gethostname(hostname, sizeof(hostname) - 1);
static long max_hostname = sysconf(_SC_HOST_NAME_MAX);
long size = (max_hostname > 255) ? max_hostname + 1 : 256;
char* hostname = (char*)malloc(size);
memset((void*)hostname, 0, size);
gethostname(hostname, size - 1);
std::string hostname_string = std::string(hostname);
free(hostname);
boost::algorithm::trim(hostname_string);
return hostname_string;
}

View File

@ -15,6 +15,7 @@
#include <osquery/flags.h>
#include <osquery/logger.h>
#include "osquery/database/db_handle.h"
#include "osquery/sql/sqlite_util.h"
DEFINE_string(query, "", "query to execute");
@ -40,6 +41,8 @@ int main(int argc, char* argv[]) {
return 1;
}
osquery::DBHandle::setAllowOpen(true);
osquery::FLAGS_database_path = "/dev/null";
osquery::Registry::setUp();
osquery::FLAGS_disable_events = true;
osquery::FLAGS_registry_exceptions = true;

View File

@ -45,23 +45,23 @@ std::map<int, std::vector<FeatureDef_t> > kCPUFeatures = {
}},
};
void cpuid(unsigned int eax, unsigned int ecx, int regs[4]) {
static inline void cpuid(unsigned int eax, unsigned int ecx, int regs[4]) {
asm volatile("cpuid"
: "=a"(regs[0]), "=b"(regs[1]), "=c"(regs[2]), "=d"(regs[3])
: "a"(eax), "c"(ecx));
}
void registerToString(int reg, std::stringstream& stream) {
static inline void registerToString(int reg, std::stringstream& stream) {
for (size_t i = 0; i < 4; i++) {
stream << ((char*)&reg)[i];
}
}
bool isBitSet(size_t bit, unsigned int reg) {
static inline bool isBitSet(size_t bit, unsigned int reg) {
return ((reg & (1 << bit)) != 0);
}
Status genVendorString(QueryData& results) {
inline Status genStrings(QueryData& results) {
int regs[4] = {-1};
cpuid(0, 0, regs);
@ -73,7 +73,7 @@ Status genVendorString(QueryData& results) {
std::stringstream vendor_string;
registerToString(regs[1], vendor_string);
registerToString(regs[3], vendor_string);
registerToString(regs[2], vendor_string);
registerToString(regs[2], vendor_string);
Row r;
r["feature"] = "vendor";
@ -83,10 +83,59 @@ Status genVendorString(QueryData& results) {
r["input_eax"] = "0";
results.push_back(r);
// The CPU canonicalized name can also be accessed via cpuid accesses.
// Subsequent accesses allow a 32-character CPU name.
std::stringstream product_name;
for (size_t i = 0; i < 3; i++) {
cpuid(0x80000002 + i, 0, regs);
registerToString(regs[0], product_name);
registerToString(regs[1], product_name);
registerToString(regs[2], product_name);
registerToString(regs[3], product_name);
}
r["feature"] = "product_name";
r["value"] = product_name.str();
r["output_register"] = "eax,ebx,ecx,edx";
r["output_bit"] = "0";
r["input_eax"] = "0x80000002";
results.push_back(r);
// Do the same to grab the optional hypervisor ID.
cpuid(0x40000000, 0, regs);
if (regs[0] && 0xFF000000 != 0) {
std::stringstream hypervisor_string;
registerToString(regs[1], hypervisor_string);
registerToString(regs[2], hypervisor_string);
registerToString(regs[3], hypervisor_string);
r["feature"] = "hypervisor_id";
r["value"] = hypervisor_string.str();
r["output_register"] = "ebx,ecx,edx";
r["output_bit"] = "0";
r["input_eax"] = "0x40000000";
results.push_back(r);
}
// Finally, check the processor serial number.
std::stringstream serial;
cpuid(1, 0, regs);
serial << std::hex << std::setw(8) << std::setfill('0') << (int)regs[0];
cpuid(3, 0, regs);
serial << std::hex << std::setw(8) << std::setfill('0') << (int)regs[0];
serial << std::hex << std::setw(8) << std::setfill('0') << (int)regs[3];
r["feature"] = "serial";
r["value"] = serial.str();
r["output_register"] = "eax,ebx,ecx,edx";
r["output_bit"] = "0";
r["input_eax"] = "1,3";
results.push_back(r);
return Status(0, "OK");
}
void genFamily(QueryData& results) {
inline void genFamily(QueryData& results) {
int regs[4] = {-1};
cpuid(1, 0, regs);
@ -108,7 +157,7 @@ void genFamily(QueryData& results) {
QueryData genCPUID(QueryContext& context) {
QueryData results;
if (!genVendorString(results).ok()) {
if (!genStrings(results).ok()) {
return results;
}

View File

@ -9,11 +9,11 @@
*/
#include <IOKit/IOKitLib.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include <mach/mach.h>
#include <osquery/database.h>
#include <osquery/tables.h>
#include <osquery/logger.h>
#include "osquery/core/conversions.h"
#include "osquery/tables/system/sysctl_utils.h"
@ -26,10 +26,10 @@ namespace tables {
const std::string kMachCpuBrandStringKey = "machdep.cpu.brand_string";
const std::string kHardwareModelNameKey = "hw.model";
Status getCpuSerial(std::string &cpu_serial) {
Status getHardwareSerial(std::string &serial) {
static std::string serial_cache;
if (!serial_cache.empty()) {
cpu_serial = serial_cache;
serial = serial_cache;
return Status(0, "OK");
}
@ -61,12 +61,8 @@ Status getCpuSerial(std::string &cpu_serial) {
return Status(1, "Could not read serial number property");
}
cpu_serial = serial_cache = stringFromCFString(serialNumber);
serial = serial_cache = stringFromCFString(serialNumber);
CFRelease(serialNumber);
if (cpu_serial.empty()) {
return Status(1, "cpu_serial was empty");
}
return Status(0, "OK");
}
@ -77,7 +73,6 @@ void genHostInfo(Row &r) {
if (host_info(host, HOST_BASIC_INFO, (host_info_t)&host_data, &count) !=
KERN_SUCCESS) {
VLOG(1) << "Error retrieving host info";
return;
}
@ -97,22 +92,21 @@ void genHostInfo(Row &r) {
QueryData genSystemInfo(QueryContext &context) {
QueryData results;
Row r;
r["hostname"] = TEXT(osquery::getHostname());
r["hostname"] = osquery::getHostname();
// OS X also defines a friendly ComputerName.
auto cn = SCDynamicStoreCopyComputerName(nullptr, nullptr);
if (cn != nullptr) {
r["computer_name"] = stringFromCFString(cn);
CFRelease(cn);
} else {
r["computer_name"] = r["hostname"];
}
std::string uuid;
auto status = osquery::getHostUUID(uuid);
if (!status.ok()) {
uuid = "";
}
r["uuid"] = TEXT(uuid);
std::string cpu_serial;
status = getCpuSerial(cpu_serial);
if (!status.ok()) {
cpu_serial = "";
}
r["cpu_serial"] = TEXT(cpu_serial);
r["uuid"] = (osquery::getHostUUID(uuid)) ? uuid : "";
std::string serial;
r["hardware_serial"] = (getHardwareSerial(serial)) ? serial : "";
genHostInfo(r);
QueryData sysctl_results;

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2014, Facebook, Inc.
* 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
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#include <stdio.h>
#include <osquery/filesystem.h>
#include <osquery/tables.h>
#include <osquery/sql.h>
namespace osquery {
namespace tables {
QueryData genSystemInfo(QueryContext &context) {
Row r;
r["hostname"] = osquery::getHostname();
r["computer_name"] = r["hostname"];
std::string uuid;
r["uuid"] = (osquery::getHostUUID(uuid)) ? uuid : "";
auto qd = SQL::selectAllFrom("cpuid");
for (const auto& row : qd) {
if (row.at("feature") == "product_name") {
r["cpu_brand"] = row.at("value");
}
}
// Can parse /proc/cpuinfo or /proc/meminfo for this data.
static long cores = sysconf(_SC_NPROCESSORS_CONF);
if (cores > 0) {
r["cpu_logical_cores"] = INTEGER(cores);
r["cpu_physical_cores"] = INTEGER(cores);
} else {
r["cpu_logical_cores"] = "-1";
r["cpu_physical_cores"] = "-1";
}
static long pages = sysconf(_SC_PHYS_PAGES);
static long pagesize = sysconf(_SC_PAGESIZE);
if (pages > 0 && pagesize > 0) {
r["physical_memory"] = BIGINT((long long)pages * (long long)pagesize);
} else {
r["physical_memory"] = "-1";
}
r["cpu_type"] = "0";
r["cpu_subtype"] = "0";
// Read the types from CPU info within proc.
std::string content;
if (readFile("/proc/cpuinfo", content)) {
for (const auto& line : osquery::split(content, "\n")) {
// Iterate each line and look for labels (there is also a model type).
if (line.find("cpu family") == 0 || line.find("model\t") == 0) {
auto details = osquery::split(line, ":");
if (details.size() == 2) {
// Not the most elegant but prevents us from splitting each line.
r[(line[0] == 'c') ? "cpu_type" : "cpu_subtype"] = details[1];
}
}
}
}
// Will require parsing DMI/SMBIOS data.
r["hardware_model"] = "";
r["hardware_serial"] = "";
return {r};
}
}
}

View File

@ -3,7 +3,6 @@ description("System information for identification.")
schema([
Column("hostname", TEXT, "Network hostname including domain"),
Column("uuid", TEXT, "Unique ID provided by the system"),
Column("cpu_serial", TEXT, "System serial number frequently used for asset tracking"),
Column("cpu_type", TEXT, "CPU type"),
Column("cpu_subtype", TEXT, "CPU subtype"),
Column("cpu_brand", TEXT, "CPU brand string"),
@ -11,5 +10,8 @@ schema([
Column("cpu_logical_cores", INTEGER, "Max number of CPU logical cores"),
Column("physical_memory", BIGINT, "Total physical memory in bytes"),
Column("hardware_model", TEXT, "Hardware model string"),
Column("hardware_serial", TEXT,
"System serial number frequently used for asset tracking"),
Column("computer_name", TEXT, "Friendly computer name (optional)"),
])
implementation("system/system_info@genSystemInfo")

View File

@ -140,7 +140,6 @@ def profile_cmd(cmd, proc=None, shell=False, timeout=0, count=1):
shell=shell,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
p = psutil.Process(pid=proc.pid)
delay = 0
@ -170,6 +169,8 @@ def profile_cmd(cmd, proc=None, shell=False, timeout=0, count=1):
else:
avg_utilization = sum(utilization) / len(utilization)
if len(stats.keys()) == 0:
raise Exception("No stats recorded, perhaps binary returns -1?")
return {
"utilization": avg_utilization,
"duration": duration,