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_service.h"
17 #include "appspawn_adapter.h"
18
19 #include <fcntl.h>
20 #include <stdbool.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <sys/capability.h>
24 #include <sys/mount.h>
25 #include <sys/prctl.h>
26 #include <sys/signalfd.h>
27 #include <sys/syscall.h>
28 #include <sys/types.h>
29 #include <sys/wait.h>
30 #include <unistd.h>
31 #include <sched.h>
32
33 #include "securec.h"
34 #include "parameter.h"
35 #include "limits.h"
36 #include "string.h"
37
38 #define DEVICE_NULL_STR "/dev/null"
39
40 // ide-asan
SetAsanEnabledEnv(struct AppSpawnContent_ * content,AppSpawnClient * client)41 static int SetAsanEnabledEnv(struct AppSpawnContent_ *content, AppSpawnClient *client)
42 {
43 AppParameter *appProperty = &((AppSpawnClientExt *)client)->property;
44 char *bundleName = appProperty->bundleName;
45
46 if ((appProperty->flags & APP_ASANENABLED) != 0) {
47 char *devPath = "/dev/asanlog";
48 char logPath[PATH_MAX] = {0};
49 int ret = snprintf_s(logPath, sizeof(logPath), sizeof(logPath) - 1,
50 "/data/app/el1/100/base/%s/log", bundleName);
51 APPSPAWN_CHECK(ret > 0, return -1, "Invalid snprintf_s");
52 char asanOptions[PATH_MAX] = {0};
53 ret = snprintf_s(asanOptions, sizeof(asanOptions), sizeof(asanOptions) - 1,
54 "log_path=%s/asan.log:include=/system/etc/asan.options", devPath);
55 APPSPAWN_CHECK(ret > 0, return -1, "Invalid snprintf_s");
56
57 #if defined (__aarch64__) || defined (__x86_64__)
58 setenv("LD_PRELOAD", "/system/lib64/libclang_rt.asan.so", 1);
59 #else
60 setenv("LD_PRELOAD", "/system/lib/libclang_rt.asan.so", 1);
61 #endif
62 setenv("UBSAN_OPTIONS", asanOptions, 1);
63 client->flags |= APP_COLD_START;
64 }
65 return 0;
66 }
67
SetProcessName(struct AppSpawnContent_ * content,AppSpawnClient * client,char * longProcName,uint32_t longProcNameLen)68 static int SetProcessName(struct AppSpawnContent_ *content, AppSpawnClient *client,
69 char *longProcName, uint32_t longProcNameLen)
70 {
71 AppSpawnClientExt *appPropertyExt = (AppSpawnClientExt *)client;
72 AppParameter *appProperty = &appPropertyExt->property;
73 int len = strlen(appProperty->processName);
74 bool isRet = longProcName == NULL || len <= 0;
75 APPSPAWN_CHECK(!isRet, return -EINVAL, "process name is nullptr or length error");
76
77 char shortName[MAX_LEN_SHORT_NAME] = {0};
78 // process short name max length 16 bytes.
79 if (len >= MAX_LEN_SHORT_NAME) {
80 isRet = strncpy_s(shortName, MAX_LEN_SHORT_NAME, appProperty->processName, MAX_LEN_SHORT_NAME - 1) != EOK;
81 APPSPAWN_CHECK(!isRet, return -EINVAL, "strncpy_s short name error: %d", errno);
82 } else {
83 if (strncpy_s(shortName, MAX_LEN_SHORT_NAME, appProperty->processName, len) != EOK) {
84 APPSPAWN_LOGE("strncpy_s short name error: %d", errno);
85 return -EINVAL;
86 }
87 }
88
89 // set short name
90 isRet = prctl(PR_SET_NAME, shortName) == -1;
91 APPSPAWN_CHECK(!isRet, return -errno, "prctl(PR_SET_NAME) error: %d", errno);
92
93 // reset longProcName
94 isRet = memset_s(longProcName, (size_t)longProcNameLen, 0, (size_t)longProcNameLen) != EOK;
95 APPSPAWN_CHECK(!isRet, return -EINVAL, "Failed to memset long process name");
96
97 // set long process name
98 isRet = strncpy_s(longProcName, longProcNameLen, appProperty->processName, len) != EOK;
99 APPSPAWN_CHECK(!isRet, return -EINVAL, "strncpy_s long name error: %d longProcNameLen %u", errno, longProcNameLen);
100
101 return 0;
102 }
103
SetKeepCapabilities(struct AppSpawnContent_ * content,AppSpawnClient * client)104 static int SetKeepCapabilities(struct AppSpawnContent_ *content, AppSpawnClient *client)
105 {
106 AppSpawnClientExt *appProperty = (AppSpawnClientExt *)client;
107 // set keep capabilities when user not root.
108 if (appProperty->property.uid != 0) {
109 bool isRet = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1;
110 APPSPAWN_CHECK(!isRet, return -errno, "set keepcaps failed: %d", errno);
111 }
112 return 0;
113 }
114
SetCapabilities(struct AppSpawnContent_ * content,AppSpawnClient * client)115 static int SetCapabilities(struct AppSpawnContent_ *content, AppSpawnClient *client)
116 {
117 // init cap
118 struct __user_cap_header_struct cap_header;
119
120 bool isRet = memset_s(&cap_header, sizeof(cap_header), 0, sizeof(cap_header)) != EOK;
121 APPSPAWN_CHECK(!isRet, return -EINVAL, "Failed to memset cap header");
122
123 cap_header.version = _LINUX_CAPABILITY_VERSION_3;
124 cap_header.pid = 0;
125
126 struct __user_cap_data_struct cap_data[2];
127 isRet = memset_s(&cap_data, sizeof(cap_data), 0, sizeof(cap_data)) != EOK;
128 APPSPAWN_CHECK(!isRet, return -EINVAL, "Failed to memset cap data");
129
130 // init inheritable permitted effective zero
131 #ifdef GRAPHIC_PERMISSION_CHECK
132 const uint64_t inheriTable = 0;
133 const uint64_t permitted = 0;
134 const uint64_t effective = 0;
135 #else
136 const uint64_t inheriTable = 0x3fffffffff;
137 const uint64_t permitted = 0x3fffffffff;
138 const uint64_t effective = 0x3fffffffff;
139 #endif
140
141 cap_data[0].inheritable = (__u32)(inheriTable);
142 cap_data[1].inheritable = (__u32)(inheriTable >> BITLEN32);
143 cap_data[0].permitted = (__u32)(permitted);
144 cap_data[1].permitted = (__u32)(permitted >> BITLEN32);
145 cap_data[0].effective = (__u32)(effective);
146 cap_data[1].effective = (__u32)(effective >> BITLEN32);
147
148 // set capabilities
149 isRet = capset(&cap_header, &cap_data[0]) == -1;
150 APPSPAWN_CHECK(!isRet, return -errno, "capset failed: %d", errno);
151 SetSelinuxCon(content, client);
152 return 0;
153 }
154
InitDebugParams(struct AppSpawnContent_ * content,AppSpawnClient * client)155 static void InitDebugParams(struct AppSpawnContent_ *content, AppSpawnClient *client)
156 {
157 #ifndef APPSPAWN_TEST
158 AppSpawnClientExt *appProperty = (AppSpawnClientExt *)client;
159 #if defined (__aarch64__) || defined (__x86_64__)
160 const char *debugSoPath = "/system/lib64/libhidebug.so";
161 #else
162 const char *debugSoPath = "/system/lib/libhidebug.so";
163 #endif
164 bool isRet = access(debugSoPath, F_OK) != 0;
165 APPSPAWN_CHECK(!isRet, return, "access failed, errno = %d", errno);
166
167 void *handle = dlopen(debugSoPath, RTLD_LAZY);
168 APPSPAWN_CHECK(handle != NULL, return, "Failed to dlopen libhidebug.so, %s", dlerror());
169
170 bool (*initParam)(const char *name);
171 initParam = (bool (*)(const char *name))dlsym(handle, "InitEnvironmentParam");
172 APPSPAWN_CHECK(initParam != NULL, dlclose(handle);
173 return, "Failed to dlsym InitEnvironmentParam, %s", dlerror());
174 (*initParam)(appProperty->property.processName);
175 dlclose(handle);
176 #endif
177 }
178
ClearEnvironment(AppSpawnContent * content,AppSpawnClient * client)179 static void ClearEnvironment(AppSpawnContent *content, AppSpawnClient *client)
180 {
181 APPSPAWN_LOGI("ClearEnvironment id %d", client->id);
182 sigset_t mask;
183 sigemptyset(&mask);
184 sigaddset(&mask, SIGCHLD);
185 sigaddset(&mask, SIGTERM);
186 sigprocmask(SIG_UNBLOCK, &mask, NULL);
187 // close child fd
188 #ifndef APPSPAWN_TEST
189 AppSpawnClientExt *appProperty = (AppSpawnClientExt *)client;
190 close(appProperty->fd[0]);
191 #endif
192 SetAsanEnabledEnv(content, client);
193 return;
194 }
195
SetUidGid(struct AppSpawnContent_ * content,AppSpawnClient * client)196 static int SetUidGid(struct AppSpawnContent_ *content, AppSpawnClient *client)
197 {
198 AppSpawnClientExt *appProperty = (AppSpawnClientExt *)client;
199 #ifdef GRAPHIC_PERMISSION_CHECK
200 // set gids
201 bool isRet = setgroups(appProperty->property.gidCount, (const gid_t *)(&appProperty->property.gidTable[0])) == -1;
202 APPSPAWN_CHECK(!isRet, return -errno, "setgroups failed: %d, gids.size=%u", errno, appProperty->property.gidCount);
203
204 if (client->cloneFlags & CLONE_NEWPID) {
205 /* setresuid and setresgid have multi-thread synchronous operations.
206 * after clone, the C library has not cleaned up the multi-thread information, so need to call syscall.
207 */
208 // set gid
209 long ret = syscall(SYS_setresgid, appProperty->property.gid,
210 appProperty->property.gid, appProperty->property.gid);
211 APPSPAWN_CHECK(ret == 0, return -errno, "setgid(%u) failed: %d", appProperty->property.gid, errno);
212
213 /* If the effective user ID is changed from 0 to nonzero,
214 * then all capabilities are cleared from the effective set
215 */
216 ret = syscall(SYS_setresuid, appProperty->property.uid, appProperty->property.uid, appProperty->property.uid);
217 APPSPAWN_CHECK(ret == 0, return -errno, "setuid(%u) failed: %d", appProperty->property.uid, errno);
218 } else {
219 // set gid
220 isRet = setresgid(appProperty->property.gid, appProperty->property.gid, appProperty->property.gid) == -1;
221 APPSPAWN_CHECK(!isRet, return -errno, "setgid(%u) failed: %d", appProperty->property.gid, errno);
222
223 /* If the effective user ID is changed from 0 to nonzero,
224 * then all capabilities are cleared from the effective set
225 */
226 isRet = setresuid(appProperty->property.uid, appProperty->property.uid, appProperty->property.uid) == -1;
227 APPSPAWN_CHECK(!isRet, return -errno, "setuid(%u) failed: %d", appProperty->property.uid, errno);
228 }
229 #endif
230 if ((appProperty->property.flags & APP_DEBUGGABLE) != 0) {
231 APPSPAWN_LOGV("Debuggable app");
232 setenv("HAP_DEBUGGABLE", "true", 1);
233 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) {
234 APPSPAWN_LOGE("Failed to set app dumpable: %s", strerror(errno));
235 }
236 }
237 return 0;
238 }
239
SetFileDescriptors(struct AppSpawnContent_ * content,AppSpawnClient * client)240 static int32_t SetFileDescriptors(struct AppSpawnContent_ *content, AppSpawnClient *client)
241 {
242 #ifndef APPSPAWN_TEST
243 // close stdin stdout stderr
244 close(STDIN_FILENO);
245 close(STDOUT_FILENO);
246 close(STDERR_FILENO);
247
248 // redirect to /dev/null
249 int dev_null_fd = open(DEVICE_NULL_STR, O_RDWR);
250 if (dev_null_fd == -1) {
251 APPSPAWN_LOGE("open dev_null error: %d", errno);
252 return (-errno);
253 }
254
255 // stdin
256 if (dup2(dev_null_fd, STDIN_FILENO) == -1) {
257 APPSPAWN_LOGE("dup2 STDIN error: %d", errno);
258 return (-errno);
259 };
260
261 // stdout
262 if (dup2(dev_null_fd, STDOUT_FILENO) == -1) {
263 APPSPAWN_LOGE("dup2 STDOUT error: %d", errno);
264 return (-errno);
265 };
266
267 // stderr
268 if (dup2(dev_null_fd, STDERR_FILENO) == -1) {
269 APPSPAWN_LOGE("dup2 STDERR error: %d", errno);
270 return (-errno);
271 };
272 #endif
273 return 0;
274 }
275
Free(char ** argv)276 static void Free(char **argv)
277 {
278 argv[0] = NULL;
279 for (int i = 0; i < NULL_INDEX; i++) {
280 if (argv[i] != NULL) {
281 free(argv[i]);
282 argv[i] = NULL;
283 }
284 }
285 free(argv);
286 }
287
288 #ifdef ASAN_DETECTOR
289 #define WRAP_VALUE_MAX_LENGTH 96
GetWrapBundleNameValue(struct AppSpawnContent_ * content,AppSpawnClient * client)290 static int GetWrapBundleNameValue(struct AppSpawnContent_ *content, AppSpawnClient *client)
291 {
292 AppParameter *appProperty = &((AppSpawnClientExt *)client)->property;
293 char wrapBundleNameKey[WRAP_VALUE_MAX_LENGTH] = {0};
294 char wrapBundleNameValue[WRAP_VALUE_MAX_LENGTH] = {0};
295
296 int len = sprintf_s(wrapBundleNameKey, WRAP_VALUE_MAX_LENGTH, "wrap.%s", appProperty->bundleName);
297 APPSPAWN_CHECK(len > 0 && (len < WRAP_VALUE_MAX_LENGTH), return -1, "Invalid to format wrapBundleNameKey");
298
299 int ret = GetParameter(wrapBundleNameKey, "", wrapBundleNameValue, WRAP_VALUE_MAX_LENGTH);
300 APPSPAWN_CHECK(ret > 0 && (!strcmp(wrapBundleNameValue, "asan_wrapper")), return -1,
301 "Not wrap %s.", appProperty->bundleName);
302 APPSPAWN_LOGI("Asan: GetParameter %s the value is %s.", wrapBundleNameKey, wrapBundleNameValue);
303 return 0;
304 }
305 #endif
306
ColdStartApp(struct AppSpawnContent_ * content,AppSpawnClient * client)307 static int ColdStartApp(struct AppSpawnContent_ *content, AppSpawnClient *client)
308 {
309 AppParameter *appProperty = &((AppSpawnClientExt *)client)->property;
310 APPSPAWN_LOGI("ColdStartApp::appName %s", appProperty->processName);
311 char buffer[32] = {0}; // 32 buffer for fd
312 int len = sprintf_s(buffer, sizeof(buffer), "%d", ((AppSpawnClientExt *)client)->fd[1]);
313 APPSPAWN_CHECK(len > 0, return -1, "Invalid to format fd");
314 char **argv = calloc(1, (NULL_INDEX + 1) * sizeof(char *));
315 APPSPAWN_CHECK(argv != NULL, return -1, "Failed to get argv");
316
317 int32_t startLen = 0;
318 const int32_t originLen = sizeof(AppParameter) + PARAM_BUFFER_LEN;
319 // param
320 char *param = malloc(originLen + APP_LEN_PROC_NAME);
321 APPSPAWN_CHECK(param != NULL, free(argv);
322 return -1, "Failed to malloc for param");
323
324 int ret = -1;
325 do {
326 argv[PARAM_INDEX] = param;
327 argv[0] = param + originLen;
328 #ifdef ASAN_DETECTOR
329 if (GetWrapBundleNameValue(content, client) == 0) {
330 ret = strcpy_s(argv[0], APP_LEN_PROC_NAME, "/system/asan/bin/appspawn");
331 } else {
332 ret = strcpy_s(argv[0], APP_LEN_PROC_NAME, "/system/bin/appspawn");
333 }
334 #else
335 ret = strcpy_s(argv[0], APP_LEN_PROC_NAME, "/system/bin/appspawn");
336 #endif
337 APPSPAWN_CHECK(ret >= 0, break, "Invalid strcpy");
338 ret = -1;
339 argv[START_INDEX] = strdup("cold-start");
340 APPSPAWN_CHECK(argv[START_INDEX] != NULL, break, "Invalid strdup");
341 argv[FD_INDEX] = strdup(buffer);
342 APPSPAWN_CHECK(argv[FD_INDEX] != NULL, break, "Invalid strdup");
343
344 len = sprintf_s(param + startLen, originLen - startLen, "%u:%u:%u:%u:%u",
345 ((AppSpawnClientExt *)client)->client.id, ((AppSpawnClientExt *)client)->client.cloneFlags,
346 appProperty->uid, appProperty->gid, appProperty->gidCount);
347 APPSPAWN_CHECK(len > 0 && (len < (originLen - startLen)), break, "Invalid to format");
348 startLen += len;
349 for (uint32_t i = 0; i < appProperty->gidCount; i++) {
350 len = sprintf_s(param + startLen, originLen - startLen, ":%u", appProperty->gidTable[i]);
351 APPSPAWN_CHECK(len > 0 && (len < (originLen - startLen)), break, "Invalid to format gid");
352 startLen += len;
353 }
354 // processName
355 if (appProperty->soPath[0] == '\0') {
356 strcpy_s(appProperty->soPath, sizeof(appProperty->soPath), "NULL");
357 }
358 len = sprintf_s(param + startLen, originLen - startLen, ":%s:%s:%s:%u:%s:%s",
359 appProperty->processName, appProperty->bundleName, appProperty->soPath,
360 appProperty->accessTokenId, appProperty->apl, appProperty->renderCmd);
361 APPSPAWN_CHECK(len > 0 && (len < (originLen - startLen)), break, "Invalid to format processName");
362 startLen += len;
363 ret = 0;
364 } while (0);
365
366 if (ret == 0) {
367 argv[NULL_INDEX] = NULL;
368 #ifndef APPSPAWN_TEST
369 ret = execv(argv[0], argv);
370 #endif
371 if (ret) {
372 APPSPAWN_LOGE("Failed to execv, errno = %d", errno);
373 }
374 }
375 Free(argv);
376 return ret;
377 }
378
GetAppSpawnClientFromArg(int argc,char * const argv[],AppSpawnClientExt * client)379 int GetAppSpawnClientFromArg(int argc, char *const argv[], AppSpawnClientExt *client)
380 {
381 APPSPAWN_CHECK(argv != NULL && argc > PARAM_INDEX, return -1, "Invalid argv argc %d", argc);
382
383 client->fd[1] = atoi(argv[FD_INDEX]);
384 APPSPAWN_LOGV("GetAppSpawnClientFromArg %s ", argv[PARAM_INDEX]);
385 char *end = NULL;
386 char *start = strtok_r(argv[PARAM_INDEX], ":", &end);
387
388 // clientid
389 APPSPAWN_CHECK(start != NULL, return -1, "Failed to get client id");
390 client->client.id = atoi(start);
391 start = strtok_r(NULL, ":", &end);
392 APPSPAWN_CHECK(start != NULL, return -1, "Failed to get client cloneFlags");
393 client->client.cloneFlags = atoi(start);
394 start = strtok_r(NULL, ":", &end);
395 APPSPAWN_CHECK(start != NULL, return -1, "Failed to get uid");
396 client->property.uid = atoi(start);
397 start = strtok_r(NULL, ":", &end);
398 APPSPAWN_CHECK(start != NULL, return -1, "Failed to get gid");
399 client->property.gid = atoi(start);
400
401 // gidCount
402 start = strtok_r(NULL, ":", &end);
403 APPSPAWN_CHECK(start != NULL, return -1, "Failed to get gidCount");
404 client->property.gidCount = atoi(start);
405 for (uint32_t i = 0; i < client->property.gidCount; i++) {
406 start = strtok_r(NULL, ":", &end);
407 APPSPAWN_CHECK(start != NULL, return -1, "Failed to get gidTable");
408 client->property.gidTable[i] = atoi(start);
409 }
410
411 // processname
412 start = strtok_r(NULL, ":", &end);
413 APPSPAWN_CHECK(start != NULL, return -1, "Failed to get processName");
414 int ret = strcpy_s(client->property.processName, sizeof(client->property.processName), start);
415 APPSPAWN_CHECK(ret == 0, return -1, "Failed to strcpy processName");
416 start = strtok_r(NULL, ":", &end);
417 APPSPAWN_CHECK(start != NULL, return -1, "Failed to get bundleName");
418 ret = strcpy_s(client->property.bundleName, sizeof(client->property.bundleName), start);
419 APPSPAWN_CHECK(ret == 0, return -1, "Failed to strcpy bundleName");
420 start = strtok_r(NULL, ":", &end);
421 APPSPAWN_CHECK(start != NULL, return -1, "Failed to get soPath");
422 if (strcmp(start, "NULL")) {
423 ret = strcpy_s(client->property.soPath, sizeof(client->property.soPath), start);
424 APPSPAWN_CHECK(ret == 0, return -1, "Failed to strcpy soPath");
425 } else {
426 client->property.soPath[0] = '\0';
427 }
428
429 // accesstoken
430 start = strtok_r(NULL, ":", &end);
431 APPSPAWN_CHECK(start != NULL, return -1, "Failed to get accessTokenId");
432 client->property.accessTokenId = atoi(start);
433 start = strtok_r(NULL, ":", &end);
434 APPSPAWN_CHECK(start != NULL, return -1, "Failed to get apl");
435 ret = strcpy_s(client->property.apl, sizeof(client->property.apl), start);
436 APPSPAWN_CHECK(ret == 0, return -1, "Failed to strcpy apl");
437 start = strtok_r(NULL, ":", &end);
438 APPSPAWN_CHECK(start != NULL, return -1, "Failed to get renderCmd");
439 ret = strcpy_s(client->property.renderCmd, sizeof(client->property.renderCmd), start);
440 APPSPAWN_CHECK(ret == 0, return -1, "Failed to strcpy renderCmd");
441
442 return 0;
443 }
444
SetContentFunction(AppSpawnContent * content)445 void SetContentFunction(AppSpawnContent *content)
446 {
447 APPSPAWN_LOGI("SetContentFunction");
448 content->clearEnvironment = ClearEnvironment;
449 content->initDebugParams = InitDebugParams;
450 content->setProcessName = SetProcessName;
451 content->setKeepCapabilities = SetKeepCapabilities;
452 content->setUidGid = SetUidGid;
453 content->setCapabilities = SetCapabilities;
454 content->setFileDescriptors = SetFileDescriptors;
455 content->setAppSandbox = SetAppSandboxProperty;
456 content->setAppAccessToken = SetAppAccessToken;
457 content->coldStartApp = ColdStartApp;
458 #ifdef ASAN_DETECTOR
459 content->getWrapBundleNameValue = GetWrapBundleNameValue;
460 #endif
461 content->setSeccompFilter = SetSeccompFilter;
462 content->setAsanEnabledEnv = SetAsanEnabledEnv;
463 }
464