mirror of
https://github.com/valitydev/osquery-1.git
synced 2024-11-07 18:08:53 +00:00
Merge pull request #1525 from theopolis/process_adds
Add state, group, and nice to processes
This commit is contained in:
commit
64c18a70a9
@ -139,7 +139,7 @@ PluginResponse TablePlugin::routeInfo() const {
|
||||
std::string columnDefinition(const TableColumns& columns) {
|
||||
std::string statement = "(";
|
||||
for (size_t i = 0; i < columns.size(); ++i) {
|
||||
statement += columns.at(i).first + " " + columns.at(i).second;
|
||||
statement += "`" + columns.at(i).first + "` " + columns.at(i).second;
|
||||
if (i < columns.size() - 1) {
|
||||
statement += ", ";
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ class sampleTablePlugin : public TablePlugin {
|
||||
|
||||
TEST_F(VirtualTableTests, test_tableplugin_columndefinition) {
|
||||
auto table = std::make_shared<sampleTablePlugin>();
|
||||
EXPECT_EQ("(foo INTEGER, bar TEXT)", table->columnDefinition());
|
||||
EXPECT_EQ("(`foo` INTEGER, `bar` TEXT)", table->columnDefinition());
|
||||
}
|
||||
|
||||
TEST_F(VirtualTableTests, test_sqlite3_attach_vtable) {
|
||||
@ -61,7 +61,8 @@ TEST_F(VirtualTableTests, test_sqlite3_attach_vtable) {
|
||||
std::string q = "SELECT sql FROM sqlite_temp_master WHERE tbl_name='sample';";
|
||||
QueryData results;
|
||||
status = queryInternal(q, results, dbc.db());
|
||||
EXPECT_EQ("CREATE VIRTUAL TABLE sample USING sample(foo INTEGER, bar TEXT)",
|
||||
EXPECT_EQ(
|
||||
"CREATE VIRTUAL TABLE sample USING sample(`foo` INTEGER, `bar` TEXT)",
|
||||
results[0]["sql"]);
|
||||
}
|
||||
|
||||
|
@ -78,8 +78,14 @@ ADD_OSQUERY_LIBRARY_ADDITIONAL(osquery_tables
|
||||
${OSQUERY_CROSS_EVENTS_TABLES}
|
||||
)
|
||||
|
||||
file(GLOB OSQUERY_CROSS_TABLES_TESTS "[!uo]*/tests/*.cpp")
|
||||
ADD_OSQUERY_TABLE_TEST(${OSQUERY_CROSS_TABLES_TESTS})
|
||||
file(GLOB OSQUERY_CROSS_TABLES_TESTS "[!uo]*/tests/*/*.cpp")
|
||||
file(GLOB OSQUERY_CATEGORY_TABLE_TESTS "[!uo]*/tests/*.cpp")
|
||||
file(GLOB OSQUERY_TABLE_TESTS "tests/*.cpp")
|
||||
ADD_OSQUERY_TABLE_TEST(
|
||||
${OSQUERY_CROSS_TABLES_TESTS}
|
||||
${OSQUERY_CATEGORY_TABLE_TESTS}
|
||||
${OSQUERY_TABLE_TESTS}
|
||||
)
|
||||
|
||||
file(GLOB OSQUERY_UTILITY_TABLES "utility/*.cpp")
|
||||
ADD_OSQUERY_LIBRARY_CORE(osquery_tables_utility
|
||||
|
@ -1,29 +0,0 @@
|
||||
/*
|
||||
* 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 <gtest/gtest.h>
|
||||
|
||||
#include <osquery/logger.h>
|
||||
|
||||
#include "osquery/core/test_util.h"
|
||||
|
||||
namespace osquery {
|
||||
namespace tables {
|
||||
|
||||
osquery::QueryData parseEtcHostsContent(const std::string& content);
|
||||
|
||||
class EtcHostsTests : public testing::Test {};
|
||||
|
||||
TEST_F(EtcHostsTests, test_parse_etc_hosts_content) {
|
||||
EXPECT_EQ(parseEtcHostsContent(getEtcHostsContent()),
|
||||
getEtcHostsExpectedResults());
|
||||
}
|
||||
}
|
||||
}
|
@ -17,11 +17,17 @@
|
||||
namespace osquery {
|
||||
namespace tables {
|
||||
|
||||
osquery::QueryData parseEtcHostsContent(const std::string& content);
|
||||
osquery::QueryData parseEtcProtocolsContent(const std::string& content);
|
||||
|
||||
class EtcProtocolsTests : public testing::Test {};
|
||||
class NetworkingTablesTests : public testing::Test {};
|
||||
|
||||
TEST_F(EtcProtocolsTests, test_parse_etc_protocols_content) {
|
||||
TEST_F(NetworkingTablesTests, test_parse_etc_hosts_content) {
|
||||
EXPECT_EQ(parseEtcHostsContent(getEtcHostsContent()),
|
||||
getEtcHostsExpectedResults());
|
||||
}
|
||||
|
||||
TEST_F(NetworkingTablesTests, test_parse_etc_protocols_content) {
|
||||
EXPECT_EQ(parseEtcProtocolsContent(getEtcProtocolsContent()),
|
||||
getEtcProtocolsExpectedResults());
|
||||
}
|
@ -81,26 +81,6 @@ std::set<int> getProcList(const QueryContext &context) {
|
||||
return pidlist;
|
||||
}
|
||||
|
||||
std::map<int, int> getParentMap(const std::set<int> &pidlist) {
|
||||
std::map<int, int> pidmap;
|
||||
|
||||
struct kinfo_proc proc;
|
||||
size_t size = sizeof(proc);
|
||||
|
||||
for (const auto &pid : pidlist) {
|
||||
int name[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
|
||||
if (sysctl((int *)name, 4, &proc, &size, nullptr, 0) == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (size > 0) {
|
||||
pidmap[pid] = (int)proc.kp_eproc.e_ppid;
|
||||
}
|
||||
}
|
||||
|
||||
return pidmap;
|
||||
}
|
||||
|
||||
inline std::string getProcPath(int pid) {
|
||||
char path[PROC_PIDPATHINFO_MAXSIZE] = {0};
|
||||
int bufsize = proc_pidpath(pid, path, sizeof(path));
|
||||
@ -112,21 +92,44 @@ inline std::string getProcPath(int pid) {
|
||||
}
|
||||
|
||||
struct proc_cred {
|
||||
uint32_t parent{0};
|
||||
uint32_t group{0};
|
||||
uint32_t status{0};
|
||||
uint32_t nice{0};
|
||||
struct {
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
uid_t uid{0};
|
||||
gid_t gid{0};
|
||||
} real, effective;
|
||||
};
|
||||
|
||||
inline bool getProcCred(int pid, proc_cred &cred) {
|
||||
struct proc_bsdshortinfo bsdinfo;
|
||||
struct proc_bsdinfo bsdinfo;
|
||||
struct proc_bsdshortinfo bsdinfo_short;
|
||||
|
||||
if (proc_pidinfo(pid, PROC_PIDT_SHORTBSDINFO, 0, &bsdinfo, sizeof(bsdinfo)) ==
|
||||
sizeof(bsdinfo)) {
|
||||
cred.real.uid = bsdinfo.pbsi_ruid;
|
||||
cred.real.gid = bsdinfo.pbsi_rgid;
|
||||
cred.effective.uid = bsdinfo.pbsi_uid;
|
||||
cred.effective.gid = bsdinfo.pbsi_gid;
|
||||
if (proc_pidinfo(pid, PROC_PIDTBSDINFO, 0, &bsdinfo, PROC_PIDTBSDINFO_SIZE) ==
|
||||
PROC_PIDTBSDINFO_SIZE) {
|
||||
cred.parent = bsdinfo.pbi_ppid;
|
||||
cred.group = bsdinfo.pbi_pgid;
|
||||
cred.status = bsdinfo.pbi_status;
|
||||
cred.nice = bsdinfo.pbi_nice;
|
||||
cred.real.uid = bsdinfo.pbi_ruid;
|
||||
cred.real.gid = bsdinfo.pbi_rgid;
|
||||
cred.effective.uid = bsdinfo.pbi_uid;
|
||||
cred.effective.gid = bsdinfo.pbi_gid;
|
||||
return true;
|
||||
} else if (proc_pidinfo(pid,
|
||||
PROC_PIDT_SHORTBSDINFO,
|
||||
0,
|
||||
&bsdinfo_short,
|
||||
PROC_PIDT_SHORTBSDINFO_SIZE) ==
|
||||
PROC_PIDT_SHORTBSDINFO_SIZE) {
|
||||
cred.parent = bsdinfo_short.pbsi_ppid;
|
||||
cred.group = bsdinfo_short.pbsi_pgid;
|
||||
cred.status = bsdinfo_short.pbsi_status;
|
||||
cred.real.uid = bsdinfo_short.pbsi_ruid;
|
||||
cred.real.gid = bsdinfo_short.pbsi_rgid;
|
||||
cred.effective.uid = bsdinfo_short.pbsi_uid;
|
||||
cred.effective.gid = bsdinfo_short.pbsi_gid;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -227,22 +230,11 @@ QueryData genProcesses(QueryContext &context) {
|
||||
}
|
||||
|
||||
auto pidlist = getProcList(context);
|
||||
auto parent_pid = getParentMap(pidlist);
|
||||
int argmax = genMaxArgs();
|
||||
|
||||
for (auto &pid : pidlist) {
|
||||
Row r;
|
||||
r["pid"] = INTEGER(pid);
|
||||
|
||||
// Find the parent process.
|
||||
const auto parent_it = parent_pid.find(pid);
|
||||
if (parent_it != parent_pid.end()) {
|
||||
r["parent"] = INTEGER(parent_it->second);
|
||||
} else {
|
||||
// On OS X a missing parent path means the pid did not exist.
|
||||
continue;
|
||||
}
|
||||
|
||||
r["path"] = getProcPath(pid);
|
||||
// OS X proc_name only returns 16 bytes, use the basename of the path.
|
||||
r["name"] = fs::path(r["path"]).filename().string();
|
||||
@ -259,11 +251,20 @@ QueryData genProcesses(QueryContext &context) {
|
||||
|
||||
proc_cred cred;
|
||||
if (getProcCred(pid, cred)) {
|
||||
r["parent"] = BIGINT(cred.parent);
|
||||
r["group"] = BIGINT(cred.group);
|
||||
// Use Linux diction for process status/state.
|
||||
r["state"] = INTEGER(cred.status);
|
||||
r["nice"] = INTEGER(cred.nice);
|
||||
r["uid"] = BIGINT(cred.real.uid);
|
||||
r["gid"] = BIGINT(cred.real.gid);
|
||||
r["euid"] = BIGINT(cred.effective.uid);
|
||||
r["egid"] = BIGINT(cred.effective.gid);
|
||||
} else {
|
||||
r["parent"] = "0";
|
||||
r["group"] = "0";
|
||||
r["state"] = "0";
|
||||
r["nice"] = "0";
|
||||
r["uid"] = "-1";
|
||||
r["gid"] = "-1";
|
||||
r["euid"] = "-1";
|
||||
|
@ -26,8 +26,7 @@ namespace tables {
|
||||
const std::string kLinuxOSRelease = "/etc/redhat-release";
|
||||
const std::string kLinuxOSRegex =
|
||||
"(?P<name>[\\w+\\s]+) .* "
|
||||
"(?P<major>[0-9]+)\\.(?P<minor>[0-9]+) "
|
||||
"(?P<patch>\\(\\w+\\))";
|
||||
"(?P<major>[0-9]+)\\.(?P<minor>[0-9]+)\\.?(?P<patch>\\w+)?";
|
||||
#else
|
||||
const std::string kLinuxOSRelease = "/etc/os-release";
|
||||
const std::string kLinuxOSRegex =
|
||||
|
@ -134,7 +134,6 @@ void genProcessMap(const std::string& pid, QueryData& results) {
|
||||
|
||||
struct SimpleProcStat {
|
||||
// Output from string parsing /proc/<pid>/status.
|
||||
std::string parent; // PPid:
|
||||
std::string name; // Name:
|
||||
std::string real_uid; // Uid: * - - -
|
||||
std::string real_gid; // Gid: * - - -
|
||||
@ -145,6 +144,11 @@ struct SimpleProcStat {
|
||||
std::string phys_footprint; // VmSize:
|
||||
|
||||
// Output from sring parsing /proc/<pid>/stat.
|
||||
std::string state;
|
||||
std::string parent;
|
||||
std::string group;
|
||||
std::string nice;
|
||||
|
||||
std::string user_time;
|
||||
std::string system_time;
|
||||
std::string start_time;
|
||||
@ -157,9 +161,12 @@ SimpleProcStat getProcStat(const std::string& pid) {
|
||||
auto detail_start = content.find_last_of(")");
|
||||
// Start parsing stats from ") <MODE>..."
|
||||
auto details = osquery::split(content.substr(detail_start + 2), " ");
|
||||
stat.state = details.at(0);
|
||||
stat.parent = details.at(1);
|
||||
stat.group = details.at(2);
|
||||
stat.user_time = details.at(11);
|
||||
stat.system_time = details.at(12);
|
||||
stat.nice = details.at(16);
|
||||
stat.start_time = TEXT(AS_LITERAL(BIGINT_LITERAL, details.at(19)) / 100);
|
||||
}
|
||||
|
||||
@ -211,6 +218,9 @@ void genProcess(const std::string& pid, QueryData& results) {
|
||||
r["parent"] = proc_stat.parent;
|
||||
r["path"] = readProcLink("exe", pid);
|
||||
r["name"] = proc_stat.name;
|
||||
r["group"] = proc_stat.group;
|
||||
r["state"] = proc_stat.state;
|
||||
r["nice"] = proc_stat.nice;
|
||||
|
||||
// Read/parse cmdline arguments.
|
||||
r["cmdline"] = readProcCMDLine(pid);
|
||||
|
38
osquery/tables/system/tests/system_tables_tests.cpp
Normal file
38
osquery/tables/system/tests/system_tables_tests.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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 <gtest/gtest.h>
|
||||
|
||||
#include <osquery/logger.h>
|
||||
#include <osquery/tables.h>
|
||||
|
||||
#include "osquery/core/test_util.h"
|
||||
|
||||
namespace osquery {
|
||||
namespace tables {
|
||||
|
||||
QueryData genOSVersion(QueryContext& context);
|
||||
|
||||
class SystemsTablesTests : public testing::Test {};
|
||||
|
||||
TEST_F(SystemsTablesTests, test_os_version) {
|
||||
QueryContext context;
|
||||
auto result = genOSVersion(context);
|
||||
EXPECT_EQ(result.size(), 1);
|
||||
|
||||
// Make sure major and minor contain data (a missing value of -1 is an error).
|
||||
EXPECT_FALSE(result[0]["major"].empty());
|
||||
EXPECT_FALSE(result[0]["minor"].empty());
|
||||
|
||||
// The OS name should be filled in too.
|
||||
EXPECT_FALSE(result[0]["name"].empty());
|
||||
}
|
||||
}
|
||||
}
|
@ -38,6 +38,11 @@ QueryData genOsqueryEvents(QueryContext& context) {
|
||||
r["events"] = INTEGER(pubref->numEvents());
|
||||
r["restarts"] = INTEGER(pubref->restartCount());
|
||||
r["active"] = (pubref->hasStarted() && !pubref->isEnding()) ? "1" : "0";
|
||||
} else {
|
||||
r["subscriptions"] = "0";
|
||||
r["events"] = "0";
|
||||
r["restarts"] = "0";
|
||||
r["active"] = "-1";
|
||||
}
|
||||
results.push_back(r);
|
||||
}
|
||||
@ -47,6 +52,8 @@ QueryData genOsqueryEvents(QueryContext& context) {
|
||||
Row r;
|
||||
r["name"] = subscriber;
|
||||
r["type"] = "subscriber";
|
||||
// Subscribers will never 'restart'.
|
||||
r["restarts"] = "0";
|
||||
|
||||
auto subref = EventFactory::getEventSubscriber(subscriber);
|
||||
if (subref != nullptr) {
|
||||
@ -54,10 +61,12 @@ QueryData genOsqueryEvents(QueryContext& context) {
|
||||
r["subscriptions"] = INTEGER(subref->numSubscriptions());
|
||||
r["events"] = INTEGER(subref->numEvents());
|
||||
|
||||
// Subscribers will never 'restart'.
|
||||
r["restarts"] = "0";
|
||||
// Subscribers are always active, even if their publisher is not.
|
||||
r["active"] = (subref->state() == SUBSCRIBER_RUNNING) ? "1" : "0";
|
||||
} else {
|
||||
r["subscriptions"] = "0";
|
||||
r["events"] = "0";
|
||||
r["active"] = "-1";
|
||||
}
|
||||
results.push_back(r);
|
||||
}
|
||||
@ -211,6 +220,13 @@ QueryData genOsquerySchedule(QueryContext& context) {
|
||||
r["name"] = TEXT(name);
|
||||
r["query"] = TEXT(query.query);
|
||||
r["interval"] = INTEGER(query.interval);
|
||||
// Set default (0) values for each query if it has not yet executed.
|
||||
r["executions"] = "0";
|
||||
r["output_size"] = "0";
|
||||
r["wall_time"] = "0";
|
||||
r["user_time"] = "0";
|
||||
r["system_time"] = "0";
|
||||
r["average_memory"] = "0";
|
||||
|
||||
// Report optional performance information.
|
||||
Config::getInstance().getPerformanceStats(
|
||||
|
@ -1,14 +1,15 @@
|
||||
table_name("processes")
|
||||
description("All running processes on the host system.")
|
||||
schema([
|
||||
Column("pid", INTEGER, "Process (or thread) ID", index=True),
|
||||
Column("pid", BIGINT, "Process (or thread) ID", index=True),
|
||||
Column("name", TEXT, "The process path or shorthand argv[0]"),
|
||||
Column("path", TEXT, "Path to executed binary"),
|
||||
Column("cmdline", TEXT, "Complete argv"),
|
||||
Column("state", TEXT, "Process state"),
|
||||
Column("cwd", TEXT, "Process current working directory"),
|
||||
Column("root", TEXT, "Process virtual root directory"),
|
||||
Column("uid", BIGINT, "Unsigned user ID"),
|
||||
Column("gid", BIGINT, "Unsgiend groud ID"),
|
||||
Column("gid", BIGINT, "Unsigned group ID"),
|
||||
Column("euid", BIGINT, "Unsigned effective user ID"),
|
||||
Column("egid", BIGINT, "Unsigned effective group ID"),
|
||||
Column("on_disk", INTEGER,
|
||||
@ -20,7 +21,9 @@ schema([
|
||||
Column("system_time", BIGINT, "CPU time spent in kernel space"),
|
||||
Column("start_time", BIGINT,
|
||||
"Process start in seconds since boot (non-sleeping)"),
|
||||
Column("parent", INTEGER, "Process parent's PID"),
|
||||
Column("parent", BIGINT, "Process parent's PID"),
|
||||
Column("group", BIGINT, "Process group"),
|
||||
Column("nice", INTEGER, "Process nice level (-20 to 20, default 0)"),
|
||||
])
|
||||
implementation("system/processes@genProcesses")
|
||||
examples([
|
||||
|
Loading…
Reference in New Issue
Block a user