1 /*
2 * Copyright (c) 2021-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 "common.h"
17 #include <fcntl.h>
18 #include <array>
19 #include <cinttypes>
20 #include <csignal>
21 #include <dirent.h>
22 #include <fstream>
23 #include <iostream>
24 #ifdef HOOK_ENABLE
25 #include <malloc.h>
26 #endif
27 #include <sstream>
28 #include <sys/file.h>
29 #include <sys/types.h>
30 #include <sys/wait.h>
31 #include <unistd.h>
32 #include <sys/stat.h>
33
34 #include "application_info.h"
35 #include "bundle_mgr_proxy.h"
36 #include "file_ex.h"
37 #include "iservice_registry.h"
38 #include "logging.h"
39 #include "system_ability_definition.h"
40
41 using namespace OHOS;
42 using namespace OHOS::AppExecFwk;
43 namespace COMMON {
44 constexpr int EXECVP_ERRNO = 2;
45 const int SHELL_UID = 2000;
46 const std::string DEFAULT_PATH = "/data/local/tmp/";
47 constexpr int READ = 0;
48 constexpr int WRITE = 1;
49 const int FILE_PATH_SIZE = 512;
50 const int BUFFER_SIZE = 1024;
51 const int INVALID_PID = -1;
52
53
IsProcessRunning(int & lockFileFd)54 bool IsProcessRunning(int& lockFileFd)
55 {
56 setgid(SHELL_UID);
57 char buffer[PATH_MAX + 1] = {0};
58 readlink("/proc/self/exe", buffer, PATH_MAX);
59 std::string processName = buffer;
60 int pos = static_cast<int>(processName.find_last_of('/'));
61 if (pos != 0) {
62 processName = processName.substr(pos + 1, processName.size());
63 }
64
65 std::string fileName = DEFAULT_PATH + processName + ".pid";
66 umask(S_IWOTH);
67 int fd = open(fileName.c_str(), O_WRONLY | O_CREAT, static_cast<mode_t>(0664)); // 0664: rw-rw-r--
68 if (fd < 0) {
69 const int bufSize = 256;
70 char buf[bufSize] = {0};
71 strerror_r(errno, buf, bufSize);
72 HILOG_ERROR(LOG_CORE, "%s:failed to open(%s), errno(%d:%s)", __func__, fileName.c_str(), errno, buf);
73 return false;
74 }
75 int flags = fcntl(fd, F_GETFD);
76 if (flags == -1) {
77 close(fd);
78 HILOG_ERROR(LOG_CORE, "%s: get fd flags failed!", __func__);
79 return false;
80 }
81 flags |= FD_CLOEXEC;
82 if (fcntl(fd, F_SETFD, flags) == -1) {
83 close(fd);
84 HILOG_ERROR(LOG_CORE, "%s: set fd_cloexec failed!", __func__);
85 return false;
86 }
87 if (flock(fd, LOCK_EX | LOCK_NB) == -1) {
88 // 进程正在运行,加锁失败
89 close(fd);
90 printf("%s is running, please don't start it again.\n", processName.c_str());
91 HILOG_ERROR(LOG_CORE, "%s is running, please don't start it again.", processName.c_str());
92 return true;
93 }
94 std::string pidStr = std::to_string(getpid());
95 auto nbytes = write(fd, pidStr.data(), pidStr.size());
96 lockFileFd = fd;
97 CHECK_TRUE(static_cast<size_t>(nbytes) == pidStr.size(), false, "write pid FAILED!");
98 return false;
99 }
100
IsProcessExist(const std::string & processName,int & pid)101 bool IsProcessExist(const std::string& processName, int& pid)
102 {
103 DIR* dir = opendir("/proc");
104 CHECK_NOTNULL(dir, false, "open /proc dir failed");
105 struct dirent* ptr;
106 int pidValue = INVALID_PID;
107 while ((ptr = readdir(dir)) != nullptr) {
108 if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0)) {
109 continue;
110 }
111 if ((!isdigit(*ptr->d_name)) || ptr->d_type != DT_DIR) {
112 continue;
113 }
114 char filePath[FILE_PATH_SIZE] = {0};
115 int len = snprintf_s(filePath, FILE_PATH_SIZE, FILE_PATH_SIZE - 1, "/proc/%s/cmdline", ptr->d_name);
116 if (len < 0) {
117 HILOG_WARN(LOG_CORE, "maybe, the contents of cmdline had be cut off");
118 continue;
119 }
120 FILE* fp = fopen(filePath, "r");
121 if (fp == nullptr) {
122 HILOG_WARN(LOG_CORE, "open file failed!");
123 break;
124 }
125 char buf[BUFFER_SIZE] = {0};
126 if (fgets(buf, sizeof(buf) - 1, fp) == nullptr) {
127 fclose(fp);
128 continue;
129 }
130 std::string str(buf);
131 size_t found = str.rfind("/");
132 std::string fullProcess;
133 if (found != std::string::npos) {
134 fullProcess = str.substr(found + 1);
135 } else {
136 fullProcess = str;
137 }
138 if (fullProcess == processName) {
139 pidValue = atoi(ptr->d_name);
140 fclose(fp);
141 break;
142 }
143 fclose(fp);
144 }
145 closedir(dir);
146 if (pidValue != INVALID_PID) {
147 pid = pidValue;
148 }
149 return pidValue != INVALID_PID;
150 }
151
CloseStdio()152 static void CloseStdio()
153 {
154 close(STDIN_FILENO);
155 close(STDOUT_FILENO);
156 close(STDERR_FILENO);
157 }
158
StartProcess(const std::string & processBin,std::vector<char * > & argv)159 int StartProcess(const std::string& processBin, std::vector<char*>& argv)
160 {
161 int pid = fork();
162 if (pid == 0) {
163 CloseStdio();
164 argv.push_back(nullptr); // last item in argv must be NULL
165 int retval = execvp(processBin.c_str(), argv.data());
166 if (retval == -1 && errno == EXECVP_ERRNO) {
167 printf("warning: %s does not exist!\n", processBin.c_str());
168 HILOG_WARN(LOG_CORE, "warning: %s does not exist!", processBin.c_str());
169 }
170 _exit(EXIT_FAILURE);
171 }
172
173 return pid;
174 }
175
KillProcess(int pid)176 int KillProcess(int pid)
177 {
178 if (pid == -1) {
179 return -1;
180 }
181 int stat;
182 kill(pid, SIGTERM);
183 if (waitpid(pid, &stat, 0) == -1) {
184 if (errno != EINTR) {
185 stat = -1;
186 }
187 }
188 return stat;
189 }
190
PrintMallinfoLog(const std::string & mallInfoPrefix)191 void PrintMallinfoLog(const std::string& mallInfoPrefix)
192 {
193 #ifdef HOOK_ENABLE
194 struct mallinfo2 mallinfo = mallinfo2();
195 std::string mallinfoLog = mallInfoPrefix;
196 mallinfoLog += "arena = " + std::to_string(mallinfo.arena) + ", ordblks = " + std::to_string(mallinfo.ordblks);
197 mallinfoLog += ", smblks = " + std::to_string(mallinfo.smblks) + ", hblks = " + std::to_string(mallinfo.hblks);
198 mallinfoLog += ", hblkhd = " + std::to_string(mallinfo.hblkhd) + ", usmblks = " + std::to_string(mallinfo.usmblks);
199 mallinfoLog +=
200 ", fsmblks = " + std::to_string(mallinfo.fsmblks) + ", uordblks = " + std::to_string(mallinfo.uordblks);
201 mallinfoLog +=
202 ", fordblks = " + std::to_string(mallinfo.fordblks) + ", keepcost = " + std::to_string(mallinfo.keepcost);
203 HILOG_INFO(LOG_CORE, "%s", mallinfoLog.c_str());
204 #endif // HOOK_ENABLE
205 }
206
CustomFdClose(int & fd)207 inline int CustomFdClose(int& fd)
208 {
209 int ret = close(fd);
210 if (ret == 0) {
211 fd = -1;
212 }
213 return ret;
214 }
215
CustomFdFclose(FILE ** fp)216 inline int CustomFdFclose(FILE** fp)
217 {
218 int ret = fclose(*fp);
219 if (ret == 0) {
220 *fp = nullptr;
221 }
222 return ret;
223 }
224
CustomPopen(const std::vector<std::string> & command,const char * type,int fds[],volatile pid_t & childPid,bool needUnblock)225 FILE* CustomPopen(const std::vector<std::string>& command, const char* type, int fds[],
226 volatile pid_t& childPid, bool needUnblock)
227 {
228 HILOG_DEBUG(LOG_CORE, "BEGN %s: ready!", __func__);
229 if (command.empty() || type == nullptr) {
230 HILOG_ERROR(LOG_CORE, "%s: param invalid", __func__);
231 return nullptr;
232 }
233
234 // only allow "r" or "w"
235 if ((type[0] != 'r' && type[0] != 'w') || type[1] != 0) {
236 errno = EINVAL;
237 return nullptr;
238 }
239
240 CHECK_TRUE(pipe(fds) == 0, nullptr, "Pipe open failed!");
241
242 pid_t pid = fork();
243 if (pid == -1) {
244 perror("fork");
245 exit(1);
246 }
247
248 if (pid == 0) {
249 char* const envp[] = {nullptr};
250 // execve : the last argv must be nullptr.
251 std::vector<char*> argv(command.size() + 1, nullptr);
252 for (size_t i = 0, cmdSize = command.size(); i < cmdSize; i++) {
253 argv[i] = const_cast<char*>(command[i].data());
254 }
255
256 if (strncmp(type, "r", strlen(type)) == 0) {
257 CHECK_TRUE(CustomFdClose(fds[READ]) == 0, nullptr, "CustomFdClose failed!");
258 dup2(fds[WRITE], STDOUT_FILENO); // Redirect stdout to pipe
259 CHECK_TRUE(CustomFdClose(fds[WRITE]) == 0, nullptr, "CustomFdClose failed!");
260 } else {
261 CHECK_TRUE(CustomFdClose(fds[WRITE]) == 0, nullptr, "CustomFdClose failed!");
262 dup2(fds[READ], STDIN_FILENO); // Redirect stdin to pipe
263 CHECK_TRUE(CustomFdClose(fds[READ]) == 0, nullptr, "CustomFdClose failed!");
264 }
265
266 setpgid(pid, pid);
267 // exe path = argv[0]; exe name = argv[1]
268 if (execve(argv[0], &argv[1], envp) == -1) {
269 HILOG_ERROR(LOG_CORE, "execve failed {%s:%s}", __func__, strerror(errno));
270 exit(EXIT_FAILURE);
271 }
272 }
273
274 if (!needUnblock) {
275 if (strncmp(type, "r", strlen(type)) == 0) {
276 // Close the WRITE end of the pipe since parent's fd is read-only
277 CHECK_TRUE(CustomFdClose(fds[WRITE]) == 0, nullptr, "%s %d CustomFdClose failed! errno(%s)\n",
278 __func__, __LINE__, strerror(errno));
279 } else {
280 // Close the READ end of the pipe since parent's fd is write-only
281 CHECK_TRUE(CustomFdClose(fds[READ]) == 0, nullptr, "%s %d CustomFdClose failed! errno(%s)\n",
282 __func__, __LINE__, strerror(errno));
283 }
284 }
285
286 // Make sure the parent pipe reads and writes exist;CustomPUnblock will use.
287 childPid = pid;
288 if (strncmp(type, "r", strlen(type)) == 0) {
289 HILOG_DEBUG(LOG_CORE, "END %s fds[READ]: success!", __func__);
290 return fdopen(fds[READ], "r");
291 }
292
293 HILOG_DEBUG(LOG_CORE, "END %s fds[WRITE]: success!", __func__);
294 return fdopen(fds[WRITE], "w");
295 }
296
CustomPclose(FILE * fp,int fds[],volatile pid_t & childPid,bool needUnblock)297 int CustomPclose(FILE* fp, int fds[], volatile pid_t& childPid, bool needUnblock)
298 {
299 HILOG_DEBUG(LOG_CORE, "BEGN %s: ready!", __func__);
300 CHECK_NOTNULL(fp, -1, "NOTE %s: fp is null", __func__);
301
302 int stat = 0;
303
304 if (needUnblock) {
305 HILOG_DEBUG(LOG_CORE, "NOTE Kill Endless Loop Child %d.", childPid);
306 kill(childPid, SIGKILL);
307 }
308
309 while (waitpid(childPid, &stat, 0) == -1) {
310 HILOG_ERROR(LOG_CORE, "%s: %s.", __func__, strerror(errno));
311 if (errno == EINTR) {
312 continue;
313 }
314 break;
315 }
316
317 if (needUnblock) {
318 if (fileno(fp) == fds[READ]) {
319 fds[READ] = -1;
320 CHECK_TRUE(CustomFdClose(fds[WRITE]) == 0, -1, "CustomFdClose failed!");
321 } else if (fileno(fp) == fds[WRITE]) {
322 fds[WRITE] = -1;
323 CHECK_TRUE(CustomFdClose(fds[READ]) == 0, -1, "CustomFdClose failed!");
324 } else {
325 HILOG_INFO(LOG_CORE, "%s: Can't find fp in fds[READ/WRITE].", __func__);
326 }
327 }
328
329 CHECK_TRUE(CustomFdFclose(&fp) == 0, -1, "CustomFdFclose failed!");
330
331 HILOG_DEBUG(LOG_CORE, "END %s: success!", __func__);
332 return stat;
333 }
334
335 // IF pipe fds is block, before release other threads, you need call CustomPUnblock
CustomPUnblock(int fds[])336 int CustomPUnblock(int fds[])
337 {
338 HILOG_DEBUG(LOG_CORE, "BEGN %s: ready!", __func__);
339
340 CHECK_TRUE(fds[READ] != -1 && fds[WRITE] != -1, -1, "END fds[READ/WRITE]=-1");
341
342 int stat = fcntl(fds[READ], F_GETFL);
343 CHECK_TRUE(stat != -1, -1, "END fcntl(F_GETFL) failed!");
344
345 if (!(stat & O_NONBLOCK)) {
346 HILOG_DEBUG(LOG_CORE, "NOTE %s: ready!Unblock r_fd and close all", __func__);
347 const char* eof = "\n\0";
348 write(fds[WRITE], eof, strlen(eof) + 1);
349 fcntl(fds[READ], F_SETFL, O_NONBLOCK);
350 }
351 HILOG_DEBUG(LOG_CORE, "END %s: success!", __func__);
352 return 0;
353 }
354
GetServicePort()355 int GetServicePort()
356 {
357 const std::string portRangePath = "/proc/sys/net/ipv4/ip_local_port_range";
358 std::ifstream file(portRangePath.c_str());
359 CHECK_TRUE(file.is_open(), -1, "Open file failed! filePath:%s", portRangePath.c_str());
360
361 std::string rangeStr;
362 copy(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>(), std::back_inserter(rangeStr));
363
364 int minPort;
365 int maxPort;
366 std::istringstream istr(rangeStr);
367 istr >> minPort >> maxPort;
368 const int offset = 3168; // To be compatible with previously used port 50051;
369 int port = (minPort + maxPort) / 2 + offset;
370 HILOG_DEBUG(LOG_CORE, "Service port is: %d", port);
371 return port;
372 }
373
SplitString(const std::string & str,const std::string & sep,std::vector<std::string> & ret)374 void SplitString(const std::string& str, const std::string &sep, std::vector<std::string>& ret)
375 {
376 if (str.empty()) {
377 HILOG_ERROR(LOG_CORE, "The string splited is empty!");
378 return;
379 }
380 std::string::size_type beginPos = str.find_first_not_of(sep);
381 std::string::size_type findPos = 0;
382 while (beginPos != std::string::npos) {
383 findPos = str.find(sep, beginPos);
384 std::string tmp;
385 if (findPos != std::string::npos) {
386 tmp = str.substr(beginPos, findPos - beginPos);
387 beginPos = findPos + sep.length();
388 } else {
389 tmp = str.substr(beginPos);
390 beginPos = findPos;
391 }
392 if (!tmp.empty()) {
393 ret.push_back(tmp);
394 tmp.clear();
395 }
396 }
397 }
398
CheckApplicationPermission(int pid,const std::string & processName)399 bool CheckApplicationPermission(int pid, const std::string& processName)
400 {
401 std::string bundleName;
402 if (pid > 0) {
403 std::string filePath = "/proc/" + std::to_string(pid) + "/cmdline";
404 if (!LoadStringFromFile(filePath, bundleName)) {
405 HILOG_ERROR(LOG_CORE, "Get process name by pid failed!");
406 return false;
407 }
408 bundleName.resize(strlen(bundleName.c_str()));
409 } else {
410 bundleName = processName;
411 }
412 CHECK_TRUE(!bundleName.empty(), false, "Pid or process name is illegal!");
413
414 sptr<ISystemAbilityManager> sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
415 CHECK_NOTNULL(sam, false, "GetSystemAbilityManager failed!");
416 sptr<IRemoteObject> remoteObject = sam->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
417 CHECK_NOTNULL(remoteObject, false, "Get BundleMgr SA failed!");
418 sptr<BundleMgrProxy> proxy = iface_cast<BundleMgrProxy>(remoteObject);
419 int uid = proxy->GetUidByDebugBundleName(bundleName, Constants::ANY_USERID);
420 CHECK_TRUE(uid >= 0, false, "Get %s uid = %d", bundleName.c_str(), uid);
421 return true;
422 }
423
VerifyPath(const std::string & filePath,const std::vector<std::string> & validPaths)424 bool VerifyPath(const std::string& filePath, const std::vector<std::string>& validPaths)
425 {
426 if (validPaths.size() == 0) {
427 return true;
428 }
429
430 for (const std::string& path : validPaths) {
431 if (filePath.rfind(path, 0) == 0) {
432 return true;
433 }
434 }
435 return false;
436 }
437
ReadFile(const std::string & filePath,const std::vector<std::string> & validPaths,std::string & fileContent)438 bool ReadFile(const std::string &filePath, const std::vector<std::string>& validPaths, std::string& fileContent)
439 {
440 char* realFilePath = realpath(filePath.c_str(), nullptr);
441 CHECK_NOTNULL(realFilePath, false, "Fail to realPath: %s", filePath.c_str());
442
443 std::string realFilePathStr(realFilePath);
444 free(realFilePath);
445 CHECK_TRUE(VerifyPath(realFilePathStr, validPaths), false, "Fail to VerifyPath: %s", realFilePathStr.c_str());
446
447 std::ifstream fileStream(realFilePathStr, std::ios::in);
448 CHECK_TRUE(fileStream.is_open(), false, "Fail to open file %s", realFilePathStr.c_str());
449
450 std::istreambuf_iterator<char> firstIt = { fileStream };
451 std::string content(firstIt, {});
452 fileContent = content;
453 return true;
454 }
455
GetErrorMsg()456 std::string GetErrorMsg()
457 {
458 const int bufSize = 256;
459 char buffer[bufSize] = { 0 };
460 strerror_r(errno, buffer, bufSize);
461 std::string errorMsg(buffer);
462 return errorMsg;
463 }
464
GetTimeStr()465 std::string GetTimeStr()
466 {
467 time_t now = time(nullptr);
468 struct tm tmTime;
469 localtime_r(&now, &tmTime);
470
471 char buffer[32] = {0};
472 // 1900: count of years
473 (void)sprintf_s(buffer, sizeof(buffer), "%04d%02d%02d_%02d%02d%02d", tmTime.tm_year + 1900, tmTime.tm_mon + 1,
474 tmTime.tm_mday, tmTime.tm_hour, tmTime.tm_min, tmTime.tm_sec);
475 std::string timeStr(buffer);
476 return timeStr;
477 }
478
479 // get clockid by str, return CLOCK_REALTIME as default
GetClockId(const std::string & clockIdStr)480 clockid_t GetClockId(const std::string& clockIdStr)
481 {
482 const std::map<std::string, clockid_t> clockIdMap = {
483 {"realtime", CLOCK_REALTIME},
484 {"mono", CLOCK_MONOTONIC},
485 {"process_cputime_id", CLOCK_PROCESS_CPUTIME_ID},
486 {"thread_cputime_id", CLOCK_THREAD_CPUTIME_ID},
487 {"mono_raw", CLOCK_MONOTONIC_RAW},
488 {"realtime_coarse", CLOCK_REALTIME_COARSE},
489 {"mono_coarse", CLOCK_MONOTONIC_COARSE},
490 {"boot", CLOCK_BOOTTIME},
491 {"realtime_alarm", CLOCK_REALTIME_ALARM},
492 {"boot_alarm", CLOCK_BOOTTIME_ALARM},
493 {"sgi_cycle", CLOCK_SGI_CYCLE},
494 {"tai", CLOCK_TAI},
495 };
496
497 clockid_t clockId = CLOCK_REALTIME;
498 auto iter = clockIdMap.find(clockIdStr);
499 if (iter != clockIdMap.end()) {
500 clockId = iter->second;
501 }
502 return clockId;
503 }
504
AdaptSandboxPath(std::string & filePath,int pid)505 void AdaptSandboxPath(std::string& filePath, int pid)
506 {
507 if (filePath.find("/data/storage") == 0 && access(filePath.c_str(), F_OK) != 0) {
508 filePath = "/proc/" + std::to_string(pid) + "/root/" + filePath;
509 }
510 }
511 } // namespace COMMON
512