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
16 #include "gwpasan_collector.h"
17
18 #include <cstdint>
19 #include <cerrno>
20 #include <cstdio>
21 #include <cstdlib>
22 #include <cstring>
23 #include <ctime>
24 #include <fcntl.h>
25 #include <mutex>
26 #include <securec.h>
27 #include <sys/time.h>
28 #include <unistd.h>
29 #include <vector>
30
31 #include "bundle_mgr_client.h"
32 #include "faultlog_util.h"
33 #include "file_util.h"
34 #include "logger.h"
35 #include "hisysevent.h"
36
37 DEFINE_LOG_LABEL(0xD002D12, "Sanitizer");
38
39 static std::stringstream g_asanlog;
40
WriteGwpAsanLog(char * buf,size_t sz)41 void WriteGwpAsanLog(char* buf, size_t sz)
42 {
43 if (buf == nullptr || sz == 0) {
44 return;
45 }
46
47 static std::mutex sMutex;
48 std::lock_guard<std::mutex> lock(sMutex);
49 // append to buffer
50 for (size_t i = 0; i < sz; i++) {
51 g_asanlog << buf[i];
52 }
53
54 char *output = strstr(buf, "End GWP-ASan report");
55 if (output) {
56 std::string asanlog = g_asanlog.str();
57 // parse log
58 ReadGwpAsanRecord(asanlog);
59 // clear buffer
60 g_asanlog.str("");
61 }
62 }
63
ReadGwpAsanRecord(std::string & gwpAsanBuffer)64 void ReadGwpAsanRecord(std::string& gwpAsanBuffer)
65 {
66 GwpAsanCurrInfo currInfo;
67 char bundleName[BUF_SIZE];
68 currInfo.description = gwpAsanBuffer;
69 currInfo.pid = getpid();
70 currInfo.uid = getuid();
71 currInfo.errType = "GWP-ASAN";
72 if (GetNameByPid(static_cast<pid_t>(currInfo.pid), bundleName) == true) {
73 currInfo.procName = std::string(bundleName);
74 }
75 if (currInfo.uid >= MIN_APP_UID) {
76 currInfo.appVersion = GetApplicationVersion(currInfo.uid, currInfo.procName);
77 } else {
78 currInfo.appVersion = "";
79 }
80 time_t timeNow = time(nullptr);
81 uint64_t timeTmp = timeNow;
82 std::string timeStr = OHOS::HiviewDFX::GetFormatedTime(timeTmp);
83 currInfo.happenTime = std::stoll(timeStr);
84
85 // Do upload when data ready
86 WriteCollectedData(currInfo);
87 HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::RELIABILITY, "ADDR_SANITIZER",
88 OHOS::HiviewDFX::HiSysEvent::EventType::FAULT,
89 "MODULE", currInfo.procName,
90 "VERSION", currInfo.appVersion,
91 "REASON", currInfo.errType,
92 "PID", currInfo.pid,
93 "UID", currInfo.uid,
94 "SUMMARY", currInfo.description,
95 "HAPPEN_TIME", currInfo.happenTime);
96 }
97
WriteNewFile(const int32_t fd,const GwpAsanCurrInfo & currInfo)98 bool WriteNewFile(const int32_t fd, const GwpAsanCurrInfo &currInfo)
99 {
100 if (fd < 0) {
101 return false;
102 }
103
104 OHOS::HiviewDFX::FileUtil::SaveStringToFd(fd, std::string("Generated by HiviewDFX @OpenHarmony") + "\n" +
105 std::string("=================================================================\n") +
106 "TIMESTAMP:" + std::to_string(currInfo.happenTime) + "\n" +
107 "Pid:" + std::to_string(currInfo.pid) + "\n" +
108 "Uid:" + std::to_string(currInfo.uid) + "\n" +
109 "Process name:" + currInfo.procName + "\n" +
110 "Fault thread Info:\n" + currInfo.description);
111
112 close(fd);
113 return true;
114 }
115
CalcCollectedLogName(const GwpAsanCurrInfo & currInfo)116 std::string CalcCollectedLogName(const GwpAsanCurrInfo &currInfo)
117 {
118 std::string filePath = "data/log/faultlog/faultlogger/";
119 std::string prefix = "gwpasan";
120 std::string name = currInfo.procName;
121 if (name.find("/") != std::string::npos) {
122 name = currInfo.procName.substr(currInfo.procName.find_last_of("/") + 1);
123 }
124
125 std::string fileName = "";
126 fileName.append(prefix);
127 fileName.append("-");
128 fileName.append(name);
129 fileName.append("-");
130 fileName.append(std::to_string(currInfo.pid));
131 fileName.append("-");
132 fileName.append(std::to_string(currInfo.happenTime));
133
134 std::string fullName = filePath + fileName;
135 return fullName;
136 }
137
WriteCollectedData(const GwpAsanCurrInfo & currInfo)138 void WriteCollectedData(const GwpAsanCurrInfo &currInfo)
139 {
140 std::string fullName = CalcCollectedLogName(currInfo);
141 if (fullName.size() == 0) {
142 return;
143 }
144 int32_t fd = CreateLogFile(fullName);
145 if (fd < 0) {
146 return;
147 }
148 WriteNewFile(fd, currInfo);
149 }
150
CreateLogFile(const std::string & name)151 int32_t CreateLogFile(const std::string& name)
152 {
153 int32_t fd = -1;
154
155 fd = open(name.c_str(), O_CREAT | O_WRONLY | O_TRUNC);
156 if (fd < 0) {
157 HIVIEW_LOGE("Fail to create %{public}s, err: %{public}s.",
158 name.c_str(), strerror(errno));
159 }
160 return fd;
161 }
162
GetNameByPid(pid_t pid,const char procName[])163 bool GetNameByPid(pid_t pid, const char procName[])
164 {
165 char pidPath[BUF_SIZE];
166 char buf[BUF_SIZE];
167 bool ret = false;
168
169 sprintf_s(pidPath, BUF_SIZE, "/proc/%d/status", pid);
170 FILE *fp = fopen(pidPath, "r");
171 if (fp != nullptr) {
172 if (fgets(buf, BUF_SIZE - 1, fp) != nullptr) {
173 if (sscanf_s(buf, "%*s %s", procName, MAX_PROCESS_PATH) == 1) {
174 ret = true;
175 }
176 } else {
177 ret = false;
178 }
179 fclose(fp);
180 }
181
182 return ret;
183 }
184
GetApplicationVersion(int32_t uid,const std::string & bundleName)185 std::string GetApplicationVersion(int32_t uid, const std::string& bundleName)
186 {
187 OHOS::AppExecFwk::BundleInfo info;
188 OHOS::AppExecFwk::BundleMgrClient client;
189 if (!client.GetBundleInfo(bundleName, OHOS::AppExecFwk::BundleFlag::GET_BUNDLE_DEFAULT,
190 info, OHOS::AppExecFwk::Constants::ALL_USERID)) {
191 HIVIEW_LOGW("Failed to query BundleInfo from bms, uid:%{public}d.", uid);
192 return "";
193 } else {
194 HIVIEW_LOGI("The version of %{public}s is %{public}s", bundleName.c_str(),
195 info.versionName.c_str());
196 }
197 return info.versionName;
198 }
199