1*325a5df9SAndroid Build Coastguard Worker /*
2*325a5df9SAndroid Build Coastguard Worker * Copyright 2022, The Android Open Source Project
3*325a5df9SAndroid Build Coastguard Worker *
4*325a5df9SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*325a5df9SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*325a5df9SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*325a5df9SAndroid Build Coastguard Worker *
8*325a5df9SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*325a5df9SAndroid Build Coastguard Worker *
10*325a5df9SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*325a5df9SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*325a5df9SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*325a5df9SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*325a5df9SAndroid Build Coastguard Worker * limitations under the License.
15*325a5df9SAndroid Build Coastguard Worker */
16*325a5df9SAndroid Build Coastguard Worker
17*325a5df9SAndroid Build Coastguard Worker #include <regex>
18*325a5df9SAndroid Build Coastguard Worker #include <string>
19*325a5df9SAndroid Build Coastguard Worker
20*325a5df9SAndroid Build Coastguard Worker #include "dmesg_parser.h"
21*325a5df9SAndroid Build Coastguard Worker
22*325a5df9SAndroid Build Coastguard Worker namespace dmesg_parser {
23*325a5df9SAndroid Build Coastguard Worker
24*325a5df9SAndroid Build Coastguard Worker const std::string kTimestampRe = "^\\[[^\\]]+\\]\\s";
25*325a5df9SAndroid Build Coastguard Worker
DmesgParser()26*325a5df9SAndroid Build Coastguard Worker DmesgParser::DmesgParser() : report_ready_(false) {
27*325a5df9SAndroid Build Coastguard Worker std::string bug_types;
28*325a5df9SAndroid Build Coastguard Worker for (auto t : {"KFENCE", "KASAN"}) {
29*325a5df9SAndroid Build Coastguard Worker if (bug_types.empty()) {
30*325a5df9SAndroid Build Coastguard Worker bug_types = t;
31*325a5df9SAndroid Build Coastguard Worker } else {
32*325a5df9SAndroid Build Coastguard Worker bug_types.append("|");
33*325a5df9SAndroid Build Coastguard Worker bug_types.append(t);
34*325a5df9SAndroid Build Coastguard Worker }
35*325a5df9SAndroid Build Coastguard Worker }
36*325a5df9SAndroid Build Coastguard Worker std::string bug_re = kTimestampRe + "\\[([0-9T\\s]+)\\]\\s(BUG: (" + bug_types + "):.*)";
37*325a5df9SAndroid Build Coastguard Worker this->bug_pattern_ = std::regex(bug_re);
38*325a5df9SAndroid Build Coastguard Worker this->ignore_pattern_ = std::regex("([ _][Rx]..|raw): [0-9a-f]{16}|"
39*325a5df9SAndroid Build Coastguard Worker "Hardware name:|Comm:");
40*325a5df9SAndroid Build Coastguard Worker this->addr64_pattern_ = std::regex("\\b(?:0x)?[0-9a-f]{16}\\b");
41*325a5df9SAndroid Build Coastguard Worker }
42*325a5df9SAndroid Build Coastguard Worker
43*325a5df9SAndroid Build Coastguard Worker /*
44*325a5df9SAndroid Build Coastguard Worker * Read a single line terminated by a newline, and process it as follows:
45*325a5df9SAndroid Build Coastguard Worker * 1. If we haven't seen a bug header, skip the current line unless it contains
46*325a5df9SAndroid Build Coastguard Worker * "BUG:".
47*325a5df9SAndroid Build Coastguard Worker * If it does, parse the line to extract the task ID (T1234), tool name
48*325a5df9SAndroid Build Coastguard Worker * (KASAN or KFENCE) and the whole report title (needed for report
49*325a5df9SAndroid Build Coastguard Worker * deduplication).
50*325a5df9SAndroid Build Coastguard Worker * 2. If the current line does not contain the known task ID, skip it.
51*325a5df9SAndroid Build Coastguard Worker * 3. If the current line contains a delimiter ("====="), stop accepting new
52*325a5df9SAndroid Build Coastguard Worker * lines.
53*325a5df9SAndroid Build Coastguard Worker * 4. Otherwise strip potential sensitive data from the current line and append
54*325a5df9SAndroid Build Coastguard Worker * it to the report.
55*325a5df9SAndroid Build Coastguard Worker */
ProcessLine(const std::string & line)56*325a5df9SAndroid Build Coastguard Worker void DmesgParser::ProcessLine(const std::string& line) {
57*325a5df9SAndroid Build Coastguard Worker if (report_ready_) return;
58*325a5df9SAndroid Build Coastguard Worker
59*325a5df9SAndroid Build Coastguard Worker // We haven't encountered a BUG: line yet.
60*325a5df9SAndroid Build Coastguard Worker if (current_report_.empty()) {
61*325a5df9SAndroid Build Coastguard Worker std::smatch m;
62*325a5df9SAndroid Build Coastguard Worker if (std::regex_search(line, m, bug_pattern_)) {
63*325a5df9SAndroid Build Coastguard Worker std::string task_re = kTimestampRe + "\\[" + std::string(m[1]) + "\\]\\s";
64*325a5df9SAndroid Build Coastguard Worker task_line_pattern_ = std::regex(task_re);
65*325a5df9SAndroid Build Coastguard Worker task_delimiter_pattern_ = std::regex(task_re + "={10,}");
66*325a5df9SAndroid Build Coastguard Worker current_title_ = m[2];
67*325a5df9SAndroid Build Coastguard Worker current_tool_ = m[3];
68*325a5df9SAndroid Build Coastguard Worker current_report_ = this->StripSensitiveData(line);
69*325a5df9SAndroid Build Coastguard Worker }
70*325a5df9SAndroid Build Coastguard Worker return;
71*325a5df9SAndroid Build Coastguard Worker }
72*325a5df9SAndroid Build Coastguard Worker
73*325a5df9SAndroid Build Coastguard Worker // If there is a delimiter, mark the current report as ready.
74*325a5df9SAndroid Build Coastguard Worker if (std::regex_search(line, task_delimiter_pattern_)) {
75*325a5df9SAndroid Build Coastguard Worker report_ready_ = true;
76*325a5df9SAndroid Build Coastguard Worker return;
77*325a5df9SAndroid Build Coastguard Worker }
78*325a5df9SAndroid Build Coastguard Worker
79*325a5df9SAndroid Build Coastguard Worker if (std::regex_search(line, task_line_pattern_)) current_report_ += StripSensitiveData(line);
80*325a5df9SAndroid Build Coastguard Worker }
81*325a5df9SAndroid Build Coastguard Worker
82*325a5df9SAndroid Build Coastguard Worker /*
83*325a5df9SAndroid Build Coastguard Worker * Return true iff the current report is ready (it was terminated by the "====="
84*325a5df9SAndroid Build Coastguard Worker * delimiter.
85*325a5df9SAndroid Build Coastguard Worker */
ReportReady() const86*325a5df9SAndroid Build Coastguard Worker bool DmesgParser::ReportReady() const {
87*325a5df9SAndroid Build Coastguard Worker return report_ready_;
88*325a5df9SAndroid Build Coastguard Worker }
89*325a5df9SAndroid Build Coastguard Worker
90*325a5df9SAndroid Build Coastguard Worker /*
91*325a5df9SAndroid Build Coastguard Worker * Return the tool that generated the currently collected report.
92*325a5df9SAndroid Build Coastguard Worker */
ReportType() const93*325a5df9SAndroid Build Coastguard Worker std::string DmesgParser::ReportType() const {
94*325a5df9SAndroid Build Coastguard Worker return current_tool_;
95*325a5df9SAndroid Build Coastguard Worker }
96*325a5df9SAndroid Build Coastguard Worker
97*325a5df9SAndroid Build Coastguard Worker /*
98*325a5df9SAndroid Build Coastguard Worker * Return the title of the currently collected report.
99*325a5df9SAndroid Build Coastguard Worker */
ReportTitle() const100*325a5df9SAndroid Build Coastguard Worker std::string DmesgParser::ReportTitle() const {
101*325a5df9SAndroid Build Coastguard Worker return current_title_;
102*325a5df9SAndroid Build Coastguard Worker }
103*325a5df9SAndroid Build Coastguard Worker
104*325a5df9SAndroid Build Coastguard Worker /*
105*325a5df9SAndroid Build Coastguard Worker * Return the report collected so far and reset the parser.
106*325a5df9SAndroid Build Coastguard Worker */
FlushReport()107*325a5df9SAndroid Build Coastguard Worker std::string DmesgParser::FlushReport() {
108*325a5df9SAndroid Build Coastguard Worker report_ready_ = false;
109*325a5df9SAndroid Build Coastguard Worker return std::move(current_report_);
110*325a5df9SAndroid Build Coastguard Worker }
111*325a5df9SAndroid Build Coastguard Worker
112*325a5df9SAndroid Build Coastguard Worker /*
113*325a5df9SAndroid Build Coastguard Worker * Strip potentially sensitive data from the reports by performing the
114*325a5df9SAndroid Build Coastguard Worker * following actions:
115*325a5df9SAndroid Build Coastguard Worker * 1. Drop the entire line, if it contains a process name:
116*325a5df9SAndroid Build Coastguard Worker * [ 69.547684] [ T6006]c7 6006 CPU: 7 PID: 6006 Comm: sh Tainted:
117*325a5df9SAndroid Build Coastguard Worker *
118*325a5df9SAndroid Build Coastguard Worker * or hardware name:
119*325a5df9SAndroid Build Coastguard Worker * [ 69.558923] [ T6006]c7 6006 Hardware name: Phone1
120*325a5df9SAndroid Build Coastguard Worker *
121*325a5df9SAndroid Build Coastguard Worker * or a memory dump, e.g.:
122*325a5df9SAndroid Build Coastguard Worker *
123*325a5df9SAndroid Build Coastguard Worker * ... raw: 4000000000010200 0000000000000000 0000000000000000
124*325a5df9SAndroid Build Coastguard Worker *
125*325a5df9SAndroid Build Coastguard Worker * or register dump:
126*325a5df9SAndroid Build Coastguard Worker *
127*325a5df9SAndroid Build Coastguard Worker * ... RIP: 0033:0x7f96443109da
128*325a5df9SAndroid Build Coastguard Worker * ... RSP: 002b:00007ffcf0b51b08 EFLAGS: 00000202 ORIG_RAX: 00000000000000af
129*325a5df9SAndroid Build Coastguard Worker * ... RAX: ffffffffffffffda RBX: 000055dc3ee521a0 RCX: 00007f96443109da
130*325a5df9SAndroid Build Coastguard Worker *
131*325a5df9SAndroid Build Coastguard Worker * (on x86_64)
132*325a5df9SAndroid Build Coastguard Worker *
133*325a5df9SAndroid Build Coastguard Worker * ... pc : lpm_cpuidle_enter+0x258/0x384
134*325a5df9SAndroid Build Coastguard Worker * ... lr : lpm_cpuidle_enter+0x1d4/0x384
135*325a5df9SAndroid Build Coastguard Worker * ... sp : ffffff800820bea0
136*325a5df9SAndroid Build Coastguard Worker * ... x29: ffffff800820bea0 x28: ffffffc2305f3ce0
137*325a5df9SAndroid Build Coastguard Worker * ... ...
138*325a5df9SAndroid Build Coastguard Worker * ... x9 : 0000000000000001 x8 : 0000000000000000
139*325a5df9SAndroid Build Coastguard Worker *
140*325a5df9SAndroid Build Coastguard Worker * (on ARM64)
141*325a5df9SAndroid Build Coastguard Worker *
142*325a5df9SAndroid Build Coastguard Worker * 2. For substrings that are known to be followed by sensitive information,
143*325a5df9SAndroid Build Coastguard Worker * cut the line after those substrings and append "DELETED\n",
144*325a5df9SAndroid Build Coastguard Worker * e.g. " by task ":
145*325a5df9SAndroid Build Coastguard Worker * ... Read at addr f0ffff87c23fdf7f by task sh/9971
146*325a5df9SAndroid Build Coastguard Worker * and "Corrupted memory at":
147*325a5df9SAndroid Build Coastguard Worker * ... Corrupted memory at 0xf0ffff87c23fdf00 [ ! . . . . . . . . . . . . . . . ]
148*325a5df9SAndroid Build Coastguard Worker *
149*325a5df9SAndroid Build Coastguard Worker * 3. Replace all strings that look like 64-bit hexadecimal values, with
150*325a5df9SAndroid Build Coastguard Worker * XXXXXXXXXXXXXXXX.
151*325a5df9SAndroid Build Coastguard Worker */
StripSensitiveData(const std::string & line) const152*325a5df9SAndroid Build Coastguard Worker std::string DmesgParser::StripSensitiveData(const std::string& line) const {
153*325a5df9SAndroid Build Coastguard Worker if (std::regex_search(line, ignore_pattern_)) return "";
154*325a5df9SAndroid Build Coastguard Worker
155*325a5df9SAndroid Build Coastguard Worker std::string ret = line;
156*325a5df9SAndroid Build Coastguard Worker for (std::string infix : {"Corrupted memory at ", " by task "}) {
157*325a5df9SAndroid Build Coastguard Worker auto pos = ret.find(infix);
158*325a5df9SAndroid Build Coastguard Worker if (pos != std::string::npos) {
159*325a5df9SAndroid Build Coastguard Worker ret = ret.substr(0, pos + infix.size()) + "DELETED\n";
160*325a5df9SAndroid Build Coastguard Worker }
161*325a5df9SAndroid Build Coastguard Worker }
162*325a5df9SAndroid Build Coastguard Worker ret = std::regex_replace(ret, addr64_pattern_, "XXXXXXXXXXXXXXXX");
163*325a5df9SAndroid Build Coastguard Worker return ret;
164*325a5df9SAndroid Build Coastguard Worker }
165*325a5df9SAndroid Build Coastguard Worker
166*325a5df9SAndroid Build Coastguard Worker } // namespace dmesg_parser
167