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 "appspawn_utils.h"
17 
18 #include <ctype.h>
19 #include <dirent.h>
20 #include <fcntl.h>
21 #include <malloc.h>
22 #include <stdint.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include <linux/if.h>
28 #include <sys/ioctl.h>
29 #include <sys/mount.h>
30 #include <sys/socket.h>
31 #include <sys/stat.h>
32 #include <sys/types.h>
33 
34 #include "appspawn_hook.h"
35 #include "cJSON.h"
36 #include "config_policy_utils.h"
37 #include "json_utils.h"
38 #include "parameter.h"
39 #include "securec.h"
40 
41 static const AppSpawnCommonEnv COMMON_ENV[] = {
42     {"HNP_PRIVATE_HOME", "/data/app", true},
43     {"HNP_PUBLIC_HOME", "/data/service/hnp", true},
44     {"PATH", "${HNP_PRIVATE_HOME}/bin:${HNP_PUBLIC_HOME}/bin:${PATH}", true},
45     {"HOME", "/storage/Users/currentUser", false},
46     {"TMPDIR", "/data/storage/el2/base/cache", false},
47     {"SHELL", "/bin/sh", false},
48     {"PWD", "/storage/Users/currentUser", false}
49 };
50 
ConvertEnvValue(const char *srcEnv, char *dstEnv, int len)51 int ConvertEnvValue(const char *srcEnv, char *dstEnv, int len)
52 {
53     char *tmpEnv = NULL;
54     char *ptr;
55     char *tmpPtr1;
56     char *tmpPtr2;
57     char *envGet;
58 
59     int srcLen = strlen(srcEnv) + 1;
60     tmpEnv = malloc(srcLen);
61     APPSPAWN_CHECK(tmpEnv != NULL, return -1, "malloc size=%{public}d fail", srcLen);
62 
63     int ret = memcpy_s(tmpEnv, srcLen, srcEnv, srcLen);
64     if (ret != EOK) {
65         APPSPAWN_LOGE("Failed to copy env value");
66         free(tmpEnv);
67         return -1;
68     }
69 
70     ptr = tmpEnv;
71     dstEnv[0] = 0;
72     while (((tmpPtr1 = strchr(ptr, '$')) != NULL) && (*(tmpPtr1 + 1) == '{') &&
73         ((tmpPtr2 = strchr(tmpPtr1, '}')) != NULL)) {
74         *tmpPtr1 = 0;
75         ret = strcat_s(dstEnv, len, ptr);
76         if (ret != 0) {
77             APPSPAWN_LOGE("Failed to strcat env value");
78             free(tmpEnv);
79             return -1;
80         }
81         *tmpPtr2 = 0;
82         tmpPtr1++;
83         ptr = tmpPtr2 + 1;
84         envGet = getenv(tmpPtr1 + 1);
85         if (envGet == NULL) {
86             continue;
87         }
88         ret = strcat_s(dstEnv, len, envGet);
89         if (ret != 0) {
90             APPSPAWN_LOGE("Failed to strcat env value");
91             free(tmpEnv);
92             return -1;
93         }
94     }
95     ret = strcat_s(dstEnv, len, ptr);
96     if (ret != 0) {
97         APPSPAWN_LOGE("Failed to strcat env value");
98         free(tmpEnv);
99         return -1;
100     }
101     free(tmpEnv);
102     return 0;
103 }
104 
InitCommonEnv(void)105 void InitCommonEnv(void)
106 {
107     uint32_t count = ARRAY_LENGTH(COMMON_ENV);
108     int32_t ret;
109     char envValue[MAX_ENV_VALUE_LEN];
110     int developerMode = IsDeveloperModeOpen();
111 
112     for (uint32_t i = 0; i < count; i++) {
113         if ((COMMON_ENV[i].developerModeEnable == true && developerMode == false)) {
114             continue;
115         }
116         ret = ConvertEnvValue(COMMON_ENV[i].envValue, envValue, MAX_ENV_VALUE_LEN);
117         APPSPAWN_CHECK(ret == 0, return, "Convert env value fail name=%{public}s, value=%{public}s",
118             COMMON_ENV[i].envName, COMMON_ENV[i].envValue);
119         ret = setenv(COMMON_ENV[i].envName, envValue, true);
120         APPSPAWN_CHECK(ret == 0, return, "Set env fail name=%{public}s, value=%{public}s",
121             COMMON_ENV[i].envName, envValue);
122     }
123 }
124 
DiffTime(const struct timespec *startTime, const struct timespec *endTime)125 uint64_t DiffTime(const struct timespec *startTime, const struct timespec *endTime)
126 {
127     APPSPAWN_CHECK_ONLY_EXPER(startTime != NULL, return 0);
128     APPSPAWN_CHECK_ONLY_EXPER(endTime != NULL, return 0);
129 
130     uint64_t diff = (uint64_t)((endTime->tv_sec - startTime->tv_sec) * 1000000);  // 1000000 s-us
131     if (endTime->tv_nsec > startTime->tv_nsec) {
132         diff += (endTime->tv_nsec - startTime->tv_nsec) / 1000;  // 1000 ns - us
133     } else {
134         diff -= (startTime->tv_nsec - endTime->tv_nsec) / 1000;  // 1000 ns - us
135     }
136     return diff;
137 }
138 
MakeDirRec(const char *path, mode_t mode, int lastPath)139 int MakeDirRec(const char *path, mode_t mode, int lastPath)
140 {
141     APPSPAWN_CHECK(path != NULL && *path != '\0', return -1, "Invalid path to create");
142     char buffer[PATH_MAX] = {0};
143     const char slash = '/';
144     const char *p = path;
145     char *curPos = strchr(path, slash);
146     while (curPos != NULL) {
147         int len = curPos - p;
148         p = curPos + 1;
149         if (len == 0) {
150             curPos = strchr(p, slash);
151             continue;
152         }
153         int ret = memcpy_s(buffer, PATH_MAX, path, p - path - 1);
154         APPSPAWN_CHECK(ret == 0, return -1, "Failed to copy path");
155         ret = mkdir(buffer, mode);
156         if (ret == -1 && errno != EEXIST) {
157             return errno;
158         }
159         curPos = strchr(p, slash);
160     }
161     if (lastPath) {
162         if (mkdir(path, mode) == -1 && errno != EEXIST) {
163             return errno;
164         }
165     }
166     return 0;
167 }
168 
TrimTail(char *buffer, uint32_t maxLen)169 static void TrimTail(char *buffer, uint32_t maxLen)
170 {
171     uint32_t index = maxLen - 1;
172     while (index > 0) {
173         if (isspace(buffer[index])) {
174             buffer[index] = '\0';
175             index--;
176             continue;
177         }
178         break;
179     }
180 }
181 
StringSplit(const char *str, const char *separator, void *context, SplitStringHandle handle)182 int32_t StringSplit(const char *str, const char *separator, void *context, SplitStringHandle handle)
183 {
184     APPSPAWN_CHECK(str != NULL && handle != NULL && separator != NULL, return APPSPAWN_ARG_INVALID, "Invalid arg ");
185 
186     int ret = 0;
187     char *tmp = (char *)str;
188     char buffer[PATH_MAX] = {0};
189     uint32_t len = strlen(separator);
190     uint32_t index = 0;
191     while ((*tmp != '\0') && (index < (uint32_t)sizeof(buffer))) {
192         if (index == 0 && isspace(*tmp)) {
193             tmp++;
194             continue;
195         }
196         if (strncmp(tmp, separator, len) != 0) {
197             buffer[index++] = *tmp;
198             tmp++;
199             continue;
200         }
201         tmp += len;
202         buffer[index] = '\0';
203         TrimTail(buffer, index);
204         index = 0;
205 
206         int result = handle(buffer, context);
207         if (result != 0) {
208             ret = result;
209         }
210     }
211     if (index > 0) {
212         buffer[index] = '\0';
213         TrimTail(buffer, index);
214         index = 0;
215         int result = handle(buffer, context);
216         if (result != 0) {
217             ret = result;
218         }
219     }
220     return ret;
221 }
222 
GetLastStr(const char *str, const char *dst)223 char *GetLastStr(const char *str, const char *dst)
224 {
225     APPSPAWN_CHECK_ONLY_EXPER(str != NULL, return NULL);
226     APPSPAWN_CHECK_ONLY_EXPER(dst != NULL, return NULL);
227 
228     char *end = (char *)str + strlen(str);
229     size_t len = strlen(dst);
230     while (end != str) {
231         if (strncmp(end, dst, len) == 0) {
232             return end;
233         }
234         end--;
235     }
236     return NULL;
237 }
238 
ReadFile(const char *fileName)239 char *ReadFile(const char *fileName)
240 {
241     APPSPAWN_CHECK_ONLY_EXPER(fileName != NULL, return NULL);
242     char *buffer = NULL;
243     FILE *fd = NULL;
244     do {
245         struct stat fileStat;
246         if (stat(fileName, &fileStat) != 0 ||
247             fileStat.st_size <= 0 || fileStat.st_size > MAX_JSON_FILE_LEN) {
248             return NULL;
249         }
250         fd = fopen(fileName, "r");
251         APPSPAWN_CHECK(fd != NULL, break, "Failed to open file  %{public}s", fileName);
252 
253         buffer = (char *)malloc((size_t)(fileStat.st_size + 1));
254         APPSPAWN_CHECK(buffer != NULL, break, "Failed to alloc mem %{public}s", fileName);
255 
256         size_t ret = fread(buffer, fileStat.st_size, 1, fd);
257         APPSPAWN_CHECK(ret == 1, break, "Failed to read %{public}s to buffer", fileName);
258         buffer[fileStat.st_size] = '\0';
259         (void)fclose(fd);
260         return buffer;
261     } while (0);
262 
263     if (fd != NULL) {
264         (void)fclose(fd);
265         fd = NULL;
266     }
267     if (buffer != NULL) {
268         free(buffer);
269     }
270     return NULL;
271 }
272 
GetJsonObjFromFile(const char *jsonPath)273 cJSON *GetJsonObjFromFile(const char *jsonPath)
274 {
275     APPSPAWN_CHECK_ONLY_EXPER(jsonPath != NULL && *jsonPath != '\0', NULL);
276     char *buffer = ReadFile(jsonPath);
277     APPSPAWN_CHECK_ONLY_EXPER(buffer != NULL, NULL);
278     cJSON *json = cJSON_Parse(buffer);
279     free(buffer);
280     return json;
281 }
282 
ParseJsonConfig(const char *basePath, const char *fileName, ParseConfig parseConfig, ParseJsonContext *context)283 int ParseJsonConfig(const char *basePath, const char *fileName, ParseConfig parseConfig, ParseJsonContext *context)
284 {
285     APPSPAWN_CHECK_ONLY_EXPER(basePath != NULL, return APPSPAWN_ARG_INVALID);
286     APPSPAWN_CHECK_ONLY_EXPER(fileName != NULL, return APPSPAWN_ARG_INVALID);
287     APPSPAWN_CHECK_ONLY_EXPER(parseConfig != NULL, return APPSPAWN_ARG_INVALID);
288 
289     // load sandbox config
290     char path[PATH_MAX] = {};
291     CfgFiles *files = GetCfgFiles(basePath);
292     if (files == NULL) {
293         return APPSPAWN_SANDBOX_NONE;
294     }
295     int ret = 0;
296     for (int i = 0; i < MAX_CFG_POLICY_DIRS_CNT; ++i) {
297         if (files->paths[i] == NULL) {
298             continue;
299         }
300         int len = snprintf_s(path, sizeof(path), sizeof(path) - 1, "%s%s", files->paths[i], fileName);
301         APPSPAWN_CHECK(len > 0 && (size_t)len < sizeof(path), ret = APPSPAWN_SANDBOX_INVALID;
302             continue, "Failed to format sandbox config file name %{public}s %{public}s", files->paths[i], fileName);
303         cJSON *root = GetJsonObjFromFile(path);
304         APPSPAWN_CHECK(root != NULL, ret = APPSPAWN_SANDBOX_INVALID;
305             continue, "Failed to load app data sandbox config %{public}s", path);
306         int rc = parseConfig(root, context);
307         if (rc != 0) {
308             ret = rc;
309         }
310         cJSON_Delete(root);
311     }
312     FreeCfgFiles(files);
313     return ret;
314 }
315 
DumpCurrentDir(char *buffer, uint32_t bufferLen, const char *dirPath)316 void DumpCurrentDir(char *buffer, uint32_t bufferLen, const char *dirPath)
317 {
318     APPSPAWN_CHECK_ONLY_EXPER(buffer != NULL, return);
319     APPSPAWN_CHECK_ONLY_EXPER(dirPath != NULL, return);
320     APPSPAWN_CHECK_ONLY_EXPER(bufferLen > 0, return);
321 
322     DIR *pDir = opendir(dirPath);
323     APPSPAWN_CHECK(pDir != NULL, return, "Read dir :%{public}s failed.%{public}d", dirPath, errno);
324 
325     struct dirent *dp;
326     while ((dp = readdir(pDir)) != NULL) {
327         if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) {
328             continue;
329         }
330         if (dp->d_type == DT_DIR) {
331             APPSPAWN_LOGW(" Current path %{public}s/%{public}s ", dirPath, dp->d_name);
332             int ret = snprintf_s(buffer, bufferLen, bufferLen - 1, "%s/%s", dirPath, dp->d_name);
333             APPSPAWN_CHECK(ret > 0, break, "Failed to snprintf_s errno: %{public}d", errno);
334             char *path = strdup(buffer);
335             DumpCurrentDir(buffer, bufferLen, path);
336             free(path);
337         }
338     }
339     closedir(pDir);
340     return;
341 }
342 
343 static FILE *g_dumpToStream = NULL;
SetDumpToStream(FILE *stream)344 void SetDumpToStream(FILE *stream)
345 {
346     g_dumpToStream = stream;
347 }
348 
349 #if defined(__clang__)
350 #    pragma clang diagnostic push
351 #    pragma clang diagnostic ignored "-Wvarargs"
352 #elif defined(__GNUC__)
353 #    pragma GCC diagnostic push
354 #    pragma GCC diagnostic ignored "-Wvarargs"
355 #elif defined(_MSC_VER)
356 #    pragma warning(push)
357 #endif
358 
AppSpawnDump(const char *fmt, ...)359 void AppSpawnDump(const char *fmt, ...)
360 {
361     if (g_dumpToStream == NULL) {
362         return;
363     }
364     APPSPAWN_CHECK_ONLY_EXPER(fmt != NULL, return);
365     char format[128] = {0};  // 128 max buffer for format
366     uint32_t size = strlen(fmt);
367     int curr = 0;
368     for (uint32_t index = 0; index < size; index++) {
369         if (curr >= (int)sizeof(format)) {  // invalid format
370             return;
371         }
372         if (fmt[index] != '%') {
373             format[curr++] = fmt[index];
374             continue;
375         }
376         if (strncmp(&fmt[index + 1], "{public}", strlen("{public}")) == 0) {
377             format[curr++] = fmt[index];
378             index += strlen("{public}");
379             continue;
380         }
381         if (strncmp(&fmt[index + 1], "{private}", strlen("{private}")) == 0) {
382             format[curr++] = fmt[index];
383             index += strlen("{private}");
384             continue;
385         }
386     }
387     va_list vargs;
388     va_start(vargs, format);
389     (void)vfprintf(g_dumpToStream, format, vargs);
390     va_end(vargs);
391     (void)fflush(g_dumpToStream);
392 }
393 
IsDeveloperModeOpennull394 int IsDeveloperModeOpen()
395 {
396     char tmp[32] = {0};  // 32 max
397     int ret = GetParameter("const.security.developermode.state", "", tmp, sizeof(tmp));
398     APPSPAWN_LOGV("IsDeveloperModeOpen ret %{public}d result: %{public}s", ret, tmp);
399     int enabled = (ret > 0 && strcmp(tmp, "true") == 0);
400     return enabled;
401 }
402 
403 #if defined(__clang__)
404 #    pragma clang diagnostic pop
405 #elif defined(__GNUC__)
406 #    pragma GCC diagnostic pop
407 #elif defined(_MSC_VER)
408 #    pragma warning(pop)
409 #endif
410 
GetSpawnTimeout(uint32_t def)411 uint32_t GetSpawnTimeout(uint32_t def)
412 {
413     uint32_t value = def;
414     char data[32] = {};  // 32 length
415     int ret = GetParameter("persist.appspawn.reqMgr.timeout", "0", data, sizeof(data));
416     if (ret > 0 && strcmp(data, "0") != 0) {
417         errno = 0;
418         value = (uint32_t)atoi(data);
419         return (errno != 0) ? def : ((value < def) ? def : value);
420     }
421     return value;
422 }
423 
EnableNewNetNamespace(void)424 int EnableNewNetNamespace(void)
425 {
426     int fd = open(DEVICE_VIRTUAL_NET_IO_FLAGS, O_WRONLY);
427     APPSPAWN_CHECK(fd >= 0, return APPSPAWN_SYSTEM_ERROR, "Failed to open file errno %{public}d", errno);
428 
429     int ret = write(fd, IFF_LOOPBACK_VALUE, IFF_LOOPBACK_SIZE);
430     if (ret < 0) {
431         APPSPAWN_LOGE("Failed to write to file errno %{public}d", errno);
432     } else {
433         APPSPAWN_LOGI("Successfully enabled new net namespace");
434     }
435 
436     close(fd);
437     return (ret >= 0) ? 0 : APPSPAWN_SYSTEM_ERROR;
438 }
439 
EnableCache(void)440 void EnableCache(void)
441 {
442     APPSPAWN_LOGV("enable cache for app process");
443     // enable cache for app process
444     mallopt(M_OHOS_CONFIG, M_TCACHE_PERFORMANCE_MODE);
445     mallopt(M_OHOS_CONFIG, M_ENABLE_OPT_TCACHE);
446     mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_ENABLE);
447     mallopt(M_DELAYED_FREE, M_DELAYED_FREE_ENABLE);
448 }
449