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 <dirent.h> 1769570cc8Sopenharmony_ci#include <fcntl.h> 1869570cc8Sopenharmony_ci#include <sched.h> 1969570cc8Sopenharmony_ci#include <signal.h> 2069570cc8Sopenharmony_ci#include <stdio.h> 2169570cc8Sopenharmony_ci#include <stdlib.h> 2269570cc8Sopenharmony_ci#include <unistd.h> 2369570cc8Sopenharmony_ci 2469570cc8Sopenharmony_ci#include "appspawn_hook.h" 2569570cc8Sopenharmony_ci#include "appspawn_manager.h" 2669570cc8Sopenharmony_ci#include "appspawn_utils.h" 2769570cc8Sopenharmony_ci#include "securec.h" 2869570cc8Sopenharmony_ci#ifdef WITH_SELINUX 2969570cc8Sopenharmony_ci#include "selinux/selinux.h" 3069570cc8Sopenharmony_ci#endif 3169570cc8Sopenharmony_ci 3269570cc8Sopenharmony_ci#define PID_NS_INIT_UID 100000 // reserved for pid_ns_init process, avoid app, render proc, etc. 3369570cc8Sopenharmony_ci#define PID_NS_INIT_GID 100000 3469570cc8Sopenharmony_ci 3569570cc8Sopenharmony_citypedef struct TagAppSpawnNamespace { 3669570cc8Sopenharmony_ci AppSpawnExtData extData; 3769570cc8Sopenharmony_ci int nsSelfPidFd; // ns pid fd of appspawn 3869570cc8Sopenharmony_ci int nsInitPidFd; // ns pid fd of pid_ns_init 3969570cc8Sopenharmony_ci} AppSpawnNamespace; 4069570cc8Sopenharmony_ci 4169570cc8Sopenharmony_ciAPPSPAWN_STATIC pid_t GetPidByName(const char *name); 4269570cc8Sopenharmony_cistatic int AppSpawnExtDataCompareDataId(ListNode *node, void *data) 4369570cc8Sopenharmony_ci{ 4469570cc8Sopenharmony_ci AppSpawnExtData *extData = (AppSpawnExtData *)ListEntry(node, AppSpawnExtData, node); 4569570cc8Sopenharmony_ci return extData->dataId - *(uint32_t *)data; 4669570cc8Sopenharmony_ci} 4769570cc8Sopenharmony_ci 4869570cc8Sopenharmony_ciAPPSPAWN_STATIC AppSpawnNamespace *GetAppSpawnNamespace(const AppSpawnMgr *content) 4969570cc8Sopenharmony_ci{ 5069570cc8Sopenharmony_ci APPSPAWN_CHECK_ONLY_EXPER(content != NULL, return NULL); 5169570cc8Sopenharmony_ci uint32_t dataId = EXT_DATA_NAMESPACE; 5269570cc8Sopenharmony_ci ListNode *node = OH_ListFind(&content->extData, (void *)&dataId, AppSpawnExtDataCompareDataId); 5369570cc8Sopenharmony_ci if (node == NULL) { 5469570cc8Sopenharmony_ci return NULL; 5569570cc8Sopenharmony_ci } 5669570cc8Sopenharmony_ci return (AppSpawnNamespace *)ListEntry(node, AppSpawnNamespace, extData); 5769570cc8Sopenharmony_ci} 5869570cc8Sopenharmony_ci 5969570cc8Sopenharmony_ciAPPSPAWN_STATIC void DeleteAppSpawnNamespace(AppSpawnNamespace *namespace) 6069570cc8Sopenharmony_ci{ 6169570cc8Sopenharmony_ci APPSPAWN_CHECK_ONLY_EXPER(namespace != NULL, return); 6269570cc8Sopenharmony_ci APPSPAWN_LOGV("DeleteAppSpawnNamespace"); 6369570cc8Sopenharmony_ci OH_ListRemove(&namespace->extData.node); 6469570cc8Sopenharmony_ci OH_ListInit(&namespace->extData.node); 6569570cc8Sopenharmony_ci 6669570cc8Sopenharmony_ci if (namespace->nsInitPidFd > 0) { 6769570cc8Sopenharmony_ci close(namespace->nsInitPidFd); 6869570cc8Sopenharmony_ci namespace->nsInitPidFd = -1; 6969570cc8Sopenharmony_ci } 7069570cc8Sopenharmony_ci if (namespace->nsSelfPidFd > 0) { 7169570cc8Sopenharmony_ci close(namespace->nsSelfPidFd); 7269570cc8Sopenharmony_ci namespace->nsSelfPidFd = -1; 7369570cc8Sopenharmony_ci } 7469570cc8Sopenharmony_ci free(namespace); 7569570cc8Sopenharmony_ci} 7669570cc8Sopenharmony_ci 7769570cc8Sopenharmony_ciAPPSPAWN_STATIC void FreeAppSpawnNamespace(struct TagAppSpawnExtData *data) 7869570cc8Sopenharmony_ci{ 7969570cc8Sopenharmony_ci AppSpawnNamespace *namespace = ListEntry(data, AppSpawnNamespace, extData); 8069570cc8Sopenharmony_ci APPSPAWN_CHECK_ONLY_EXPER(namespace != NULL, return); 8169570cc8Sopenharmony_ci DeleteAppSpawnNamespace(namespace); 8269570cc8Sopenharmony_ci} 8369570cc8Sopenharmony_ci 8469570cc8Sopenharmony_ciAPPSPAWN_STATIC AppSpawnNamespace *CreateAppSpawnNamespace(void) 8569570cc8Sopenharmony_ci{ 8669570cc8Sopenharmony_ci APPSPAWN_LOGV("CreateAppSpawnNamespace"); 8769570cc8Sopenharmony_ci AppSpawnNamespace *namespace = (AppSpawnNamespace *)calloc(1, sizeof(AppSpawnNamespace)); 8869570cc8Sopenharmony_ci APPSPAWN_CHECK(namespace != NULL, return NULL, "Failed to create sandbox"); 8969570cc8Sopenharmony_ci namespace->nsInitPidFd = -1; 9069570cc8Sopenharmony_ci namespace->nsSelfPidFd = -1; 9169570cc8Sopenharmony_ci // ext data init 9269570cc8Sopenharmony_ci OH_ListInit(&namespace->extData.node); 9369570cc8Sopenharmony_ci namespace->extData.dataId = EXT_DATA_NAMESPACE; 9469570cc8Sopenharmony_ci namespace->extData.freeNode = FreeAppSpawnNamespace; 9569570cc8Sopenharmony_ci namespace->extData.dumpNode = NULL; 9669570cc8Sopenharmony_ci return namespace; 9769570cc8Sopenharmony_ci} 9869570cc8Sopenharmony_ci 9969570cc8Sopenharmony_ciAPPSPAWN_STATIC pid_t GetPidByName(const char *name) 10069570cc8Sopenharmony_ci{ 10169570cc8Sopenharmony_ci int pid = -1; // initial pid set to -1 10269570cc8Sopenharmony_ci DIR *dir = opendir("/proc"); 10369570cc8Sopenharmony_ci if (dir == NULL) { 10469570cc8Sopenharmony_ci return -1; 10569570cc8Sopenharmony_ci } 10669570cc8Sopenharmony_ci 10769570cc8Sopenharmony_ci struct dirent *entry; 10869570cc8Sopenharmony_ci while ((entry = readdir(dir)) != NULL) { 10969570cc8Sopenharmony_ci if (entry->d_type != DT_DIR) { 11069570cc8Sopenharmony_ci continue; 11169570cc8Sopenharmony_ci } 11269570cc8Sopenharmony_ci long pidNum = strtol(entry->d_name, NULL, 10); // pid will not exceed a 10-digit decimal number 11369570cc8Sopenharmony_ci if (pidNum <= 0) { 11469570cc8Sopenharmony_ci continue; 11569570cc8Sopenharmony_ci } 11669570cc8Sopenharmony_ci 11769570cc8Sopenharmony_ci char path[32]; // path that contains the process name 11869570cc8Sopenharmony_ci if (snprintf_s(path, sizeof(path), sizeof(path) - 1, "/proc/%s/comm", entry->d_name) < 0) { 11969570cc8Sopenharmony_ci continue; 12069570cc8Sopenharmony_ci } 12169570cc8Sopenharmony_ci FILE *file = fopen(path, "r"); 12269570cc8Sopenharmony_ci if (file == NULL) { 12369570cc8Sopenharmony_ci continue; 12469570cc8Sopenharmony_ci } 12569570cc8Sopenharmony_ci char buffer[32]; // read the process name 12669570cc8Sopenharmony_ci if (fgets(buffer, sizeof(buffer), file) == NULL) { 12769570cc8Sopenharmony_ci (void)fclose(file); 12869570cc8Sopenharmony_ci continue; 12969570cc8Sopenharmony_ci } 13069570cc8Sopenharmony_ci buffer[strcspn(buffer, "\n")] = 0; 13169570cc8Sopenharmony_ci if (strcmp(buffer, name) != 0) { 13269570cc8Sopenharmony_ci (void)fclose(file); 13369570cc8Sopenharmony_ci continue; 13469570cc8Sopenharmony_ci } 13569570cc8Sopenharmony_ci 13669570cc8Sopenharmony_ci APPSPAWN_LOGI("get pid of %{public}s success", name); 13769570cc8Sopenharmony_ci pid = (int)pidNum; 13869570cc8Sopenharmony_ci (void)fclose(file); 13969570cc8Sopenharmony_ci break; 14069570cc8Sopenharmony_ci } 14169570cc8Sopenharmony_ci 14269570cc8Sopenharmony_ci closedir(dir); 14369570cc8Sopenharmony_ci return pid; 14469570cc8Sopenharmony_ci} 14569570cc8Sopenharmony_ci 14669570cc8Sopenharmony_ciAPPSPAWN_STATIC int NsInitFunc() 14769570cc8Sopenharmony_ci{ 14869570cc8Sopenharmony_ci setuid(PID_NS_INIT_UID); 14969570cc8Sopenharmony_ci setgid(PID_NS_INIT_GID); 15069570cc8Sopenharmony_ci#ifdef WITH_SELINUX 15169570cc8Sopenharmony_ci setcon("u:r:pid_ns_init:s0"); 15269570cc8Sopenharmony_ci#endif 15369570cc8Sopenharmony_ci char *argv[] = {"/system/bin/pid_ns_init", NULL}; 15469570cc8Sopenharmony_ci execve("/system/bin/pid_ns_init", argv, NULL); 15569570cc8Sopenharmony_ci#ifndef APPSPAWN_TEST 15669570cc8Sopenharmony_ci _exit(0); 15769570cc8Sopenharmony_ci#endif 15869570cc8Sopenharmony_ci return 0; 15969570cc8Sopenharmony_ci} 16069570cc8Sopenharmony_ci 16169570cc8Sopenharmony_ciAPPSPAWN_STATIC int GetNsPidFd(pid_t pid) 16269570cc8Sopenharmony_ci{ 16369570cc8Sopenharmony_ci char nsPath[256]; // filepath of ns pid 16469570cc8Sopenharmony_ci int ret = snprintf_s(nsPath, sizeof(nsPath), sizeof(nsPath) - 1, "/proc/%d/ns/pid", pid); 16569570cc8Sopenharmony_ci if (ret < 0) { 16669570cc8Sopenharmony_ci APPSPAWN_LOGE("SetPidNamespace failed, snprintf_s error:%{public}s", strerror(errno)); 16769570cc8Sopenharmony_ci return -1; 16869570cc8Sopenharmony_ci } 16969570cc8Sopenharmony_ci int nsFd = open(nsPath, O_RDONLY); 17069570cc8Sopenharmony_ci if (nsFd < 0) { 17169570cc8Sopenharmony_ci APPSPAWN_LOGE("open ns pid:%{public}d failed, err:%{public}s", pid, strerror(errno)); 17269570cc8Sopenharmony_ci return -1; 17369570cc8Sopenharmony_ci } 17469570cc8Sopenharmony_ci return nsFd; 17569570cc8Sopenharmony_ci} 17669570cc8Sopenharmony_ci 17769570cc8Sopenharmony_ciAPPSPAWN_STATIC int PreLoadEnablePidNs(AppSpawnMgr *content) 17869570cc8Sopenharmony_ci{ 17969570cc8Sopenharmony_ci APPSPAWN_LOGI("Enable pid namespace flags: 0x%{public}x", content->content.sandboxNsFlags); 18069570cc8Sopenharmony_ci if (IsColdRunMode(content)) { 18169570cc8Sopenharmony_ci return 0; 18269570cc8Sopenharmony_ci } 18369570cc8Sopenharmony_ci if (IsNWebSpawnMode(content)) { // only for appspawn 18469570cc8Sopenharmony_ci return 0; 18569570cc8Sopenharmony_ci } 18669570cc8Sopenharmony_ci if (!(content->content.sandboxNsFlags & CLONE_NEWPID)) { 18769570cc8Sopenharmony_ci return 0; 18869570cc8Sopenharmony_ci } 18969570cc8Sopenharmony_ci AppSpawnNamespace *namespace = CreateAppSpawnNamespace(); 19069570cc8Sopenharmony_ci APPSPAWN_CHECK(namespace != NULL, return -1, "Failed to create namespace"); 19169570cc8Sopenharmony_ci 19269570cc8Sopenharmony_ci int ret = -1; 19369570cc8Sopenharmony_ci // check if process pid_ns_init exists, this is the init process for pid namespace 19469570cc8Sopenharmony_ci pid_t pid = GetPidByName("pid_ns_init"); 19569570cc8Sopenharmony_ci if (pid == -1) { 19669570cc8Sopenharmony_ci APPSPAWN_LOGI("Start Create pid_ns_init %{public}d", pid); 19769570cc8Sopenharmony_ci pid = clone(NsInitFunc, NULL, CLONE_NEWPID, NULL); 19869570cc8Sopenharmony_ci if (pid < 0) { 19969570cc8Sopenharmony_ci APPSPAWN_LOGE("clone pid ns init failed"); 20069570cc8Sopenharmony_ci DeleteAppSpawnNamespace(namespace); 20169570cc8Sopenharmony_ci return ret; 20269570cc8Sopenharmony_ci } 20369570cc8Sopenharmony_ci } else { 20469570cc8Sopenharmony_ci APPSPAWN_LOGI("pid_ns_init exists, no need to create"); 20569570cc8Sopenharmony_ci } 20669570cc8Sopenharmony_ci 20769570cc8Sopenharmony_ci namespace->nsSelfPidFd = GetNsPidFd(getpid()); 20869570cc8Sopenharmony_ci if (namespace->nsSelfPidFd < 0) { 20969570cc8Sopenharmony_ci APPSPAWN_LOGE("open ns pid of appspawn fail"); 21069570cc8Sopenharmony_ci DeleteAppSpawnNamespace(namespace); 21169570cc8Sopenharmony_ci return ret; 21269570cc8Sopenharmony_ci } 21369570cc8Sopenharmony_ci 21469570cc8Sopenharmony_ci namespace->nsInitPidFd = GetNsPidFd(pid); 21569570cc8Sopenharmony_ci if (namespace->nsInitPidFd < 0) { 21669570cc8Sopenharmony_ci APPSPAWN_LOGE("open ns pid of pid_ns_init fail"); 21769570cc8Sopenharmony_ci DeleteAppSpawnNamespace(namespace); 21869570cc8Sopenharmony_ci return ret; 21969570cc8Sopenharmony_ci } 22069570cc8Sopenharmony_ci OH_ListAddTail(&content->extData, &namespace->extData.node); 22169570cc8Sopenharmony_ci APPSPAWN_LOGI("Enable pid namespace success."); 22269570cc8Sopenharmony_ci return 0; 22369570cc8Sopenharmony_ci} 22469570cc8Sopenharmony_ci 22569570cc8Sopenharmony_ci// after calling setns, new process will be in the same pid namespace of the input pid 22669570cc8Sopenharmony_cistatic int SetPidNamespace(int nsPidFd, int nsType) 22769570cc8Sopenharmony_ci{ 22869570cc8Sopenharmony_ci APPSPAWN_LOGI("SetPidNamespace 0x%{public}x", nsType); 22969570cc8Sopenharmony_ci#ifndef APPSPAWN_TEST 23069570cc8Sopenharmony_ci if (setns(nsPidFd, nsType) < 0) { 23169570cc8Sopenharmony_ci APPSPAWN_LOGE("set pid namespace nsType:%{public}d failed", nsType); 23269570cc8Sopenharmony_ci return -1; 23369570cc8Sopenharmony_ci } 23469570cc8Sopenharmony_ci#endif 23569570cc8Sopenharmony_ci return 0; 23669570cc8Sopenharmony_ci} 23769570cc8Sopenharmony_ci 23869570cc8Sopenharmony_ciAPPSPAWN_STATIC int PreForkSetPidNamespace(AppSpawnMgr *content, AppSpawningCtx *property) 23969570cc8Sopenharmony_ci{ 24069570cc8Sopenharmony_ci AppSpawnNamespace *namespace = GetAppSpawnNamespace(content); 24169570cc8Sopenharmony_ci if (namespace == NULL) { 24269570cc8Sopenharmony_ci return 0; 24369570cc8Sopenharmony_ci } 24469570cc8Sopenharmony_ci if (content->content.sandboxNsFlags & CLONE_NEWPID) { 24569570cc8Sopenharmony_ci SetPidNamespace(namespace->nsInitPidFd, CLONE_NEWPID); // pid_ns_init is the init process 24669570cc8Sopenharmony_ci } 24769570cc8Sopenharmony_ci return 0; 24869570cc8Sopenharmony_ci} 24969570cc8Sopenharmony_ci 25069570cc8Sopenharmony_ciAPPSPAWN_STATIC int PostForkSetPidNamespace(AppSpawnMgr *content, AppSpawningCtx *property) 25169570cc8Sopenharmony_ci{ 25269570cc8Sopenharmony_ci AppSpawnNamespace *namespace = GetAppSpawnNamespace(content); 25369570cc8Sopenharmony_ci if (namespace == NULL) { 25469570cc8Sopenharmony_ci return 0; 25569570cc8Sopenharmony_ci } 25669570cc8Sopenharmony_ci if (content->content.sandboxNsFlags & CLONE_NEWPID) { 25769570cc8Sopenharmony_ci SetPidNamespace(namespace->nsSelfPidFd, 0); // go back to original pid namespace 25869570cc8Sopenharmony_ci } 25969570cc8Sopenharmony_ci 26069570cc8Sopenharmony_ci return 0; 26169570cc8Sopenharmony_ci} 26269570cc8Sopenharmony_ci 26369570cc8Sopenharmony_ciMODULE_CONSTRUCTOR(void) 26469570cc8Sopenharmony_ci{ 26569570cc8Sopenharmony_ci AddPreloadHook(HOOK_PRIO_LOWEST, PreLoadEnablePidNs); 26669570cc8Sopenharmony_ci AddAppSpawnHook(STAGE_PARENT_PRE_FORK, HOOK_PRIO_LOWEST, PreForkSetPidNamespace); 26769570cc8Sopenharmony_ci AddAppSpawnHook(STAGE_PARENT_POST_FORK, HOOK_PRIO_HIGHEST, PostForkSetPidNamespace); 26869570cc8Sopenharmony_ci} 269