• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 "appspawn_server.h"
17 
18 #include <stdlib.h>
19 #include <errno.h>
20 #include <sys/stat.h>
21 #include <unistd.h>
22 #include <signal.h>
23 #undef _GNU_SOURCE
24 #define _GNU_SOURCE
25 #include <sched.h>
26 #ifdef OHOS_DEBUG
27 #include <time.h>
28 #endif // OHOS_DEBUG
29 #include <stdbool.h>
30 
31 #include "syspara/parameter.h"
32 #include "securec.h"
33 
34 #define DEFAULT_UMASK 0002
35 
36 #ifndef APPSPAWN_TEST
37 #ifndef OHOS_LITE
38 void DisallowInternet(void);
39 #endif
40 #endif
41 
42 #define SANDBOX_STACK_SIZE (1024 * 1024 * 8)
43 #define APPSPAWN_CHECK_EXIT "AppSpawnCheckUnexpectedExitCall"
44 
SetInternetPermission(const AppSpawnClient * client)45 static void SetInternetPermission(const AppSpawnClient *client)
46 {
47 #ifndef APPSPAWN_TEST
48 #ifndef OHOS_LITE
49     if (client == NULL) {
50         return;
51     }
52 
53     APPSPAWN_LOGI("SetInternetPermission id %d setAllowInternet %hhu allowInternet %hhu", client->id,
54                   client->setAllowInternet, client->allowInternet);
55     if (client->setAllowInternet == 1 && client->allowInternet == 0) {
56         DisallowInternet();
57     }
58 #endif
59 #endif
60 }
61 
NotifyResToParent(struct AppSpawnContent_ * content,AppSpawnClient * client,int result)62 static void NotifyResToParent(struct AppSpawnContent_ *content, AppSpawnClient *client, int result)
63 {
64     if (content->notifyResToParent != NULL) {
65         content->notifyResToParent(content, client, result);
66     }
67 }
68 
ProcessExit(int code)69 static void ProcessExit(int code)
70 {
71     APPSPAWN_LOGI("App exit: %{public}d", code);
72 #ifndef APPSPAWN_TEST
73 #ifdef OHOS_LITE
74     _exit(0x7f); // 0x7f user exit
75 #else
76     quick_exit(0);
77 #endif
78 #endif
79 }
80 
81 #ifdef APPSPAWN_HELPER
82 __attribute__((visibility("default")))
83 _Noreturn
exit(int code)84 void exit(int code)
85 {
86     char *checkExit = getenv(APPSPAWN_CHECK_EXIT);
87     if (checkExit && atoi(checkExit) == getpid()) {
88         APPSPAWN_LOGF("Unexpected exit call: %{public}d", code);
89         abort();
90     }
91     // hook `exit` to `ProcessExit` to ensure app exit in a clean way
92     ProcessExit(code);
93     // should not come here
94     abort();
95 }
96 #endif
97 
DoStartApp(struct AppSpawnContent_ * content,AppSpawnClient * client,char * longProcName,uint32_t longProcNameLen)98 int DoStartApp(struct AppSpawnContent_ *content, AppSpawnClient *client, char *longProcName, uint32_t longProcNameLen)
99 {
100     SetInternetPermission(client);
101 
102     APPSPAWN_LOGI("DoStartApp id %d longProcNameLen %u", client->id, longProcNameLen);
103     int32_t ret = 0;
104 
105     if ((client->cloneFlags & CLONE_NEWNS) && (content->setAppSandbox)) {
106         ret = content->setAppSandbox(content, client);
107         APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
108             return ret, "Failed to set app sandbox");
109     }
110 
111     (void)umask(DEFAULT_UMASK);
112     if (content->setKeepCapabilities) {
113         ret = content->setKeepCapabilities(content, client);
114         APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
115             return ret, "Failed to set KeepCapabilities");
116     }
117 
118     if (content->setProcessName) {
119         ret = content->setProcessName(content, client, longProcName, longProcNameLen);
120         APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
121             return ret, "Failed to set setProcessName");
122     }
123 
124     if (content->setSeccompFilter) {
125         content->setSeccompFilter(content, client);
126     }
127 
128     if (content->setUidGid) {
129         ret = content->setUidGid(content, client);
130         APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
131             return ret, "Failed to setUidGid");
132     }
133 
134     if (content->setFileDescriptors) {
135         ret = content->setFileDescriptors(content, client);
136         APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
137             return ret, "Failed to setFileDescriptors");
138     }
139 
140     if (content->setCapabilities) {
141         ret = content->setCapabilities(content, client);
142         APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
143             return ret, "Failed to setCapabilities");
144     }
145 
146     // notify success to father process and start app process
147     NotifyResToParent(content, client, 0);
148     return 0;
149 }
150 
AppSpawnChildRun(void * arg)151 static int AppSpawnChildRun(void *arg)
152 {
153     APPSPAWN_CHECK(arg != NULL, return -1, "Invalid arg for appspawn child");
154     AppSandboxArg *sandbox = (AppSandboxArg *)arg;
155     struct AppSpawnContent_ *content = sandbox->content;
156     AppSpawnClient *client = sandbox->client;
157 
158 #ifdef OHOS_DEBUG
159     struct timespec tmStart = {0};
160     GetCurTime(&tmStart);
161 #endif // OHOS_DEBUG
162 
163     // close socket id and signal for child
164     if (content->clearEnvironment != NULL) {
165         content->clearEnvironment(content, client);
166     }
167 
168     if (content->setAppAccessToken != NULL) {
169         content->setAppAccessToken(content, client);
170     }
171 
172     int ret = -1;
173 #ifdef ASAN_DETECTOR
174     if ((content->getWrapBundleNameValue != NULL && content->getWrapBundleNameValue(content, client) == 0)
175         || ((client->flags & APP_COLD_START) != 0)) {
176 #else
177     if ((client->flags & APP_COLD_START) != 0) {
178 #endif
179         if (content->coldStartApp != NULL && content->coldStartApp(content, client) == 0) {
180 #ifndef APPSPAWN_TEST
181             _exit(0x7f); // 0x7f user exit
182 #endif
183             return -1;
184         } else {
185             ret = DoStartApp(content, client, content->longProcName, content->longProcNameLen);
186         }
187     } else {
188         ret = DoStartApp(content, client, content->longProcName, content->longProcNameLen);
189     }
190     if (content->initDebugParams != NULL) {
191         content->initDebugParams(content, client);
192     }
193 #ifdef OHOS_DEBUG
194     struct timespec tmEnd = {0};
195     GetCurTime(&tmEnd);
196     // 1s = 1000000000ns
197     long timeUsed = (tmEnd.tv_sec - tmStart.tv_sec) * 1000000000L + (tmEnd.tv_nsec - tmStart.tv_nsec);
198     APPSPAWN_LOGI("App timeused %d %ld ns.", getpid(), timeUsed);
199 #endif  // OHOS_DEBUG
200 
201     if (ret == 0 && content->runChildProcessor != NULL) {
202         content->runChildProcessor(content, client);
203     }
204     return 0;
205 }
206 
207 int AppSpawnChild(void *arg)
208 {
209     char checkExit[16] = ""; // 16 is enough to store an int
210     if (GetIntParameter("persist.init.debug.checkexit", false)) {
211         (void)sprintf_s(checkExit, sizeof(checkExit), "%d", getpid());
212     }
213     setenv(APPSPAWN_CHECK_EXIT, checkExit, true);
214     int ret = AppSpawnChildRun(arg);
215     unsetenv(APPSPAWN_CHECK_EXIT);
216     return ret;
217 }
218 
219 int AppSpawnProcessMsg(AppSandboxArg *sandbox, pid_t *childPid)
220 {
221     pid_t pid;
222     APPSPAWN_CHECK(sandbox != NULL && sandbox->content != NULL, return -1, "Invalid content for appspawn");
223     APPSPAWN_CHECK(sandbox->client != NULL && childPid != NULL, return -1, "Invalid client for appspawn");
224     APPSPAWN_LOGI("AppSpawnProcessMsg id %d 0x%x", sandbox->client->id, sandbox->client->flags);
225 
226 #ifndef APPSPAWN_TEST
227     AppSpawnClient *client = sandbox->client;
228     if (client->cloneFlags & CLONE_NEWPID) {
229         APPSPAWN_CHECK(client->cloneFlags & CLONE_NEWNS, return -1, "clone flags error");
230         char *childStack = (char *)malloc(SANDBOX_STACK_SIZE);
231         APPSPAWN_CHECK(childStack != NULL, return -1, "malloc failed");
232 
233         pid = clone(AppSpawnChild, childStack + SANDBOX_STACK_SIZE, client->cloneFlags | SIGCHLD, (void *)sandbox);
234         if (pid > 0) {
235             free(childStack);
236             *childPid = pid;
237             return 0;
238         }
239 
240         client->cloneFlags &= ~CLONE_NEWPID;
241         free(childStack);
242     }
243 
244     pid = fork();
245     APPSPAWN_CHECK(pid >= 0, return -errno, "fork child process error: %d", -errno);
246     *childPid = pid;
247 #else
248     pid = 0;
249     *childPid = pid;
250 #endif
251     if (pid == 0) {
252         ProcessExit(AppSpawnChild((void *)sandbox));
253     }
254     return 0;
255 }
256 
257 #ifdef OHOS_DEBUG
258 void GetCurTime(struct timespec *tmCur)
259 {
260     if (tmCur == NULL) {
261         return;
262     }
263 
264     if (clock_gettime(CLOCK_REALTIME, tmCur) != 0) {
265         APPSPAWN_LOGE("[appspawn] invoke, get time failed! err %d", errno);
266     }
267 }
268 #endif  // OHOS_DEBUG
269