• 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 #include <time.h>
27 #ifdef SECURITY_COMPONENT_ENABLE
28 #include "sec_comp_enhance_kit_c.h"
29 #endif
30 
31 #define DEFAULT_UMASK 0002
32 #define SANDBOX_STACK_SIZE (1024 * 1024 * 8)
33 
DiffTime(struct timespec * startTime)34 long long DiffTime(struct timespec *startTime)
35 {
36     struct timespec tmEnd = {0};
37     clock_gettime(CLOCK_REALTIME, &tmEnd);
38     long long diff = (long long)((tmEnd.tv_sec - startTime->tv_sec) * 1000000); // 1000000 1000ms
39     if (tmEnd.tv_nsec > startTime->tv_nsec) {
40         diff += (tmEnd.tv_nsec - startTime->tv_nsec) / 1000; // 1000 ms
41     } else {
42         diff -= (startTime->tv_nsec - tmEnd.tv_nsec) / 1000; // 1000 ms
43     }
44     return diff;
45 }
46 
NotifyResToParent(struct AppSpawnContent_ * content,AppSpawnClient * client,int result)47 static void NotifyResToParent(struct AppSpawnContent_ *content, AppSpawnClient *client, int result)
48 {
49     if (content->notifyResToParent != NULL) {
50         content->notifyResToParent(content, client, result);
51     }
52 }
53 
ProcessExit(int code)54 static void ProcessExit(int code)
55 {
56     APPSPAWN_LOGI("App exit code: %{public}d", code);
57 #ifdef OHOS_LITE
58     _exit(0x7f); // 0x7f user exit
59 #else
60 #ifndef APPSPAWN_TEST
61     quick_exit(0);
62 #endif
63 #endif
64 }
65 
66 #ifdef APPSPAWN_HELPER
67 __attribute__((visibility("default")))
68 _Noreturn
exit(int code)69 void exit(int code)
70 {
71     char *checkExit = getenv(APPSPAWN_CHECK_EXIT);
72     if (checkExit && atoi(checkExit) == getpid()) {
73         APPSPAWN_LOGF("Unexpected call: exit(%{public}d)", code);
74         abort();
75     }
76     // hook `exit` to `ProcessExit` to ensure app exit in a clean way
77     ProcessExit(code);
78     // should not come here
79     abort();
80 }
81 #endif
82 
DoStartApp(struct AppSpawnContent_ * content,AppSpawnClient * client,char * longProcName,uint32_t longProcNameLen)83 int DoStartApp(struct AppSpawnContent_ *content, AppSpawnClient *client, char *longProcName, uint32_t longProcNameLen)
84 {
85     int32_t ret = 0;
86     APPSPAWN_LOGV("DoStartApp id %{public}d longProcNameLen %{public}u", client->id, longProcNameLen);
87     if (content->handleInternetPermission != NULL) {
88         content->handleInternetPermission(client);
89     }
90 
91     if (content->setAppSandbox) {
92         ret = content->setAppSandbox(content, client);
93         APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
94             return ret, "Failed to set app sandbox");
95     }
96 
97     (void)umask(DEFAULT_UMASK);
98     if (content->setKeepCapabilities) {
99         ret = content->setKeepCapabilities(content, client);
100         APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
101             return ret, "Failed to set KeepCapabilities");
102     }
103 
104     if (content->setProcessName) {
105         ret = content->setProcessName(content, client, longProcName, longProcNameLen);
106         APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
107             return ret, "Failed to set setProcessName");
108     }
109 
110     if (content->setXpmRegion) {
111         ret = content->setXpmRegion(content);
112         APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
113             return ret, "Failed to set setXpmRegion");
114     }
115 
116     if (content->setUidGid) {
117         ret = content->setUidGid(content, client);
118         APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
119             return ret, "Failed to setUidGid");
120     }
121 
122     if (content->setFileDescriptors) {
123         ret = content->setFileDescriptors(content, client);
124         APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
125             return ret, "Failed to setFileDescriptors");
126     }
127 
128     if (content->setCapabilities) {
129         ret = content->setCapabilities(content, client);
130         APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
131             return ret, "Failed to setCapabilities");
132     }
133 
134     if (content->waitForDebugger) {
135         ret = content->waitForDebugger(client);
136         APPSPAWN_CHECK(ret == 0, NotifyResToParent(content, client, ret);
137             return ret, "Failed to waitForDebugger");
138     }
139 
140 #ifdef SECURITY_COMPONENT_ENABLE
141     InitSecCompClientEnhance();
142 #endif
143 
144     // notify success to father process and start app process
145     NotifyResToParent(content, client, 0);
146     return 0;
147 }
148 
AppSpawnChild(void * arg)149 static int AppSpawnChild(void *arg)
150 {
151     APPSPAWN_CHECK(arg != NULL, return -1, "Invalid arg for appspawn child");
152     AppSandboxArg *sandbox = (AppSandboxArg *)arg;
153     struct AppSpawnContent_ *content = sandbox->content;
154     AppSpawnClient *client = sandbox->client;
155     int ret = -1;
156 
157 #ifdef OHOS_DEBUG
158     struct timespec tmStart = {0};
159     clock_gettime(CLOCK_REALTIME, &tmStart);
160 #endif
161     // close socket id and signal for child
162     if (content->clearEnvironment != NULL) {
163         content->clearEnvironment(content, client);
164     }
165 
166     if (content->setAppAccessToken != NULL) {
167         ret = content->setAppAccessToken(content, client);
168         if (ret != 0) {
169             APPSPAWN_LOGE("AppSpawnChild, set app token id failed");
170             return -1;
171         }
172     }
173 
174     if ((content->getWrapBundleNameValue != NULL && content->getWrapBundleNameValue(content, client) == 0) ||
175         ((client->flags & APP_COLD_START) != 0)) {
176         // cold start fail, to start normal
177         if (content->coldStartApp != NULL && content->coldStartApp(content, client) == 0) {
178             return 0;
179         }
180     }
181     ret = DoStartApp(content, client, content->longProcName, content->longProcNameLen);
182     if (content->initDebugParams != NULL) {
183         content->initDebugParams(content, client);
184     }
185 #ifdef OHOS_DEBUG
186     long long diff = DiffTime(&tmStart);
187     APPSPAWN_LOGI("App timeused %{public}d %lld ns.", getpid(), diff);
188 #endif
189     if (ret == 0 && content->runChildProcessor != NULL) {
190         content->runChildProcessor(content, client);
191     }
192     return 0;
193 }
194 
CloneAppSpawn(void * arg)195 static int CloneAppSpawn(void *arg)
196 {
197     int ret = AppSpawnChild(arg);
198     ProcessExit(ret);
199     return ret;
200 }
201 
202 #ifndef APPSPAWN_TEST
AppSpawnFork(int (* childFunc)(void * arg),void * args)203 pid_t AppSpawnFork(int (*childFunc)(void *arg), void *args)
204 {
205     pid_t pid = fork();
206     if (pid == 0) {
207         ProcessExit(childFunc(args));
208     }
209     return pid;
210 }
211 #endif
212 
AppSpawnProcessMsg(AppSandboxArg * sandbox,pid_t * childPid)213 int AppSpawnProcessMsg(AppSandboxArg *sandbox, pid_t *childPid)
214 {
215     APPSPAWN_CHECK(sandbox != NULL && sandbox->content != NULL, return -1, "Invalid content for appspawn");
216     APPSPAWN_CHECK(sandbox->client != NULL && childPid != NULL, return -1, "Invalid client for appspawn");
217     APPSPAWN_LOGI("AppSpawnProcessMsg id %{public}d 0x%{public}x", sandbox->client->id, sandbox->client->flags);
218 
219 #ifndef OHOS_LITE
220     AppSpawnClient *client = sandbox->client;
221     if (client->cloneFlags & CLONE_NEWPID) {
222         APPSPAWN_CHECK(client->cloneFlags & CLONE_NEWNS, return -1, "clone flags error");
223         char *childStack = (char *)malloc(SANDBOX_STACK_SIZE);
224         APPSPAWN_CHECK(childStack != NULL, return -1, "malloc failed");
225         pid_t pid = clone(CloneAppSpawn,
226             childStack + SANDBOX_STACK_SIZE, client->cloneFlags | SIGCHLD, (void *)sandbox);
227         if (pid > 0) {
228             free(childStack);
229             *childPid = pid;
230             return 0;
231         }
232         client->cloneFlags &= ~CLONE_NEWPID;
233         free(childStack);
234     }
235 #endif
236     *childPid = AppSpawnFork(AppSpawnChild, (void *)sandbox);
237     APPSPAWN_CHECK(*childPid >= 0, return -errno, "fork child process error: %{public}d", -errno);
238     return 0;
239 }
240 
241