• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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