mirror of
https://github.com/valitydev/osquery-1.git
synced 2024-11-06 09:35:20 +00:00
Prefer /etc/os-release for Linux os_version (#2667)
This commit is contained in:
parent
5bb5ae1030
commit
df25f27efb
@ -8,6 +8,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <boost/xpressive/xpressive.hpp>
|
#include <boost/xpressive/xpressive.hpp>
|
||||||
@ -23,38 +24,80 @@ namespace xp = boost::xpressive;
|
|||||||
namespace osquery {
|
namespace osquery {
|
||||||
namespace tables {
|
namespace tables {
|
||||||
|
|
||||||
#if defined(REDHAT_BASED)
|
const std::string kOSRelease = "/etc/os-release";
|
||||||
const std::string kLinuxOSRelease = "/etc/redhat-release";
|
const std::string kRedhatRelease = "/etc/redhat-release";
|
||||||
const std::string kLinuxOSRegex =
|
|
||||||
"(?P<name>[\\w+\\s]+) .* "
|
|
||||||
"(?P<major>[0-9]+)\\.(?P<minor>[0-9]+)\\.?(?P<patch>\\w+)?";
|
|
||||||
#elif defined(DEBIAN)
|
|
||||||
const std::string kLinuxOSRelease = "/etc/os-release";
|
|
||||||
const std::string kLinuxOSRegex =
|
|
||||||
"PRETTY_NAME=\"(?P<name>[\\w \\/]*) "
|
|
||||||
"(?P<major>[0-9]+)[\\.]{0,1}(?P<minor>[0-9]*)[\\.]{0,1}(?P<patch>[0-9]*).*"
|
|
||||||
"\"";
|
|
||||||
#else
|
|
||||||
const std::string kLinuxOSRelease = "/etc/os-release";
|
|
||||||
#ifdef UBUNTU_XENIAL
|
|
||||||
const std::string kLinuxOSRegex =
|
|
||||||
"VERSION=\"(?P<major>[0-9]+)\\.(?P<minor>[0-9]+)[\\.]{0,1}(?P<patch>[0-9]+)"
|
|
||||||
"?.* \\((?P<name>[\\w ]*)\\)\"$";
|
|
||||||
#else
|
|
||||||
const std::string kLinuxOSRegex =
|
|
||||||
"VERSION=\"(?P<major>[0-9]+)\\.(?P<minor>[0-9]+)[\\.]{0,1}(?P<patch>[0-9]+)"
|
|
||||||
"?.*, (?P<name>[\\w ]*)\"$";
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QueryData genOSVersion(QueryContext& context) {
|
const std::map<std::string, std::string> kOSReleaseColumns = {
|
||||||
|
{"NAME", "name"},
|
||||||
|
{"VERSION", "version"},
|
||||||
|
{"BUILD_ID", "build"},
|
||||||
|
{"ID", "platform"},
|
||||||
|
{"ID_LIKE", "platform_like"},
|
||||||
|
{"VERSION_CODENAME", "codename"},
|
||||||
|
{"VERSION_ID", "_id"},
|
||||||
|
};
|
||||||
|
|
||||||
|
QueryData genOSRelease() {
|
||||||
|
// This will parse /etc/os-version according to the systemd manual.
|
||||||
std::string content;
|
std::string content;
|
||||||
if (!forensicReadFile(kLinuxOSRelease, content).ok()) {
|
if (!readFile(kOSRelease, content).ok()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Row r;
|
Row r;
|
||||||
auto rx = xp::sregex::compile(kLinuxOSRegex);
|
for (const auto& line : osquery::split(content, "\n")) {
|
||||||
|
auto fields = osquery::split(line, "=", 1);
|
||||||
|
if (fields.size() != 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto column = std::ref(kOSReleaseColumns.at("VERSION_CODENAME"));
|
||||||
|
if (kOSReleaseColumns.count(fields[0]) != 0) {
|
||||||
|
column = std::ref(kOSReleaseColumns.at(fields[0]));
|
||||||
|
} else if (fields[0].find("CODENAME") == std::string::npos) {
|
||||||
|
// Some distros may attach/invent their own CODENAME field.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
r[column] = std::move(fields[1]);
|
||||||
|
if (!r.at(column).empty() && r.at(column)[0] == '"') {
|
||||||
|
// This is quote-enclosed string, make it pretty!
|
||||||
|
r[column] = r[column].substr(1, r.at(column).size() - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (column.get() == "_id") {
|
||||||
|
auto parts = osquery::split(r.at(column), ".", 2);
|
||||||
|
switch (parts.size()) {
|
||||||
|
case 3:
|
||||||
|
r["patch"] = parts[2];
|
||||||
|
case 2:
|
||||||
|
r["minor"] = parts[1];
|
||||||
|
case 1:
|
||||||
|
r["major"] = parts[0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {r};
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryData genOSVersion(QueryContext& context) {
|
||||||
|
if (isReadable(kOSRelease)) {
|
||||||
|
return genOSRelease();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string content;
|
||||||
|
if (!isReadable(kRedhatRelease) || !readFile(kRedhatRelease, content).ok()) {
|
||||||
|
// This is an unknown Linux OS.
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Row r;
|
||||||
|
// This is an older version of a Redhat-based OS.
|
||||||
|
auto rx = xp::sregex::compile(
|
||||||
|
"(?P<name>[\\w+\\s]+) .* "
|
||||||
|
"(?P<major>[0-9]+)\\.(?P<minor>[0-9]+)\\.?(?P<patch>\\w+)?");
|
||||||
xp::smatch matches;
|
xp::smatch matches;
|
||||||
for (const auto& line : osquery::split(content, "\n")) {
|
for (const auto& line : osquery::split(content, "\n")) {
|
||||||
if (xp::regex_search(line, matches, rx)) {
|
if (xp::regex_search(line, matches, rx)) {
|
||||||
@ -67,6 +110,9 @@ QueryData genOSVersion(QueryContext& context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r["version"] = content;
|
||||||
|
r["platform_like"] = "rhel";
|
||||||
|
|
||||||
// No build name.
|
// No build name.
|
||||||
r["build"] = "";
|
r["build"] = "";
|
||||||
return {r};
|
return {r};
|
||||||
|
@ -26,22 +26,13 @@ class SystemsTablesTests : public testing::Test {};
|
|||||||
TEST_F(SystemsTablesTests, test_os_version) {
|
TEST_F(SystemsTablesTests, test_os_version) {
|
||||||
auto results = SQL("select * from os_version");
|
auto results = SQL("select * from os_version");
|
||||||
|
|
||||||
// Issue #2564: There is no os_version on Windows.
|
|
||||||
if (!isPlatform(PlatformType::TYPE_WINDOWS)) {
|
|
||||||
EXPECT_EQ(results.rows().size(), 1U);
|
EXPECT_EQ(results.rows().size(), 1U);
|
||||||
|
|
||||||
// Make sure major and minor have data (a missing value of -1 is an error).
|
// Make sure major and minor have data (a missing value of -1 is an error).
|
||||||
EXPECT_FALSE(results.rows()[0].at("major").empty());
|
EXPECT_FALSE(results.rows()[0].at("major").empty());
|
||||||
|
|
||||||
// Debian does not define a minor.
|
|
||||||
#if !defined(DEBIAN)
|
|
||||||
EXPECT_FALSE(results.rows()[0].at("minor").empty());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// The OS name should be filled in too.
|
// The OS name should be filled in too.
|
||||||
EXPECT_FALSE(results.rows()[0].at("name").empty());
|
EXPECT_FALSE(results.rows()[0].at("name").empty());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(SystemsTablesTests, test_process_info) {
|
TEST_F(SystemsTablesTests, test_process_info) {
|
||||||
auto results = SQL("select * from osquery_info join processes using (pid)");
|
auto results = SQL("select * from osquery_info join processes using (pid)");
|
||||||
|
@ -2,10 +2,14 @@ table_name("os_version")
|
|||||||
description("A single row containing the operating system name and version.")
|
description("A single row containing the operating system name and version.")
|
||||||
schema([
|
schema([
|
||||||
Column("name", TEXT, "Distribution or product name"),
|
Column("name", TEXT, "Distribution or product name"),
|
||||||
|
Column("version", TEXT, "Pretty, suitable for presentation, OS version"),
|
||||||
Column("major", INTEGER, "Major release version"),
|
Column("major", INTEGER, "Major release version"),
|
||||||
Column("minor", INTEGER, "Minor release version"),
|
Column("minor", INTEGER, "Minor release version"),
|
||||||
Column("patch", INTEGER, "Optional patch release"),
|
Column("patch", INTEGER, "Optional patch release"),
|
||||||
Column("build", TEXT, "Optional build-specific or variant string"),
|
Column("build", TEXT, "Optional build-specific or variant string"),
|
||||||
|
Column("platform", TEXT, "OS Platform or ID"),
|
||||||
|
Column("platform_like", TEXT, "Closely related platforms"),
|
||||||
|
Column("codename", TEXT, "OS version codename"),
|
||||||
])
|
])
|
||||||
implementation("system/os_version@genOSVersion")
|
implementation("system/os_version@genOSVersion")
|
||||||
fuzz_paths([
|
fuzz_paths([
|
||||||
|
Loading…
Reference in New Issue
Block a user