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