Adding kernel panics table (#2488)

This commit is contained in:
Nick Anderson 2016-09-23 19:04:50 -07:00 committed by Teddy Reed
parent 2a7824e583
commit e167619bfa
2 changed files with 151 additions and 0 deletions

View File

@ -0,0 +1,133 @@
/*
* Copyright (c) 2014-present, 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 <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/regex.hpp>
#include <osquery/filesystem.h>
#include <osquery/tables.h>
#include "osquery/core/conversions.h"
#include "osquery/tables/system/system_utils.h"
namespace fs = boost::filesystem;
namespace alg = boost::algorithm;
namespace osquery {
namespace tables {
/// Location of the kernel panic crash logs in OS X
const std::string kDiagnosticReportsPath = "/Library/Logs/DiagnosticReports";
/// List of all register values we wish to catch
const std::set<std::string> kRegisters = {
"CR0", "RAX", "RSP", "R8", "R12", "RFL",
};
/// List of the days of the Week, used to grab our timestamp.
const std::set<std::string> kDays = {"Mon", "Tue", "Wed", "Thu", "Fri"};
/// Map of the values we currently parse out of the log file
const std::map<std::string, std::string> kKernelPanicKeys = {
{"dependency", "dependencies"},
{"BSD process name corresponding to current thread", "name"},
{"System model name", "system_model"},
{"System uptime in nanoseconds", "uptime"},
};
void readKernelPanic(const std::string& appLog, QueryData& results) {
Row r;
r["path"] = appLog;
std::string content;
if (!readFile(appLog, content).ok()) {
return;
}
boost::regex rxSpaces("\\s+");
auto lines = osquery::split(content, "\n");
for (auto it = lines.begin(); it != lines.end(); it++) {
auto line = *it;
boost::trim(line);
auto toks = osquery::split(line, ":");
if (toks.size() == 0) {
continue;
}
auto timeTokens = osquery::split(toks[0], " ");
if (timeTokens.size() >= 1 && kDays.count(timeTokens[0]) > 0) {
r["time"] = line;
}
if (kRegisters.count(toks[0]) > 0) {
auto registerTokens = osquery::split(line, ",");
if (registerTokens.size() == 0) {
continue;
}
for (auto& tok_ : registerTokens) {
auto regHolder = osquery::split(tok_, ":");
if (regHolder.size() != 2) {
continue;
}
auto reg = std::move(regHolder[0]);
auto val = std::move(regHolder[1]);
if (reg.size() > 0 && val.size() > 0) {
std::string regLine = reg + ":" + val;
r["registers"] += (r["registers"].empty()) ? std::move(regLine)
: " " + std::move(regLine);
}
}
} else if (boost::starts_with(toks[0], "last loaded kext at") &&
toks.size() == 2) {
r["last_loaded"] = boost::regex_replace(toks[1], rxSpaces, " ");
} else if (boost::starts_with(toks[0], "last unloaded kext at") &&
toks.size() == 2) {
r["last_unloaded"] = boost::regex_replace(toks[1], rxSpaces, " ");
} else if (boost::starts_with(toks[0], "Backtrace") &&
std::next(it) != lines.end()) {
r["frame_backtrace"] = *(std::next(it));
} else if (boost::starts_with(toks[0], "Kernel Extensions in backtrace") &&
std::next(it) != lines.end()) {
r["module_backtrace"] = *(std::next(it));
} else if (boost::starts_with(toks[0], "Mac OS version") &&
std::next(it) != lines.end()) {
r["os_version"] = *(std::next(it));
} else if (boost::starts_with(toks[0], "Kernel version") &&
std::next(it) != lines.end()) {
r["kernel_version"] = *(std::next(it));
} else if (kKernelPanicKeys.count(toks[0]) != 0 && toks.size() == 2) {
r[kKernelPanicKeys.at(toks[0])] = toks[1];
}
}
results.push_back(r);
}
QueryData genKernelPanics(QueryContext& context) {
QueryData results;
if (context.constraints["uid"].notExistsOrMatches("0")) {
std::vector<std::string> files;
if (listFilesInDirectory(kDiagnosticReportsPath, files)) {
for (const auto& lf : files) {
if (alg::ends_with(lf, ".panic")) {
readKernelPanic(lf, results);
}
}
}
}
return results;
}
}
}

View File

@ -0,0 +1,18 @@
table_name("kernel_panics")
description("Kernel Panics")
schema([
Column("path", TEXT, "Location of log file"),
Column("time", TEXT, "Formatted time of the event"),
Column("registers", TEXT, "A space delimited line of register:value pairs"),
Column("frame_backtrace", TEXT, "Backtrace of the crashed module"),
Column("module_backtrace", TEXT, "Modules appearing in the crashed module's backtrace"),
Column("dependencies", TEXT, "Module dependencies existing in crashed module's backtrace"),
Column("name", TEXT, "Process name corresponding to crashed thread"),
Column("os_version", TEXT, "Version of the operating system"),
Column("kernel_version", TEXT, "Version of the system kernel"),
Column("system_model", TEXT, "Physical system model, for example 'MacBookPro12,1 (Mac-E43C1C25D4880AD6)'"),
Column("uptime", BIGINT, "System uptime at kernel panic in nanoseconds"),
Column("last_loaded", TEXT, "Last loaded module before panic"),
Column("last_unloaded", TEXT, "Last unloaded module before panic"),
])
implementation("kernel_panics@genKernelPanics")