xref: /aosp_15_r20/system/dmesgd/dmesg_parser.cpp (revision 325a5df984070639bfcfcc2d7b58a6181e21cf50)
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