• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
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 "zip_helper.h"
17 
18 #include <algorithm>
19 #include <cerrno>
20 #include <cstdio>
21 #include <cstdlib>
22 #include <cstring>
23 #include <ctime>
24 #include <fcntl.h>
25 #include <regex>
26 #include <sys/ioctl.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #include "file_util.h"
31 #include "string_ex.h"
32 #include "securec.h"
33 
34 #include "bundle_mgr_client.h"
35 #include "sanitizerd_log.h"
36 #include "parameters.h"
37 
38 namespace OHOS {
39 namespace HiviewDFX {
40 using namespace OHOS::AppExecFwk;
IsLinkFile(const std::string & sfilename)41 bool IsLinkFile(const std::string& sfilename)
42 {
43     struct stat statinfo {};
44     bool isslnk = false;
45 
46     if (lstat(sfilename.c_str(), &statinfo) < 0) {
47         SANITIZERD_LOGE("IsLinkFile lstat %{public}s err: %{public}s", sfilename.c_str(), strerror(errno));
48         return isslnk;
49     }
50 
51     if (!S_ISLNK(statinfo.st_mode) && statinfo.st_nlink > 1) {
52         SANITIZERD_LOGI("IsLinkFile hardlink %{public}s", sfilename.c_str());
53     } else if (S_ISLNK(statinfo.st_mode)) {
54         isslnk = true;
55     }
56     return isslnk;
57 }
58 
GetRealPath(const std::string & fn,std::string & out)59 bool GetRealPath(const std::string& fn, std::string& out)
60 {
61     char buf[SL_BUF_LEN];
62     ssize_t count = readlink(fn.c_str(), buf, sizeof(buf));
63     if (count != -1 && count <= static_cast<ssize_t>(sizeof(buf))) {
64         buf[count] = '\0';
65         out = std::string(buf);
66         return true;
67     }
68     return false;
69 }
70 
ReadNormalFileToString(const std::string & path,std::string & content)71 bool ReadNormalFileToString(const std::string& path, std::string& content)
72 {
73     if (!FileUtil::FileExists(path)) {
74         SANITIZERD_LOGW("file %{public}s not exists.", path.c_str());
75     }
76     int32_t fd = open(path.c_str(), O_RDONLY);
77     if (fd < 0) {
78         SANITIZERD_LOGE("open file %{public}s err: %{public}s", path.c_str(), strerror(errno));
79         return false;
80     }
81 
82     struct stat sb {};
83     if (fstat(fd, &sb) != -1 && sb.st_size > 0) {
84         content.resize(sb.st_size);
85     }
86     ssize_t n;
87     size_t remaining = sb.st_size;
88     auto p = reinterpret_cast<char *>(content.data());
89     while (remaining > 0) {
90         n = read(fd, p, remaining);
91         if (n < 0) {
92             return false;
93         }
94         p += n;
95         remaining -= n;
96     }
97     close(fd);
98     fd = -1;
99     return true;
100 }
101 
ReadFileToString(const std::string & path,std::string & out)102 bool ReadFileToString(const std::string& path, std::string& out)
103 {
104     std::string realfpath;
105     if (IsLinkFile(path)) {
106         GetRealPath(path, realfpath);
107     } else {
108         realfpath = path;
109     }
110     return FileUtil::LoadStringFromFile(path, out);
111 }
112 
SplitString(const std::string & input,const std::string & regex)113 std::vector<std::string> SplitString(const std::string& input, const std::string& regex)
114 {
115     std::regex re(regex);
116     std::sregex_token_iterator first {input.begin(), input.end(), re, -1}, last;
117     return {first, last};
118 }
119 
HashString(const std::string & input)120 unsigned HashString(const std::string& input)
121 {
122     unsigned hash = 0;
123     for (size_t i = 0; i < input.length(); ++i) {
124         hash = hash * HASH_FACTOR + input[i];
125     }
126     return hash;
127 }
128 
GetNameByPid(pid_t pid,const char * procName)129 bool GetNameByPid(pid_t pid, const char *procName)
130 {
131     char pidPath[BUF_SIZE];
132     char buf[BUF_SIZE];
133     bool ret = false;
134 
135     sprintf_s(pidPath, BUF_SIZE, "/proc/%d/status", pid);
136     FILE *fp = fopen(pidPath, "r");
137     if (fp != nullptr) {
138         if (fgets(buf, BUF_SIZE - 1, fp) != nullptr) {
139             if (sscanf_s(buf, "%*s %s", procName, MAX_PROCESS_PATH) == 1) {
140                 ret = true;
141             }
142         } else {
143             ret = false;
144         }
145         fclose(fp);
146     }
147 
148     return ret;
149 }
150 
IsNameValid(const std::string & name,const std::string & sep,bool canEmpty)151 bool IsNameValid(const std::string& name, const std::string& sep, bool canEmpty)
152 {
153     std::vector<std::string> nameVec;
154     SplitStr(name, sep, nameVec, canEmpty, false);
155     std::regex re("^[a-zA-Z][a-zA-Z0-9_]*$");
156     for (auto const& splitName : nameVec) {
157         if (!std::regex_match(splitName, re)) {
158             SANITIZERD_LOGI("Invalid splitName:%{public}s", splitName.c_str());
159             return false;
160         }
161     }
162     return true;
163 }
164 
IsModuleNameValid(const std::string & name)165 bool IsModuleNameValid(const std::string& name)
166 {
167     if (name.empty() || name.size() > MAX_NAME_LENGTH) {
168         SANITIZERD_LOGI("invalid log name.");
169         return false;
170     }
171 
172     if (name.find("/") != std::string::npos || name.find(".") == std::string::npos) {
173         std::string path = name.substr(1); // may skip first .
174         path.erase(path.find_last_not_of(" \n\r\t") + 1);
175         SANITIZERD_LOGI("module name:%{public}s", name.c_str());
176         return IsNameValid(path, "/", false);
177     }
178 
179     return IsNameValid(name, ".", true);
180 }
181 
GetApplicationNameById(int32_t uid)182 std::string GetApplicationNameById(int32_t uid)
183 {
184     std::string bundleName;
185     AppExecFwk::BundleMgrClient client;
186     if (!client.GetBundleNameForUid(uid, bundleName)) {
187         SANITIZERD_LOGW("Failed to query bundleName from bms, uid:%{public}d.", uid);
188     } else {
189         SANITIZERD_LOGI("bundleName of uid:%{public}d is %{public}s", uid, bundleName.c_str());
190     }
191     return bundleName;
192 }
193 
GetApplicationVersion(int32_t uid,const std::string & bundleName)194 std::string GetApplicationVersion(int32_t uid, const std::string& bundleName)
195 {
196     AppExecFwk::BundleInfo info;
197     AppExecFwk::BundleMgrClient client;
198     if (!client.GetBundleInfo(bundleName, AppExecFwk::BundleFlag::GET_BUNDLE_DEFAULT,
199                               info, Constants::ALL_USERID)) {
200         SANITIZERD_LOGW("Failed to query BundleInfo from bms, uid:%{public}d.", uid);
201         return "";
202     } else {
203         SANITIZERD_LOGI("The version of %{public}s is %{public}s", bundleName.c_str(),
204                         info.versionName.c_str());
205     }
206     return info.versionName;
207 }
208 
CreateMultiTierDirectory(const std::string & directoryPath,const std::string & rootDirPath,const uid_t dirOwner,const gid_t dirGroup)209 int32_t CreateMultiTierDirectory(const std::string &directoryPath, const std::string &rootDirPath,
210                                  const uid_t dirOwner, const gid_t dirGroup)
211 {
212     int32_t ret = -1;
213     uint32_t dirPathLen = directoryPath.length();
214     if (dirPathLen > PATH_MAX) {
215         return ret;
216     }
217     char tmpDirPath[PATH_MAX] = { 0 };
218     for (uint32_t i = 0; i < dirPathLen; ++i) {
219         tmpDirPath[i] = directoryPath[i];
220         if (i < rootDirPath.length() && directoryPath[i] != rootDirPath[i]) {
221             return ret;
222         } else if (i < rootDirPath.length() || tmpDirPath[i] != '/') {
223             continue;
224         }
225         if (access(tmpDirPath, 0) != 0) {
226             ret = mkdir(tmpDirPath, DEFAULT_LOG_DIR_MODE);
227             ret += chown(tmpDirPath, dirOwner, dirGroup);
228             if (ret != 0) {
229                 SANITIZERD_LOGE("Fail to create dir %{public}s,  err: %{public}s.",
230                                 tmpDirPath, strerror(errno));
231                 return ret;
232             }
233         }
234     }
235     return 0;
236 }
237 
GetCollectedDataSavePath(const T_SANITIZERD_PARAMS * params)238 static std::string GetCollectedDataSavePath(const T_SANITIZERD_PARAMS *params)
239 {
240     std::string faultLogPath = std::string(ROOT_FAULTLOG_LOG_PATH);
241     std::string filePath = std::string(CUSTOM_SANITIZER_LOG_PATH);
242     return filePath;
243 }
244 
CalcCollectedLogName(T_SANITIZERD_PARAMS * params)245 static std::string CalcCollectedLogName(T_SANITIZERD_PARAMS *params)
246 {
247     std::string filePath = GetCollectedDataSavePath(params);
248     if (filePath.size() == 0) {
249         return filePath;
250     }
251     std::string prefix = std::string(SANITIZERD_TYPE_STR[params->type][PREFIXFILENAME]);
252     std::string name = params->procName;
253     if (name.find("/") != std::string::npos) {
254         name = params->procName.substr(params->procName.find_last_of("/") + 1);
255     }
256 
257     std::string fileName = "";
258     fileName.append(prefix);
259     fileName.append("-");
260     fileName.append(name);
261     fileName.append("-");
262     fileName.append(std::to_string(params->uid));
263     fileName.append("-");
264     fileName.append(std::to_string(params->happenTime));
265 
266     std::string fullName = filePath + fileName;
267 
268     params->logName = fileName;
269 
270     return fullName;
271 }
272 
CreateLogFile(const std::string & name)273 static int32_t CreateLogFile(const std::string& name)
274 {
275     int32_t fd = -1;
276     if (!FileUtil::FileExists(name)) {
277         SANITIZERD_LOGW("file %{public}s is creating now.", name.c_str());
278     }
279     fd = open(name.c_str(), O_CREAT | O_WRONLY | O_TRUNC, DEFAULT_LOG_FILE_MODE);
280     return fd;
281 }
282 
WriteNewFile(const int32_t fd,const T_SANITIZERD_PARAMS * params)283 static bool WriteNewFile(const int32_t fd, const T_SANITIZERD_PARAMS *params)
284 {
285     if (fd < 0) {
286         return false;
287     }
288 
289     FileUtil::SaveStringToFd(fd, "Generated by HiviewDFX @OpenHarmony " +
290             system::GetParameter(DEVICE_OHOS_VERSION_PARAM, EMPTY_PARAM) + "\n" +
291             "=================================================================\n" +
292             "TIMESTAMP:" + std::to_string(params->happenTime) + "\n" +
293             "Pid:" + std::to_string(params->pid) + "\n" +
294             "Uid:" + std::to_string(params->uid) + "\n" +
295             "Process name:" + params->procName + "\n" +
296             "Reason:" + std::string(SANITIZERD_TYPE_STR[params->type][ORISANITIZERTYPE]) + ":" +
297             params->errType + "\n" +
298             "Fault thread Info:\n" +
299             params->description);
300 
301     close(fd);
302     return true;
303 }
304 
WriteCollectedData(T_SANITIZERD_PARAMS * params)305 void WriteCollectedData(T_SANITIZERD_PARAMS *params)
306 {
307     std::string fullName = CalcCollectedLogName(params);
308     if (fullName.size() == 0) {
309         return;
310     }
311     int32_t fd = CreateLogFile(fullName);
312     if (fd < 0) {
313         return;
314     }
315 
316     if (!WriteNewFile(fd, params)) {
317         SANITIZERD_LOGE("Fail to write %{public}s,  err: %{public}s.", fullName.c_str(), strerror(errno));
318     }
319 }
320 } // namespace HiviewDFX
321 } // namespace OHOS
322