1 /*
2 * Copyright (c) 2024 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 <errno.h>
17 #include <inttypes.h>
18 #include <limits.h>
19 #include <fcntl.h>
20 #include <signal.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27
28 #include "appspawn_adapter.h"
29 #include "appspawn_hook.h"
30 #include "appspawn_manager.h"
31 #include "appspawn_utils.h"
32 #include "securec.h"
33
GetCgroupPath(const AppSpawnedProcessInfo * appInfo,char * buffer,uint32_t buffLen)34 APPSPAWN_STATIC int GetCgroupPath(const AppSpawnedProcessInfo *appInfo, char *buffer, uint32_t buffLen)
35 {
36 const int userId = appInfo->uid / UID_BASE;
37 #ifdef APPSPAWN_TEST
38 int ret = snprintf_s(buffer, buffLen, buffLen - 1, APPSPAWN_BASE_DIR "/dev/pids/testpids/%d/%s/%d/",
39 userId, appInfo->name, appInfo->pid);
40 #else
41 int ret = snprintf_s(buffer, buffLen, buffLen - 1, "/dev/pids/%d/%s/app_%d/", userId, appInfo->name, appInfo->pid);
42 #endif
43 APPSPAWN_CHECK(ret > 0, return ret, "Failed to snprintf_s errno: %{public}d", errno);
44 APPSPAWN_LOGV("Cgroup path %{public}s ", buffer);
45 return 0;
46 }
47
48
WriteToFile(const char * path,int truncated,pid_t pids[],uint32_t count)49 APPSPAWN_STATIC int WriteToFile(const char *path, int truncated, pid_t pids[], uint32_t count)
50 {
51 char pidName[32] = {0}; // 32 max len
52 int fd = open(path, O_RDWR | (truncated ? O_TRUNC : O_APPEND));
53 APPSPAWN_CHECK(fd >= 0, return APPSPAWN_SYSTEM_ERROR,
54 "Failed to open file errno: %{public}d path: %{public}s", errno, path);
55 int ret = 0;
56 for (uint32_t i = 0; i < count; i++) {
57 APPSPAWN_LOGV(" WriteToFile pid %{public}d ", pids[i]);
58 ret = snprintf_s(pidName, sizeof(pidName), sizeof(pidName) - 1, "%d\n", pids[i]);
59 APPSPAWN_CHECK(ret > 0, break, "Failed to snprintf_s errno: %{public}d", errno);
60 ret = write(fd, pidName, strlen(pidName));
61 APPSPAWN_CHECK(ret > 0, break,
62 "Failed to write file errno: %{public}d path: %{public}s %{public}s", errno, path, pidName);
63 ret = 0;
64 }
65 close(fd);
66 return ret;
67 }
68
SetForkDenied(const AppSpawnedProcessInfo * appInfo)69 static void SetForkDenied(const AppSpawnedProcessInfo *appInfo)
70 {
71 char pathForkDenied[PATH_MAX] = {};
72 int ret = GetCgroupPath(appInfo, pathForkDenied, sizeof(pathForkDenied));
73 APPSPAWN_CHECK(ret == 0, return, "Failed to get cgroup path errno: %{public}d", errno);
74 ret = strcat_s(pathForkDenied, sizeof(pathForkDenied), "pids.fork_denied");
75 APPSPAWN_CHECK(ret == 0, return, "Failed to strcat_s fork_denied path errno: %{public}d", errno);
76 int fd = open(pathForkDenied, O_RDWR);
77 if (fd < 0) {
78 APPSPAWN_LOGW("SetForkDenied %{public}d open failed ", appInfo->pid);
79 return;
80 }
81 do {
82 ret = write(fd, "1", 1);
83 APPSPAWN_CHECK(ret >= 0, break,
84 "Failed to write file errno: %{public}d path: %{public}s %{public}d", errno, pathForkDenied, ret);
85 fsync(fd);
86 APPSPAWN_LOGI("SetForkDenied success, cgroup's owner:%{public}d", appInfo->pid);
87 } while (0);
88 close(fd);
89 }
90
KillProcessesByCGroup(const char * path,AppSpawnMgr * content,const AppSpawnedProcessInfo * appInfo)91 static void KillProcessesByCGroup(const char *path, AppSpawnMgr *content, const AppSpawnedProcessInfo *appInfo)
92 {
93 SetForkDenied(appInfo);
94 FILE *file = fopen(path, "r");
95 APPSPAWN_CHECK(file != NULL, return, "Open file fail %{public}s errno: %{public}d", path, errno);
96 pid_t pid = 0;
97 while (fscanf_s(file, "%d\n", &pid) == 1 && pid > 0) {
98 APPSPAWN_LOGV(" KillProcessesByCGroup pid %{public}d ", pid);
99 if (pid == appInfo->pid) {
100 continue;
101 }
102 AppSpawnedProcessInfo *tmp = GetSpawnedProcess(pid);
103 if (tmp != NULL) {
104 APPSPAWN_LOGI("Got app %{public}s in same group for pid %{public}d.", tmp->name, pid);
105 continue;
106 }
107 APPSPAWN_LOGI("Kill app pid %{public}d now ...", pid);
108 #ifndef APPSPAWN_TEST
109 if (kill(pid, SIGKILL) != 0) {
110 APPSPAWN_LOGE("unable to kill process, pid: %{public}d ret %{public}d", pid, errno);
111 }
112 #endif
113 }
114 (void)fclose(file);
115 }
116
ProcessMgrRemoveApp(const AppSpawnMgr * content,const AppSpawnedProcessInfo * appInfo)117 APPSPAWN_STATIC int ProcessMgrRemoveApp(const AppSpawnMgr *content, const AppSpawnedProcessInfo *appInfo)
118 {
119 APPSPAWN_CHECK_ONLY_EXPER(content != NULL, return -1);
120 APPSPAWN_CHECK_ONLY_EXPER(appInfo != NULL, return -1);
121 if (IsNWebSpawnMode(content) || strcmp(appInfo->name, NWEBSPAWN_SERVER_NAME) == 0) {
122 return 0;
123 }
124 char cgroupPath[PATH_MAX] = {};
125 APPSPAWN_LOGV("ProcessMgrRemoveApp %{public}d %{public}d to cgroup ", appInfo->pid, appInfo->uid);
126 int ret = GetCgroupPath(appInfo, cgroupPath, sizeof(cgroupPath));
127 APPSPAWN_CHECK(ret == 0, return -1, "Failed to get real path errno: %{public}d", errno);
128 char procPath[PATH_MAX] = {};
129 ret = memcpy_s(procPath, sizeof(procPath), cgroupPath, sizeof(cgroupPath));
130 if (ret != 0) {
131 return APPSPAWN_ERROR_UTILS_MEM_FAIL;
132 }
133 ret = strcat_s(procPath, sizeof(procPath), "cgroup.procs");
134 APPSPAWN_CHECK(ret == 0, return ret, "Failed to strcat_s errno: %{public}d", errno);
135 KillProcessesByCGroup(procPath, (AppSpawnMgr *)content, appInfo);
136 ret = rmdir(cgroupPath);
137 if (ret != 0) {
138 return APPSPAWN_ERROR_FILE_RMDIR_FAIL;
139 }
140 return ret;
141 }
142
ProcessMgrAddApp(const AppSpawnMgr * content,const AppSpawnedProcessInfo * appInfo)143 APPSPAWN_STATIC int ProcessMgrAddApp(const AppSpawnMgr *content, const AppSpawnedProcessInfo *appInfo)
144 {
145 APPSPAWN_CHECK_ONLY_EXPER(content != NULL, return -1);
146 APPSPAWN_CHECK_ONLY_EXPER(appInfo != NULL, return -1);
147 if (IsNWebSpawnMode(content)) {
148 return 0;
149 }
150 char path[PATH_MAX] = {};
151 APPSPAWN_LOGV("ProcessMgrAddApp %{public}d %{public}d to cgroup ", appInfo->pid, appInfo->uid);
152 int ret = GetCgroupPath(appInfo, path, sizeof(path));
153 APPSPAWN_CHECK(ret == 0, return -1, "Failed to get real path errno: %{public}d", errno);
154 (void)CreateSandboxDir(path, 0755); // 0755 default mode
155 ret = strcat_s(path, sizeof(path), "cgroup.procs");
156 APPSPAWN_CHECK(ret == 0, return ret, "Failed to strcat_s errno: %{public}d", errno);
157 ret = WriteToFile(path, 0, (pid_t *)&appInfo->pid, 1);
158 APPSPAWN_CHECK(ret == 0, return ret, "write pid to cgroup.procs fail %{public}s", path);
159 APPSPAWN_LOGV("Add app %{public}d to cgroup %{public}s success", appInfo->pid, path);
160 return 0;
161 }
162
MODULE_CONSTRUCTOR(void)163 MODULE_CONSTRUCTOR(void)
164 {
165 AddProcessMgrHook(STAGE_SERVER_APP_ADD, 0, ProcessMgrAddApp);
166 AddProcessMgrHook(STAGE_SERVER_APP_DIED, 0, ProcessMgrRemoveApp);
167 }
168