From 49c28d9411f9d48da99d082766825caa29199b08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=BD=E8=BF=90=E7=90=86?= Date: Tue, 2 Sep 2025 17:13:19 +0800 Subject: [PATCH] =?UTF-8?q?add=20el1=20isolate=20Dir=20Signed-off-by:=20?= =?UTF-8?q?=E6=96=BD=E8=BF=90=E7=90=86=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/common/BUILD.gn | 3 + modules/common/appspawn_common.c | 69 ------ modules/common/appspawn_isolate.c | 207 ++++++++++++++++++ .../unittest/app_spawn_standard_test/BUILD.gn | 8 + .../app_spawn_common_test.cpp | 25 --- .../app_spawn_isolate_test.cpp | 63 ++++++ 6 files changed, 281 insertions(+), 94 deletions(-) create mode 100644 modules/common/appspawn_isolate.c create mode 100644 test/unittest/app_spawn_standard_test/app_spawn_isolate_test.cpp diff --git a/modules/common/BUILD.gn b/modules/common/BUILD.gn index 709b5da3..cd9407ee 100644 --- a/modules/common/BUILD.gn +++ b/modules/common/BUILD.gn @@ -29,6 +29,9 @@ ohos_shared_library("appspawn_common") { if (is_debug || build_variant == "root") { sources += [ "appspawn_begetctl.c" ] } + if (appspawn_custom_sandbox == true) { + sources += [ "appspawn_isolate.c" ] + } include_dirs = [ ".", diff --git a/modules/common/appspawn_common.c b/modules/common/appspawn_common.c index 7c6095d7..c16d2aad 100644 --- a/modules/common/appspawn_common.c +++ b/modules/common/appspawn_common.c @@ -70,11 +70,6 @@ #define PID_NS_INIT_UID 100000 // reserved for pid_ns_init process, avoid app, render proc, etc. #define PID_NS_INIT_GID 100000 #define PREINSTALLED_HAP_FLAG 0x01 // hapFlags 0x01: SELINUX_HAP_RESTORECON_PREINSTALLED_APP in selinux -#define ISOLATE_PATH_NUM 2 -#define ISOLATE_PATH_SIZE 4096 -#define HM_DEC_IOCTL_BASE 's' -#define HM_ADD_ISOLATE_DIR 16 -#define ADD_ISOLATE_DIR_CMD _IOWR(HM_DEC_IOCTL_BASE, HM_ADD_ISOLATE_DIR, IsolateDirInfo) static int SetProcessName(const AppSpawnMgr *content, const AppSpawningCtx *property) { @@ -437,65 +432,6 @@ static int SpawnSetPreInstalledFlag(AppSpawningCtx *property) return 0; } -typedef struct { - char isolatePath[ISOLATE_PATH_NUM][ISOLATE_PATH_SIZE]; - int pathNum; -} IsolateDirInfo; - -/* - * Open isolate dir to prevent vnode from being released and ensure that - * vflag in vnode which we set by ioctl is valid during the app running. - * Fd will be automatically released when process exits. - */ -#ifdef CUSTOM_SANDBOX -static void HoldIsolateDir(IsolateDirInfo *isolateDirInfo) -{ - DIR *dir = opendir(isolateDirInfo->isolatePath[0]); - APPSPAWN_CHECK_ONLY_LOG(!(dir == NULL), "open isolate dir %{public}s failed, errno is %{public}d", - isolateDirInfo->isolatePath[0], errno); - - DIR *dir1 = opendir(isolateDirInfo->isolatePath[1]); - APPSPAWN_CHECK_ONLY_LOG(!(dir1 == NULL), "open isolate dir %{public}s failed, errno is %{public}d", - isolateDirInfo->isolatePath[1], errno); -} -#endif - -APPSPAWN_STATIC int SetIsolateDir(const AppSpawningCtx *property) -{ -#ifdef CUSTOM_SANDBOX - const char *bundleName = GetBundleName(property); - APPSPAWN_CHECK(bundleName != NULL, return -1, "Can not get bundle name"); - - AppSpawnMsgDacInfo *dacInfo = (AppSpawnMsgDacInfo *)GetAppProperty(property, TLV_DAC_INFO); - APPSPAWN_CHECK(dacInfo != NULL, return APPSPAWN_TLV_NONE, - "No tlv %{public}d in msg %{public}s", TLV_DOMAIN_INFO, bundleName); - APPSPAWN_ONLY_EXPER(dacInfo->uid / UID_BASE == 0, return 0); - - int ret = 0; - IsolateDirInfo isolateDirInfo = {0}; - ret = snprintf_s(isolateDirInfo.isolatePath[0], ISOLATE_PATH_SIZE, ISOLATE_PATH_SIZE - 1, "%s/%u/%s", - "/data/app/el2", dacInfo->uid / UID_BASE, "base"); - APPSPAWN_CHECK(ret >= 0, return ret, "snprintf_s el2 path failed, errno %{public}d", errno); - ret = snprintf_s(isolateDirInfo.isolatePath[1], ISOLATE_PATH_SIZE, ISOLATE_PATH_SIZE - 1, "%s/%u/%s", - "/storage/media", dacInfo->uid / UID_BASE, "local/files/Docs"); - APPSPAWN_CHECK(ret >= 0, return ret, "snprintf_s storage path failed, errno %{public}d", errno); - isolateDirInfo.pathNum = ISOLATE_PATH_NUM; - - HoldIsolateDir(&isolateDirInfo); - - int fd = open("/dev/dec", O_RDWR); - APPSPAWN_CHECK(fd >= 0, return fd, "open dec file fail, errno %{public}d", errno); - - ret = ioctl(fd, ADD_ISOLATE_DIR_CMD, &isolateDirInfo); - APPSPAWN_CHECK(ret == 0, close(fd); - return ret, "ioctl ADD_ISOLATE_DIR_CMD fail, errno %{public}d", errno); - - APPSPAWN_LOGI("ioctl ADD_ISOLATE_DIR_CMD success"); - close(fd); -#endif - return 0; -} - static int SpawnInitSpawningEnv(AppSpawnMgr *content, AppSpawningCtx *property) { APPSPAWN_LOGV("Spawning: clear env"); @@ -509,11 +445,6 @@ static int SpawnInitSpawningEnv(AppSpawnMgr *content, AppSpawningCtx *property) ret = SetAppAccessToken(content, property); APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret); - if ((IsAppSpawnMode(content) || IsHybridSpawnMode(content) || IsNativeSpawnMode(content))) { - ret = SetIsolateDir(property); - APPSPAWN_CHECK_ONLY_LOG(ret == 0, "Failed to set isolate dir, ret %{public}d", ret); - } - ret = SpawnSetPreInstalledFlag(property); APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret); return 0; diff --git a/modules/common/appspawn_isolate.c b/modules/common/appspawn_isolate.c new file mode 100644 index 00000000..fb899774 --- /dev/null +++ b/modules/common/appspawn_isolate.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include "securec.h" +#include "appspawn_utils.h" +#include "appspawn_msg.h" +#include "appspawn_hook.h" +#include "appspawn_manager.h" + +#define ISOLATE_PATH_BUFF_SIZE 512 +#define ISOLATE_PATH_NUM 3 +#define ISOLATE_PATH_CAPACITY 16 +#define HM_DEC_IOCTL_BASE 's' +#define HM_ADD_ISOLATE_DIR 16 +#define ADD_ISOLATE_DIR_CMD _IOWR(HM_DEC_IOCTL_BASE, HM_ADD_ISOLATE_DIR, IsolateDirInfo) + +typedef struct { + char *path; + int len; +} IsolateDir; + +typedef struct { + IsolateDir dirs[ISOLATE_PATH_CAPACITY]; + int dirNum; +} IsolateDirInfo; + +typedef struct { + const char *prefix; + const char *suffix; +} IsolateDirAffix; + +static const IsolateDirAffix g_dirAffix[ISOLATE_PATH_NUM] = {{"/data/app/el2", "base"}, + {"/storage/media", "local/files/Docs"}, + {"/data/app/el1", "base"}}; + +static void FreeIsolatePath(IsolateDirInfo *isolateDirInfo) +{ + for (int i = 0; i < isolateDirInfo->dirNum; ++i) { + free(isolateDirInfo->dirs[i].path); + isolateDirInfo->dirs[i].path = NULL; + } + + isolateDirInfo->dirNum = 0; +} + +/* + * To avoid memory leaks, + * it needs to be called in pairs with FreeIsolatePath. + */ +static int MallocIsolatePath(IsolateDirInfo *isolateDirInfo) +{ + isolateDirInfo->dirNum = 0; + + for (int i = 0; i < ISOLATE_PATH_NUM; ++i) { + char *path = (char *)calloc(1, ISOLATE_PATH_BUFF_SIZE); + if (path == NULL) { + APPSPAWN_LOGE("Failed to calloc buffer for path"); + FreeIsolatePath(isolateDirInfo); + return APPSPAWN_SYSTEM_ERROR; + } + + isolateDirInfo->dirs[i].path = path; + ++isolateDirInfo->dirNum; + } + + return 0; +} + +static int GetNormalUser(const AppSpawningCtx *property, uid_t *user) +{ + const char *bundleName = GetBundleName(property); + APPSPAWN_CHECK(bundleName != NULL, return APPSPAWN_ARG_INVALID, "Can not get bundle name"); + + AppSpawnMsgDacInfo *dacInfo = (AppSpawnMsgDacInfo *)GetAppProperty(property, TLV_DAC_INFO); + APPSPAWN_CHECK(dacInfo != NULL, return APPSPAWN_TLV_NONE, "No tlv %{public}d in msg %{public}s", + TLV_DOMAIN_INFO, bundleName); + APPSPAWN_CHECK(dacInfo->uid / UID_BASE != 0, return APPSPAWN_ARG_INVALID, "Not normal user"); + + *user = dacInfo->uid / UID_BASE; + return APPSPAWN_OK; +} + +static int FillIsolateInfo(const AppSpawningCtx *property, IsolateDirInfo *isolateDirInfo) +{ + uid_t user = 0; + int ret = GetNormalUser(property, &user); + if (ret != 0) { + APPSPAWN_LOGE("Get normal User failed, ret %{public}d", ret); + return ret; + } + + for (int dirIdx = 0; dirIdx < ISOLATE_PATH_NUM; dirIdx++) { + ret = snprintf_s(isolateDirInfo->dirs[dirIdx].path, ISOLATE_PATH_BUFF_SIZE, + ISOLATE_PATH_BUFF_SIZE - 1, "%s/%u/%s", + g_dirAffix[dirIdx].prefix, user, g_dirAffix[dirIdx].suffix); + if (ret < 0) { + APPSPAWN_LOGE("snprintf_s dir path failed, dirIdx %{public}d, ret %{public}d", dirIdx, ret); + isolateDirInfo->dirs[dirIdx].len = 0; + continue; + } + + isolateDirInfo->dirs[dirIdx].len = ret; + } + + return 0; +} + +/* + * Open isolate dir to prevent vnode from being released and ensure that + * vflag in vnode which we set by ioctl is valid during the app running. + * Fd will be automatically released when process exits. + */ +static void HoldIsolateDir(IsolateDirInfo *isolateDirInfo) +{ + for (int i = 0; i < isolateDirInfo->dirNum; ++i) { + DIR *dir = opendir(isolateDirInfo->dirs[i].path); + APPSPAWN_CHECK_ONLY_LOG(dir != NULL, "Open isolate dir %{public}s failed, errno is %{public}d", + isolateDirInfo->dirs[i].path, errno); + } +} + +APPSPAWN_STATIC int SetIsolateDir(const AppSpawningCtx *property) +{ + int ret = 0; + IsolateDirInfo isolateDirInfo = {0}; + + ret = MallocIsolatePath(&isolateDirInfo); + if (ret != 0) { + APPSPAWN_LOGE("Failed to malloc isolate dir"); + return APPSPAWN_SYSTEM_ERROR; + } + + ret = FillIsolateInfo(property, &isolateDirInfo); + if (ret != 0) { + APPSPAWN_LOGE("Failed to fill isolate dir info"); + FreeIsolatePath(&isolateDirInfo); + return APPSPAWN_SYSTEM_ERROR; + } + + HoldIsolateDir(&isolateDirInfo); + + int fd = open("/dev/dec", O_RDWR); + if (fd < 0) { + APPSPAWN_LOGE("Open dec file fail, errno %{public}d", errno); + FreeIsolatePath(&isolateDirInfo); + return APPSPAWN_SYSTEM_ERROR; + } + + ret = ioctl(fd, ADD_ISOLATE_DIR_CMD, &isolateDirInfo); + if (ret != 0) { + APPSPAWN_LOGE("ioctl ADD_ISOLATE_DIR_CMD fail, errno %{public}d", errno); + FreeIsolatePath(&isolateDirInfo); + close(fd); + return APPSPAWN_SYSTEM_ERROR; + } + + APPSPAWN_LOGI("ioctl ADD_ISOLATE_DIR_CMD success"); + close(fd); + + FreeIsolatePath(&isolateDirInfo); + return APPSPAWN_OK; +} + +static bool IsIsolateDirNeeded(const AppSpawnMgr *content) +{ + /* + * NWebSpawn is used for spawn render process and gpu process, + * so it is no need to set isolate dir. + */ + if (IsNWebSpawnMode(content)) { + return false; + } + + return true; +} + +static int SpawnSetIsolateDir(AppSpawnMgr *content, AppSpawningCtx *property) +{ + if (IsIsolateDirNeeded(content)) { + int ret = SetIsolateDir(property); + APPSPAWN_CHECK_ONLY_LOG(ret == 0, "Failed to set isolate dir, ret %{public}d", ret); + } + + return APPSPAWN_OK; +} + +MODULE_CONSTRUCTOR(void) +{ + AddAppSpawnHook(STAGE_CHILD_PRE_COLDBOOT, HOOK_PRIO_HIGHEST, SpawnSetIsolateDir); +} diff --git a/test/unittest/app_spawn_standard_test/BUILD.gn b/test/unittest/app_spawn_standard_test/BUILD.gn index 5bfa7924..24142043 100644 --- a/test/unittest/app_spawn_standard_test/BUILD.gn +++ b/test/unittest/app_spawn_standard_test/BUILD.gn @@ -494,6 +494,10 @@ ohos_unittest("AppSpawn_common_ut") { ] sources += appspawn_sandbox_src + if (appspawn_custom_sandbox == true) { + sources += [ "${appspawn_path}/modules/common/appspawn_isolate.c" ] + } + # add stub include_dirs += [ "${appspawn_path}/test/mock" ] sources += [ @@ -513,6 +517,10 @@ ohos_unittest("AppSpawn_common_ut") { defines += [ "APPSPAWN_SANDBOX_NEW" ] } + if (appspawn_custom_sandbox == true) { + sources += [ "${appspawn_path}/test/unittest/app_spawn_standard_test/app_spawn_isolate_test.cpp" ] + } + configs = [ "${appspawn_path}:appspawn_config" ] external_deps = [ "ability_base:want", diff --git a/test/unittest/app_spawn_standard_test/app_spawn_common_test.cpp b/test/unittest/app_spawn_standard_test/app_spawn_common_test.cpp index 5fb39ebf..26d99bc9 100644 --- a/test/unittest/app_spawn_standard_test/app_spawn_common_test.cpp +++ b/test/unittest/app_spawn_standard_test/app_spawn_common_test.cpp @@ -1419,31 +1419,6 @@ HWTEST_F(AppSpawnCommonTest, App_Spawn_SetFdEnv, TestSize.Level0) free(property.message); } -HWTEST_F(AppSpawnCommonTest, App_Spawn_SetIsolateDir, TestSize.Level0) -{ - AppSpawnClientHandle clientHandle = nullptr; - AppSpawnReqMsgHandle reqHandle = 0; - AppSpawningCtx *property = nullptr; - int ret = -1; - do { - // create msg - ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle); - APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME); - reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_APP_SPAWN, 0); - APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, - "Failed to create req %{public}s", APPSPAWN_SERVER_NAME); - // set custom sandbox flag - ret = AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_CUSTOM_SANDBOX); - APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break); - property = g_testHelper.GetAppProperty(clientHandle, reqHandle); - APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break); - ret = SetIsolateDir(property); - } while (0); - DeleteAppSpawningCtx(property); - AppSpawnClientDestroy(clientHandle); - ASSERT_EQ(ret, 0); -} - #ifdef APPSPAWN_HITRACE_OPTION HWTEST_F(AppSpawnCommonTest, App_Spawn_FilterAppSpawnTrace, TestSize.Level0) { diff --git a/test/unittest/app_spawn_standard_test/app_spawn_isolate_test.cpp b/test/unittest/app_spawn_standard_test/app_spawn_isolate_test.cpp new file mode 100644 index 00000000..82dbf2f1 --- /dev/null +++ b/test/unittest/app_spawn_standard_test/app_spawn_isolate_test.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "appspawn.h" +#include "appspawn_hook.h" +#include "app_spawn_stub.h" +#include "app_spawn_test_helper.h" + +using namespace testing; +using namespace testing::ext; +using namespace OHOS; + +namespace OHOS { +static AppSpawnTestHelper g_testHelper; +class AppSpawnIsolateTest : public testing::Test { +public: + static void SetUpTestCase() {} + static void TearDownTestCase() {} + void SetUp() {} + void TearDown() {} +}; + +HWTEST_F(AppSpawnIsolateTest, App_Spawn_SetIsolateDir, TestSize.Level0) +{ + AppSpawnClientHandle clientHandle = nullptr; + AppSpawnReqMsgHandle reqHandle = 0; + AppSpawningCtx *property = nullptr; + int ret = -1; + do { + // create msg + ret = AppSpawnClientInit(APPSPAWN_SERVER_NAME, &clientHandle); + APPSPAWN_CHECK(ret == 0, break, "Failed to create reqMgr %{public}s", APPSPAWN_SERVER_NAME); + reqHandle = g_testHelper.CreateMsg(clientHandle, MSG_APP_SPAWN, 0); + APPSPAWN_CHECK(reqHandle != INVALID_REQ_HANDLE, break, + "Failed to create req %{public}s", APPSPAWN_SERVER_NAME); + // set custom sandbox flag + ret = AppSpawnReqMsgSetAppFlag(reqHandle, APP_FLAGS_CUSTOM_SANDBOX); + APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break); + property = g_testHelper.GetAppProperty(clientHandle, reqHandle); + APPSPAWN_CHECK_ONLY_EXPER(property != nullptr, break); + ret = SetIsolateDir(property); + } while (0); + + DeleteAppSpawningCtx(property); + AppSpawnClientDestroy(clientHandle); + ASSERT_EQ(ret, 0); +} + +} // namespace OHOS -- Gitee