From 7abe4ca74a1c9546cd22a3905f1062db42e55ed0 Mon Sep 17 00:00:00 2001 From: wangfenging Date: Fri, 4 Jul 2025 10:58:20 +0800 Subject: [PATCH] Compile new sandbox files Signed-off-by: wangfenging --- .../{ => modern}/appspawn_mount_template.c | 0 .../sandbox/{ => modern}/appspawn_sandbox.c | 0 .../sandbox/{ => modern}/appspawn_sandbox.h | 0 .../sandbox/{ => modern}/sandbox_adapter.cpp | 0 .../sandbox/{ => modern}/sandbox_adapter.h | 0 modules/sandbox/{ => modern}/sandbox_cfgvar.c | 0 .../sandbox/{ => modern}/sandbox_debug_mode.c | 0 modules/sandbox/{ => modern}/sandbox_expand.c | 0 modules/sandbox/{ => modern}/sandbox_load.c | 0 .../sandbox/{ => modern}/sandbox_manager.c | 0 modules/sandbox/{ => modern}/sandbox_shared.c | 0 modules/sandbox/{ => modern}/sandbox_shared.h | 0 .../normal/appspawn_sandbox_manager.cpp | 161 +++ modules/sandbox/normal/sandbox_common.cpp | 989 ++++++++++++++++++ modules/sandbox/normal/sandbox_common.h | 145 +++ modules/sandbox/normal/sandbox_def.h | 161 +++ .../sandbox/normal/sandbox_shared_mount.cpp | 636 +++++++++++ modules/sandbox/normal/sandbox_shared_mount.h | 70 ++ test/unittest/app_spawn_client_test/BUILD.gn | 2 + .../unittest/app_spawn_standard_test/BUILD.gn | 48 +- 20 files changed, 2191 insertions(+), 21 deletions(-) rename modules/sandbox/{ => modern}/appspawn_mount_template.c (100%) rename modules/sandbox/{ => modern}/appspawn_sandbox.c (100%) rename modules/sandbox/{ => modern}/appspawn_sandbox.h (100%) rename modules/sandbox/{ => modern}/sandbox_adapter.cpp (100%) rename modules/sandbox/{ => modern}/sandbox_adapter.h (100%) rename modules/sandbox/{ => modern}/sandbox_cfgvar.c (100%) rename modules/sandbox/{ => modern}/sandbox_debug_mode.c (100%) rename modules/sandbox/{ => modern}/sandbox_expand.c (100%) rename modules/sandbox/{ => modern}/sandbox_load.c (100%) rename modules/sandbox/{ => modern}/sandbox_manager.c (100%) rename modules/sandbox/{ => modern}/sandbox_shared.c (100%) rename modules/sandbox/{ => modern}/sandbox_shared.h (100%) create mode 100644 modules/sandbox/normal/appspawn_sandbox_manager.cpp create mode 100644 modules/sandbox/normal/sandbox_common.cpp create mode 100644 modules/sandbox/normal/sandbox_common.h create mode 100644 modules/sandbox/normal/sandbox_def.h create mode 100644 modules/sandbox/normal/sandbox_shared_mount.cpp create mode 100644 modules/sandbox/normal/sandbox_shared_mount.h diff --git a/modules/sandbox/appspawn_mount_template.c b/modules/sandbox/modern/appspawn_mount_template.c similarity index 100% rename from modules/sandbox/appspawn_mount_template.c rename to modules/sandbox/modern/appspawn_mount_template.c diff --git a/modules/sandbox/appspawn_sandbox.c b/modules/sandbox/modern/appspawn_sandbox.c similarity index 100% rename from modules/sandbox/appspawn_sandbox.c rename to modules/sandbox/modern/appspawn_sandbox.c diff --git a/modules/sandbox/appspawn_sandbox.h b/modules/sandbox/modern/appspawn_sandbox.h similarity index 100% rename from modules/sandbox/appspawn_sandbox.h rename to modules/sandbox/modern/appspawn_sandbox.h diff --git a/modules/sandbox/sandbox_adapter.cpp b/modules/sandbox/modern/sandbox_adapter.cpp similarity index 100% rename from modules/sandbox/sandbox_adapter.cpp rename to modules/sandbox/modern/sandbox_adapter.cpp diff --git a/modules/sandbox/sandbox_adapter.h b/modules/sandbox/modern/sandbox_adapter.h similarity index 100% rename from modules/sandbox/sandbox_adapter.h rename to modules/sandbox/modern/sandbox_adapter.h diff --git a/modules/sandbox/sandbox_cfgvar.c b/modules/sandbox/modern/sandbox_cfgvar.c similarity index 100% rename from modules/sandbox/sandbox_cfgvar.c rename to modules/sandbox/modern/sandbox_cfgvar.c diff --git a/modules/sandbox/sandbox_debug_mode.c b/modules/sandbox/modern/sandbox_debug_mode.c similarity index 100% rename from modules/sandbox/sandbox_debug_mode.c rename to modules/sandbox/modern/sandbox_debug_mode.c diff --git a/modules/sandbox/sandbox_expand.c b/modules/sandbox/modern/sandbox_expand.c similarity index 100% rename from modules/sandbox/sandbox_expand.c rename to modules/sandbox/modern/sandbox_expand.c diff --git a/modules/sandbox/sandbox_load.c b/modules/sandbox/modern/sandbox_load.c similarity index 100% rename from modules/sandbox/sandbox_load.c rename to modules/sandbox/modern/sandbox_load.c diff --git a/modules/sandbox/sandbox_manager.c b/modules/sandbox/modern/sandbox_manager.c similarity index 100% rename from modules/sandbox/sandbox_manager.c rename to modules/sandbox/modern/sandbox_manager.c diff --git a/modules/sandbox/sandbox_shared.c b/modules/sandbox/modern/sandbox_shared.c similarity index 100% rename from modules/sandbox/sandbox_shared.c rename to modules/sandbox/modern/sandbox_shared.c diff --git a/modules/sandbox/sandbox_shared.h b/modules/sandbox/modern/sandbox_shared.h similarity index 100% rename from modules/sandbox/sandbox_shared.h rename to modules/sandbox/modern/sandbox_shared.h diff --git a/modules/sandbox/normal/appspawn_sandbox_manager.cpp b/modules/sandbox/normal/appspawn_sandbox_manager.cpp new file mode 100644 index 00000000..db71f08f --- /dev/null +++ b/modules/sandbox/normal/appspawn_sandbox_manager.cpp @@ -0,0 +1,161 @@ +/* + * 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 "securec.h" +#include "appspawn_hook.h" +#include "appspawn_manager.h" +#include "appspawn_utils.h" +#include "sandbox_core.h" + +#define USER_ID_SIZE 16 +#define DIR_MODE 0711 + +int32_t SetAppSandboxProperty(AppSpawnMgr *content, AppSpawningCtx *property) +{ + APPSPAWN_CHECK(property != nullptr, return -1, "Invalid appspwn client"); + APPSPAWN_CHECK(content != nullptr, return -1, "Invalid appspwn content"); + // clear g_mountInfo in the child process + std::map* mapPtr = static_cast*>(GetEl1BundleMountCount()); + if (mapPtr == nullptr) { + APPSPAWN_LOGE("Get el1 bundle mount count failed"); + return APPSPAWN_ARG_INVALID; + } + mapPtr->clear(); + int ret = 0; + // no sandbox + if (CheckAppMsgFlagsSet(property, APP_FLAGS_NO_SANDBOX)) { + return 0; + } + if ((content->content.sandboxNsFlags & CLONE_NEWPID) == CLONE_NEWPID) { + ret = getprocpid(); + if (ret < 0) { + return ret; + } + } + uint32_t sandboxNsFlags = CLONE_NEWNS; + + if (OHOS::AppSpawn::SandboxCore::NeedNetworkIsolated(property)) { + sandboxNsFlags |= content->content.sandboxNsFlags & CLONE_NEWNET ? CLONE_NEWNET : 0; + } + + APPSPAWN_LOGV("SetAppSandboxProperty sandboxNsFlags 0x%{public}x", sandboxNsFlags); + + if (IsNWebSpawnMode(content)) { + ret = OHOS::AppSpawn::SandboxCore::SetAppSandboxPropertyNweb(property, sandboxNsFlags); + } else { + ret = OHOS::AppSpawn::SandboxCore::SetAppSandboxProperty(property, sandboxNsFlags); + } + // for module test do not create sandbox, use APP_FLAGS_IGNORE_SANDBOX to ignore sandbox result + if (CheckAppMsgFlagsSet(property, APP_FLAGS_IGNORE_SANDBOX)) { + APPSPAWN_LOGW("Do not care sandbox result %{public}d", ret); + return 0; + } + return ret; +} + +static int SpawnMountDirToShared(AppSpawnMgr *content, AppSpawningCtx *property) +{ +#ifndef APPSPAWN_SANDBOX_NEW + if (!IsNWebSpawnMode(content)) { + // mount dynamic directory + MountToShared(content, property); + } +#endif + return 0; +} + +static int UninstallDebugSandbox(AppSpawnMgr *content, AppSpawningCtx *property) +{ + APPSPAWN_CHECK(property != nullptr && content != nullptr, return -1, + "Invalid appspawn client or property"); + return OHOS::AppSpawn::SandboxCore::UninstallDebugSandbox(content, property); +} + +static int InstallDebugSandbox(AppSpawnMgr *content, AppSpawningCtx *property) +{ + APPSPAWN_CHECK(property != nullptr && content != nullptr, return -1, + "Invalid appspawn client or property"); + return OHOS::AppSpawn::SandboxCore::InstallDebugSandbox(content, property); +} + +static void UmountDir(const char *rootPath, const char *targetPath, const AppSpawnedProcessInfo *appInfo) +{ + size_t allPathSize = strlen(rootPath) + USER_ID_SIZE + strlen(appInfo->name) + strlen(targetPath) + 2; + char *path = reinterpret_cast(malloc(sizeof(char) * (allPathSize))); + APPSPAWN_CHECK(path != nullptr, return, "Failed to malloc path"); + + int ret = sprintf_s(path, allPathSize, "%s%u/%s%s", rootPath, appInfo->uid / UID_BASE, + appInfo->name, targetPath); + APPSPAWN_CHECK(ret > 0 && ((size_t)ret < allPathSize), free(path); + return, "Failed to get sandbox path errno %{public}d", errno); + + ret = umount2(path, MNT_DETACH); + if (ret == 0) { + APPSPAWN_LOGI("Umount2 sandbox path %{public}s success", path); + } else { + APPSPAWN_LOGW("Failed to umount2 sandbox path %{public}s errno %{public}d", path, errno); + } + free(path); +} + +static int UmountSandboxPath(const AppSpawnMgr *content, const AppSpawnedProcessInfo *appInfo) +{ + APPSPAWN_CHECK(content != nullptr && appInfo != nullptr && appInfo->name != NULL, + return -1, "Invalid content or appInfo"); + if (!IsAppSpawnMode(content)) { + return 0; + } + APPSPAWN_LOGV("UmountSandboxPath name %{public}s pid %{public}d", appInfo->name, appInfo->pid); + const char rootPath[] = "/mnt/sandbox/"; + const char el1Path[] = "/data/storage/el1/bundle"; + + std::string varBundleName = std::string(appInfo->name); + if (appInfo->appIndex > 0) { + varBundleName = "+clone-" + std::to_string(appInfo->appIndex) + "+" + varBundleName; + } + + uint32_t userId = appInfo->uid / UID_BASE; + std::string key = std::to_string(userId) + "-" + varBundleName; + std::map *el1BundleCountMap = static_cast*>(GetEl1BundleMountCount()); + if (el1BundleCountMap == nullptr || el1BundleCountMap->find(key) == el1BundleCountMap->end()) { + return 0; + } + (*el1BundleCountMap)[key]--; + if ((*el1BundleCountMap)[key] == 0) { + APPSPAWN_LOGV("no app %{public}s use it in userId %{public}u, need umount", appInfo->name, userId); + UmountDir(rootPath, el1Path, appInfo); + el1BundleCountMap->erase(key); + } else { + APPSPAWN_LOGV("app %{public}s use it mount times %{public}d in userId %{public}u, not need umount", + appInfo->name, (*el1BundleCountMap)[key], userId); + } + return 0; +} + +#ifndef APPSPAWN_SANDBOX_NEW +MODULE_CONSTRUCTOR(void) +{ + APPSPAWN_LOGV("Load sandbox module ..."); + (void)AddServerStageHook(STAGE_SERVER_PRELOAD, HOOK_PRIO_SANDBOX, + OHOS::AppSpawn::SandboxCommon::LoadAppSandboxConfigCJson); + (void)AddAppSpawnHook(STAGE_PARENT_PRE_FORK, HOOK_PRIO_COMMON, SpawnMountDirToShared); + (void)AddAppSpawnHook(STAGE_CHILD_EXECUTE, HOOK_PRIO_SANDBOX, SetAppSandboxProperty); + (void)AddAppSpawnHook(STAGE_PARENT_UNINSTALL, HOOK_PRIO_SANDBOX, UninstallDebugSandbox); + (void)AddAppSpawnHook(STAGE_PARENT_PRE_FORK, HOOK_PRIO_SANDBOX, InstallDebugSandbox); + (void)AddProcessMgrHook(STAGE_SERVER_APP_UMOUNT, HOOK_PRIO_SANDBOX, UmountSandboxPath); + (void)AddServerStageHook(STAGE_SERVER_EXIT, HOOK_PRIO_SANDBOX, + OHOS::AppSpawn::SandboxCommon::FreeAppSandboxConfigCJson); +} +#endif \ No newline at end of file diff --git a/modules/sandbox/normal/sandbox_common.cpp b/modules/sandbox/normal/sandbox_common.cpp new file mode 100644 index 00000000..1b6b2a4e --- /dev/null +++ b/modules/sandbox/normal/sandbox_common.cpp @@ -0,0 +1,989 @@ +/* + * 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 "sandbox_common.h" + +#include +#include +#include +#include +#include +#include +#include "appspawn_manager.h" +#include "appspawn_utils.h" +#include "sandbox_def.h" +#include "parameters.h" +#include "init_param.h" +#include "init_utils.h" +#include "parameter.h" +#include "config_policy_utils.h" + +#ifdef WITH_SELINUX +#include "hap_restorecon.h" +#ifdef APPSPAWN_MOUNT_TMPSHM +#include "policycoreutils.h" +#endif // APPSPAWN_MOUNT_TMPSHM +#endif // WITH_SELINUX + +namespace OHOS { +namespace AppSpawn { + +int32_t SandboxCommon::deviceTypeEnable_ = -1; +std::map> appSandboxCJsonConfig_ = {}; + +// 加载配置文件 +uint32_t SandboxCommon::GetSandboxNsFlags(bool isNweb) +{ + uint32_t nsFlags = 0; + if (!IsTotalSandboxEnabled(nullptr)) { + return nsFlags; + } + + const std::map NamespaceFlagsMap = { {"pid", CLONE_NEWPID}, + {"net", CLONE_NEWNET} }; + const char *prefixStr = + isNweb ? SandboxCommonDef::g_privatePrefix : SandboxCommonDef::g_commonPrefix; + const char *baseStr = isNweb ? SandboxCommonDef::g_ohosRender.c_str() : SandboxCommonDef::g_appBase; + + auto processor = [&baseStr, &NamespaceFlagsMap, &nsFlags](cJSON *item) { + cJSON *internal = cJSON_GetObjectItemCaseSensitive(item, baseStr); + if (!internal || !cJSON_IsArray(internal)) { + return 0; + } + + // 获取数组中第一个元素 + cJSON *firstElem = cJSON_GetArrayItem(internal, 0); + if (!firstElem) { + return 0; + } + + // 获取 "sandbox-ns-flags" 数组 + cJSON *nsFlagsJson = cJSON_GetObjectItemCaseSensitive(firstElem, SandboxCommonDef::g_sandBoxNsFlags); + if (!nsFlagsJson || !cJSON_IsArray(nsFlagsJson)) { + return 0; + } + cJSON *nsIte = nullptr; + cJSON_ArrayForEach(nsIte, nsFlagsJson) { + const char *sandboxNs = cJSON_GetStringValue(nsIte); + if (sandboxNs == nullptr) { + continue; + } + std::string sandboxNsStr = sandboxNs; + if (!NamespaceFlagsMap.count(sandboxNsStr)) { + continue; + } + nsFlags |= NamespaceFlagsMap.at(sandboxNsStr); + } + return 0; + }; + + for (auto& config : GetJsonConfig(SandboxCommonDef::SANBOX_APP_JSON_CONFIG)) { + // 获取 "individual" 数组 + cJSON *individual = cJSON_GetObjectItemCaseSensitive(config, prefixStr); + if (!individual || !cJSON_IsArray(individual)) { + return nsFlags; + } + (void)HandleArrayForeach(individual, processor); + } + + if (!nsFlags) { + APPSPAWN_LOGE("config is not found %{public}s ns config", isNweb ? "Nweb" : "App"); + } + return nsFlags; +} + +bool SandboxCommon::AppSandboxPidNsIsSupport(void) +{ + char buffer[10] = {0}; + uint32_t buffSize = sizeof(buffer); + + if (SystemGetParameter("const.sandbox.pidns.support", buffer, &buffSize) != 0) { + return true; + } + if (!strcmp(buffer, "false")) { + return false; + } + return true; +} + +void SandboxCommon::StoreCJsonConfig(cJSON *root, SandboxCommonDef::SandboxConfigType type) +{ + appSandboxCJsonConfig_[type].push_back(root); +} + +int32_t SandboxCommon::HandleArrayForeach(cJSON *arrayJson, ArrayItemProcessor processor) +{ + if (!arrayJson || !cJSON_IsArray(arrayJson) || !processor) { + return APPSPAWN_ERROR_UTILS_DECODE_JSON_FAIL; + } + + int ret = 0; + cJSON *item; + cJSON_ArrayForEach(item, arrayJson) { + ret = processor(item); + if (ret != 0) { + return ret; + } + } + return ret; +} + +int SandboxCommon::LoadAppSandboxConfigCJson(AppSpawnMgr *content) +{ + // load sandbox config + cJSON *sandboxCJsonRoot; + CfgFiles *files = GetCfgFiles("etc/sandbox"); + for (int i = 0; (files != nullptr) && (i < MAX_CFG_POLICY_DIRS_CNT); ++i) { + if (files->paths[i] == nullptr) { + continue; + } + std::string path = files->paths[i]; + std::string appPath = path + SandboxCommonDef::APP_JSON_CONFIG; + APPSPAWN_LOGI("LoadAppSandboxConfig %{public}s", appPath.c_str()); + sandboxCJsonRoot = GetJsonObjFromFile(appPath.c_str()); + APPSPAWN_CHECK((sandboxCJsonRoot != nullptr && cJSON_IsObject(sandboxCJsonRoot)), continue, + "Failed to load app data sandbox config %{public}s", appPath.c_str()); + StoreCJsonConfig(sandboxCJsonRoot, SandboxCommonDef::SANBOX_APP_JSON_CONFIG); + + std::string isolatedPath = path + SandboxCommonDef::APP_ISOLATED_JSON_CONFIG; + APPSPAWN_LOGI("LoadAppSandboxConfig %{public}s", isolatedPath.c_str()); + sandboxCJsonRoot = GetJsonObjFromFile(appPath.c_str()); + APPSPAWN_CHECK((sandboxCJsonRoot != nullptr && cJSON_IsObject(sandboxCJsonRoot)), continue, + "Failed to load app data sandbox config %{public}s", appPath.c_str()); + StoreCJsonConfig(sandboxCJsonRoot, SandboxCommonDef::SANBOX_ISOLATED_JSON_CONFIG); + } + FreeCfgFiles(files); + + bool isNweb = IsNWebSpawnMode(content); + if (!isNweb && !AppSandboxPidNsIsSupport()) { + return 0; + } + content->content.sandboxNsFlags = GetSandboxNsFlags(isNweb); + return 0; +} + +void SandboxCommon::FreeAppSandboxConfigCJson(AppSpawnMgr *content) +{ + UNUSED(content); + std::vector normalJsonVec = GetCJsonConfig(SandboxCommonDef::SANBOX_APP_JSON_CONFIG); + for (auto& normal : normalJsonVec) { + cJSON_Delete(normal); + } + + std::vector isolatedJsonVec = GetCJsonConfig(SandboxCommonDef::SANBOX_APP_JSON_CONFIG); + for (auto& isolated : normalJsonVec) { + cJSON_Delete(isolated); + } +} + +std::vector &SandboxCommon::GetCJsonConfig(SandboxCommonDef::SandboxConfigType type) +{ + return appSandboxCJsonConfig_[type]; +} + +// 获取应用信息 +std::string SandboxCommon::GetExtraInfoByType(const AppSpawningCtx *appProperty, const std::string &type) +{ + uint32_t len = 0; + char *info = reinterpret_cast(GetAppPropertyExt(appProperty, type.c_str(), &len)); + if (info == nullptr) { + return ""; + } + return std::string(info, len); +} + +std::string SandboxCommon::GetSandboxRootPath(const AppSpawningCtx *appProperty, cJSON *config) +{ + AppSpawnMsgDacInfo *dacInfo = reinterpret_cast(GetAppProperty(appProperty, TLV_DAC_INFO)); + if (dacInfo == nullptr) { + return ""; + } + + std::string sandboxRoot = ""; + std::string isolatedFlagText = CheckAppMsgFlagsSet(appProperty, APP_FLAGS_ISOLATED_SANDBOX_TYPE) ? "isolated/" : ""; + AppSpawnMsgBundleInfo *bundleInfo = + reinterpret_cast(GetAppProperty(appProperty, TLV_BUNDLE_INFO)); + if (bundleInfo == nullptr) { + return ""; + } + std::string tmpBundlePath = bundleInfo->bundleName; + std::ostringstream variablePackageName; + if (CheckAppSpawnMsgFlag(appProperty->message, TLV_MSG_FLAGS, APP_FLAGS_CLONE_ENABLE)) { + variablePackageName << "+clone-" << bundleInfo->bundleIndex << "+" << bundleInfo->bundleName; + tmpBundlePath = variablePackageName.str(); + } + const std::string variableSandboxRoot = SandboxCommonDef::g_sandBoxRootDir + + std::to_string(dacInfo->uid / UID_BASE) + "/" + isolatedFlagText.c_str() + tmpBundlePath; + + const char *sandboxRootChr = GetStringFromJsonObj(config, SandboxCommonDef::g_sandboxRootPrefix); + if (sandboxRootChr != nullptr) { + sandboxRoot = sandboxRootChr; + if (sandboxRoot == SandboxCommonDef::g_originSandboxPath || + sandboxRoot == SandboxCommonDef::g_sandboxRootPathTemplate) { + sandboxRoot = variableSandboxRoot; + } else { + sandboxRoot = ConvertToRealPath(appProperty, sandboxRoot); + APPSPAWN_LOGV("set sandbox-root name is %{public}s", sandboxRoot.c_str()); + } + } else { + sandboxRoot = variableSandboxRoot; + APPSPAWN_LOGV("set sandbox-root to default rootapp name is %{public}s", GetBundleName(appProperty)); + } + + return sandboxRoot; +} + +int SandboxCommon::CreateDirRecursive(const std::string &path, mode_t mode) +{ + return MakeDirRec(path.c_str(), mode, 1); +} + +void SandboxCommon::CreateDirRecursiveWithClock(const std::string &path, mode_t mode) +{ + size_t size = path.size(); + if (size == 0) { + return; + } +#ifdef APPSPAWN_HISYSEVENT + struct timespec startClock = {0}; + clock_gettime(CLOCK_MONOTONIC, &startClock); +#endif + size_t index = 0; + do { + size_t pathIndex = path.find_first_of('/', index); + index = pathIndex == std::string::npos ? size : pathIndex + 1; + std::string dir = path.substr(0, index); +#ifndef APPSPAWN_TEST + APPSPAWN_CHECK(!(access(dir.c_str(), F_OK) < 0 && mkdir(dir.c_str(), mode) < 0), + return, "errno is %{public}d, mkdir %{public}s failed", errno, dir.c_str()); +#endif + } while (index < size); + +#ifdef APPSPAWN_HISYSEVENT + struct timespec endClock = {0}; + clock_gettime(CLOCK_MONOTONIC, &endClock); + uint64_t diff = DiffTime(&startClock, &endClock); + + APPSPAWN_CHECK_ONLY_EXPER(diff < FUNC_REPORT_DURATION, + ReportAbnormalDuration("MakeDirRecursive", diff)); +#endif +} + +bool SandboxCommon::VerifyDirRecursive(const std::string &path) +{ + size_t size = path.size(); + if (size == 0) { + return false; + } + size_t index = 0; + do { + size_t pathIndex = path.find_first_of('/', index); + index = pathIndex == std::string::npos ? size : pathIndex + 1; + std::string dir = path.substr(0, index); +#ifndef APPSPAWN_TEST + APPSPAWN_CHECK(access(dir.c_str(), F_OK) == 0, + return false, "check dir %{public}s failed, strerror: %{public}s", dir.c_str(), strerror(errno)); +#endif + } while (index < size); + return true; +} + +void SandboxCommon::CreateFileIfNotExist(const char *file) +{ + if (access(file, F_OK) == 0) { + APPSPAWN_LOGI("file %{public}s already exist", file); + return; + } + std::string path = file; + auto pos = path.find_last_of('/'); + APPSPAWN_CHECK(pos != std::string::npos, return, "file %{public}s error", file); + std::string dir = path.substr(0, pos); + (void)CreateDirRecursive(dir, SandboxCommonDef::FILE_MODE); + int fd = open(file, O_CREAT, SandboxCommonDef::FILE_MODE); + if (fd < 0) { + APPSPAWN_LOGW("failed create %{public}s, err=%{public}d", file, errno); + } else { + close(fd); + } + return; +} + +void SandboxCommon::SetSandboxPathChmod(cJSON *jsonConfig, std::string &sandboxRoot) +{ + const std::map modeMap = {{"S_IRUSR", S_IRUSR}, {"S_IWUSR", S_IWUSR}, {"S_IXUSR", S_IXUSR}, + {"S_IRGRP", S_IRGRP}, {"S_IWGRP", S_IWGRP}, {"S_IXGRP", S_IXGRP}, + {"S_IROTH", S_IROTH}, {"S_IWOTH", S_IWOTH}, {"S_IXOTH", S_IXOTH}, + {"S_IRWXU", S_IRWXU}, {"S_IRWXG", S_IRWXG}, {"S_IRWXO", S_IRWXO}}; + const char *fileMode = GetStringFromJsonObj(jsonConfig, SandboxCommonDef::g_destMode); + if (fileMode == nullptr) { + return; + } + + mode_t mode = 0; + std::string fileModeStr = fileMode; + std::vector modeVec = SplitString(fileModeStr, "|"); + for (unsigned int i = 0; i < modeVec.size(); i++) { + if (modeMap.count(modeVec[i])) { + mode |= modeMap.at(modeVec[i]); + } + } + + chmod(sandboxRoot.c_str(), mode); +} + +// 获取挂载配置参数信息 +unsigned long SandboxCommon::GetMountFlagsFromConfig(const std::vector &vec) +{ + const std::map MountFlagsMap = { {"rec", MS_REC}, {"MS_REC", MS_REC}, + {"bind", MS_BIND}, {"MS_BIND", MS_BIND}, + {"move", MS_MOVE}, {"MS_MOVE", MS_MOVE}, + {"slave", MS_SLAVE}, {"MS_SLAVE", MS_SLAVE}, + {"rdonly", MS_RDONLY}, {"MS_RDONLY", MS_RDONLY}, + {"shared", MS_SHARED}, {"MS_SHARED", MS_SHARED}, + {"unbindable", MS_UNBINDABLE}, + {"MS_UNBINDABLE", MS_UNBINDABLE}, + {"remount", MS_REMOUNT}, {"MS_REMOUNT", MS_REMOUNT}, + {"nosuid", MS_NOSUID}, {"MS_NOSUID", MS_NOSUID}, + {"nodev", MS_NODEV}, {"MS_NODEV", MS_NODEV}, + {"noexec", MS_NOEXEC}, {"MS_NOEXEC", MS_NOEXEC}, + {"noatime", MS_NOATIME}, {"MS_NOATIME", MS_NOATIME}, + {"lazytime", MS_LAZYTIME}, {"MS_LAZYTIME", MS_LAZYTIME}}; + + unsigned long mountFlags = 0; + for (unsigned int i = 0; i < vec.size(); i++) { + if (MountFlagsMap.count(vec[i])) { + mountFlags |= MountFlagsMap.at(vec[i]); + } + } + return mountFlags; +} + +bool SandboxCommon::IsDacOverrideEnabled(cJSON *config) // GetSandboxDacOverrideEnable +{ + return GetBoolValueFromJsonObj(config, SandboxCommonDef::g_dacOverrideSensitive, false); +} + +bool SandboxCommon::GetSwitchStatus(cJSON *config) // GetSbxSwitchStatusByConfig +{ + // if not find sandbox-switch node, default switch status is true + return GetBoolValueFromJsonObj(config, SandboxCommonDef::g_sbxSwitchCheck, true); +} + +uint32_t SandboxCommon::ConvertFlagStr(const std::string &flagStr) +{ + const std::map flagsMap = {{"0", 0}, {"START_FLAGS_BACKUP", 1}, + {"DLP_MANAGER", 2}, + {"DEVELOPER_MODE", 17}, + {"PREINSTALLED_HAP", 29}, + {"CUSTOM_SANDBOX_HAP", 31}}; + + if (flagsMap.count(flagStr)) { + return 1 << flagsMap.at(flagStr); + } + return 0; +} + +unsigned long SandboxCommon::GetMountFlags(cJSON *config) // GetSandboxMountFlags +{ + unsigned long mountFlags = SandboxCommonDef::BASIC_MOUNT_FLAGS; + std::vector vec; + cJSON *customizedFlags = IsDacOverrideEnabled(config) ? + cJSON_GetObjectItemCaseSensitive(config, SandboxCommonDef::g_sandBoxFlagsCustomized) : + cJSON_GetObjectItemCaseSensitive(config, SandboxCommonDef::g_sandBoxFlags) + if (customizedFlags == nullptr || !cJSON_IsArray(customizedFlags)) { + return mountFlags; + } + + auto processor = [&vec](cJSON *item) { + const char *strItem = cJSON_GetStringValue(item); + if (strItem == nullptr) { + return -1; + } + vec.emplace_back(strItem); + return 0; + } + + if (HandleArrayForeach(customizedFlags, processor) != 0) { + return mountFlags; + } + return GetMountFlagsFromConfig(vec); +} + +std::string SandboxCommon::GetFsType(cJSON *config) // GetSandboxFsType +{ + std::string fsType = ""; + const char *fsTypeChr = GetStringFromJsonObj(config, SandboxCommonDef::g_fsType); + if (fsTypeChr == nullptr) { + return fsType; + } + fsType = fsTypeChr; + return fsType; +} + +std::string SandboxCommon::GetOptions(const AppSpawningCtx *appProperty, cJSON *config) // GetSandboxOptions +{ + AppSpawnMsgDacInfo *dacInfo = reinterpret_cast(GetAppProperty(appProperty, TLV_DAC_INFO)); + if (dacInfo == nullptr) { + return ""; + } + + std::string options = ""; + const char *optionsChr = GetStringFromJsonObj(config, SandboxCommonDef::g_sandBoxOptions); + if (optionsChr == nullptr) { + return options; + } + options = optionsChr; + options += ",user_id=" + std::to_string(dacInfo->uid /UID_BASE); + return options; +} + +std::vector SandboxCommon::GetDecPath(const AppSpawningCtx *appProperty, cJSON *config) // GetSandboxDecPath +{ + AppSpawnMsgDacInfo *dacInfo = reinterpret_cast(GetAppProperty(appProperty, TLV_DAC_INFO)); + if (dacInfo == nullptr) { + return {}; + } + + std::vector decPaths = {}; + cJSON *decPathJson = cJSON_GetObjectItemCaseSensitive(config, SandboxCommonDef::g_sandBoxDecPath); + if (decPathJson == nullptr || !cJSON_IsArray(decPathJson)) { + return {}; + } + + auto processor = [&appProperty, &decPaths](cJSON *item) { + const char *strItem = cJSON_GetStringValue(item); + if (strItem == nullptr) { + return -1; + } + std::string decPath = ConvertToRealPath(appProperty, strItem); + decPaths.emplace_back(std::move(decPath)); + return 0; + }; + if (HandleArrayForeach(decPathJson, processor) != 0) { + return {}; + } + return decPaths; +} + +bool SandboxCommon::IsCreateSandboxPathEnabled(cJSON *json, std::string srcPath) // GetCreateSandboxPath +{ + bool isRet = GetBoolValueFromJsonObj(json, SandboxCommonDef::CREATE_SANDBOX_PATH, false); + if (!isRet && access(srcPath.c_str(), F_OK) != 0) { + return false; + } + return true; +} + +bool SandboxCommon::IsTotalSandboxEnabled(const AppSpawningCtx *appProperty) // CheckTotalSandboxSwitchStatus +{ + SandboxCommonDef::SandboxConfigType type = CheckAppMsgFlagsSet(appProperty, APP_FLAGS_ISOLATED_SANDBOX_TYPE) ? + SandboxCommonDef::SANBOX_ISOLATED_JSON_CONFIG : SandboxCommonDef::SANBOX_APP_JSON_CONFIG; + + for (auto& wholeConfig : GetJsonConfig(type)) { + // 获取 "common" 数组 + cJSON *common = cJSON_GetObjectItemCaseSensitive(wholeConfig, SandboxCommonDef::g_commonPrefix); + if (!common || !cJSON_IsArray(common)) { + continue; + } + // 获取第一个字段 + cJSON *firstCommon = cJSON_GetArrayItem(common, 0); + if (!firstCommon) { + continue; + } + return GetBoolValueFromJsonObj(firstCommon, SandboxCommonDef::g_topSandBoxSwitchPrefix, true); + } + // default sandbox switch is on + return true; +} + +bool SandboxCommon::IsAppSandboxEnabled(const AppSpawningCtx *appProperty) // CheckAppSandboxSwitchStatus +{ + SandboxCommonDef::SandboxConfigType type = CheckAppMsgFlagsSet(appProperty, APP_FLAGS_ISOLATED_SANDBOX_TYPE) ? + SandboxCommonDef::SANBOX_ISOLATED_JSON_CONFIG : SandboxCommonDef::SANBOX_APP_JSON_CONFIG; + + for (auto& wholeConfig : GetJsonConfig(type)) { + // 获取 "individual" 数组 + cJSON *individual = cJSON_GetObjectItemCaseSensitive(wholeConfig, SandboxCommonDef::g_privatePrefix); + if (!individual || !cJSON_IsArray(individual)) { + continue; + } + cJSON *bundleNameInfo = cJSON_GetObjectItemCaseSensitive(individual, GetBundleName(appProperty)); + if (!bundleNameInfo || !cJSON_IsArray(bundleNameInfo)) { + continue; + } + // 获取第一个字段 + cJSON *firstCommon = cJSON_GetArrayItem(bundleNameInfo, 0); + if (!firstCommon) { + continue; + } + return GetSwitchStatus(firstCommon); + } + // default sandbox switch is on + return true; +} + +void SandboxCommon::GetSandboxMountConfig(const AppSpawningCtx *appProperty, const std::string §ion, + cJSON *mntPoint, SandboxMountConfig &mountConfig) +{ + if (section.compare(SandboxCommonDef::g_permissionPrefix) == 0) { + mountConfig.optionsPoint = GetOptions(appProperty, mntPoint); + mountConfig.fsType = GetFsType(mntPoint); + mountConfig.decPaths = GetDecPath(appProperty, mntPoint); + } else { + mountConfig.fsType = GetFsType(mntPoint); + mountConfig.optionsPoint = ""; + mountConfig.decPaths = {}; + } + return; +} + +// 校验操作 +bool SandboxCommon::IsNeededCheckPathStatus(const AppSpawningCtx *appProperty, const char *path) +{ + if (strstr(path, "data/app/el1/") || strstr(path, "data/app/el2/")) { + return true; + } + if ((strstr(path, "data/app/el3/") || strstr(path, "data/app/el4/") || strstr(path, "data/app/el5/")) && + CheckAppMsgFlagsSet(appProperty, APP_FLAGS_UNLOCKED_STATUS)) { + return true; + } + return false; +} + +void SandboxCommon::CheckMountStatus(const std::string &path) +{ + std::ifstream file("/proc/self/mountinfo"); + if (!file.is_open()) { + APPSPAWN_LOGE("Failed to open /proc/self/mountinfo errno %{public}d", errno); + return; + } + + bool flag = false; + std::string line; + while (std::getline(file, line)) { + if (line.find(path) != std::string::npos) { + flag = true; + APPSPAWN_LOGI("Current mountinfo %{public}s", line.c_str()); + } + } + file.close(); + APPSPAWN_CHECK_ONLY_LOG(flag, "Mountinfo not contains %{public}s", path.c_str()); +} + +bool SandboxCommon::HasPrivateInBundleName(const std::string &bundleName) // CheckBundleNameForPrivate +{ + if (bundleName.find(SandboxCommonDef::g_internal) != std::string::npos) { + return false; + } + return true; +} + +bool SandboxCommon::IsMountSuccessful(cJSON *mntPoint) // GetCheckStatus +{ + // default false + return GetBoolValueFromJsonObj(mntPoint, SandboxCommonDef::g_actionStatuc, false); +} + +int SandboxCommon::CheckBundleName(const std::string &bundleName) +{ + if (bundleName.empty() || bundleName.size() > APP_LEN_BUNDLE_NAME) { + return -1; + } + if (bundleName.find('\\') != std::string::npos || bundleName.find('/') != std::string::npos) { + return -1; + } + return 0; +} + +int32_t SandboxCommon::CheckAppFullMountEnable() +{ + if (deviceTypeEnable_ != -1) { + return deviceTypeEnable_; + } + + char value[] = "false"; + int32_t ret = GetParameter("const.filemanager.full_mount.enable", "false", value, sizeof(value)); + if (ret > 0 && (strcmp(value, "true")) == 0) { + deviceTypeEnable_ = SandboxCommonDef::FILE_CROSS_APP_STATUS; + } else if (ret > 0 && (strcmp(value, "false")) == 0) { + deviceTypeEnable_ = SandboxCommonDef::FILE_ACCESS_COMMON_DIR_STATUS; + } else { + deviceTypeEnable_ = -1; + } + + return deviceTypeEnable_; +} + +bool SandboxCommon::IsPrivateSharedStatus(const std::string &bundleName, AppSpawningCtx *appProperty) +{ + bool result = false; + SandboxCommonDef::SandboxConfigType type = CheckAppMsgFlagsSet(appProperty, APP_FLAGS_ISOLATED_SANDBOX_TYPE) ? + SandboxCommonDef::SANBOX_ISOLATED_JSON_CONFIG : SandboxCommonDef::SANBOX_APP_JSON_CONFIG; + + for (auto& config : GetJsonConfig(type)) { + // 获取 "individual" 数组 + cJSON *individual = cJSON_GetObjectItemCaseSensitive(config, SandboxCommonDef::g_privatePrefix); + if (!individual || !cJSON_IsArray(individual)) { + return result; + } + cJSON *bundleNameInfo = cJSON_GetObjectItemCaseSensitive(individual, bundleName.c_str()); + if (!bundleNameInfo || !cJSON_IsArray(bundleNameInfo)) { + return result; + } + result = GetBoolValueFromJsonObj(bundleNameInfo, SandboxCommonDef::g_sandBoxShared, false); + } + return result; +} + +bool SandboxCommon::IsValidMountConfig(cJSON *mntPoint, const AppSpawningCtx *appProperty, bool checkFlag) +{ + const char *srcPath = GetStringFromJsonObj(mntPoint, SandboxCommonDef::g_srcPath); + const char *sandboxPath = GetStringFromJsonObj(mntPoint, SandboxCommonDef::g_sandBoxPath); + cJSON *customizedFlags = cJSON_GetObjectItemCaseSensitive(mntPoint, SandboxCommonDef::g_sandBoxFlagsCustomized); + cJSON *flags = cJSON_GetObjectItemCaseSensitive(mntPoint, SandboxCommonDef::g_sandBoxFlags); + if (srcPath == nullptr || sandboxPath == nullptr || (customizedFlags == nullptr && flags == nullptr)) { + APPSPAWN_LOGE("read mount config failed, app name is %{public}s", GetBundleName(appProperty)); + return false; + } + + AppSpawnMsgDomainInfo *info = + reinterpret_cast(GetAppProperty(appProperty, TLV_DOMAIN_INFO)); + APPSPAWN_CHECK(info != nullptr, return false, "Filed to get domain info %{public}s", GetBundleName(appProperty)); + const char *appAplName = GetStringFromJsonObj(mntPoint, SandboxCommonDef::g_appAplName); + if (appAplName != nullptr) { + if (!strcmp(appAplName, info->apl)) { + return false; + } + } + + const std::string configSrcPath = srcPath; + // special handle wps and don't use /data/app/xxx/ config + if (checkFlag && (configSrcPath.find("/data/app") != std::string::npos && + (configSrcPath.find("/base") != std::string::npos || + configSrcPath.find("/database") != std::string::npos + ) && configSrcPath.find(SandboxCommonDef::g_packageName) != std::string::npos)) { + return false; + } + + return true; +} + +// 路径处理 +std::string SandboxCommon::ReplaceAllVariables(std::string str, const std::string& from, const std::string& to) +{ + while (true) { + std::string::size_type pos(0); + if ((pos = str.find(from)) != std::string::npos) { + str.replace(pos, from.length(), to); + } else { + break; + } + } + return str; +} + +std::vector SandboxCommon::SplitString(std::string &str, const std::string &delimiter) +{ + std::string::size_type pos; + std::vector result; + str += delimiter; + size_t size = str.size(); + for (unsigned int i = 0; i < size; i++) { + pos = str.find(delimiter, i); + if (pos < size) { + std::string s = str.substr(i, pos - i); + result.push_back(s); + i = pos + delimiter.size() - 1; + } + } + + return result; +} + +void SandboxCommon::MakeAtomicServiceDir(const AppSpawningCtx *appProperty, std::string path, + std::string variablePackageName) +{ + AppSpawnMsgDacInfo *dacInfo = reinterpret_cast(GetAppProperty(appProperty, TLV_DAC_INFO)); + APPSPAWN_CHECK(dacInfo != nullptr, return, "No dac info in msg app property"); + if (path.find("/mnt/share") != std::string::npos) { + path = "/data/service/el2/" + std::to_string(dacInfo->uid / UID_BASE) + "/share/" + variablePackageName; + } + struct stat st = {}; + if (stat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode)) { + return; + } + + int ret = mkdir(path.c_str(), S_IRWXU); + APPSPAWN_CHECK(ret == 0, return, "mkdir %{public}s failed, errno %{public}d", path.c_str(), errno); + + if (path.find("/database") != std::string::npos || path.find("/data/service/el2") != std::string::npos) { + ret = chmod(path.c_str(), S_IRWXU | S_IRWXG | S_ISGID); + } else if (path.find("/log") != std::string::npos) { + ret = chmod(path.c_str(), S_IRWXU | S_IRWXG); + } + APPSPAWN_CHECK(ret == 0, return, "chmod %{public}s failed, errno %{public}d", path.c_str(), errno); + +#ifdef WITH_SELINUX + AppSpawnMsgDomainInfo *msgDomainInfo = + reinterpret_cast(GetAppProperty(appProperty, TLV_DOMAIN_INFO)); + APPSPAWN_CHECK(msgDomainInfo != nullptr, return, "No domain info for %{public}s", GetProcessName(appProperty)); + HapContext hapContext; + HapFileInfo hapFileInfo; + hapFileInfo.pathNameOrig.push_back(path); + hapFileInfo.apl = msgDomainInfo->apl; + hapFileInfo.packageName = GetBundleName(appProperty); + hapFileInfo.hapFlags = msgDomainInfo->hapFlags; + if (CheckAppMsgFlagsSet(appProperty, APP_FLAGS_DEBUGGABLE)) { + hapFileInfo.hapFlags |= SELINUX_HAP_DEBUGGABLE; + } + if ((path.find("/base") != std::string::npos) || (path.find("/database") != std::string::npos)) { + ret = hapContext.HapFileRestorecon(hapFileInfo); + APPSPAWN_CHECK(ret == 0, return, "set dir %{public}s selinuxLabel failed, apl %{public}s, ret %{public}d", + path.c_str(), hapFileInfo.apl.c_str(), ret); + } +#endif + if (path.find("/base") != std::string::npos || path.find("/data/service/el2") != std::string::npos) { + ret = chown(path.c_str(), dacInfo->uid, dacInfo->gid); + } else if (path.find("/database") != std::string::npos) { + ret = chown(path.c_str(), dacInfo->uid, DecodeGid("ddms")); + } else if (path.find("/log") != std::string::npos) { + ret = chown(path.c_str(), dacInfo->uid, DecodeGid("log")); + } + APPSPAWN_CHECK(ret == 0, return, "chown %{public}s failed, errno %{public}d", path.c_str(), errno); + return; +} + +std::string SandboxCommon::ReplaceVariablePackageName(const AppSpawningCtx *appProperty, const std::string &path) +{ + std::string tmpSandboxPath = path; + AppSpawnMsgBundleInfo *bundleInfo = + reinterpret_cast(GetAppProperty(appProperty, TLV_BUNDLE_INFO)); + APPSPAWN_CHECK(bundleInfo != nullptr, return "", "No bundle info in msg %{public}s", GetBundleName(appProperty)); + + char *extension; + uint32_t flags = CheckAppSpawnMsgFlag(appProperty->message, TLV_MSG_FLAGS, APP_FLAGS_ATOMIC_SERVICE) ? 0x4 : 0; + if (flags == 0) { + flags = (CheckAppSpawnMsgFlag(appProperty->message, TLV_MSG_FLAGS, APP_FLAGS_CLONE_ENABLE) && + bundleInfo->bundleIndex > 0) ? 0x1 : 0; + flags |= CheckAppSpawnMsgFlag(appProperty->message, TLV_MSG_FLAGS, APP_FLAGS_EXTENSION_SANDBOX) ? 0x2 : 0; + extension = reinterpret_cast( + GetAppSpawnMsgExtInfo(appProperty->message, MSG_EXT_NAME_APP_EXTENSION, nullptr)); + } + std::ostringstream variablePackageName; + switch (flags) { + case SANDBOX_PACKAGENAME_DEFAULT: // 0 default + variablePackageName << bundleInfo->bundleName; + break; + case SANDBOX_PACKAGENAME_CLONE: // 1 +clone-bundleIndex+packageName + variablePackageName << "+clone-" << bundleInfo->bundleIndex << "+" << bundleInfo->bundleName; + break; + case SANDBOX_PACKAGENAME_EXTENSION: { // 2 +extension-+packageName + APPSPAWN_CHECK(extension != nullptr, return "", "Invalid extension data "); + variablePackageName << "+extension-" << extension << "+" << bundleInfo->bundleName; + break; + } + case SANDBOX_PACKAGENAME_CLONE_AND_EXTENSION: { // 3 +clone-bundleIndex+extension-+packageName + APPSPAWN_CHECK(extension != nullptr, return "", "Invalid extension data "); + variablePackageName << "+clone-" << bundleInfo->bundleIndex << "+extension" << "-" << + extension << "+" << bundleInfo->bundleName; + break; + } + case SANDBOX_PACKAGENAME_ATOMIC_SERVICE: { // 4 +auid-+packageName + std::string accountId = GetExtraInfoByType(appProperty, MSG_EXT_NAME_ACCOUNT_ID); + variablePackageName << "+auid-" << accountId << "+" << bundleInfo->bundleName; + std::string atomicServicePath = path; + atomicServicePath = ReplaceAllVariables(atomicServicePath, SandboxCommonDef::g_variablePackageName, + variablePackageName.str()); + MakeAtomicServiceDir(appProperty, atomicServicePath, variablePackageName.str()); + break; + } + default: + variablePackageName << bundleInfo->bundleName; + break; + } + tmpSandboxPath = ReplaceAllVariables(tmpSandboxPath, SandboxCommonDef::g_variablePackageName, + variablePackageName.str()); + APPSPAWN_LOGV("tmpSandboxPath %{public}s", tmpSandboxPath.c_str()); + return tmpSandboxPath; +} + +std::string SandboxCommon::ReplaceHostUserId(const AppSpawningCtx *appProperty, const std::string &path) +{ + std::string tmpSandboxPath = path; + int32_t uid = 0; + const char *userId = + (const char *)(GetAppSpawnMsgExtInfo(appProperty->message, MSG_EXT_NAME_PARENT_UID, nullptr)); + if (userId != nullptr) { + uid = atoi(userId); + } + tmpSandboxPath = ReplaceAllVariables(tmpSandboxPath, SandboxCommonDef::g_hostUserId, + std::to_string(uid / UID_BASE)); + APPSPAWN_LOGV("tmpSandboxPath %{public}s", tmpSandboxPath.c_str()); + return tmpSandboxPath; +} + +std::string SandboxCommon::ReplaceClonePackageName(const AppSpawningCtx *appProperty, const std::string &path) +{ + std::string tmpSandboxPath = path; + AppSpawnMsgBundleInfo *bundleInfo = + reinterpret_cast(GetAppProperty(appProperty, TLV_BUNDLE_INFO)); + APPSPAWN_CHECK(bundleInfo != nullptr, return "", "No bundle info in msg %{public}s", GetBundleName(appProperty)); + + std::string tmpBundlePath = bundleInfo->bundleName; + std::ostringstream variablePackageName; + if (CheckAppSpawnMsgFlag(appProperty->message, TLV_MSG_FLAGS, APP_FLAGS_CLONE_ENABLE)) { + variablePackageName << "+clone-" << bundleInfo->bundleIndex << "+" << bundleInfo->bundleName; + tmpBundlePath = variablePackageName.str(); + } + + tmpSandboxPath = ReplaceAllVariables(tmpSandboxPath, SandboxCommonDef::g_clonePackageName, tmpBundlePath); + APPSPAWN_LOGV("tmpSandboxPath %{public}s", tmpSandboxPath.c_str()); + return tmpSandboxPath; +} + +const std::string& SandboxCommon::GetArkWebPackageName(void) +{ + static std::string arkWebPackageName; + if (arkWebPackageName.empty()) { + arkWebPackageName = system::GetParameter(SandboxCommonDef::ARK_WEB_PERSIST_PACKAGE_NAME, ""); + } + return arkWebPackageName; +} + +std::string SandboxCommon::ConvertToRealPathWithPermission(const AppSpawningCtx *appProperty, std::string path) +{ + AppSpawnMsgBundleInfo *info = + reinterpret_cast(GetAppProperty(appProperty, TLV_BUNDLE_INFO)); + if (info == nullptr) { + return ""; + } + if (path.find(SandboxCommonDef::g_packageNameIndex) != std::string::npos) { + std::string bundleNameWithIndex = info->bundleName; + if (info->bundleIndex != 0) { + bundleNameWithIndex = std::to_string(info->bundleIndex) + "_" + bundleNameWithIndex; + } + path = ReplaceAllVariables(path, SandboxCommonDef::g_packageNameIndex, bundleNameWithIndex); + } + + if (path.find(SandboxCommonDef::g_packageName) != std::string::npos) { + path = ReplaceAllVariables(path, SandboxCommonDef::g_packageName, info->bundleName); + } + + if (path.find(SandboxCommonDef::g_userId) != std::string::npos) { + if (deviceTypeEnable_ == SandboxCommonDef::FILE_CROSS_APP_STATUS) { + path = ReplaceAllVariables(path, SandboxCommonDef::g_userId, "currentUser"); + } else if (deviceTypeEnable_ == SandboxCommonDef::FILE_ACCESS_COMMON_DIR_STATUS) { + path = ReplaceAllVariables(path, SandboxCommonDef::g_userId, "currentUser"); + } else { + return ""; + } + } + return path; +} + +std::string SandboxCommon::ConvertToRealPath(const AppSpawningCtx *appProperty, std::string path) +{ + AppSpawnMsgBundleInfo *info = + reinterpret_cast(GetAppProperty(appProperty, TLV_BUNDLE_INFO)); + AppSpawnMsgDacInfo *dacInfo = reinterpret_cast(GetAppProperty(appProperty, TLV_DAC_INFO)); + if (info == nullptr || dacInfo == nullptr) { + return ""; + } + if (path.find(SandboxCommonDef::g_packageNameIndex) != std::string::npos) { + std::string bundleNameWithIndex = info->bundleName; + if (info->bundleIndex != 0) { + bundleNameWithIndex = std::to_string(info->bundleIndex) + "_" + bundleNameWithIndex; + } + path = ReplaceAllVariables(path, SandboxCommonDef::g_packageNameIndex, bundleNameWithIndex); + } + + if (path.find(SandboxCommonDef::g_packageName) != std::string::npos) { + path = ReplaceAllVariables(path, SandboxCommonDef::g_packageName, info->bundleName); + } + + if (path.find(SandboxCommonDef::g_userId) != std::string::npos) { + path = ReplaceAllVariables(path, SandboxCommonDef::g_userId, std::to_string(dacInfo->uid / UID_BASE)); + } + + if (path.find(SandboxCommonDef::g_hostUserId) != std::string::npos) { + path = ReplaceHostUserId(appProperty, path); + } + + if (path.find(SandboxCommonDef::g_variablePackageName) != std::string::npos) { + path = ReplaceVariablePackageName(appProperty, path); + } + + if (path.find(SandboxCommonDef::g_clonePackageName) != std::string::npos) { + path = ReplaceClonePackageName(appProperty, path); + } + + if (path.find(SandboxCommonDef::g_arkWebPackageName) != std::string::npos) { + path = ReplaceAllVariables(path, SandboxCommonDef::g_arkWebPackageName, GetArkWebPackageName()); + APPSPAWN_LOGV("arkWeb sandbox, path %{public}s, package:%{public}s", + path.c_str(), GetArkWebPackageName().c_str()); + } + + return path; +} + +// 挂载操作 +int32_t SandboxCommon::DoAppSandboxMountOnce(const AppSpawningCtx *appProperty, const SharedMountArgs *arg) +{ + if (!(arg && arg->srcPath && arg->destPath && arg->srcPath[0] != '\0' && arg->destPath[0] != '\0')) { + return 0; + } + if (strstr(arg->srcPath, "system/etc/hosts") != nullptr || strstr(arg->srcPath, "system/etc/profile") != nullptr) { + CreateFileIfNotExist(arg->destPath); + } else { + (void)CreateDirRecursive(arg->destPath, SandboxCommonDef::FILE_MODE); + } + + int ret = 0; + // to mount fs and bind mount files or directory + struct timespec mountStart = {0}; + clock_gettime(CLOCK_MONOTONIC_COARSE, &mountStart); + APPSPAWN_LOGV("Bind mount %{public}s to %{public}s '%{public}s' '%{public}lu' '%{public}s' '%{public}u'", + arg->srcPath, arg->destPath, arg->fsType, arg->mountFlags, arg->options, arg->mountSharedFlag); + ret = mount(arg->srcPath, arg->destPath, arg->fsType, arg->mountFlags, arg->options); + struct timespec mountEnd = {0}; + clock_gettime(CLOCK_MONOTONIC_COARSE, &mountEnd); + uint64_t diff = DiffTime(&mountStart, &mountEnd); + APPSPAWN_CHECK_ONLY_LOG(diff < SandboxCommonDef::MAX_MOUNT_TIME, "mount %{public}s time %{public}" PRId64 " us", + arg->srcPath, diff); +#ifdef APPSPAWN_HISYSEVENT + APPSPAWN_CHECK_ONLY_EXPER(diff < FUNC_REPORT_DURATION, ReportAbnormalDuration("MOUNT", diff)); +#endif + if (ret != 0) { + APPSPAWN_LOGI("errno is: %{public}d, bind mount %{public}s to %{public}s", errno, arg->srcPath, arg->destPath); + if (errno == ENOENT && IsNeededCheckPathStatus(appProperty, arg->srcPath)) { + VerifyDirRecursive(arg->srcPath); + } + return ret; + } + + ret = mount(nullptr, arg->destPath, nullptr, arg->mountSharedFlag, nullptr); + if (ret != 0) { + APPSPAWN_LOGI("errno is: %{public}d, private mount to %{public}s '%{public}u' failed", + errno, arg->destPath, arg->mountSharedFlag); + if (errno == EINVAL) { + CheckMountStatus(arg->destPath); + } + return ret; + } + return 0; +} + +} // namespace AppSpawn +} // namespace OHOS \ No newline at end of file diff --git a/modules/sandbox/normal/sandbox_common.h b/modules/sandbox/normal/sandbox_common.h new file mode 100644 index 00000000..19947f6c --- /dev/null +++ b/modules/sandbox/normal/sandbox_common.h @@ -0,0 +1,145 @@ +/* + * 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. + */ + +#ifndef SANDBOX_COMMON_H +#define SANDBOX_COMMON_H + +#include +#include +#include +#include +#include "sandbox_def.h" +#include "appspawn_msg.h" +#include "appspawn_server.h" +#include "appspawn_manager.h" +#include "sandbox_shared_mount.h" +#include "json_utils.h" + +namespace OHOS { +namespace AppSpawn { + +// 挂载选项 +typedef struct SandboxMountConfig { + unsigned long mountFlags; + std::string optionsPoint; + std::string fsType; + std::string sandboxPath; + std::vector decPaths; +} SandboxMountConfig; + +typedef struct MountPointProcessParams { + const AppSpawningCtx *appProperty; // 引用属性 + bool checkFlag; // 检查标志 + std::string section; // 分区名称 + std::string sandboxRoot; // 沙箱根路径 + std::string bundleName; // 包名 +} MountPointProcessParams; + +using ArrayItemProcessor = std::function; + +class SandboxCommon { +public: + // 加载配置文件 + static int LoadAppSandboxConfigCJson(AppSpawnMgr *content); + static void FreeAppSandboxConfigCJson(AppSpawnMgr *content); + static void StoreJsonConfig(cJSON *appSandboxConfig, SandboxCommonDef::SandboxConfigType type); + static std::vector &GetCJsonConfig(SandboxCommonDef::SandboxConfigType type); + + static int32_t HandleArrayForeach(cJSON *arrayJson, ArrayItemProcessor processor); + + // 获取应用信息 + static std::string GetExtraInfoByType(const AppSpawningCtx *appProperty, const std::string &type); + static std::string GetSandboxRootPath(const AppSpawningCtx *appProperty, cJSON *config); // GetSbxPathByConfig + + // 文件操作 + static int CreateDirRecursive(const std::string &path, mode_t mode); // MakeDirRecursive + static void CreateDirRecursiveWithClock(const std::string &path, mode_t mode); // MakeDirRecursiveWithClock + static void SetSandboxPathChmod(cJSON *jsonConfig, std::string &sandboxRoot); // DoSandboxChmod + + // 获取挂载配置参数信息 + static uint32_t ConvertFlagStr(const std::string &flagStr); + static unsigned long GetMountFlags(cJSON *config); // GetSandboxMountFlags + static bool IsCreateSandboxPathEnabled(cJSON *json, std::string srcPath); // GetCreateSandboxPath + static bool IsTotalSandboxEnabled(const AppSpawningCtx *appProperty); // CheckTotalSandboxSwitchStatus + static bool IsAppSandboxEnabled(const AppSpawningCtx *appProperty); // CheckAppSandboxSwitchStatus + static void GetSandboxMountConfig(const AppSpawningCtx *appProperty, const std::string §ion, + cJSON *mntPoint, SandboxMountConfig &mountConfig); + + // 校验操作 + static bool HasPrivateInBundleName(const std::string &bundleName); // CheckBundleNameForPrivate + static bool IsMountSuccessful(cJSON *mntPoint); // GetCheckStatus + static int CheckBundleName(const std::string &bundleName); + static bool IsValidMountConfig(cJSON *mntPoint, const AppSpawningCtx *appProperty, + bool checkFlag); // CheckMountConfig + static bool IsPrivateSharedStatus(const std::string &bundleName, + AppSpawningCtx *appProperty); // GetSandboxPrivateSharedStatus + static int32_t CheckAppFullMountEnable(); + + // 路径处理 + static std::vector SplitString(std::string &str, const std::string &delimiter); // split + static std::string ReplaceAllVariables(std::string str, const std::string& from, + const std::string& to); // replace_all + static std::string ConvertToRealPath(const AppSpawningCtx *appProperty, std::string path); + static std::string ConvertToRealPathWithPermission(const AppSpawningCtx *appProperty, std::string path); + + // 挂载操作 + static int32_t DoAppSandboxMountOnce(const AppSpawningCtx *appProperty, const SharedMountArgs *arg); + +private: + // 加载配置文件 + static uint32_t GetSandboxNsFlags(bool isNweb); + static bool AppSandboxPidNsIsSupport(void); + static void StoreCJsonConfig(cJSON *root, SandboxCommonDef::SandboxConfigType type); + + // 文件操作 + static bool VerifyDirRecursive(const std::string &path); // CheckDirRecursive + static void CreateFileIfNotExist(const char *file); // CheckAndCreatFile + + // 获取挂载配置参数信息 + static bool GetSwitchStatus(cJSON *config); // GetSbxSwitchStatusByConfig + static unsigned long GetMountFlagsFromConfig(const std::vector &vec); + static bool IsDacOverrideEnabled(cJSON *config); // GetSandboxDacOverrideEnable + static std::string GetFsType(cJSON *config); // GetSandboxFsType + static std::string GetOptions(const AppSpawningCtx *appProperty, cJSON *config); // GetSandboxOptions + static std::vector GetDecPath(const AppSpawningCtx *appProperty, cJSON *config); // GetSandboxDecPath + + // 校验操作 + static bool IsNeededCheckPathStatus(const AppSpawningCtx *appProperty, const char *path); + static void CheckMountStatus(const std::string &path); + + // 路径处理 + static std::string ReplaceVariablePackageName(const AppSpawningCtx *appProperty, const std::string &path); + static void MakeAtomicServiceDir(const AppSpawningCtx *appProperty, std::string path, + std::string variablePackageName); + static std::string ReplaceHostUserId(const AppSpawningCtx *appProperty, const std::string &path); + static std::string ReplaceClonePackageName(const AppSpawningCtx *appProperty, const std::string &path); + static const std::string &GetArkWebPackageName(void); + +private: + static int32_t deviceTypeEnable_; + static std::map> appSandboxCJsonConfig_; // sandboxManager + typedef enum { + SANDBOX_PACKAGENAME_DEFAULT = 0, + SANDBOX_PACKAGENAME_CLONE, + SANDBOX_PACKAGENAME_EXTENSION, + SANDBOX_PACKAGENAME_CLONE_AND_EXTENSION, + SANDBOX_PACKAGENAME_ATOMIC_SERVICE, + } SandboxVarPackageNameType; +}; + +} // namespace AppSpawn +} // namespace OHOS + +#endif // SANDBOX_COMMON_H \ No newline at end of file diff --git a/modules/sandbox/normal/sandbox_def.h b/modules/sandbox/normal/sandbox_def.h new file mode 100644 index 00000000..f3ddb728 --- /dev/null +++ b/modules/sandbox/normal/sandbox_def.h @@ -0,0 +1,161 @@ +/* + * 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. + */ + +#ifndef SANDBOX_DEF_H +#define SANDBOX_DEF_H + +#include +#include +#include +#include + +namespace OHOS { +namespace AppSpawn { +namespace SandboxCommonDef { +// 全局常量定义 +constexpr int32_t OPTIONS_MAX_LEN = 256; +constexpr int32_t FILE_ACCESS_COMMON_DIR_STATUS = 0; +constexpr int32_t FILE_CROSS_APP_STATUS = 1; +constexpr static mode_t FILE_MODE = 0711; +constexpr static mode_t BASIC_MOUNT_FLAGS = MS_REC | MS_BIND; +constexpr int32_t MAX_MOUNT_TIME = 500; // 500us +constexpr int32_t LOCK_STATUS_SIZE = 16; + +// 沙盒配置文件 +const std::string APP_JSON_CONFIG = "/appdata-sandbox.json"; +const std::string APP_ISOLATED_JSON_CONFIG = "/appdata-sandbox-isolated.json"; + +/* 沙盒配置文件中关键字 */ +// 公共属性 +constexpr const char *g_sandboxRootPrefix = "sandbox-root"; +constexpr const char *g_sandBoxNsFlags = "sandbox-ns-flags"; +constexpr const char *g_topSandBoxSwitchPrefix = "top-sandbox-switch"; +constexpr const char *g_sandBoxSwitchPrefix = "sandbox-switch"; +const std::string g_ohosGpu = "__internal__.com.ohos.gpu"; +const std::string g_ohosRender = "__internal__.com.ohos.render"; +constexpr const char *g_commonPrefix = "common"; +constexpr const char *g_privatePrefix = "individual"; +constexpr const char *g_permissionPrefix = "permission"; +constexpr const char *g_appBase = "app-base"; +constexpr const char *g_appResources = "app-resources"; +constexpr const char *g_flagePoint = "flags-point"; +const std::string g_internal = "__internal__"; +const std::string g_mntTmpRoot = "/mnt/debugtmp/"; +const std::string g_mntShareRoot = "/mnt/debug/"; +const std::string g_sandboxRootPathTemplate = "/mnt/sandbox//"; +const std::string g_originSandboxPath = "/mnt/sandbox/"; + +// 挂载目录字段 +constexpr const char *g_mountPrefix = "mount-paths"; +constexpr const char *g_srcPath = "src-path"; +constexpr const char *g_sandBoxPath = "sandbox-path"; +constexpr const char *g_sandBoxFlags = "sandbox-flags"; +constexpr const char *g_fsType = "fs-type"; +constexpr const char *g_sandBoxOptions = "options"; +constexpr const char *g_actionStatuc = "check-action-status"; +constexpr const char *g_destMode = "dest-mode"; +constexpr const char *g_flags = "flags"; + +// 挂载可选属性 +constexpr const char *g_sandBoxShared = "sandbox-shared"; +constexpr const char *g_mountSharedFlag = "mount-shared-flag"; +constexpr const char *g_dacOverrideSensitive = "dac-override-sensitive"; +constexpr const char *g_sandBoxFlagsCustomized = "sandbox-flags-customized"; +constexpr const char *g_appAplName = "app-apl-name"; +constexpr const char *g_sandBoxDecPath = "dec-paths"; +constexpr const char *CREATE_SANDBOX_PATH = "create-sandbox-path"; + +// link目录字段 +constexpr const char *g_symlinkPrefix = "symbol-links"; +constexpr const char *g_targetName = "target-name"; +constexpr const char *g_linkName = "link-name"; + +constexpr const char *g_gidPrefix = "gids"; + +// 可变参数 +const std::string g_userId = ""; +const std::string g_permissionUser = ""; +const std::string g_packageName = ""; +const std::string g_packageNameIndex = ""; +const std::string g_variablePackageName = ""; +const std::string g_clonePackageName = ""; +const std::string g_arkWebPackageName = ""; +const std::string g_hostUserId = ""; + +/* HSP */ +const std::string HSPLIST_SOCKET_TYPE = "HspList"; +const std::string g_hspList_key_bundles = "bundles"; +const std::string g_hspList_key_modules = "modules"; +const std::string g_hspList_key_versions = "versions"; +const std::string g_sandboxHspInstallPath = "/data/storage/el1/bundle/"; + +/* DataGroup */ +const std::string DATA_GROUP_SOCKET_TYPE = "DataGroup"; +const std::string g_groupList_key_dataGroupId = "dataGroupId"; +const std::string g_groupList_key_gid = "gid"; +const std::string g_groupList_key_dir = "dir"; +const std::string g_groupList_key_uuid = "uuid"; + +/* Overlay */ +const std::string OVERLAY_SOCKET_TYPE = "Overlay"; +const std::string g_overlayPath = "/data/storage/overlay/"; + +/* system hap */ +const std::string APL_SYSTEM_CORE = "system_core"; +const std::string APL_SYSTEM_BASIC = "system_basic"; +const std::string g_physicalAppInstallPath = "/data/app/el1/bundle/public/"; +const std::string g_dataBundles = "/data/bundles/"; + +/* bundle resource with APP_FLAGS_BUNDLE_RESOURCES */ +const std::string g_bundleResourceSrcPath = "/data/service/el1/public/bms/bundle_resources/"; +const std::string g_bundleResourceDestPath = "/data/storage/bundle_resources/"; + +/* 配置文件中value校验值 */ +const std::string g_sandBoxRootDir = "/mnt/sandbox/"; +const std::string g_sandBoxRootDirNweb = "/mnt/sandbox/com.ohos.render/"; +const std::string DEV_SHM_DIR = "/dev/shm/"; +const std::string g_statusCheck = "true"; +const std::string g_sbxSwitchCheck = "ON"; +const std::string g_dlpBundleName = "com.ohos.dlpmanager"; + +/* debug hap */ +constexpr const char *g_mntTmpSandboxRoot = "/mnt/debugtmp//debug_hap/"; +constexpr const char *g_mntShareSandboxRoot = "/mnt/debug//debug_hap/"; +constexpr const char *g_debughap = "debug"; + +/* 分割符 */ +constexpr const char *g_fileSeparator = "/"; +constexpr const char *g_overlayDecollator = "|"; + +/* 权限名 */ +const std::string FILE_CROSS_APP_MODE = "ohos.permission.FILE_CROSS_APP"; +const std::string FILE_ACCESS_COMMON_DIR_MODE = "ohos.permission.FILE_ACCESS_COMMON_DIR"; +const std::string ACCESS_DLP_FILE_MODE = "ohos.permission.ACCESS_DLP_FILE"; +const std::string FILE_ACCESS_MANAGER_MODE = "ohos.permission.FILE_ACCESS_MANAGER"; +const std::string READ_WRITE_USER_FILE_MODE = "ohos.permission.READ_WRITE_USER_FILE"; +const std::string GET_ALL_PROCESSES_MODE = "ohos.permission.GET_ALL_PROCESSES"; +const std::string ARK_WEB_PERSIST_PACKAGE_NAME = "persist.arkwebcore.package_name"; + +// 枚举类型 +enum SandboxConfigType { + SANBOX_APP_JSON_CONFIG, + SANBOX_ISOLATED_JSON_CONFIG +}; + +} // namespace SandboxCommonDef +} // namespace AppSpawn +} // namespace OHOS + +#endif // SANDBOX_DEF_H \ No newline at end of file diff --git a/modules/sandbox/normal/sandbox_shared_mount.cpp b/modules/sandbox/normal/sandbox_shared_mount.cpp new file mode 100644 index 00000000..ee824179 --- /dev/null +++ b/modules/sandbox/normal/sandbox_shared_mount.cpp @@ -0,0 +1,636 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include "securec.h" + +#include "sandbox_shared_mount.h" +#include "appspawn_mount_permission.h" +#include "appspawn_utils.h" +#include "parameter.h" + +#define USER_ID_SIZE 16 +#define DIR_MODE 0711 +#define LOCK_STATUS_SIZE 16 + +#define DATA_GROUP_SOCKET_TYPE "DataGroup" +#define GROUPLIST_KEY_DATAGROUPID "dataGroupId" +#define GROUPLIST_KEY_GID "gid" +#define GROUPLIST_KEY_DIR "dir" +#define GROUPLIST_KEY_UUID "uuid" + +static const MountSharedTemplate MOUNT_SHARED_MAP[] = { + {"/data/storage/el2", nullptr}, + {"/data/storage/el3", nullptr}, + {"/data/storage/el4", nullptr}, + {"/data/storage/el5", "ohos.permission.PROTECT_SCREEN_LOCK_DATA"}, +}; + +static const DataGroupSandboxPathTemplate DATA_GROUP_SANDBOX_PATH_MAP[] = { + {"el2", EL2, "/data/storage/el2/group/", nullptr}, + {"el3", EL3, "/data/storage/el3/group/", nullptr}, + {"el4", EL4, "/data/storage/el4/group/", nullptr}, + {"el5", EL5, "/data/storage/el5/group/", "ohos.permission.PROTECT_SCREEN_LOCK_DATA"}, +}; + +static std::map g_mountInfoMap; + +int GetElxInfoFromDir(const char *path) +{ + int ret = ELX_MAX; + if (path == nullptr) { + return ret; + } + uint32_t count = ARRAY_LENGTH(DATA_GROUP_SANDBOX_PATH_MAP); + for (uint32_t i = 0; i < count; ++i) { + if (strstr(path, DATA_GROUP_SANDBOX_PATH_MAP[i].elxName) != nullptr) { + return DATA_GROUP_SANDBOX_PATH_MAP[i].category; + } + } + APPSPAWN_LOGE("Get elx info from dir failed, path %{public}s", path); + return ret; +} + +const DataGroupSandboxPathTemplate *GetDataGroupArgTemplate(uint32_t category) +{ + uint32_t count = ARRAY_LENGTH(DATA_GROUP_SANDBOX_PATH_MAP); + if (category > count) { + APPSPAWN_LOGE("category %{public}d is out of range", category); + return nullptr; + } + for (uint32_t i = 0; i < count; ++i) { + if (DATA_GROUP_SANDBOX_PATH_MAP[i].category == category) { + return &DATA_GROUP_SANDBOX_PATH_MAP[i]; + } + } + return nullptr; +} + +bool IsValidDataGroupItem(cJSON *item) +{ + // Check if the item contains the specified key and if the value corresponding to the key is a string + cJSON *datagroupId = cJSON_GetObjectItem(item, GROUPLIST_KEY_DATAGROUPID); + cJSON *gid = cJSON_GetObjectItem(item, GROUPLIST_KEY_GID); + cJSON *dir = cJSON_GetObjectItem(item, GROUPLIST_KEY_DIR); + cJSON *uuid = cJSON_GetObjectItem(item, GROUPLIST_KEY_UUID); + + if (datagroupId && cJSON_IsString(datagroupId) && + gid && cJSON_IsString(gid) && + dir && cJSON_IsString(dir) && + uuid && cJSON_IsString(uuid)) { + return true; + } + return false; +} + +void *GetEl1BundleMountCount(void) +{ + return static_cast(&g_mountInfoMap); +} + +#ifndef APPSPAWN_SANDBOX_NEW +static bool IsUnlockStatus(uint32_t uid) +{ + const int userIdBase = UID_BASE; + uid = uid / userIdBase; + if (uid == 0) { + return true; + } + std::string lockStatusParam = "startup.appspawn.lockstatus_" + std::to_string(uid); + char userLockStatus[LOCK_STATUS_SIZE] = {0}; + int ret = GetParameter(lockStatusParam.c_str(), "1", userLockStatus, sizeof(userLockStatus)); + APPSPAWN_LOGI("lockStatus %{public}u %{public}s", uid, userLockStatus); + if (ret > 0 && (strcmp(userLockStatus, "0") == 0)) { // 0:unlock status 1:lock status + return true; + } + return false; +} + +static int DoSharedMount(const SharedMountArgs *arg) +{ + if (arg == nullptr || arg->srcPath == nullptr || arg->destPath == nullptr) { + APPSPAWN_LOGE("Invalid arg"); + return APPSPAWN_ARG_INVALID; + } + + APPSPAWN_LOGV("Mount arg: '%{public}s' '%{public}s' %{public}lu '%{public}s' %{public}s => %{public}s", + arg->fsType, arg->mountSharedFlag == MS_SHARED ? "MS_SHARED" : "MS_SLAVE", + arg->mountFlags, arg->options, arg->srcPath, arg->destPath); + + int ret = mount(arg->srcPath, arg->destPath, arg->fsType, arg->mountFlags, arg->options); + if (ret != 0) { + APPSPAWN_LOGE("mount %{public}s to %{public}s failed, errno %{public}d", + arg->srcPath, arg->destPath, errno); + return ret; + } + ret = mount(nullptr, arg->destPath, nullptr, arg->mountSharedFlag, nullptr); + if (ret != 0) { + APPSPAWN_LOGE("mount path %{public}s to shared failed, errno %{public}d", arg->destPath, errno); + return ret; + } + APPSPAWN_LOGI("mount path %{public}s to shared success", arg->destPath); + return 0; +} + +static bool SetSandboxPathShared(const std::string &sandboxPath) +{ + int ret = mount(nullptr, sandboxPath.c_str(), nullptr, MS_SHARED, nullptr); + if (ret != 0) { + APPSPAWN_LOGW("Need to mount %{public}s to shared, errno %{public}d", sandboxPath.c_str(), errno); + return false; + } + return true; +} + +static int MountEl1Bundle(const AppSpawningCtx *property, const AppDacInfo *info, const char *varBundleName) +{ + /* /data/app/el1/bundle/public/ */ + AppSpawnMsgBundleInfo *bundleInfo = + reinterpret_cast(GetAppProperty(property, TLV_BUNDLE_INFO)); + if (bundleInfo == nullptr) { + return APPSPAWN_SANDBOX_INVALID; + } + char sourcePath[PATH_MAX_LEN] = {0}; + int ret = snprintf_s(sourcePath, PATH_MAX_LEN, PATH_MAX_LEN - 1, "/data/app/el1/bundle/public/%s", + bundleInfo->bundleName); + if (ret <= 0) { + APPSPAWN_LOGE("snprintf data/app/el1/bundle/public/%{public}s failed, errno %{public}d", + bundleInfo->bundleName, errno); + return APPSPAWN_ERROR_UTILS_MEM_FAIL; + } + + /* /mnt/sandbox///data/storage/el1/bundle */ + char targetPath[PATH_MAX_LEN] = {0}; + ret = snprintf_s(targetPath, PATH_MAX_LEN, PATH_MAX_LEN - 1, "/mnt/sandbox/%u/%s/data/storage/el1/bundle", + info->uid/ UID_BASE, varBundleName); + if (ret <= 0) { + APPSPAWN_LOGE("snprintf el1 bundle sandbox path failed, errno %{public}d", errno); + return APPSPAWN_ERROR_UTILS_MEM_FAIL; + } + + ret = MakeDirRec(targetPath, DIR_MODE, 1); + if (ret != 0) { + APPSPAWN_LOGE("mkdir %{public}s failed, errno %{public}d", targetPath, errno); + return APPSPAWN_SANDBOX_ERROR_MKDIR_FAIL; + } + + ret = umount2(targetPath, MNT_DETACH); + if (ret != 0) { + APPSPAWN_LOGE("umount2 %{public}s failed, errno %{public}d", targetPath, errno); + } + + SharedMountArgs arg = { + .srcPath = sourcePath, + .destPath = targetPath, + .fsType = nullptr, + .mountFlags = MS_BIND | MS_REC, + .options = nullptr, + .mountSharedFlag = MS_SHARED + }; + ret = DoSharedMount(&arg); + if (ret != 0) { + APPSPAWN_LOGE("mount %{public}s shared failed, ret %{public}d", targetPath, ret); + } + std::string key = std::to_string(info->uid / UID_BASE) + "-" + std::string(varBundleName); + g_mountInfoMap[key]++; + return ret; +} + +static int MountWithFileMgr(const AppSpawningCtx *property, const AppDacInfo *info, const char *varBundleName) +{ + /* /mnt/user//nosharefs/docs */ + char nosharefsDocsDir[PATH_MAX_LEN] = {0}; + int ret = snprintf_s(nosharefsDocsDir, PATH_MAX_LEN, PATH_MAX_LEN - 1, "/mnt/user/%u/nosharefs/docs", + info->uid / UID_BASE); + if (ret <= 0) { + APPSPAWN_LOGE("snprintf nosharefsDocsDir failed, errno %{public}d", errno); + return APPSPAWN_ERROR_UTILS_MEM_FAIL; + } + + /* /mnt/sandbox//storage/Users */ + char storageUserPath[PATH_MAX_LEN] = {0}; + ret = snprintf_s(storageUserPath, PATH_MAX_LEN, PATH_MAX_LEN - 1, "/mnt/sandbox/%u/%s/storage/Users", + info->uid / UID_BASE, varBundleName); + if (ret <= 0) { + APPSPAWN_LOGE("snprintf storageUserPath failed, errno %{public}d", errno); + return APPSPAWN_ERROR_UTILS_MEM_FAIL; + } + + // Check whether the directory is a shared mount point + if (SetSandboxPathShared(storageUserPath)) { + APPSPAWN_LOGV("shared mountpoint is exist"); + return 0; + } + + ret = MakeDirRec(storageUserPath, DIR_MODE, 1); + if (ret != 0) { + APPSPAWN_LOGE("mkdir %{public}s failed, errno %{public}d", storageUserPath, errno); + return APPSPAWN_SANDBOX_ERROR_MKDIR_FAIL; + } + + SharedMountArgs arg = { + .srcPath = nosharefsDocsDir, + .destPath = storageUserPath, + .fsType = nullptr, + .mountFlags = MS_BIND | MS_REC, + .options = nullptr, + .mountSharedFlag = MS_SHARED + }; + ret = DoSharedMount(&arg); + if (ret != 0) { + APPSPAWN_LOGE("mount %{public}s shared failed, ret %{public}d", storageUserPath, ret); + } + return ret; +} + +static int MountWithOther(const AppSpawningCtx *property, const AppDacInfo *info, const char *varBundleName) +{ + /* /mnt/user//sharefs/docs */ + char sharefsDocsDir[PATH_MAX_LEN] = {0}; + int ret = snprintf_s(sharefsDocsDir, PATH_MAX_LEN, PATH_MAX_LEN - 1, "/mnt/user/%u/sharefs/docs", + info->uid / UID_BASE); + if (ret <= 0) { + APPSPAWN_LOGE("snprintf sharefsDocsDir failed, errno %{public}d", errno); + return APPSPAWN_ERROR_UTILS_MEM_FAIL; + } + + /* /mnt/sandbox//storage/Users */ + char storageUserPath[PATH_MAX_LEN] = {0}; + ret = snprintf_s(storageUserPath, PATH_MAX_LEN, PATH_MAX_LEN - 1, "/mnt/sandbox/%u/%s/storage/Users", + info->uid / UID_BASE, varBundleName); + if (ret <= 0) { + APPSPAWN_LOGE("snprintf storageUserPath failed, errno %{public}d", errno); + return APPSPAWN_ERROR_UTILS_MEM_FAIL; + } + + // Check whether the directory is a shared mount point + if (SetSandboxPathShared(storageUserPath)) { + APPSPAWN_LOGV("shared mountpoint is exist"); + return 0; + } + + ret = MakeDirRec(storageUserPath, DIR_MODE, 1); + if (ret != 0) { + APPSPAWN_LOGE("mkdir %{public}s failed, errno %{public}d", storageUserPath, errno); + return APPSPAWN_SANDBOX_ERROR_MKDIR_FAIL; + } + + char options[PATH_MAX_LEN] = {0}; + ret = snprintf_s(options, PATH_MAX_LEN, PATH_MAX_LEN - 1, "override_support_delete,user_id=%u", + info->uid / UID_BASE); + if (ret <= 0) { + APPSPAWN_LOGE("snprintf options failed, errno %{public}d", errno); + return APPSPAWN_ERROR_UTILS_MEM_FAIL; + } + + SharedMountArgs arg = { + .srcPath = sharefsDocsDir, + .destPath = storageUserPath, + .fsType = "sharefs", + .mountFlags = MS_NODEV, + .options = options, + .mountSharedFlag = MS_SHARED + }; + ret = DoSharedMount(&arg); + if (ret != 0) { + APPSPAWN_LOGE("mount %{public}s shared failed, ret %{public}d", storageUserPath, ret); + } + return ret; +} + +static void MountStorageUsers(const AppSpawningCtx *property, const AppDacInfo *info, const char *varBundleName) +{ + int ret = 0; + int index = GetPermissionIndex(nullptr, "ohos.permission.FILE_ACCESS_MANAGER"); + int checkRes = CheckAppPermissionFlagSet(property, static_cast(index)); + if (checkRes == 0) { + /* mount /mnt/user//sharefs/docs to /mnt/sandbox///storage/Users */ + ret = MountWithOther(property, info, varBundleName); + } else { + /* mount /mnt/user//nosharefs/docs to /mnt/sandbox///storage/Users + */ + ret = MountWithFileMgr(property, info, varBundleName); + } + if (ret != 0) { + APPSPAWN_LOGE("Update %{public}s storage dir failed, ret %{public}d", + checkRes == 0 ? "sharefs dir" : "no sharefs dir", ret); + } else { + APPSPAWN_LOGI("Update %{public}s storage dir success", checkRes == 0 ? "sharefs dir" : "no sharefs dir"); + } +} + +static int MountSharedMapItem(const AppSpawningCtx *property, const AppDacInfo *info, const char *varBundleName, + const char *sandboxPathItem) +{ + /* /mnt/sandbox///data/storage/el */ + char sandboxPath[PATH_MAX_LEN] = {0}; + int ret = snprintf_s(sandboxPath, PATH_MAX_LEN, PATH_MAX_LEN - 1, "/mnt/sandbox/%u/%s%s", + info->uid / UID_BASE, varBundleName, sandboxPathItem); + if (ret <= 0) { + APPSPAWN_LOGE("snprintf sandboxPath failed, errno %{public}d", errno); + return APPSPAWN_ERROR_UTILS_MEM_FAIL; + } + + // Check whether the directory is a shared mount point + if (SetSandboxPathShared(sandboxPath)) { + APPSPAWN_LOGV("shared mountpoint is exist"); + return 0; + } + + ret = MakeDirRec(sandboxPath, DIR_MODE, 1); + if (ret != 0) { + APPSPAWN_LOGE("mkdir %{public}s failed, errno %{public}d", sandboxPath, errno); + return APPSPAWN_SANDBOX_ERROR_MKDIR_FAIL; + } + + SharedMountArgs arg = { + .srcPath = sandboxPath, + .destPath = sandboxPath, + .fsType = nullptr, + .mountFlags = MS_BIND | MS_REC, + .options = nullptr, + .mountSharedFlag = MS_SHARED + }; + ret = DoSharedMount(&arg); + if (ret != 0) { + APPSPAWN_LOGE("mount %{public}s shared failed, ret %{public}d", sandboxPath, ret); + } + return ret; +} + +static void MountSharedMap(const AppSpawningCtx *property, const AppDacInfo *info, const char *varBundleName) +{ + int length = sizeof(MOUNT_SHARED_MAP) / sizeof(MOUNT_SHARED_MAP[0]); + for (int i = 0; i < length; i++) { + if (MOUNT_SHARED_MAP[i].permission == nullptr) { + MountSharedMapItem(property, info, varBundleName, MOUNT_SHARED_MAP[i].sandboxPath); + } else { + int index = GetPermissionIndex(nullptr, MOUNT_SHARED_MAP[i].permission); + APPSPAWN_LOGV("mount dir on lock mountPermissionFlags %{public}d", index); + if (CheckAppPermissionFlagSet(property, static_cast(index))) { + MountSharedMapItem(property, info, varBundleName, MOUNT_SHARED_MAP[i].sandboxPath); + } + } + } + APPSPAWN_LOGI("mount shared map success"); +} + +static inline bool CheckPath(const std::string& name) +{ + return !name.empty() && name != "." && name != ".." && name.find("/") == std::string::npos; +} + +static int DataGroupCtxNodeCompare(ListNode *node, void *data) +{ + DataGroupCtx *existingNode = (DataGroupCtx *)ListEntry(node, DataGroupCtx, node); + DataGroupCtx *newNode = (DataGroupCtx *)data; + if (existingNode == nullptr || newNode == nullptr) { + APPSPAWN_LOGE("Invalid param"); + return APPSPAWN_ARG_INVALID; + } + + // compare src path and sandbox path + bool isSrcPathEqual = (strcmp(existingNode->srcPath.path, newNode->srcPath.path) == 0); + bool isDestPathEqual = (strcmp(existingNode->destPath.path, newNode->destPath.path) == 0); + + return (isSrcPathEqual && isDestPathEqual) ? 0 : 1; +} + +static int AddDataGroupItemToQueue(AppSpawnMgr *content, const std::string &srcPath, const std::string &destPath, + const std::string &dataGroupUuid) +{ + DataGroupCtx *dataGroupNode = (DataGroupCtx *)calloc(1, sizeof(DataGroupCtx)); + APPSPAWN_CHECK(dataGroupNode != nullptr, return APPSPAWN_ERROR_UTILS_MEM_FAIL, "Calloc dataGroupNode failed"); + if (strcpy_s(dataGroupNode->srcPath.path, PATH_MAX_LEN - 1, srcPath.c_str()) != EOK || + strcpy_s(dataGroupNode->destPath.path, PATH_MAX_LEN - 1, destPath.c_str()) != EOK || + strcpy_s(dataGroupNode->dataGroupUuid, UUID_MAX_LEN, dataGroupUuid.c_str()) != EOK) { + APPSPAWN_LOGE("strcpy dataGroupNode->srcPath failed"); + free(dataGroupNode); + return APPSPAWN_ERROR_UTILS_MEM_FAIL; + } + dataGroupNode->srcPath.pathLen = strlen(dataGroupNode->srcPath.path); + dataGroupNode->destPath.pathLen = strlen(dataGroupNode->destPath.path); + ListNode *node = OH_ListFind(&content->dataGroupCtxQueue, (void *)dataGroupNode, DataGroupCtxNodeCompare); + if (node != nullptr) { + APPSPAWN_LOGI("DataGroupCtxNode %{public}s is exist", dataGroupNode->srcPath.path); + free(dataGroupNode); + dataGroupNode = nullptr; + return 0; + } + OH_ListInit(&dataGroupNode->node); + OH_ListAddTail(&content->dataGroupCtxQueue, &dataGroupNode->node); + return 0; +} + +static void DumpDataGroupCtxQueue(const ListNode *front) +{ + if (front == nullptr) { + return; + } + + uint32_t count = 0; + ListNode *node = front->next; + while (node != front) { + DataGroupCtx *dataGroupNode = (DataGroupCtx *)ListEntry(node, DataGroupCtx, node); + count++; + APPSPAWN_LOGV(" ************************************** %{public}d", count); + APPSPAWN_LOGV(" srcPath: %{public}s", dataGroupNode->srcPath.path); + APPSPAWN_LOGV(" destPath: %{public}s", dataGroupNode->destPath.path); + APPSPAWN_LOGV(" uuid: %{public}s", dataGroupNode->dataGroupUuid); + node = node->next; + } +} + +static inline cJSON *GetJsonObjFromExtInfo(const AppSpawningCtx *property, const char *name) +{ + uint32_t size = 0; + char *extInfo = (char *)(GetAppSpawnMsgExtInfo(property->message, name, &size)); + if (size == 0 || extInfo == nullptr) { + return nullptr; + } + APPSPAWN_LOGV("Get json name %{public}s value %{public}s", name, extInfo); + cJSON *extInfoJson = cJSON_Parse(extInfo); // need to free + APPSPAWN_CHECK(extInfoJson != nullptr, return nullptr, "Invalid ext info %{public}s for %{public}s", extInfo, name); + return extInfoJson; +} + +static int ParseDataGroupList(AppSpawnMgr *content, const AppSpawningCtx *property, AppDacInfo *info, + const char *varBundleName) +{ + int ret = 0; + const char *dataGroupList = (char *)GetJsonObjFromExtInfo(property, DATA_GROUP_SOCKET_TYPE); + if (dataGroupList == nullptr || !cJSON_IsArray(dataGroupList)) { + APPSPAWN_LOGE("dataGroupList is empty"); + return APPSPAWN_ARG_INVALID; + } + + // Iterate through the array (assuming groups is an array) + cJSON *item = NULL; + cJSON_ArrayForEach(item, dataGroupList) { + // Check if the item is valid + APPSPAWN_CHECK((item != nullptr && IsValidDataGroupItem(item)), break, + "Element is not a valid data group item"); + + cJSON *dirItem = cJSON_GetObjectItemCaseSensitive(item, "dir"); + cJSON *uuidItem = cJSON_GetObjectItemCaseSensitive(item, "uuid"); + if (dirItem == NULL || !cJSON_IsString(dirItem) || uuidItem == NULL || !cJSON_IsString(uuidItem)) { + APPSPAWN_LOGE("Data group element is invalid"); + break; + } + + const char *srcPath = dirItem->valuestring; + APPSPAWN_CHECK(!CheckPath(srcPath), break, "src path %{public}s is invalid", srcPath); + + int elxValue = GetElxInfoFromDir(srcPath); + APPSPAWN_CHECK((elxValue >= EL2 && elxValue < ELX_MAX), break, "Get elx value failed"); + + const DataGroupSandboxPathTemplate *templateItem = GetDataGroupArgTemplate(elxValue); + APPSPAWN_CHECK(templateItem != NULL, break, "Get data group arg template failed"); + + // If permission isn't null, need check permission flag + if (templateItem->permission != NULL) { + int index = GetPermissionIndex(nullptr, templateItem->permission); + APPSPAWN_LOGV("mount dir no lock mount permission flag %{public}d", index); + if (CheckAppPermissionFlagSet(property, static_cast(index)) == 0) { + continue; + } + } + // sandboxPath: /mnt/sandbox///data/storage/el/group + std::string sandboxPath = "/mnt/sandbox/" + std::to_string(info->uid / UID_BASE) + "/" + varBundleName + + templateItem->sandboxPath; + + ret = AddDataGroupItemToQueue(content, srcPath, sandboxPath, uuidItem->valuestring); + APPSPAWN_LOGE("Add datagroup item to dataGroupCtxQueue failed, el%{public}d", elxValue); + OH_ListRemoveAll(&content->dataGroupCtxQueue, nullptr); + break;; + } + cJSON_Delete(dataGroupList); + + DumpDataGroupCtxQueue(&content->dataGroupCtxQueue); + return ret; +} + +int UpdateDataGroupDirs(AppSpawnMgr *content) +{ + if (content == nullptr) { + return APPSPAWN_ARG_INVALID; + } + + ListNode *node = content->dataGroupCtxQueue.next; + while (node != &content->dataGroupCtxQueue) { + DataGroupCtx *dataGroupNode = (DataGroupCtx *)ListEntry(node, DataGroupCtx, node); + char sandboxPath[PATH_MAX_LEN] = {0}; + int ret = snprintf_s(sandboxPath, PATH_MAX_LEN, PATH_MAX_LEN - 1, "%s%s", dataGroupNode->destPath.path, + dataGroupNode->dataGroupUuid); + if (ret <= 0) { + APPSPAWN_LOGE("snprintf_s sandboxPath: %{public}s failed, errno %{public}d", + dataGroupNode->destPath.path, errno); + return APPSPAWN_ERROR_UTILS_MEM_FAIL; + } + + SharedMountArgs args = { + .srcPath = dataGroupNode->srcPath.path, + .destPath = sandboxPath, + .fsType = nullptr, + .mountFlags = MS_BIND | MS_REC, + .options = nullptr, + .mountSharedFlag = MS_SHARED + }; + ret = DoSharedMount(&args); + if (ret != 0) { + APPSPAWN_LOGE("Shared mount %{public}s to %{public}s failed, errno %{public}d", args.srcPath, + sandboxPath, ret); + } + node = node->next; + } + OH_ListRemoveAll(&content->dataGroupCtxQueue, nullptr); + return 0; +} + +static std::string ReplaceVarBundleName(const AppSpawningCtx *property) +{ + AppSpawnMsgBundleInfo *bundleInfo = + reinterpret_cast(GetAppProperty(property, TLV_BUNDLE_INFO)); + if (bundleInfo == nullptr) { + return ""; + } + + std::string tmpBundlePath = bundleInfo->bundleName; + std::ostringstream variablePackageName; + if (CheckAppSpawnMsgFlag(property->message, TLV_MSG_FLAGS, APP_FLAGS_CLONE_ENABLE)) { + variablePackageName << "+clone-" << bundleInfo->bundleIndex << "+" << bundleInfo->bundleName; + tmpBundlePath = variablePackageName.str(); + } + return tmpBundlePath; +} + +static void MountDirToShared(AppSpawnMgr *content, const AppSpawningCtx *property) +{ + if (property == nullptr) { + return; + } + + AppDacInfo *info = reinterpret_cast(GetAppProperty(property, TLV_DAC_INFO)); + std::string varBundleName = ReplaceVarBundleName(property); + if (info == nullptr || varBundleName == "") { + APPSPAWN_LOGE("Invalid app dac info or varBundleName"); + return; + } + + MountEl1Bundle(property, info, varBundleName.c_str()); + + if (IsUnlockStatus(info->uid)) { + SetAppSpawnMsgFlag(property->message, TLV_MSG_FLAGS, APP_FLAGS_UNLOCKED_STATUS); + return; + } + + MountSharedMap(property, info, varBundleName.c_str()); + MountStorageUsers(property, info, varBundleName.c_str()); + ParseDataGroupList(content, property, info, varBundleName.c_str()); + + std::string lockSbxPathStamp = "/mnt/sandbox/" + std::to_string(info->uid / UID_BASE) + "/"; + lockSbxPathStamp += CheckAppMsgFlagsSet(property, APP_FLAGS_ISOLATED_SANDBOX_TYPE) ? "isolated/" : ""; + lockSbxPathStamp += varBundleName; + lockSbxPathStamp += "_locked"; + int ret = MakeDirRec(lockSbxPathStamp.c_str(), DIR_MODE, 1); + if (ret != 0) { + APPSPAWN_LOGE("mkdir %{public}s failed, errno %{public}d", lockSbxPathStamp.c_str(), errno); + } +} +#endif + +int MountToShared(AppSpawnMgr *content, const AppSpawningCtx *property) +{ +#ifndef APPSPAWN_SANDBOX_NEW + // mount dynamic directory to shared + MountDirToShared(content, property); +#endif + return 0; +} + +MODULE_CONSTRUCTOR(void) +{ +#ifndef APPSPAWN_SANDBOX_NEW + (void)AddServerStageHook(STAGE_SERVER_LOCK, HOOK_PRIO_COMMON, UpdateDataGroupDirs); +#endif +} diff --git a/modules/sandbox/normal/sandbox_shared_mount.h b/modules/sandbox/normal/sandbox_shared_mount.h new file mode 100644 index 00000000..0a09a3eb --- /dev/null +++ b/modules/sandbox/normal/sandbox_shared_mount.h @@ -0,0 +1,70 @@ +/* + * 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. + */ + +#ifndef SANDBOX_SHARED_MOUNT_H +#define SANDBOX_SHARED_MOUNT_H + +#include "nlohmann/json.hpp" + +#include "appspawn.h" +#include "appspawn_hook.h" +#include "appspawn_manager.h" +#include "appspawn_utils.h" +#include "list.h" +#include "json_utils.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MountSharedTemplate { + const char *sandboxPath; + const char *permission; +} MountSharedTemplate; + +enum { + EL2 = 0, + EL3, + EL4, + EL5, + ELX_MAX +}; + +typedef struct DataGroupSandboxPathTemplate { + const char *elxName; + uint32_t category; + const char *sandboxPath; + const char *permission; +} DataGroupSandboxPathTemplate; + +struct SharedMountArgs { + const char *srcPath; + const char *destPath; + const char *fsType = ""; + unsigned long mountFlags = MS_REC | MS_BIND; + const char *options = ""; + mode_t mountSharedFlag = MS_SLAVE; +}; + +bool IsValidDataGroupItem(cJSON *item); +int GetElxInfoFromDir(const char *path); +const DataGroupSandboxPathTemplate *GetDataGroupArgTemplate(uint32_t category); +void *GetEl1BundleMountCount(void); +int MountToShared(AppSpawnMgr *content, const AppSpawningCtx *property); + +#ifdef __cplusplus +} +#endif +#endif // SANDBOX_SHARED_MOUNT_H diff --git a/test/unittest/app_spawn_client_test/BUILD.gn b/test/unittest/app_spawn_client_test/BUILD.gn index 136553b5..d8c8f61c 100644 --- a/test/unittest/app_spawn_client_test/BUILD.gn +++ b/test/unittest/app_spawn_client_test/BUILD.gn @@ -39,6 +39,8 @@ ohos_unittest("AppSpawn_client_ut") { "${appspawn_path}/modules/ace_adapter", "${appspawn_path}/modules/common", "${appspawn_path}/modules/sandbox", + "${appspawn_path}/modules/sandbox/normal", + "${appspawn_path}/modules/sandbox/modern", "${appspawn_path}/modules/module_engine/include", "${appspawn_path}/modules/sysevent", "${appspawn_innerkits_path}/client", diff --git a/test/unittest/app_spawn_standard_test/BUILD.gn b/test/unittest/app_spawn_standard_test/BUILD.gn index 15a882f5..370e4c54 100644 --- a/test/unittest/app_spawn_standard_test/BUILD.gn +++ b/test/unittest/app_spawn_standard_test/BUILD.gn @@ -64,6 +64,8 @@ ohos_unittest("AppSpawn_ut") { "${appspawn_path}/modules/ace_adapter", "${appspawn_path}/modules/common", "${appspawn_path}/modules/sandbox", + "${appspawn_path}/modules/sandbox/normal", + "${appspawn_path}/modules/sandbox/modern", "${appspawn_path}/modules/sysevent", "${appspawn_innerkits_path}/client", "${appspawn_innerkits_path}/include", @@ -104,15 +106,15 @@ ohos_unittest("AppSpawn_ut") { "${appspawn_path}/modules/common/appspawn_namespace.c", "${appspawn_path}/modules/common/appspawn_silk.c", "${appspawn_path}/modules/nweb_adapter/nwebspawn_adapter.cpp", - "${appspawn_path}/modules/sandbox/appspawn_mount_template.c", + "${appspawn_path}/modules/sandbox/modern/appspawn_mount_template.c", "${appspawn_path}/modules/sandbox/appspawn_permission.c", - "${appspawn_path}/modules/sandbox/appspawn_sandbox.c", - "${appspawn_path}/modules/sandbox/sandbox_adapter.cpp", - "${appspawn_path}/modules/sandbox/sandbox_cfgvar.c", + "${appspawn_path}/modules/sandbox/modern/appspawn_sandbox.c", + "${appspawn_path}/modules/sandbox/modern/sandbox_adapter.cpp", + "${appspawn_path}/modules/sandbox/modern/sandbox_cfgvar.c", "${appspawn_path}/modules/sandbox/sandbox_dec.c", - "${appspawn_path}/modules/sandbox/sandbox_expand.c", - "${appspawn_path}/modules/sandbox/sandbox_load.c", - "${appspawn_path}/modules/sandbox/sandbox_manager.c", + "${appspawn_path}/modules/sandbox/modern/sandbox_expand.c", + "${appspawn_path}/modules/sandbox/modern/sandbox_load.c", + "${appspawn_path}/modules/sandbox/modern/sandbox_manager.c", ] # add stub @@ -272,6 +274,8 @@ ohos_unittest("AppSpawn_coldrun_ut") { "${appspawn_path}/modules/ace_adapter", "${appspawn_path}/modules/common", "${appspawn_path}/modules/sandbox", + "${appspawn_path}/modules/sandbox/normal", + "${appspawn_path}/modules/sandbox/modern", "${appspawn_path}/modules/sysevent", "${appspawn_innerkits_path}/client", "${appspawn_innerkits_path}/include", @@ -312,15 +316,15 @@ ohos_unittest("AppSpawn_coldrun_ut") { "${appspawn_path}/modules/common/appspawn_namespace.c", "${appspawn_path}/modules/common/appspawn_silk.c", "${appspawn_path}/modules/nweb_adapter/nwebspawn_adapter.cpp", - "${appspawn_path}/modules/sandbox/appspawn_mount_template.c", + "${appspawn_path}/modules/sandbox/modern/appspawn_mount_template.c", "${appspawn_path}/modules/sandbox/appspawn_permission.c", - "${appspawn_path}/modules/sandbox/appspawn_sandbox.c", - "${appspawn_path}/modules/sandbox/sandbox_adapter.cpp", - "${appspawn_path}/modules/sandbox/sandbox_cfgvar.c", + "${appspawn_path}/modules/sandbox/modern/appspawn_sandbox.c", + "${appspawn_path}/modules/sandbox/modern/sandbox_adapter.cpp", + "${appspawn_path}/modules/sandbox/modern/sandbox_cfgvar.c", "${appspawn_path}/modules/sandbox/sandbox_dec.c", - "${appspawn_path}/modules/sandbox/sandbox_expand.c", - "${appspawn_path}/modules/sandbox/sandbox_load.c", - "${appspawn_path}/modules/sandbox/sandbox_manager.c", + "${appspawn_path}/modules/sandbox/modern/sandbox_expand.c", + "${appspawn_path}/modules/sandbox/modern/sandbox_load.c", + "${appspawn_path}/modules/sandbox/modern/sandbox_manager.c", ] if (appspawn_use_encaps == true) { @@ -463,6 +467,8 @@ ohos_unittest("AppSpawn_common_ut") { "${appspawn_path}/modules/ace_adapter", "${appspawn_path}/modules/common", "${appspawn_path}/modules/sandbox", + "${appspawn_path}/modules/sandbox/normal", + "${appspawn_path}/modules/sandbox/modern", "${appspawn_path}/modules/sysevent", "${appspawn_innerkits_path}/client", "${appspawn_innerkits_path}/include", @@ -504,15 +510,15 @@ ohos_unittest("AppSpawn_common_ut") { "${appspawn_path}/modules/common/appspawn_namespace.c", "${appspawn_path}/modules/common/appspawn_silk.c", "${appspawn_path}/modules/nweb_adapter/nwebspawn_adapter.cpp", - "${appspawn_path}/modules/sandbox/appspawn_mount_template.c", + "${appspawn_path}/modules/sandbox/modern/appspawn_mount_template.c", "${appspawn_path}/modules/sandbox/appspawn_permission.c", - "${appspawn_path}/modules/sandbox/appspawn_sandbox.c", - "${appspawn_path}/modules/sandbox/sandbox_adapter.cpp", - "${appspawn_path}/modules/sandbox/sandbox_cfgvar.c", + "${appspawn_path}/modules/sandbox/modern/appspawn_sandbox.c", + "${appspawn_path}/modules/sandbox/modern/sandbox_adapter.cpp", + "${appspawn_path}/modules/sandbox/modern/sandbox_cfgvar.c", "${appspawn_path}/modules/sandbox/sandbox_dec.c", - "${appspawn_path}/modules/sandbox/sandbox_expand.c", - "${appspawn_path}/modules/sandbox/sandbox_load.c", - "${appspawn_path}/modules/sandbox/sandbox_manager.c", + "${appspawn_path}/modules/sandbox/modern/sandbox_expand.c", + "${appspawn_path}/modules/sandbox/modern/sandbox_load.c", + "${appspawn_path}/modules/sandbox/modern/sandbox_manager.c", ] # add stub -- Gitee