• 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 
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