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