169570cc8Sopenharmony_ci/* 269570cc8Sopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd. 369570cc8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 469570cc8Sopenharmony_ci * you may not use this file except in compliance with the License. 569570cc8Sopenharmony_ci * You may obtain a copy of the License at 669570cc8Sopenharmony_ci * 769570cc8Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 869570cc8Sopenharmony_ci * 969570cc8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 1069570cc8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 1169570cc8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1269570cc8Sopenharmony_ci * See the License for the specific language governing permissions and 1369570cc8Sopenharmony_ci * limitations under the License. 1469570cc8Sopenharmony_ci */ 1569570cc8Sopenharmony_ci 1669570cc8Sopenharmony_ci#include <errno.h> 1769570cc8Sopenharmony_ci#include <inttypes.h> 1869570cc8Sopenharmony_ci#include <limits.h> 1969570cc8Sopenharmony_ci#include <fcntl.h> 2069570cc8Sopenharmony_ci#include <signal.h> 2169570cc8Sopenharmony_ci#include <stdio.h> 2269570cc8Sopenharmony_ci#include <stdlib.h> 2369570cc8Sopenharmony_ci#include <string.h> 2469570cc8Sopenharmony_ci#include <unistd.h> 2569570cc8Sopenharmony_ci#include <sys/stat.h> 2669570cc8Sopenharmony_ci#include <sys/types.h> 2769570cc8Sopenharmony_ci 2869570cc8Sopenharmony_ci#include "appspawn_adapter.h" 2969570cc8Sopenharmony_ci#include "appspawn_hook.h" 3069570cc8Sopenharmony_ci#include "appspawn_manager.h" 3169570cc8Sopenharmony_ci#include "appspawn_utils.h" 3269570cc8Sopenharmony_ci#include "securec.h" 3369570cc8Sopenharmony_ci#include "cJSON.h" 3469570cc8Sopenharmony_ci#include <sys/ioctl.h> 3569570cc8Sopenharmony_ci 3669570cc8Sopenharmony_ciAPPSPAWN_STATIC int GetCgroupPath(const AppSpawnedProcessInfo *appInfo, char *buffer, uint32_t buffLen) 3769570cc8Sopenharmony_ci{ 3869570cc8Sopenharmony_ci const int userId = appInfo->uid / UID_BASE; 3969570cc8Sopenharmony_ci#ifdef APPSPAWN_TEST 4069570cc8Sopenharmony_ci int ret = snprintf_s(buffer, buffLen, buffLen - 1, APPSPAWN_BASE_DIR "/dev/pids/testpids/%d/%s/%d/", 4169570cc8Sopenharmony_ci userId, appInfo->name, appInfo->pid); 4269570cc8Sopenharmony_ci#else 4369570cc8Sopenharmony_ci int ret = snprintf_s(buffer, buffLen, buffLen - 1, "/dev/pids/%d/%s/app_%d/", userId, appInfo->name, appInfo->pid); 4469570cc8Sopenharmony_ci#endif 4569570cc8Sopenharmony_ci APPSPAWN_CHECK(ret > 0, return ret, "Failed to snprintf_s errno: %{public}d", errno); 4669570cc8Sopenharmony_ci APPSPAWN_LOGV("Cgroup path %{public}s ", buffer); 4769570cc8Sopenharmony_ci return 0; 4869570cc8Sopenharmony_ci} 4969570cc8Sopenharmony_ci 5069570cc8Sopenharmony_ci 5169570cc8Sopenharmony_ciAPPSPAWN_STATIC int WriteToFile(const char *path, int truncated, pid_t pids[], uint32_t count) 5269570cc8Sopenharmony_ci{ 5369570cc8Sopenharmony_ci char pidName[32] = {0}; // 32 max len 5469570cc8Sopenharmony_ci int fd = open(path, O_RDWR | (truncated ? O_TRUNC : O_APPEND)); 5569570cc8Sopenharmony_ci APPSPAWN_CHECK(fd >= 0, return APPSPAWN_SYSTEM_ERROR, 5669570cc8Sopenharmony_ci "Failed to open file errno: %{public}d path: %{public}s", errno, path); 5769570cc8Sopenharmony_ci int ret = 0; 5869570cc8Sopenharmony_ci for (uint32_t i = 0; i < count; i++) { 5969570cc8Sopenharmony_ci APPSPAWN_LOGV(" WriteToFile pid %{public}d ", pids[i]); 6069570cc8Sopenharmony_ci ret = snprintf_s(pidName, sizeof(pidName), sizeof(pidName) - 1, "%d\n", pids[i]); 6169570cc8Sopenharmony_ci APPSPAWN_CHECK(ret > 0, break, "Failed to snprintf_s errno: %{public}d", errno); 6269570cc8Sopenharmony_ci ret = write(fd, pidName, strlen(pidName)); 6369570cc8Sopenharmony_ci APPSPAWN_CHECK(ret > 0, break, 6469570cc8Sopenharmony_ci "Failed to write file errno: %{public}d path: %{public}s %{public}s", errno, path, pidName); 6569570cc8Sopenharmony_ci ret = 0; 6669570cc8Sopenharmony_ci } 6769570cc8Sopenharmony_ci close(fd); 6869570cc8Sopenharmony_ci return ret; 6969570cc8Sopenharmony_ci} 7069570cc8Sopenharmony_ci 7169570cc8Sopenharmony_ci#define APP_PIDS_MAX_ENCAPS "encaps" 7269570cc8Sopenharmony_ci#define APP_PIDS_MAX_OHOS_ENCAPS_COUNT_KEY "ohos.encaps.count" 7369570cc8Sopenharmony_ci#define APP_PIDS_MAX_OHOS_ENCAPS_FORK_KEV "ohos.encaps.fork" 7469570cc8Sopenharmony_ci#define APP_PIDS_MAX_OHOS_ENCAPS_FORK_DFX_KEY "ohos.encaps.fork.dfx" 7569570cc8Sopenharmony_ci#define APP_PIDS_MAX_OHOS_ENCAPS_FORK_WEBDFX_KEY "ohos.encaps.fork.webdfx" 7669570cc8Sopenharmony_ci#define APP_PIDS_MAX_OHOS_ENCAPS_COUNT_VALUE 3 7769570cc8Sopenharmony_ci#define APP_PIDS_MAX_OHOS_ENCAPS_FORK_DFX_AND_WEBDFX_VALUE 5 7869570cc8Sopenharmony_ci#define APP_ENABLE_ENCAPS 1 7969570cc8Sopenharmony_ci#define ASSICN_ENCAPS_CMD _lOW('E', 0x1A, char *) 8069570cc8Sopenharmony_cistatic int WritePidMax(const char *path, uint32_t max) 8169570cc8Sopenharmony_ci{ 8269570cc8Sopenharmony_ci#if APP_ENABLE_ENCAPS == 0 8369570cc8Sopenharmony_ci cJSON *encaps = cJSON_CreateObject(); 8469570cc8Sopenharmony_ci cJSON_AddNumberToObject(encaps, APP_PIDS_MAX_OHOS_ENCAPS_COUNT_KEY, 8569570cc8Sopenharmony_ci APP_PIDS_MAX_OHOS_ENCAPS_COUNT_VALUE); 8669570cc8Sopenharmony_ci cJSON_AddNumberToObject(encaps, APP_PIDS_MAX_OHOS_ENCAPS_FORK_KEV, max); 8769570cc8Sopenharmony_ci cJSON_AddNumberToObject(encaps, APP_PIDS_MAX_OHOS_ENCAPS_FORK_DFX_KEY, 8869570cc8Sopenharmony_ci APP_PIDS_MAX_OHOS_ENCAPS_FORK_DFX_AND_WEBDFX_VALUE); 8969570cc8Sopenharmony_ci cJSON_AddNumberToObject(encaps, APP_PIDS_MAX_OHOS_ENCAPS_FORK_WEBDFX_KEY, 9069570cc8Sopenharmony_ci APP_PIDS_MAX_OHOS_ENCAPS_FORK_DFX_AND_WEBDFX_VALUE); 9169570cc8Sopenharmony_ci cJSON *addGinseng = cJSON_CreateObject(); 9269570cc8Sopenharmony_ci cJSON_AddItemToObject(addGinseng, APP_PIDS_MAX_ENCAPS, encaps); 9369570cc8Sopenharmony_ci char *maxPid = cJSON_PrintUnformatted(addGinseng); 9469570cc8Sopenharmony_ci int ret = 0; 9569570cc8Sopenharmony_ci int fd = 0; 9669570cc8Sopenharmony_ci fd = open("dev/encaps", O_RDWR); 9769570cc8Sopenharmony_ci ret = ioctl(fd, ASSICN_ENCAPS_CMD, maxPid); 9869570cc8Sopenharmony_ci close(fd); 9969570cc8Sopenharmony_ci free(maxPid); 10069570cc8Sopenharmony_ci cJSON_Delete(addGinseng); 10169570cc8Sopenharmony_ci cJSON_Delete(encaps); 10269570cc8Sopenharmony_ci return ret; 10369570cc8Sopenharmony_ci#else 10469570cc8Sopenharmony_ci char value[32] = {0}; // 32 max len 10569570cc8Sopenharmony_ci int fd = open(path, O_RDWR | O_TRUNC); 10669570cc8Sopenharmony_ci APPSPAWN_CHECK(fd >= 0, return -1, 10769570cc8Sopenharmony_ci "Failed to open file errno: %{public}d path: %{public}s", errno, path); 10869570cc8Sopenharmony_ci int ret = 0; 10969570cc8Sopenharmony_ci do { 11069570cc8Sopenharmony_ci ret = snprintf_s(value, sizeof(value), sizeof(value) - 1, "%u\n", max); 11169570cc8Sopenharmony_ci APPSPAWN_CHECK(ret > 0, break, "Failed to snprintf_s errno: %{public}d", errno); 11269570cc8Sopenharmony_ci ret = write(fd, value, strlen(value)); 11369570cc8Sopenharmony_ci APPSPAWN_CHECK(ret > 0, break, 11469570cc8Sopenharmony_ci "Failed to write file errno: %{public}d path: %{public}s %{public}s %{public}d", errno, path, value, ret); 11569570cc8Sopenharmony_ci ret = 0; 11669570cc8Sopenharmony_ci } while (0); 11769570cc8Sopenharmony_ci close(fd); 11869570cc8Sopenharmony_ci return ret; 11969570cc8Sopenharmony_ci#endif 12069570cc8Sopenharmony_ci} 12169570cc8Sopenharmony_ci 12269570cc8Sopenharmony_cistatic void SetForkDenied(const AppSpawnedProcessInfo *appInfo) 12369570cc8Sopenharmony_ci{ 12469570cc8Sopenharmony_ci char pathForkDenied[PATH_MAX] = {}; 12569570cc8Sopenharmony_ci int ret = GetCgroupPath(appInfo, pathForkDenied, sizeof(pathForkDenied)); 12669570cc8Sopenharmony_ci APPSPAWN_CHECK(ret == 0, return, "Failed to get cgroup path errno: %{public}d", errno); 12769570cc8Sopenharmony_ci ret = strcat_s(pathForkDenied, sizeof(pathForkDenied), "pids.fork_denied"); 12869570cc8Sopenharmony_ci APPSPAWN_CHECK(ret == 0, return, "Failed to strcat_s fork_denied path errno: %{public}d", errno); 12969570cc8Sopenharmony_ci int fd = open(pathForkDenied, O_RDWR); 13069570cc8Sopenharmony_ci if (fd < 0) { 13169570cc8Sopenharmony_ci APPSPAWN_LOGW("SetForkDenied %{public}d open failed ", appInfo->pid); 13269570cc8Sopenharmony_ci return; 13369570cc8Sopenharmony_ci } 13469570cc8Sopenharmony_ci do { 13569570cc8Sopenharmony_ci ret = write(fd, "1", 1); 13669570cc8Sopenharmony_ci APPSPAWN_CHECK(ret >= 0, break, 13769570cc8Sopenharmony_ci "Failed to write file errno: %{public}d path: %{public}s %{public}d", errno, pathForkDenied, ret); 13869570cc8Sopenharmony_ci fsync(fd); 13969570cc8Sopenharmony_ci APPSPAWN_LOGI("SetForkDenied success, cgroup's owner:%{public}d", appInfo->pid); 14069570cc8Sopenharmony_ci } while (0); 14169570cc8Sopenharmony_ci close(fd); 14269570cc8Sopenharmony_ci} 14369570cc8Sopenharmony_ci 14469570cc8Sopenharmony_cistatic void KillProcessesByCGroup(const char *path, AppSpawnMgr *content, const AppSpawnedProcessInfo *appInfo) 14569570cc8Sopenharmony_ci{ 14669570cc8Sopenharmony_ci SetForkDenied(appInfo); 14769570cc8Sopenharmony_ci FILE *file = fopen(path, "r"); 14869570cc8Sopenharmony_ci APPSPAWN_CHECK(file != NULL, return, "Open file fail %{public}s errno: %{public}d", path, errno); 14969570cc8Sopenharmony_ci pid_t pid = 0; 15069570cc8Sopenharmony_ci while (fscanf_s(file, "%d\n", &pid) == 1 && pid > 0) { 15169570cc8Sopenharmony_ci APPSPAWN_LOGV(" KillProcessesByCGroup pid %{public}d ", pid); 15269570cc8Sopenharmony_ci if (pid == appInfo->pid) { 15369570cc8Sopenharmony_ci continue; 15469570cc8Sopenharmony_ci } 15569570cc8Sopenharmony_ci AppSpawnedProcessInfo *tmp = GetSpawnedProcess(pid); 15669570cc8Sopenharmony_ci if (tmp != NULL) { 15769570cc8Sopenharmony_ci APPSPAWN_LOGI("Got app %{public}s in same group for pid %{public}d.", tmp->name, pid); 15869570cc8Sopenharmony_ci continue; 15969570cc8Sopenharmony_ci } 16069570cc8Sopenharmony_ci APPSPAWN_LOGI("Kill app pid %{public}d now ...", pid); 16169570cc8Sopenharmony_ci#ifndef APPSPAWN_TEST 16269570cc8Sopenharmony_ci if (kill(pid, SIGKILL) != 0) { 16369570cc8Sopenharmony_ci APPSPAWN_LOGE("unable to kill process, pid: %{public}d ret %{public}d", pid, errno); 16469570cc8Sopenharmony_ci } 16569570cc8Sopenharmony_ci#endif 16669570cc8Sopenharmony_ci } 16769570cc8Sopenharmony_ci (void)fclose(file); 16869570cc8Sopenharmony_ci} 16969570cc8Sopenharmony_ci 17069570cc8Sopenharmony_ciAPPSPAWN_STATIC int ProcessMgrRemoveApp(const AppSpawnMgr *content, const AppSpawnedProcessInfo *appInfo) 17169570cc8Sopenharmony_ci{ 17269570cc8Sopenharmony_ci APPSPAWN_CHECK_ONLY_EXPER(content != NULL, return -1); 17369570cc8Sopenharmony_ci APPSPAWN_CHECK_ONLY_EXPER(appInfo != NULL, return -1); 17469570cc8Sopenharmony_ci if (IsNWebSpawnMode(content) || strcmp(appInfo->name, NWEBSPAWN_SERVER_NAME) == 0) { 17569570cc8Sopenharmony_ci return 0; 17669570cc8Sopenharmony_ci } 17769570cc8Sopenharmony_ci char cgroupPath[PATH_MAX] = {}; 17869570cc8Sopenharmony_ci APPSPAWN_LOGV("ProcessMgrRemoveApp %{public}d %{public}d to cgroup ", appInfo->pid, appInfo->uid); 17969570cc8Sopenharmony_ci int ret = GetCgroupPath(appInfo, cgroupPath, sizeof(cgroupPath)); 18069570cc8Sopenharmony_ci APPSPAWN_CHECK(ret == 0, return -1, "Failed to get real path errno: %{public}d", errno); 18169570cc8Sopenharmony_ci char procPath[PATH_MAX] = {}; 18269570cc8Sopenharmony_ci ret = memcpy_s(procPath, sizeof(procPath), cgroupPath, sizeof(cgroupPath)); 18369570cc8Sopenharmony_ci if (ret != 0) { 18469570cc8Sopenharmony_ci return APPSPAWN_ERROR_UTILS_MEM_FAIL; 18569570cc8Sopenharmony_ci } 18669570cc8Sopenharmony_ci ret = strcat_s(procPath, sizeof(procPath), "cgroup.procs"); 18769570cc8Sopenharmony_ci APPSPAWN_CHECK(ret == 0, return ret, "Failed to strcat_s errno: %{public}d", errno); 18869570cc8Sopenharmony_ci KillProcessesByCGroup(procPath, (AppSpawnMgr *)content, appInfo); 18969570cc8Sopenharmony_ci ret = rmdir(cgroupPath); 19069570cc8Sopenharmony_ci if (ret != 0) { 19169570cc8Sopenharmony_ci return APPSPAWN_ERROR_FILE_RMDIR_FAIL; 19269570cc8Sopenharmony_ci } 19369570cc8Sopenharmony_ci return ret; 19469570cc8Sopenharmony_ci} 19569570cc8Sopenharmony_ci 19669570cc8Sopenharmony_ciAPPSPAWN_STATIC int ProcessMgrAddApp(const AppSpawnMgr *content, const AppSpawnedProcessInfo *appInfo) 19769570cc8Sopenharmony_ci{ 19869570cc8Sopenharmony_ci APPSPAWN_CHECK_ONLY_EXPER(content != NULL, return -1); 19969570cc8Sopenharmony_ci APPSPAWN_CHECK_ONLY_EXPER(appInfo != NULL, return -1); 20069570cc8Sopenharmony_ci if (IsNWebSpawnMode(content)) { 20169570cc8Sopenharmony_ci return 0; 20269570cc8Sopenharmony_ci } 20369570cc8Sopenharmony_ci char path[PATH_MAX] = {}; 20469570cc8Sopenharmony_ci APPSPAWN_LOGV("ProcessMgrAddApp %{public}d %{public}d to cgroup ", appInfo->pid, appInfo->uid); 20569570cc8Sopenharmony_ci int ret = GetCgroupPath(appInfo, path, sizeof(path)); 20669570cc8Sopenharmony_ci APPSPAWN_CHECK(ret == 0, return -1, "Failed to get real path errno: %{public}d", errno); 20769570cc8Sopenharmony_ci (void)CreateSandboxDir(path, 0750); // 0750 default mode 20869570cc8Sopenharmony_ci uint32_t pathLen = strlen(path); 20969570cc8Sopenharmony_ci ret = strcat_s(path, sizeof(path), "cgroup.procs"); 21069570cc8Sopenharmony_ci APPSPAWN_CHECK(ret == 0, return ret, "Failed to strcat_s errno: %{public}d", errno); 21169570cc8Sopenharmony_ci ret = WriteToFile(path, 0, (pid_t *)&appInfo->pid, 1); 21269570cc8Sopenharmony_ci APPSPAWN_CHECK(ret == 0, return ret, "write pid to cgroup.procs fail %{public}s", path); 21369570cc8Sopenharmony_ci if (appInfo->max != 0) { 21469570cc8Sopenharmony_ci path[pathLen] = '\0'; 21569570cc8Sopenharmony_ci ret = strcat_s(path, sizeof(path), "pids.max"); 21669570cc8Sopenharmony_ci APPSPAWN_CHECK(ret == 0, return ret, "Failed to strcat_s errno: %{public}d", errno); 21769570cc8Sopenharmony_ci ret = WritePidMax(path, appInfo->max); 21869570cc8Sopenharmony_ci APPSPAWN_CHECK(ret == 0, return ret, "write max to pids.max fail %{public}s", path); 21969570cc8Sopenharmony_ci } 22069570cc8Sopenharmony_ci APPSPAWN_LOGV("Add app %{public}d to cgroup %{public}s success", appInfo->pid, path); 22169570cc8Sopenharmony_ci return 0; 22269570cc8Sopenharmony_ci} 22369570cc8Sopenharmony_ci 22469570cc8Sopenharmony_ciMODULE_CONSTRUCTOR(void) 22569570cc8Sopenharmony_ci{ 22669570cc8Sopenharmony_ci AddProcessMgrHook(STAGE_SERVER_APP_ADD, 0, ProcessMgrAddApp); 22769570cc8Sopenharmony_ci AddProcessMgrHook(STAGE_SERVER_APP_DIED, 0, ProcessMgrRemoveApp); 22869570cc8Sopenharmony_ci} 229