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