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