• 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_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