• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "asan_collector.h"
17 #include <fcntl.h>
18 #include <map>
19 #include <regex>
20 #include <sys/time.h>
21 #include <sys/stat.h>
22 #include <unistd.h>
23 #include "faultlog_util.h"
24 #include "file_util.h"
25 #include "logger.h"
26 #include "reporter.h"
27 #include "zip_helper.h"
28 
29 namespace OHOS {
30 namespace HiviewDFX {
31 DEFINE_LOG_TAG("Faultlogger");
32 const char CLANGLIB[] = "libclang_rt";
33 const std::string SKIP_SPECIAL_PROCESS = "sa_main appspawn";
34 const std::string SKIP_SPECIAL_LIB = "libclang_rt libc libutils libcutils";
35 
36 const std::string ASAN_RECORD_REGEX =
37                 std::string("==([0-9a-zA-Z_.]{1,})==(\\d+)==ERROR: (AddressSanitizer|LeakSanitizer): "
38                             "(\\S+) (.|\\r|\\n)*?SUMMARY: AddressSanitizer:(.|\\r|\\n)*");
39 
40 enum FieldOfAsanRecord {
41     DESCRIPTION_FIELD,
42     PROCNAME_FIELD,
43     PID_FIELD,
44     ORISANITIZERTYPE_FIELD,
45     ERRTYPE_FIELD,
46     MAX_FIELD
47 };
48 
49 const char XDIGIT_REGEX[] = "0[xX][0-9a-fA-F]+";
50 
51 static std::map<std::string, std::string> g_faultTypeInShort = {
52     {"heap-use-after-free", "uaf"},  {"heap-buffer-overflow", "of"},
53     {"stack-buffer-underflow", "uf"},  {"initialization-order-fiasco", "iof"},
54     {"stack-buffer-overflow", "of"},  {"stack-use-after-return", "uar"},
55     {"stack-use-after-scope", "uas"},  {"global-buffer-overflow", "of"},
56     {"use-after-poison", "uap"},  {"dynamic-stack-buffer-overflow", "of"},
57     {"SEGV", "SEGV"},
58 };
59 
AsanCollector(std::unordered_map<std::string,std::string> & stkmap)60 AsanCollector::AsanCollector(std::unordered_map<std::string, std::string> &stkmap) : SanitizerdCollector(stkmap)
61 {
62     curr_.type = ASAN_LOG_RPT;
63     curr_.pid = -1;
64     curr_.uid = -1;
65     curr_.procName = "0";
66     curr_.appVersion = "0";
67     curr_.happenTime = 0;
68 }
69 
~AsanCollector()70 AsanCollector::~AsanCollector()
71 {
72 }
73 
ProcessStackTrace(const std::string & asanDump,bool printDiagnostics,unsigned * hash)74 void AsanCollector::ProcessStackTrace(
75     const std::string& asanDump,
76     bool printDiagnostics,
77     unsigned *hash)
78 {
79     // std::string delimiter = "[\\r\\n]+";
80     // include blankline
81     std::string delimiter = "(?:\\r\\n|\\r|\\n)";
82     auto str_lines = OHOS::HiviewDFX::SplitString(asanDump, delimiter);
83 
84     // Match lines such as the following and grab out "function_name".
85     // The ? may or may not be present.
86     //
87     // : #0 0x7215208f97  (/vendor/lib64/hwcam/hwcam.hi3660.m.DUKE.so+0x289f97)
88 
89     std::string stackEntry =
90         "    #(\\d+) " + std::string(XDIGIT_REGEX) +       // Matches "0x7215208f97"
91         "([\\s\\?(]+)" +                                     // Matches " ? ("
92         "([^\\+ )]+\\+" + std::string(XDIGIT_REGEX) + ")";   // Matches until delimiter reached
93     static const std::regex STACK_ENTRY_RE(stackEntry);
94     std::match_results<std::string::iterator> stack_entry_captured;
95 
96     std::string hashable;
97     std::string previous_hashable;
98 
99     *hash = 0;
100     // Stacktrace end until "is located" is reached.
101     std::string stackEnd = " is located";
102     static const std::regex STACK_END_RE(stackEnd);
103     std::match_results<std::string::iterator> stack_end_captured;
104 
105     for (auto str_line: str_lines) {
106         std::string frm_no;
107         std::string xdigit;
108         std::string function_name;
109         if (std::regex_search(str_line.begin(), str_line.end(), stack_entry_captured, STACK_ENTRY_RE)) {
110             frm_no = stack_entry_captured[1].str();
111             xdigit = stack_entry_captured[2].str();
112             function_name = stack_entry_captured[3].str();
113 
114             if (frm_no == "0") {
115                 if (printDiagnostics) {
116                     HIVIEW_LOGI("Stack trace starting.%{public}s",
117                                 hashable.empty() ? "" : "  Saving prior trace.");
118                 }
119                 previous_hashable = hashable;
120                 hashable.clear();
121                 curr_.func.clear();
122             }
123 
124             if (!hashable.empty())
125                 hashable.append("|");
126             hashable.append(function_name);
127 
128             if (curr_.func.empty()) {
129                 if (!function_name.empty()) {
130                     // skip special libclang_rt lib
131                     if (function_name.find(CLANGLIB) == std::string::npos) {
132                         curr_.func = function_name;
133                     }
134                 }
135             }
136         } else if (std::regex_search(str_line.begin(), str_line.end(), stack_end_captured, STACK_END_RE)) {
137             if (printDiagnostics) {
138                 SANITIZERD_LOGI("end of stack matched reline:(%{public}s)\n", str_line.c_str());
139             }
140             break;
141         }
142     }
143 
144     // If the hashable is empty (meaning all frames are uncertain,
145     // for whatever reason) also use the previous frame, as it cannot be any
146     // worse.
147     if (hashable.empty()) {
148         hashable = previous_hashable;
149     }
150 
151     *hash = OHOS::HiviewDFX::HashString(hashable);
152 }
153 
154 // Compute the stacktrace signature
ComputeStackSignature(const std::string & asanDump,std::string & asanSignature,bool printDiagnostics)155 bool AsanCollector::ComputeStackSignature(const std::string& asanDump, std::string& asanSignature,
156                                           bool printDiagnostics)
157 {
158     unsigned stackHash = 0;
159     std::string human_string;
160 
161     ProcessStackTrace(asanDump,
162                       printDiagnostics,
163                       &stackHash);
164 
165     if (stackHash == 0) {
166         if (printDiagnostics) {
167             HIVIEW_LOGI("Maple Found not a stack, failing.");
168         }
169         return false;
170     }
171 
172     // Format to the hex string
173     asanSignature = "%08X" + std::to_string(stackHash);
174     return true;
175 }
176 
IsDuplicate(const std::string & hash)177 bool AsanCollector::IsDuplicate(const std::string& hash)
178 {
179     auto back_iter = stacks_.find(hash);
180     return (back_iter != stacks_.end());
181 }
182 
UpdateCollectedData(const std::string & hash,const std::string & rfile)183 int AsanCollector::UpdateCollectedData(const std::string& hash, const std::string& rfile)
184 {
185     auto jstack = std::pair<std::string, std::string> {hash, rfile};
186     std::lock_guard<std::mutex> lockGuard(mutex_);
187     stacks_.insert(jstack);
188 
189     HIVIEW_LOGI("Updating collected data ...");
190     // Do upload when data ready
191     OHOS::HiviewDFX::Upload(&curr_);
192     return 0;
193 }
194 
CalibrateErrTypeProcName()195 void AsanCollector::CalibrateErrTypeProcName()
196 {
197     std::map<std::string, std::string>::iterator fault_type_iter;
198 
199     fault_type_iter = g_faultTypeInShort.find(curr_.errType);
200     if (fault_type_iter != g_faultTypeInShort.end()) {
201         curr_.errTypeInShort = fault_type_iter->second;
202     } else {
203         curr_.errTypeInShort = curr_.errType;
204     }
205 
206     if (curr_.uid >= MIN_APP_USERID) {
207         curr_.procName = GetApplicationNameById(curr_.uid);
208         DfxBundleInfo info;
209         if (GetDfxBundleInfo(curr_.procName, info)) {
210             curr_.appVersion = info.versionName;
211         }
212     }
213 }
214 
SetHappenTime()215 void AsanCollector::SetHappenTime()
216 {
217     time_t timeNow = time(nullptr);
218     uint64_t timeTmp = timeNow;
219     std::string timeStr = GetFormatedTime(timeTmp);
220     curr_.happenTime = std::stoll(timeStr);
221 }
222 
ReadRecordToString(std::string & fullFile,const std::string & fileName)223 bool AsanCollector::ReadRecordToString(std::string& fullFile, const std::string& fileName)
224 {
225     // A record is a log dump. It has an associated size of "record_size".
226     std::string record;
227     std::smatch captured;
228     record.clear();
229     if (!FileUtil::LoadStringFromFile(fullFile, record)) {
230         HIVIEW_LOGI("Unable to open %{public}s", fullFile.c_str());
231         return false;
232     }
233     int hitcount = 0;
234     struct stat st;
235     if (stat(fullFile.c_str(), &st) == -1) {
236         HIVIEW_LOGI("stat %{public}s error", fullFile.c_str());
237     } else {
238         curr_.uid = static_cast<int32_t>(st.st_uid);
239     }
240 
241     static const std::regex RECORD_RE(ASAN_RECORD_REGEX);
242     while (std::regex_search(record, captured, RECORD_RE)) {
243         std::string signature;
244 
245         curr_.description = captured[DESCRIPTION_FIELD].str();
246         curr_.procName = captured[PROCNAME_FIELD].str();
247         curr_.pid = stoi(captured[PID_FIELD].str());
248         if (captured[ORISANITIZERTYPE_FIELD].str().compare(
249             std::string(SANITIZERD_TYPE_STR[LSAN_LOG_RPT][ORISANITIZERTYPE])) == 0) {
250             curr_.errType = captured[ORISANITIZERTYPE_FIELD].str();
251             curr_.type = LSAN_LOG_RPT;
252         } else {
253             curr_.errType = captured[ERRTYPE_FIELD].str();
254         }
255 
256         CalibrateErrTypeProcName();
257 
258         // if record_found
259         if (ComputeStackSignature(captured[DESCRIPTION_FIELD].str(), signature, false)) {
260             // Do filtering here before upload the data
261             // for capture from hilog whith multiple asan fault log
262             SetHappenTime();
263             curr_.logName = fileName;
264             curr_.hash = signature;
265         }
266 
267         if (hitcount > 0) {
268             sleep(1);
269         }
270 
271         // Sync hash map in memory
272         UpdateCollectedData(signature, fullFile);
273         hitcount++;
274         record = captured.suffix().str();
275     }
276 
277     return true;
278 }
279 
Collect(const std::string & filepath)280 void AsanCollector::Collect(const std::string& filepath)
281 {
282     // Compose the full path string
283     std::string strAsanLogPath(ASAN_LOG_PATH);
284     std::string fullPath = strAsanLogPath + "/" + filepath;
285     ReadRecordToString(fullPath, filepath);
286 }
287 } // namespace HiviewDFX
288 } // namespace OHOS
289