• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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