1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd. All rights reserved.
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 #include "gwpasan_collector.h"
16
17 #include <cerrno>
18 #include <cstdlib>
19 #include <cstring>
20 #include <ctime>
21 #include <fcntl.h>
22 #include <mutex>
23 #include <securec.h>
24 #include <sys/time.h>
25 #include <time_util.h>
26 #include <unistd.h>
27
28 #include "bundle_mgr_client.h"
29 #include "event_publish.h"
30 #include "faultlog_util.h"
31 #include "file_util.h"
32 #include "hisysevent.h"
33 #include "json/json.h"
34 #include "hilog/log.h"
35 #include "hiview_logger.h"
36 #include "parameter_ex.h"
37
38 #undef LOG_DOMAIN
39 #define LOG_DOMAIN 0xD002D12
40
41 #undef LOG_TAG
42 #define LOG_TAG "Sanitizer"
43
44 namespace {
45 constexpr unsigned ASAN_LOG_SIZE = 350 * 1024;
46 constexpr unsigned BUF_SIZE = 128;
47 constexpr unsigned HWASAN_ERRTYPE_FIELD = 1;
48 constexpr unsigned ASAN_ERRTYPE_FIELD = 2;
49 static std::stringstream g_asanlog;
50 }
51
WriteGwpAsanLog(char * buf,size_t sz)52 void WriteGwpAsanLog(char* buf, size_t sz)
53 {
54 if (buf == nullptr || sz == 0) {
55 return;
56 }
57 static std::mutex sMutex;
58 std::lock_guard<std::mutex> lock(sMutex);
59 // append to buffer
60 for (size_t i = 0; i < sz; i++) {
61 g_asanlog << buf[i];
62 }
63 char *gwpOutput = strstr(buf, "End GWP-ASan report");
64 char *tsanOutput = strstr(buf, "End Tsan report");
65 char *cfiOutput = strstr(buf, "End CFI report");
66 char *ubsanOutput = strstr(buf, "End Ubsan report");
67 char *hwasanOutput = strstr(buf, "End Hwasan report");
68 char *asanOutput = strstr(buf, "End Asan report");
69 if (gwpOutput) {
70 std::string gwpasanlog = g_asanlog.str();
71 std::string errType = "GWP-ASAN";
72 ReadGwpAsanRecord(gwpasanlog, errType);
73 // clear buffer
74 g_asanlog.str("");
75 } else if (tsanOutput) {
76 std::string tsanlog = g_asanlog.str();
77 std::string errType = "TSAN";
78 ReadGwpAsanRecord(tsanlog, errType);
79 // clear buffer
80 g_asanlog.str("");
81 } else if (cfiOutput || ubsanOutput) {
82 std::string ubsanlog = g_asanlog.str();
83 std::string errType = "UBSAN";
84 ReadGwpAsanRecord(ubsanlog, errType);
85 // clear buffer
86 g_asanlog.str("");
87 } else if (hwasanOutput) {
88 std::string hwasanlog = g_asanlog.str();
89 std::string errType = "HWASAN_" + GetErrorTypeFromHwAsanLog(hwasanlog);
90 ReadGwpAsanRecord(hwasanlog, errType);
91 // clear buffer
92 g_asanlog.str("");
93 } else if (asanOutput) {
94 std::string asanlog = g_asanlog.str();
95 std::string errType = "ASAN_" + GetErrorTypeFromAsanLog(asanlog);
96 ReadGwpAsanRecord(asanlog, errType);
97 // clear buffer
98 g_asanlog.str("");
99 }
100 }
101
GetErrorTypeFromHwAsanLog(const std::string & hwAsanBuffer)102 std::string GetErrorTypeFromHwAsanLog(const std::string& hwAsanBuffer)
103 {
104 constexpr const char* const hwAsanRecordRegex = "Cause: ([\\w -]+)";
105 static const std::regex hwAsanRecordRe(hwAsanRecordRegex);
106 return GetErrorTypeFromLog(hwAsanBuffer, hwAsanRecordRe, HWASAN_ERRTYPE_FIELD, "HWASAN");
107 }
108
GetErrorTypeFromAsanLog(const std::string & asanBuffer)109 std::string GetErrorTypeFromAsanLog(const std::string& asanBuffer)
110 {
111 constexpr const char* const asanRecordRegex =
112 "SUMMARY: (AddressSanitizer|LeakSanitizer): (\\S+)";
113 static const std::regex asanRecordRe(asanRecordRegex);
114 return GetErrorTypeFromLog(asanBuffer, asanRecordRe, ASAN_ERRTYPE_FIELD, "ASAN");
115 }
116
GetErrorTypeFromLog(const std::string & logBuffer,const std::regex & recordRe,int errTypeField,const std::string & defaultType)117 std::string GetErrorTypeFromLog(const std::string& logBuffer, const std::regex& recordRe,
118 int errTypeField, const std::string& defaultType)
119 {
120 std::smatch captured;
121 if (!std::regex_search(logBuffer, captured, recordRe)) {
122 HILOG_INFO(LOG_CORE, "%{public}s Regex not match, set default type.", defaultType.c_str());
123 return defaultType;
124 }
125 std::string errType = captured[errTypeField].str();
126 HILOG_INFO(LOG_CORE, "%{public}s errType is %{public}s", defaultType.c_str(), errType.c_str());
127 return errType;
128 }
129
ReadGwpAsanRecord(const std::string & gwpAsanBuffer,const std::string & errType)130 void ReadGwpAsanRecord(const std::string& gwpAsanBuffer, const std::string& errType)
131 {
132 GwpAsanCurrInfo currInfo;
133 currInfo.description = ((gwpAsanBuffer.size() > ASAN_LOG_SIZE) ? (gwpAsanBuffer.substr(0, ASAN_LOG_SIZE) +
134 "\nEnd Asan report") : gwpAsanBuffer);
135 currInfo.pid = getpid();
136 currInfo.uid = getuid();
137 currInfo.errType = errType;
138 currInfo.procName = GetNameByPid(currInfo.pid);
139 currInfo.appVersion = "";
140 time_t timeNow = time(nullptr);
141 uint64_t timeTmp = timeNow;
142 std::string timeStr = OHOS::HiviewDFX::GetFormatedTime(timeTmp);
143 currInfo.happenTime = std::stoll(timeStr);
144 std::string fullName = CalcCollectedLogName(currInfo);
145 currInfo.logPath = fullName;
146 HILOG_INFO(LOG_CORE, "ReportSanitizerAppEvent: uid:%{public}d, logPath:%{public}s.",
147 currInfo.uid, currInfo.logPath.c_str());
148
149 // Do upload when data ready
150 HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::RELIABILITY, "ADDR_SANITIZER",
151 OHOS::HiviewDFX::HiSysEvent::EventType::FAULT,
152 "MODULE", currInfo.procName,
153 "VERSION", currInfo.appVersion,
154 "REASON", currInfo.errType,
155 "PID", currInfo.pid,
156 "UID", currInfo.uid,
157 "SUMMARY", currInfo.description,
158 "HAPPEN_TIME", currInfo.happenTime,
159 "LOG_PATH", currInfo.logPath);
160 }
161
CalcCollectedLogName(const GwpAsanCurrInfo & currInfo)162 std::string CalcCollectedLogName(const GwpAsanCurrInfo &currInfo)
163 {
164 std::string filePath = "/data/log/faultlog/faultlogger/";
165 std::string prefix = "";
166 if (currInfo.errType.compare("GWP-ASAN") == 0) {
167 prefix = "gwpasan";
168 } else if (currInfo.errType.compare("TSAN") == 0) {
169 prefix = "tsan";
170 } else if (currInfo.errType.compare("UBSAN") == 0) {
171 prefix = "ubsan";
172 } else if (currInfo.errType.find("HWASAN") != std::string::npos) {
173 prefix = "hwasan";
174 } else if (currInfo.errType.find("ASAN") != std::string::npos) {
175 prefix = "asan";
176 } else {
177 prefix = "sanitizer";
178 }
179 std::string name = currInfo.procName;
180 if (name.find("/") != std::string::npos) {
181 name = currInfo.procName.substr(currInfo.procName.find_last_of("/") + 1);
182 }
183
184 std::string fileName = "";
185 fileName.append(prefix);
186 fileName.append("-");
187 fileName.append(name);
188 fileName.append("-");
189 fileName.append(std::to_string(currInfo.uid));
190 fileName.append("-");
191 fileName.append(std::to_string(currInfo.happenTime));
192
193 std::string fullName = filePath + fileName;
194 return fullName;
195 }
196
GetNameByPid(int32_t pid)197 std::string GetNameByPid(int32_t pid)
198 {
199 char path[BUF_SIZE] = { 0 };
200 int err = snprintf_s(path, sizeof(path), sizeof(path) - 1, "/proc/%d/cmdline", pid);
201 if (err <= 0) {
202 return "";
203 }
204 char cmdline[BUF_SIZE] = { 0 };
205 size_t i = 0;
206 FILE *fp = fopen(path, "r");
207 if (fp == nullptr) {
208 return "";
209 }
210 while (i < (BUF_SIZE - 1)) {
211 char c = static_cast<char>(fgetc(fp));
212 // 0. don't need args of cmdline
213 // 1. ignore unvisible character
214 if (!isgraph(c)) {
215 break;
216 }
217 cmdline[i] = c;
218 i++;
219 }
220 (void)fclose(fp);
221 return cmdline;
222 }
223