blob: 951f63ab5c7b547843a350fa78cca27db035f211 [file] [log] [blame]
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Defines base class LogReader and its derived classes AuditReader and
// MessageReader. AuditReader parses SELinux logs from /var/log/audit/audit.log
// and MessageReader parses other logs from /var/log/messages and
// /var/log/upstart.log.
#ifndef CRASH_REPORTER_ANOMALY_DETECTOR_LOG_READER_H_
#define CRASH_REPORTER_ANOMALY_DETECTOR_LOG_READER_H_
#include "crash-reporter/anomaly_detector_text_file_reader.h"
#include <string>
#include <base/files/file_util.h>
#include <base/time/time.h>
#include <re2/re2.h>
namespace anomaly {
// First group captures unix timestamp.
// Second group captures the log message.
// e.g.
// `type=AVC msg=audit(1588751099.358:13): avc: denied { module_request }`
// ` for pid=1795 comm="init" kmod="fs-cgroup2" scontext=u:r:init:s0`
// ` tcontext=u:r:kernel:s0 tclass=system permissive=0`
constexpr char kAuditLogPattern[] = R"([^(]+\(([\d\.]+)\S+ (.+))";
// First group captures timestamp in RFC3339 format.
// Second group captures the tag (i.e. service name).
// Third group captures the log message.
// e.g.
// `2020-05-10T22:45:04.419261Z ERR tpm_managerd[790]: TPM error`
// ` 0x3011 (Communication failure): Failed to connect context.`
// e.g.2
// `2020-05-10T22:45:04.419261Z ERR kernel: [ 893.009245]`
// ` atme1_mxt_ts 3-004b: Status: 00 Config Checksum: 673e89`
// e.g.3
// `2020-05-14T19:37:04.202906Z INFO VM(3)[8947]:`
// ` [devices/src/virtio/balloon.rs:290] ballon config changed`
constexpr char kMessageLogPattern[] = R"((\S+) \S+ (\S*?)(?:\[\d+\])?:\s+(.+))";
// First group captures timestamp in RFC3339 format.
// Second group captures the service name.
// Third group captures the log message.
// e.g.
// `2020-05-15T16:34:00.678394Z INFO kernel:`
// ` [ 1608.687863] init: Connection from private client`
constexpr char kUpstartLogPattern[] =
R"((\S+) \S+ \S+: \[\s*\S+\] (\w+):\s+(.+))";
// Describes an entry in log files.
// tag: name of the service that generated the log.
// message: content of the log.
// timestamp: timestamp of the log.
struct LogEntry {
std::string tag;
std::string message;
base::Time timestamp;
};
// LogReader parses newline-delimited log entries into structs that can
// be parsed by log parsers (in anomaly_detector.h) to be analysed for errors.
// It uses anomaly::TextFileReader for reading lines in the log files and
// handling log rotations.
class LogReader {
public:
explicit LogReader(const base::FilePath& path);
LogReader(const LogReader&) = delete;
LogReader& operator=(const LogReader&) = delete;
virtual ~LogReader() = 0;
// Returns true while there are log entries in the log file. It will update
// the output parameter 'entry' if one is found.
bool GetNextEntry(LogEntry* entry);
private:
const base::FilePath log_file_path_;
// TextFileReader is defined in anomaly_detector_text_file_reader.h.
TextFileReader log_file_;
// Parses a line from log_file_ to generate LogEntry.
virtual bool ReadLine(const std::string& line, LogEntry* entry) = 0;
// Moves the position of log_file_ to the beginning.
// Only used for testing.
void SeekToBegin();
FRIEND_TEST(AnomalyDetectorLogReaderTest, AuditReaderTest);
FRIEND_TEST(AnomalyDetectorLogReaderTest, MessageReaderTest);
FRIEND_TEST(AnomalyDetectorLogReaderTest, UpstartMessageReaderTest);
};
// AuditReader specialises in parsing log entries generated by SELinux.
class AuditReader : public LogReader {
public:
explicit AuditReader(const base::FilePath& path, const char* pattern)
: LogReader(path), pattern_(pattern) {}
// Each line in log file is checked against pattern_ to retrieve relevant
// info.
const RE2 pattern_;
private:
bool ReadLine(const std::string& line, LogEntry* entry) override;
};
// MessageReader specialises in parsing syslog formatted logs in
// /var/log/messages and /var/log/upstart.log.
class MessageReader : public LogReader {
public:
explicit MessageReader(const base::FilePath& path, const char* pattern)
: LogReader(path), pattern_(pattern) {}
// Each line in log file is checked against pattern_ to retrieve relevant
// info.
const RE2 pattern_;
private:
bool ReadLine(const std::string& line, LogEntry* entry) override;
};
} // namespace anomaly
#endif // CRASH_REPORTER_ANOMALY_DETECTOR_LOG_READER_H_