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