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 41static 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 51int 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 105void 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 125uint64_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 139int 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 169static 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 182int32_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 223char *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 239char *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 273cJSON *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 283int 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 316void 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 343static FILE *g_dumpToStream = NULL; 344void 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 359void 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 394int 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 411uint32_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 424int 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 440void 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