From 145ff2cd13ed469464c2aaa1eac52d747f448e87 Mon Sep 17 00:00:00 2001 From: wangfenging Date: Thu, 19 Jun 2025 14:20:44 +0800 Subject: [PATCH] Refactoring the sandbox_util class Signed-off-by: wangfenging --- modules/sandbox/sandbox_common.cpp | 948 +++++++++++++++++++++++ modules/sandbox/sandbox_common.h | 103 +++ modules/sandbox/sandbox_def.h | 132 ++++ modules/sandbox/sandbox_manager.cpp | 1087 +++++++++++++++++++++++++++ modules/sandbox/sandbox_manager.h | 78 ++ modules/sandbox/sandbox_utils.cpp | 6 +- 6 files changed, 2350 insertions(+), 4 deletions(-) create mode 100644 modules/sandbox/sandbox_common.cpp create mode 100644 modules/sandbox/sandbox_common.h create mode 100644 modules/sandbox/sandbox_def.h create mode 100644 modules/sandbox/sandbox_manager.cpp create mode 100644 modules/sandbox/sandbox_manager.h diff --git a/modules/sandbox/sandbox_common.cpp b/modules/sandbox/sandbox_common.cpp new file mode 100644 index 00000000..e4651d6d --- /dev/null +++ b/modules/sandbox/sandbox_common.cpp @@ -0,0 +1,948 @@ +/* + * 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 "appspawn_hook.h" +#include "appspawn_manager.h" +#include "appspawn_utils.h" +#include "sandbox_def.h" + +namespace OHOS { +namespace AppSpawn { + +// 加载配置文件 +uint32_t SandboxCommon::GetSandboxNsFlags(bool isNweb) +{ + uint32_t nsFlags = 0; + nlohmann::json appConfig; + const std::map NamespaceFlagsMap = { {"pid", CLONE_NEWPID}, + {"net", CLONE_NEWNET} }; + + if (!IsTotalSandboxEnabled(nullptr)) { + return nsFlags; + } + + for (auto& config : GetJsonConfig(SANBOX_APP_JSON_CONFIG)) { + if (isNweb) { + nlohmann::json& privateAppConfig = config[g_privatePrefix][0]; + if (privateAppConfig.find(g_ohosRender) == privateAppConfig.end()) { + continue; + } + appConfig = privateAppConfig[g_ohosRender][0]; + } else { + nlohmann::json& baseConfig = config[g_commonPrefix][0]; + if (baseConfig.find(g_appBase) == baseConfig.end()) { + continue; + } + appConfig = baseConfig[g_appBase][0]; + } + if (appConfig.find(g_sandBoxNsFlags) == appConfig.end()) { + continue; + } + const auto vec = appConfig[g_sandBoxNsFlags].get>(); + for (unsigned int j = 0; j < vec.size(); j++) { + if (NamespaceFlagsMap.count(vec[j])) { + nsFlags |= NamespaceFlagsMap.at(vec[j]); + } + } + } + + 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; +} + +int SandboxCommon::LoadAppSandboxConfig(AppSpawnMgr *content) +{ + bool rc = true; + // load sandbox config + nlohmann::json appSandboxConfig; + 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 + APP_JSON_CONFIG; + APPSPAWN_LOGI("LoadAppSandboxConfig %{public}s", appPath.c_str()); + rc = GetJsonObjFromJson(appSandboxConfig, appPath); + APPSPAWN_CHECK(rc, continue, "Failed to load app data sandbox config %{public}s", appPath.c_str()); + StoreJsonConfig(appSandboxConfig, SANBOX_APP_JSON_CONFIG); + + std::string isolatedPath = path + APP_ISOLATED_JSON_CONFIG; + APPSPAWN_LOGI("LoadAppSandboxConfig %{public}s", isolatedPath.c_str()); + rc = GetJsonObjFromJson(appSandboxConfig, isolatedPath); + APPSPAWN_CHECK(rc, continue, "Failed to load app data sandbox config %{public}s", isolatedPath.c_str()); + StoreJsonConfig(appSandboxConfig, SANBOX_ISOLATED_JSON_CONFIG); + } + FreeCfgFiles(files); + bool isNweb = IsNWebSpawnMode(content); + if (!isNweb && !AppSandboxPidNsIsSupport()) { + return 0; + } + content->content.sandboxNsFlags = GetSandboxNsFlags(isNweb); + return 0; +} + +bool SandboxCommon::GetJsonObjFromJson(nlohmann::json &jsonObj, const std::string &jsonPath) +{ + APPSPAWN_CHECK(jsonPath.length() <= PATH_MAX, return false, "jsonPath is too long"); + std::ifstream jsonFileStream; + jsonFileStream.open(jsonPath.c_str(), std::ios::in); + APPSPAWN_CHECK_ONLY_EXPER(jsonFileStream.is_open(), return false); + std::ostringstream buf; + char ch; + while (buf && jsonFileStream.get(ch)) { + buf.put(ch); + } + jsonFileStream.close(); + jsonObj = nlohmann::json::parse(buf.str(), nullptr, false); + APPSPAWN_CHECK(!jsonObj.is_discarded() && jsonObj.is_structured(), return false, "Parse json file failed"); + return true; +} + +bool SandboxCommon::GetStringFromJson(const nlohmann::json &json, const std::string &key, std::string &value) +{ + APPSPAWN_CHECK(json != nullptr && json.is_object(), return false, "json is not object."); + bool isRet = json.find(key) != json.end() && json.at(key).is_string(); + if (isRet) { + value = json.at(key).get(); + APPSPAWN_LOGV("Find key[%{public}s] : %{public}s successful.", key.c_str(), value.c_str()); + } + return isRet; +} + +void SandboxCommon::StoreJsonConfig(nlohmann::json &appSandboxConfig, SandboxConfigType type) +{ + SandboxUtils::appSandboxConfig_[type].push_back(appSandboxConfig); +} + +std::vector &SandboxCommon::GetJsonConfig(SandboxConfigType type) +{ + return appSandboxConfig_[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, nlohmann::json &config) +{ + AppSpawnMsgDacInfo *dacInfo = reinterpret_cast(GetAppProperty(appProperty, TLV_DAC_INFO)); + if (dacInfo == nullptr) { + return ""; + } + + std::string sandboxRoot = ""; + const std::string sandboxRootPathTemplate = "/mnt/sandbox//"; + const std::string originSandboxPath = "/mnt/sandbox/"; + 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 = g_sandBoxRootDir + to_string(dacInfo->uid / UID_BASE) + + "/" + isolatedFlagText.c_str() + tmpBundlePath; + if (config.find(g_sandboxRootPrefix) != config.end()) { + sandboxRoot = config[g_sandboxRootPrefix].get(); + if (sandboxRoot == originSandboxPath || sandboxRoot == 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; +} + +bool SandboxCommon::NeedNetworkIsolated(AppSpawningCtx *property) +{ + int developerMode = IsDeveloperModeOpen(); + if (CheckAppMsgFlagsSet(property, APP_FLAGS_ISOLATED_SANDBOX) && !developerMode) { + return true; + } + + if (CheckAppMsgFlagsSet(property, APP_FLAGS_ISOLATED_NETWORK)) { + std::string extensionType = GetExtraInfoByType(property, MSG_EXT_NAME_EXTENSION_TYPE); + if (extensionType.length() == 0 || !developerMode) { + return true; + } + } + + return false; +} + +uint32_t SandboxCommon::GetAppMsgFlags(const AppSpawningCtx *property) +{ + APPSPAWN_CHECK(property != nullptr && property->message != nullptr, + return 0, "Invalid property for name %{public}u", TLV_MSG_FLAGS); + AppSpawnMsgFlags *msgFlags = (AppSpawnMsgFlags *)GetAppSpawnMsgInfo(property->message, TLV_MSG_FLAGS); + APPSPAWN_CHECK(msgFlags != nullptr, + return 0, "No TLV_MSG_FLAGS in msg %{public}s", property->message->msgHeader.processName); + return msgFlags->flags[0]; +} + +void SandboxCommon::UpdateMsgFlagsWithPermission(AppSpawningCtx *appProperty) +{ + int32_t processIndex = GetPermissionIndex(nullptr, GET_ALL_PROCESSES_MODE.c_str()); + if ((CheckAppPermissionFlagSet(appProperty, static_cast(processIndex)) == 0)) { + APPSPAWN_LOGV("Don't need set GET_ALL_PROCESSES_MODE flag"); + return; + } + + int ret = SetAppSpawnMsgFlag(appProperty->message, TLV_MSG_FLAGS, APP_FLAGS_GET_ALL_PROCESSES); + if (ret != 0) { + APPSPAWN_LOGV("Set GET_ALL_PROCESSES_MODE flag failed"); + } +} + +int32_t SandboxCommon::UpdatePermissionFlags(AppSpawningCtx *appProperty) +{ + int32_t index = 0; + int32_t appFullMountStatus = CheckAppFullMountEnable(); + if (appFullMountStatus == FILE_CROSS_APP_STATUS) { + index = GetPermissionIndex(nullptr, FILE_CROSS_APP_MODE.c_str()); + } else if (appFullMountStatus == FILE_ACCESS_COMMON_DIR_STATUS) { + index = GetPermissionIndex(nullptr, FILE_ACCESS_COMMON_DIR_MODE.c_str()); + } + int32_t userFileIndex = GetPermissionIndex(nullptr, READ_WRITE_USER_FILE_MODE.c_str()); + int32_t fileMgrIndex = GetPermissionIndex(nullptr, FILE_ACCESS_MANAGER_MODE.c_str()); + if ((CheckAppPermissionFlagSet(appProperty, static_cast(userFileIndex)) != 0) && + (CheckAppPermissionFlagSet(appProperty, static_cast(fileMgrIndex)) != 0)) { + APPSPAWN_LOGE("invalid msg request."); + return -1; + } + if (index > 0 && (fileMgrIndex > 0 && userFileIndex > 0) && + (CheckAppPermissionFlagSet(appProperty, static_cast(userFileIndex)) == 0) && + (CheckAppPermissionFlagSet(appProperty, static_cast(fileMgrIndex)) == 0)) { + return SetAppPermissionFlags(appProperty, index); + } + return 0; +} + +void SandboxCommon::CreateDirRecursive(const std::string &path, mode_t mode) +{ + return MakeDirRec(path, 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); + MakeDirRecursive(dir, FILE_MODE); + int fd = open(file, O_CREAT, FILE_MODE); + if (fd < 0) { + APPSPAWN_LOGW("failed create %{public}s, err=%{public}d", file, errno); + } else { + close(fd); + } + return; +} + +void SandboxCommon::CreateFileIfNotExist(const char *file) // CheckAndCreatFile +{ + 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); + MakeDirRecursive(dir, FILE_MODE); + int fd = open(file, O_CREAT, FILE_MODE); + if (fd < 0) { + APPSPAWN_LOGW("failed create %{public}s, err=%{public}d", file, errno); + } else { + close(fd); + } + return; +} + +void SandboxCommon::SetSandboxPathChmod(nlohmann::json 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}}; + std::string fileModeStr; + mode_t mode = 0; + + bool rc = GetStringFromJson(jsonConfig, g_destMode, fileModeStr); + if (rc == false) { + return; + } + + 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(nlohmann::json &config) // GetSandboxDacOverrideEnable +{ + std::string dacOverrideSensitive = ""; + if (config.find(g_dacOverrideSensitive) == config.end()) { + return false; + } + dacOverrideSensitive = config[g_dacOverrideSensitive].get(); + if (dacOverrideSensitive.compare("true") == 0) { + return true; + } + return false; +} + +bool SandboxCommon::GetSwitchStatus(nlohmann::json &config) // GetSbxSwitchStatusByConfig +{ + if (config.find(g_sandBoxSwitchPrefix) != config.end()) { + std::string switchStatus = config[g_sandBoxSwitchPrefix].get(); + if (switchStatus == g_sbxSwitchCheck) { + return true; + } else { + return false; + } + } + + // if not find sandbox-switch node, default switch status is true + return 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(nlohmann::json &config) // GetSandboxMountFlags +{ + unsigned long mountFlags = BASIC_MOUNT_FLAGS; + if (IsDacOverrideEnabled(config) && (config.find(g_sandBoxFlagsCustomized) != config.end())) { + mountFlags = GetMountFlagsFromConfig(config[g_sandBoxFlagsCustomized].get>()); + } else if (config.find(g_sandBoxFlags) != config.end()) { + mountFlags = GetMountFlagsFromConfig(config[g_sandBoxFlags].get>()); + } + return mountFlags; +} +std::string SandboxCommon::GetFsType(nlohmann::json &config) // GetSandboxFsType +{ + std::string fsType = ""; + if (IsDacOverrideEnabled(config) && (config.find(g_fsType) != config.end())) { + fsType = config[g_fsType].get(); + } + return fsType; +} + +std::string SandboxCommon::GetOptions(const AppSpawningCtx *appProperty, nlohmann::json &config) // GetSandboxOptions +{ + AppSpawnMsgDacInfo *dacInfo = reinterpret_cast(GetAppProperty(appProperty, TLV_DAC_INFO)); + if (dacInfo == nullptr) { + return ""; + } + + std::string options = ""; + const int userIdBase = UID_BASE; + if (IsDacOverrideEnabled(config) && (config.find(g_sandBoxOptions) != config.end())) { + options = config[g_sandBoxOptions].get() + ",user_id="; + options += std::to_string(dacInfo->uid / userIdBase); + } + return options; +} + +std::vector SandboxCommon::GetDecPath(const AppSpawningCtx *appProperty, nlohmann::json &config) // GetSandboxDecPath +{ + AppSpawnMsgDacInfo *dacInfo = reinterpret_cast(GetAppProperty(appProperty, TLV_DAC_INFO)); + if (dacInfo == nullptr) { + return {}; + } + + std::vector decPaths = {}; + if (config.find(g_sandBoxDecPath) != config.end()) { + for (auto decPath : config[g_sandBoxDecPath].get>()) { + decPath = ConvertToRealPath(appProperty, decPath); + decPaths.push_back(decPath); + } + } + return decPaths; +} + +bool SandboxCommon::IsCreateSandboxPathEnabled(nlohmann::json &json, std::string srcPath) // GetCreateSandboxPath +{ + APPSPAWN_CHECK(json != nullptr && json.is_object(), return true, "json is not object."); + bool isRet = json.find(CREATE_SANDBOX_PATH) != json.end() && json.at(CREATE_SANDBOX_PATH).is_string(); + if (isRet) { + std::string value = json.at(CREATE_SANDBOX_PATH).get(); + APPSPAWN_LOGV("Find create-sandbox-path: %{public}s successful.", value.c_str()); + if (value == "false" && access(srcPath.c_str(), F_OK) != 0) { + return false; + } + } + return true; +} + +bool SandboxCommon::IsTotalSandboxEnabled(const AppSpawningCtx *appProperty) // CheckTotalSandboxSwitchStatus +{ + SandboxConfigType type = CheckAppMsgFlagsSet(appProperty, APP_FLAGS_ISOLATED_SANDBOX_TYPE) ? + SANBOX_ISOLATED_JSON_CONFIG : SANBOX_APP_JSON_CONFIG; + + for (auto& wholeConfig : GetJsonConfig(type)) { + if (wholeConfig.find(g_commonPrefix) == wholeConfig.end()) { + continue; + } + nlohmann::json& commonAppConfig = wholeConfig[g_commonPrefix][0]; + if (commonAppConfig.find(g_topSandBoxSwitchPrefix) != commonAppConfig.end()) { + std::string switchStatus = commonAppConfig[g_topSandBoxSwitchPrefix].get(); + return switchStatus == g_sbxSwitchCheck; + } + } + // default sandbox switch is on + return true; +} + +bool SandboxCommon::IsAppSandboxEnabled(const AppSpawningCtx *appProperty) // CheckAppSandboxSwitchStatus +{ + bool rc = true; + SandboxConfigType type = CheckAppMsgFlagsSet(appProperty, APP_FLAGS_ISOLATED_SANDBOX_TYPE) ? + SANBOX_ISOLATED_JSON_CONFIG : SANBOX_APP_JSON_CONFIG; + + for (auto& wholeConfig : SandboxUtils::GetJsonConfig(type)) { + if (wholeConfig.find(g_privatePrefix) == wholeConfig.end()) { + continue; + } + nlohmann::json& privateAppConfig = wholeConfig[g_privatePrefix][0]; + if (privateAppConfig.find(GetBundleName(appProperty)) != privateAppConfig.end()) { + nlohmann::json& appConfig = privateAppConfig[GetBundleName(appProperty)][0]; + rc = GetSwitchStatus(appConfig); + if (rc) { + break; + } + } + } + // default sandbox switch is on + return rc; +} + +// 校验操作 +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(g_internal) != std::string::npos) { + return false; + } + return true; +} + +bool SandboxCommon::IsMountSuccessful(nlohmann::json &mntPoint) // GetCheckStatus +{ + std::string value = g_statusCheck; + (void)GetStringFromJson(mntPoint, g_actionStatuc, value); + if (value == g_statusCheck) { + return true; + } + return 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_ = FILE_CROSS_APP_STATUS; + } else if (ret > 0 && (strcmp(value, "false")) == 0) { + deviceTypeEnable_ = FILE_ACCESS_COMMON_DIR_STATUS; + } else { + deviceTypeEnable_ = -1; + } + + return deviceTypeEnable_; +} + +bool IsValidMountConfig(nlohmann::json &mntPoint, const AppSpawningCtx *appProperty, bool checkFlag) +{ + bool istrue = mntPoint.find(g_srcPath) == mntPoint.end() || (!mntPoint[g_srcPath].is_string()) || + mntPoint.find(g_sandBoxPath) == mntPoint.end() || (!mntPoint[g_sandBoxPath].is_string()) || + ((mntPoint.find(g_sandBoxFlags) == mntPoint.end()) && + (mntPoint.find(g_sandBoxFlagsCustomized) == mntPoint.end())); + APPSPAWN_CHECK(!istrue, return false, + "read mount config failed, app name is %{public}s", GetBundleName(appProperty)); + + AppSpawnMsgDomainInfo *info = + reinterpret_cast(GetAppProperty(appProperty, TLV_DOMAIN_INFO)); + APPSPAWN_CHECK(info != nullptr, return false, "Filed to get domain info %{public}s", GetBundleName(appProperty)); + + if (mntPoint[g_appAplName] != nullptr) { + std::string app_apl_name = mntPoint[g_appAplName].get(); + const char *p_app_apl = nullptr; + p_app_apl = app_apl_name.c_str(); + if (!strcmp(p_app_apl, info->apl)) { + return false; + } + } + + const std::string configSrcPath = mntPoint[g_srcPath].get(); + // 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(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(const std::string &str, const std::string &delimiter) +{ + std::string::size_type pos; + std::vector result; + str += pattern; + size_t size = str.size(); + for (unsigned int i = 0; i < size; i++) { + pos = str.find(pattern, i); + if (pos < size) { + std::string s = str.substr(i, pos - i); + result.push_back(s); + i = pos + pattern.size() - 1; + } + } + + return result; +} + +static void MakeAtomicServiceDir(const AppSpawningCtx *appProperty, std::string path, std::string variablePackageName) +{ + AppSpawnMsgDacInfo *dacInfo = reinterpret_cast(GetAppProperty(appProperty, TLV_DAC_INFO)); + APPSPAWN_CHECK(dacInfo != NULL, 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 != NULL, 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; +} + +static std::string ReplaceVariablePackageName(const AppSpawningCtx *appProperty, const std::string &path) +{ + std::string tmpSandboxPath = path; + AppSpawnMsgBundleInfo *bundleInfo = + reinterpret_cast(GetAppProperty(appProperty, TLV_BUNDLE_INFO)); + APPSPAWN_CHECK(bundleInfo != NULL, 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, NULL)); + } + std::ostringstream variablePackageName; + switch (flags) { + case 0: // 0 default + variablePackageName << bundleInfo->bundleName; + break; + case 1: // 1 +clone-bundleIndex+packageName + variablePackageName << "+clone-" << bundleInfo->bundleIndex << "+" << bundleInfo->bundleName; + break; + case 2: { // 2 +extension-+packageName + APPSPAWN_CHECK(extension != NULL, return "", "Invalid extension data "); + variablePackageName << "+extension-" << extension << "+" << bundleInfo->bundleName; + break; + } + case 3: { // 3 +clone-bundleIndex+extension-+packageName + APPSPAWN_CHECK(extension != NULL, return "", "Invalid extension data "); + variablePackageName << "+clone-" << bundleInfo->bundleIndex << "+extension" << "-" << + extension << "+" << bundleInfo->bundleName; + break; + } + case 4: { // 4 +auid-+packageName + std::string accountId = SandboxUtils::GetExtraInfoByType(appProperty, MSG_EXT_NAME_ACCOUNT_ID); + variablePackageName << "+auid-" << accountId << "+" << bundleInfo->bundleName; + std::string atomicServicePath = path; + atomicServicePath = SandboxCommon::ReplaceAllVariables(atomicServicePath, g_variablePackageName, + variablePackageName.str()); + MakeAtomicServiceDir(appProperty, atomicServicePath, variablePackageName.str()); + break; + } + default: + variablePackageName << bundleInfo->bundleName; + break; + } + tmpSandboxPath = SandboxCommon::ReplaceAllVariables(tmpSandboxPath, + g_variablePackageName, variablePackageName.str()); + APPSPAWN_LOGV("tmpSandboxPath %{public}s", tmpSandboxPath.c_str()); + return tmpSandboxPath; +} + +static std::string 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, NULL)); + if (userId != nullptr) { + uid = atoi(userId); + } + tmpSandboxPath = SandboxCommon::ReplaceAllVariables(tmpSandboxPath, g_hostUserId, std::to_string(uid / UID_BASE)); + APPSPAWN_LOGV("tmpSandboxPath %{public}s", tmpSandboxPath.c_str()); + return tmpSandboxPath; +} + +static std::string ReplaceClonePackageName(const AppSpawningCtx *appProperty, const std::string &path) +{ + std::string tmpSandboxPath = path; + AppSpawnMsgBundleInfo *bundleInfo = + reinterpret_cast(GetAppProperty(appProperty, TLV_BUNDLE_INFO)); + APPSPAWN_CHECK(bundleInfo != NULL, 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 = SandboxCommon::ReplaceAllVariables(tmpSandboxPath, g_clonePackageName, tmpBundlePath); + APPSPAWN_LOGV("tmpSandboxPath %{public}s", tmpSandboxPath.c_str()); + return tmpSandboxPath; +} + +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(g_packageNameIndex) != std::string::npos) { + std::string bundleNameWithIndex = info->bundleName; + if (info->bundleIndex != 0) { + bundleNameWithIndex = std::to_string(info->bundleIndex) + "_" + bundleNameWithIndex; + } + path = SandboxCommon::ReplaceAllVariables(path, g_packageNameIndex, bundleNameWithIndex); + } + + if (path.find(g_packageName) != std::string::npos) { + path = SandboxCommon::ReplaceAllVariables(path, g_packageName, info->bundleName); + } + + if (path.find(g_userId) != std::string::npos) { + path = SandboxCommon::ReplaceAllVariables(path, g_userId, std::to_string(dacInfo->uid / UID_BASE)); + } + + if (path.find(g_hostUserId) != std::string::npos) { + path = ReplaceHostUserId(appProperty, path); + } + + if (path.find(g_variablePackageName) != std::string::npos) { + path = ReplaceVariablePackageName(appProperty, path); + } + + if (path.find(g_clonePackageName) != std::string::npos) { + path = ReplaceClonePackageName(appProperty, path); + } + + if (path.find(g_arkWebPackageName) != std::string::npos) { + path = SandboxCommon::ReplaceAllVariables(path, g_arkWebPackageName, getArkWebPackageName()); + APPSPAWN_LOGV( + "arkWeb sandbox, path %{public}s, package:%{public}s", + path.c_str(), getArkWebPackageName().c_str()); + } + + return path; +} + +// 挂载操作 +int32_t 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 { + CreateDirRecursive(arg->destPath, 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 < 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)) { + CheckDirRecursive(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/sandbox_common.h b/modules/sandbox/sandbox_common.h new file mode 100644 index 00000000..365393c5 --- /dev/null +++ b/modules/sandbox/sandbox_common.h @@ -0,0 +1,103 @@ +/* + * 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 "sandbox_def.h" +#include "appspawn_msg.h" +#include "appspawn_server.h" +#include "appspawn_manager.h" +#include "sandbox_shared_mount.h" + +namespace OHOS { +namespace AppSpawn { + +class SandboxCommon { +// 挂载选项 +typedef struct SandboxMountConfig { + unsigned long mountFlags; + std::string optionsPoint; + std::string fsType; + std::string sandboxPath; + std::vector decPaths; +} SandboxMountConfig; + +public: + // 加载配置文件 + static uint32_t GetSandboxNsFlags(bool isNweb); + static bool AppSandboxPidNsIsSupport(void); + static int LoadAppSandboxConfig(AppSpawnMgr *content); + static bool GetJsonObjFromJson(nlohmann::json &jsonObj, const std::string &jsonPath); + static bool GetStringFromJson(const nlohmann::json &json, const std::string &key, std::string &value); + static void StoreJsonConfig(nlohmann::json &appSandboxConfig, SandboxConfigType type); + static std::vector &GetJsonConfig(SandboxConfigType type); + + // 获取应用信息 + static std::string GetExtraInfoByType(const AppSpawningCtx *appProperty, const std::string &type); + static std::string GetSandboxRootPath(const AppSpawningCtx *appProperty, nlohmann::json &config); // GetSbxPathByConfig + static bool NeedNetworkIsolated(AppSpawningCtx *property); + static uint32_t GetAppMsgFlags(const AppSpawningCtx *property); + static void UpdateMsgFlagsWithPermission(AppSpawningCtx *appProperty); + static int32_t UpdatePermissionFlags(AppSpawningCtx *appProperty); + + // 文件操作 + static void CreateDirRecursive(const std::string &path, mode_t mode); // MakeDirRecursive + static void CreateDirRecursiveWithClock(const std::string &path, mode_t mode); // MakeDirRecursiveWithClock + static bool VerifyDirRecursive(const std::string &path); // CheckDirRecursive + static void CreateFileIfNotExist(const char *file); // CheckAndCreatFile + static void SetSandboxPathChmod(nlohmann::json jsonConfig, std::string &sandboxRoot); // DoSandboxChmod + + // 获取挂载配置参数信息 + static unsigned long GetMountFlagsFromConfig(const std::vector &vec); + static bool IsDacOverrideEnabled(nlohmann::json &config); // GetSandboxDacOverrideEnable + static bool GetSwitchStatus(nlohmann::json &config); // GetSbxSwitchStatusByConfig + static uint32_t ConvertFlagStr(const std::string &flagStr); + static unsigned long GetMountFlags(nlohmann::json &config); // GetSandboxMountFlags + static std::string GetFsType(nlohmann::json &config); // GetSandboxFsType + static std::string GetOptions(const AppSpawningCtx *appProperty, nlohmann::json &config); // GetSandboxOptions + static std::vector GetDecPath(const AppSpawningCtx *appProperty, nlohmann::json &config); // GetSandboxDecPath + static bool IsCreateSandboxPathEnabled(nlohmann::json &json, std::string srcPath); // GetCreateSandboxPath + static bool IsTotalSandboxEnabled(const AppSpawningCtx *appProperty); // CheckTotalSandboxSwitchStatus + static bool IsAppSandboxEnabled(const AppSpawningCtx *appProperty); // CheckAppSandboxSwitchStatus + + // 校验操作 + static bool IsNeededCheckPathStatus(const AppSpawningCtx *appProperty, const char *path); + static void CheckMountStatus(const std::string &path); + static bool HasPrivateInBundleName(const std::string &bundleName); // CheckBundleNameForPrivate + static bool IsMountSuccessful(nlohmann::json &mntPoint); // GetCheckStatus + static int CheckBundleName(const std::string &bundleName); + static int32_t CheckAppFullMountEnable(); + static bool IsValidMountConfig(nlohmann::json &mntPoint, const AppSpawningCtx *appProperty, bool checkFlag); // CheckMountConfig + + // 路径处理 + static std::string ReplaceAllVariables(std::string str, const std::string& from, const std::string& to); // replace_all + static std::vector SplitString(const std::string &str, const std::string &delimiter); // split + static std::string ConvertToRealPath(const AppSpawningCtx *appProperty, std::string path); + + // 挂载操作 + static int32_t DoAppSandboxMountOnce(const AppSpawningCtx *appProperty, const SharedMountArgs *arg); + + static std::map> appSandboxConfig_; + static int32_t deviceTypeEnable_ = -1; +}; + +} // namespace AppSpawn +} // namespace OHOS + +#endif // SANDBOX_COMMON_H \ No newline at end of file diff --git a/modules/sandbox/sandbox_def.h b/modules/sandbox/sandbox_def.h new file mode 100644 index 00000000..72e977ee --- /dev/null +++ b/modules/sandbox/sandbox_def.h @@ -0,0 +1,132 @@ +// sandbox_def.h +#ifndef SANDBOX_DEF_H +#define SANDBOX_DEF_H + +#include + +namespace OHOS { +namespace AppSpawn { + +// 全局常量定义 +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"; + +/* 沙盒配置文件中关键字 */ +// 公共属性 +const char *g_sandboxRootPrefix = "sandbox-root"; +const char *g_sandBoxNsFlags = "sandbox-ns-flags"; +const char *g_topSandBoxSwitchPrefix = "top-sandbox-switch"; +const char *g_sandBoxSwitchPrefix = "sandbox-switch"; +const std::string g_ohosGpu = "__internal__.com.ohos.gpu"; +const std::string g_ohosRender = "__internal__.com.ohos.render"; +const char *g_commonPrefix = "common"; +const char *g_privatePrefix = "individual"; +const char *g_permissionPrefix = "permission"; +const char *g_appBase = "app-base"; +const char *g_appResources = "app-resources"; +const char *g_flagePoint = "flags-point"; +const std::string g_internal = "__internal__"; + +// 挂载目录字段 +const char *g_mountPrefix = "mount-paths"; +const char *g_srcPath = "src-path"; +const char *g_sandBoxPath = "sandbox-path"; +const char *g_sandBoxFlags = "sandbox-flags"; +const char *g_fsType = "fs-type"; +const char *g_sandBoxOptions = "options"; +const char *g_actionStatuc = "check-action-status"; + +// 挂载可选属性 +const char *g_sandBoxShared = "sandbox-shared"; +const char *g_mountSharedFlag = "mount-shared-flag"; +const char *g_dacOverrideSensitive = "dac-override-sensitive"; +const char *g_sandBoxFlagsCustomized = "sandbox-flags-customized"; +const char *g_appAplName = "app-apl-name"; +const char *g_sandBoxDecPath = "dec-paths"; +const char *CREATE_SANDBOX_PATH = "create-sandbox-path"; + +// link目录字段 +const char *g_symlinkPrefix = "symbol-links"; +const char *g_targetName = "target-name"; +const char *g_linkName = "link-name"; + +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"; + +/* 分割符 */ +const char* g_fileSeparator = "/"; +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 AppSpawn +} // namespace OHOS + +#endif // SANDBOX_DEF_H \ No newline at end of file diff --git a/modules/sandbox/sandbox_manager.cpp b/modules/sandbox/sandbox_manager.cpp new file mode 100644 index 00000000..a8e01a6b --- /dev/null +++ b/modules/sandbox/sandbox_manager.cpp @@ -0,0 +1,1087 @@ +/* + * 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_manager.h" + +#include +#include +#include +#include "appspawn_hook.h" +#include "appspawn_manager.h" +#include "appspawn_utils.h" +#include "sandbox_def.h" +#include "sandbox_common.h" + +namespace OHOS { +namespace AppSpawn { +int32_t SandboxManager::DoDlpAppMountStrategy(const AppSpawningCtx *appProperty, const std::string &srcPath, + const std::string &sandboxPath, const std::string &fsType, unsigned long mountFlags) +{ + AppSpawnMsgDacInfo *dacInfo = reinterpret_cast(GetAppProperty(appProperty, TLV_DAC_INFO)); + if (dacInfo == nullptr) { + return -1; + } + + // umount fuse path, make sure that sandbox path is not a mount point + umount2(sandboxPath.c_str(), MNT_DETACH); + + int fd = open("/dev/fuse", O_RDWR); + APPSPAWN_CHECK(fd != -1, return -EINVAL, "open /dev/fuse failed, errno is %{public}d", errno); + + char options[OPTIONS_MAX_LEN]; + (void)sprintf_s(options, sizeof(options), "fd=%d," + "rootmode=40000,user_id=%u,group_id=%u,allow_other," + "context=\"u:object_r:dlp_fuse_file:s0\"," + "fscontext=u:object_r:dlp_fuse_file:s0", + fd, dacInfo->uid, dacInfo->gid); + + // To make sure destinationPath exist + MakeDirRecursive(sandboxPath, FILE_MODE); + + int ret = 0; +#ifndef APPSPAWN_TEST + APPSPAWN_LOGV("Bind mount %{public}s to %{public}s '%{public}s' '%{public}lu' '%{public}s'", + srcPath.c_str(), sandboxPath.c_str(), fsType.c_str(), mountFlags, options); + ret = mount(srcPath.c_str(), sandboxPath.c_str(), fsType.c_str(), mountFlags, options); + APPSPAWN_CHECK(ret == 0, close(fd); + return ret, "DoDlpAppMountStrategy failed, bind mount %{public}s to %{public}s failed %{public}d", + srcPath.c_str(), sandboxPath.c_str(), errno); + + ret = mount(nullptr, sandboxPath.c_str(), nullptr, MS_SHARED, nullptr); + APPSPAWN_CHECK(ret == 0, close(fd); + return ret, "errno is: %{public}d, private mount to %{public}s failed", errno, sandboxPath.c_str()); +#endif + /* set DLP_FUSE_FD */ +#ifdef WITH_DLP + SetDlpFuseFd(fd); +#endif + ret = fd; + return ret; +} + +int32_t SandboxManager::HandleSpecialAppMount(const AppSpawningCtx *appProperty, const std::string &srcPath, + const std::string &sandboxPath, const std::string &fsType, unsigned long mountFlags) +{ + std::string bundleName = GetBundleName(appProperty); + std::string processName = GetProcessName(appProperty); + /* dlp application mount strategy */ + /* dlp is an example, we should change to real bundle name later */ + if (bundleName.find(g_dlpBundleName) != std::string::npos && + processName.compare(g_dlpBundleName) == 0) { + if (!fsType.empty()) { + return DoDlpAppMountStrategy(appProperty, srcPath, sandboxPath, fsType, mountFlags); + } + } + return -1; +} + +int32_t SandboxManager::SetDecWithDir(const AppSpawningCtx *appProperty, uint32_t userId) +{ + AppSpawnMsgAccessToken *tokenInfo = + reinterpret_cast(GetAppProperty(appProperty, TLV_ACCESS_TOKEN_INFO)); + APPSPAWN_CHECK(tokenInfo != NULL, return APPSPAWN_MSG_INVALID, "Get token id failed."); + + AppSpawnMsgBundleInfo *bundleInfo = + reinterpret_cast(GetAppProperty(appProperty, TLV_BUNDLE_INFO)); + APPSPAWN_CHECK(bundleInfo != NULL, return APPSPAWN_MSG_INVALID, "No bundle info in msg %{public}s", + GetBundleName(appProperty)); + + 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; + } + std::ostringstream clonePackageName; + if (flags == 1) { + clonePackageName << "+clone-" << bundleInfo->bundleIndex << "+" << bundleInfo->bundleName; + } else { + clonePackageName << bundleInfo->bundleName; + } + std::string dir = "/storage/Users/currentUser/Download/" + clonePackageName.str(); + DecPolicyInfo decPolicyInfo = {0}; + decPolicyInfo.pathNum = 1; + PathInfo pathInfo = {0}; + pathInfo.path = strdup(dir.c_str()); + if (pathInfo.path == nullptr) { + APPSPAWN_LOGE("strdup %{public}s failed, err %{public}d", dir.c_str(), errno); + return APPSPAWN_MSG_INVALID; + } + pathInfo.pathLen = static_cast(strlen(pathInfo.path)); + pathInfo.mode = SANDBOX_MODE_WRITE | SANDBOX_MODE_READ; + decPolicyInfo.path[0] = pathInfo; + decPolicyInfo.tokenId = tokenInfo->accessTokenIdEx; + decPolicyInfo.flag = true; + SetDecPolicyInfos(&decPolicyInfo); + + if (decPolicyInfo.path[0].path) { + free(decPolicyInfo.path[0].path); + decPolicyInfo.path[0].path = nullptr; + } + return 0; +} + +int32_t SandboxManager::SetDecPolicyWithPermission(const AppSpawningCtx *appProperty, SandboxMountConfig &mountConfig) +{ + if (mountConfig.decPaths.size() == 0) { + return 0; + } + AppSpawnMsgAccessToken *tokenInfo = + reinterpret_cast(GetAppProperty(appProperty, TLV_ACCESS_TOKEN_INFO)); + APPSPAWN_CHECK(tokenInfo != NULL, return APPSPAWN_MSG_INVALID, "Get token id failed."); + + DecPolicyInfo decPolicyInfo = {0}; + decPolicyInfo.pathNum = mountConfig.decPaths.size(); + int ret = 0; + for (uint32_t i = 0; i < decPolicyInfo.pathNum; i++) { + PathInfo pathInfo = {0}; + pathInfo.path = strdup(mountConfig.decPaths[i].c_str()); + if (pathInfo.path == nullptr) { + APPSPAWN_LOGE("strdup %{public}s failed, err %{public}d", mountConfig.decPaths[i].c_str(), errno); + ret = APPSPAWN_ERROR_UTILS_MEM_FAIL; + goto EXIT; + } + pathInfo.pathLen = static_cast(strlen(pathInfo.path)); + pathInfo.mode = SANDBOX_MODE_WRITE | SANDBOX_MODE_READ; + decPolicyInfo.path[i] = pathInfo; + } + decPolicyInfo.tokenId = tokenInfo->accessTokenIdEx; + decPolicyInfo.flag = true; + SetDecPolicyInfos(&decPolicyInfo); +EXIT: + for (uint32_t i = 0; i < decPolicyInfo.pathNum; i++) { + if (decPolicyInfo.path[i].path) { + free(decPolicyInfo.path[i].path); + decPolicyInfo.path[i].path = nullptr; + } + } + return ret; +} + +void SandboxManager::SetDecDenyWithDir(const AppSpawningCtx *appProperty) +{ + int32_t userFileIndex = GetPermissionIndex(nullptr, READ_WRITE_USER_FILE_MODE.c_str()); + if (CheckAppPermissionFlagSet(appProperty, static_cast(userFileIndex)) == 0) { + APPSPAWN_LOGV("The app doesn't have %{public}s, no need to set deny rules", READ_WRITE_USER_FILE_MODE.c_str()); + return; + } + + AppSpawnMsgAccessToken *tokenInfo = + reinterpret_cast(GetAppProperty(appProperty, TLV_ACCESS_TOKEN_INFO)); + APPSPAWN_CHECK(tokenInfo != NULL, return, "Get token id failed"); + + DecPolicyInfo decPolicyInfo = {0}; + decPolicyInfo.pathNum = 0; + uint32_t count = ARRAY_LENGTH(DEC_DENY_PATH_MAP); + for (uint32_t i = 0, j = 0; i < count; i++) { + int32_t index = GetPermissionIndex(nullptr, DEC_DENY_PATH_MAP[i].permission); + if (CheckAppPermissionFlagSet(appProperty, static_cast(index))) { + continue; + } + PathInfo pathInfo = {0}; + pathInfo.path = const_cast(DEC_DENY_PATH_MAP[i].decPath); + pathInfo.pathLen = static_cast(strlen(pathInfo.path)); + pathInfo.mode = DEC_MODE_DENY_READ | DEC_MODE_DENY_WRITE; + decPolicyInfo.path[j++] = pathInfo; + decPolicyInfo.pathNum += 1; + } + decPolicyInfo.tokenId = tokenInfo->accessTokenIdEx; + decPolicyInfo.flag = true; + SetDecPolicyInfos(&decPolicyInfo); +} + +int SandboxManager::DoAllMntPointsMount(const AppSpawningCtx *appProperty, nlohmann::json &appConfig, + const char *typeName, const std::string §ion) +{ + std::string bundleName = GetBundleName(appProperty); + if (appConfig.find(g_mountPrefix) == appConfig.end()) { + APPSPAWN_LOGV("mount config is not found in %{public}s, app name is %{public}s", + section.c_str(), bundleName.c_str()); + return 0; + } + std::string sandboxRoot = GetSbxPathByConfig(appProperty, appConfig); + bool checkFlag = CheckMountFlag(appProperty, bundleName, appConfig); + nlohmann::json& mountPoints = appConfig[g_mountPrefix]; + unsigned int mountPointSize = mountPoints.size(); + for (unsigned int i = 0; i < mountPointSize; i++) { + nlohmann::json& mntPoint = mountPoints[i]; + APPSPAWN_CHECK_ONLY_EXPER(CheckMountConfig(mntPoint, appProperty, checkFlag), continue); + + std::string srcPath = ConvertToRealPath(appProperty, mntPoint[g_srcPath].get()); + APPSPAWN_CHECK_ONLY_EXPER(GetCreateSandboxPath(mntPoint, srcPath), continue); + std::string sandboxPath = GetSandboxPath(appProperty, mntPoint, section, sandboxRoot); + SandboxMountConfig mountConfig = {0}; + GetSandboxMountConfig(appProperty, section, mntPoint, mountConfig); + SharedMountArgs arg = { + .srcPath = srcPath.c_str(), + .destPath = sandboxPath.c_str(), + .fsType = mountConfig.fsType.c_str(), + .mountFlags = GetSandboxMountFlags(mntPoint), + .options = mountConfig.optionsPoint.c_str(), + .mountSharedFlag = (mntPoint.find(g_mountSharedFlag) != mntPoint.end()) ? MS_SHARED : MS_SLAVE + }; + + /* if app mount failed for special strategy, we need deal with common mount config */ + int ret = HandleSpecialAppMount(appProperty, arg.srcPath, arg.destPath, arg.fsType, arg.mountFlags); + if (ret < 0) { + ret = DoAppSandboxMountOnce(appProperty, &arg); + } + APPSPAWN_CHECK(ret == 0 || !GetCheckStatus(mntPoint), +#ifdef APPSPAWN_HISYSEVENT + ReportMountFail(bundleName.c_str(), arg.srcPath, arg.destPath, errno); + ret = APPSPAWN_SANDBOX_MOUNT_FAIL; +#endif + return ret, + "DoAppSandboxMountOnce section %{public}s failed, %{public}s", section.c_str(), arg.destPath); + SetDecPolicyWithPermission(appProperty, mountConfig); + DoSandboxChmod(mntPoint, sandboxRoot); + } + return 0; +} + +int32_t SandboxManager::DoAddGid(AppSpawningCtx *appProperty, nlohmann::json &appConfig, + const char* permissionName, const std::string §ion) +{ + std::string bundleName = GetBundleName(appProperty); + if (appConfig.find(g_gidPrefix) == appConfig.end()) { + return 0; + } + AppSpawnMsgDacInfo *dacInfo = reinterpret_cast(GetAppProperty(appProperty, TLV_DAC_INFO)); + if (dacInfo == nullptr) { + return 0; + } + + nlohmann::json& gids = appConfig[g_gidPrefix]; + unsigned int gidSize = gids.size(); + for (unsigned int i = 0; i < gidSize; i++) { + if (dacInfo->gidCount < APP_MAX_GIDS) { + APPSPAWN_LOGI("add gid to gitTable in %{public}s, permission is %{public}s, gid:%{public}u", + bundleName.c_str(), permissionName, gids[i].get()); + dacInfo->gidTable[dacInfo->gidCount++] = gids[i].get(); + } + } + return 0; +} + +int SandboxManager::DoAllSymlinkPointslink(const AppSpawningCtx *appProperty, nlohmann::json &appConfig) +{ + APPSPAWN_CHECK(appConfig.find(g_symlinkPrefix) != appConfig.end(), return 0, "symlink config is not found," + "maybe result sandbox launch failed app name is %{public}s", GetBundleName(appProperty)); + + nlohmann::json& symlinkPoints = appConfig[g_symlinkPrefix]; + std::string sandboxRoot = GetSbxPathByConfig(appProperty, appConfig); + unsigned int symlinkPointSize = symlinkPoints.size(); + + for (unsigned int i = 0; i < symlinkPointSize; i++) { + nlohmann::json& symPoint = symlinkPoints[i]; + + // Check the validity of the symlink configuration + if (symPoint.find(g_targetName) == symPoint.end() || (!symPoint[g_targetName].is_string()) || + symPoint.find(g_linkName) == symPoint.end() || (!symPoint[g_linkName].is_string())) { + APPSPAWN_LOGE("read symlink config failed, app name is %{public}s", GetBundleName(appProperty)); + continue; + } + + std::string targetName = ConvertToRealPath(appProperty, symPoint[g_targetName].get()); + std::string linkName = sandboxRoot + ConvertToRealPath(appProperty, symPoint[g_linkName].get()); + APPSPAWN_LOGV("symlink, from %{public}s to %{public}s", targetName.c_str(), linkName.c_str()); + + int ret = symlink(targetName.c_str(), linkName.c_str()); + if (ret && errno != EEXIST) { + APPSPAWN_LOGE("errno is %{public}d, symlink failed, %{public}s", errno, linkName.c_str()); + + std::string actionStatus = g_statusCheck; + (void)SandboxCommon::GetStringFromJson(symPoint, g_actionStatuc, actionStatus); + if (actionStatus == g_statusCheck) { + return ret; + } + } + + SetSandboxPathChmod(symPoint, sandboxRoot); + } + + return 0; +} + +int32_t SandboxManager::DoSandboxFilePrivateBind(const AppSpawningCtx *appProperty, nlohmann::json &wholeConfig) +{ + const char *bundleName = GetBundleName(appProperty); + nlohmann::json& privateAppConfig = wholeConfig[g_privatePrefix][0]; + if (privateAppConfig.find(bundleName) != privateAppConfig.end()) { + APPSPAWN_LOGV("DoSandboxFilePrivateBind %{public}s", bundleName); + DoAddGid((AppSpawningCtx *)appProperty, privateAppConfig[bundleName][0], "", g_privatePrefix); + return DoAllMntPointsMount(appProperty, privateAppConfig[bundleName][0], nullptr, g_privatePrefix); + } + + return 0; +} + +int32_t DoSandboxFilePermissionBind(AppSpawningCtx *appProperty, nlohmann::json &wholeConfig) +{ + if (wholeConfig.find(g_permissionPrefix) == wholeConfig.end()) { + APPSPAWN_LOGV("DoSandboxFilePermissionBind not found permission information in config file"); + return 0; + } + nlohmann::json& permissionAppConfig = wholeConfig[g_permissionPrefix][0]; + for (nlohmann::json::iterator it = permissionAppConfig.begin(); it != permissionAppConfig.end(); ++it) { + const std::string permission = it.key(); + int index = GetPermissionIndex(nullptr, permission.c_str()); + APPSPAWN_LOGV("DoSandboxFilePermissionBind mountPermissionFlags %{public}d", index); + if (CheckAppPermissionFlagSet(appProperty, static_cast(index))) { + DoAddGid(appProperty, permissionAppConfig[permission][0], permission.c_str(), g_permissionPrefix); + DoAllMntPointsMount(appProperty, permissionAppConfig[permission][0], permission.c_str(), + g_permissionPrefix); + } else { + APPSPAWN_LOGV("DoSandboxFilePermissionBind false %{public}s permission %{public}s", + GetBundleName(appProperty), permission.c_str()); + } + } + return 0; +} + +int32_t SandboxManager::DoSandboxFilePrivateSymlink(const AppSpawningCtx *appProperty, nlohmann::json &wholeConfig) +{ + const char *bundleName = GetBundleName(appProperty); + nlohmann::json& privateAppConfig = wholeConfig[g_privatePrefix][0]; + if (privateAppConfig.find(bundleName) != privateAppConfig.end()) { + return DoAllSymlinkPointslink(appProperty, privateAppConfig[bundleName][0]); + } + + return 0; +} + +int32_t SandboxManager::HandleFlagsPoint(const AppSpawningCtx *appProperty, nlohmann::json &wholeConfig) +{ + if (appConfig.find(g_flagePoint) == appConfig.end()) { + return 0; + } + + nlohmann::json& flagsPoints = appConfig[g_flagePoint]; + unsigned int flagsPointSize = flagsPoints.size(); + + for (unsigned int i = 0; i < flagsPointSize; i++) { + nlohmann::json& flagPoint = flagsPoints[i]; + + if (flagPoint.find(g_flags) != flagPoint.end() && flagPoint[g_flags].is_string()) { + std::string flagsStr = flagPoint[g_flags].get(); + uint32_t flag = ConvertFlagStr(flagsStr); + if ((GetAppMsgFlags(appProperty) & flag) == 0) { + continue; + } + int ret = DoAllMntPointsMount(appProperty, flagPoint, nullptr, g_flagePoint); + if (ret != 0) { + APPSPAWN_LOGE("DoAllMntPointsMount failed ret: %{public}d", ret); + } + } else { + APPSPAWN_LOGE("read flags config failed, app name is %{public}s", GetBundleName(appProperty)); + } + } + + return 0; +} + +int32_t SandboxManager::DoSandboxFilePrivateFlagsPointHandle(const AppSpawningCtx *appProperty, + nlohmann::json &wholeConfig) +{ + const char *bundleName = GetBundleName(appProperty); + nlohmann::json& privateAppConfig = wholeConfig[g_privatePrefix][0]; + if (privateAppConfig.find(bundleName) != privateAppConfig.end()) { + return HandleFlagsPoint(appProperty, privateAppConfig[bundleName][0]); + } + + return 0; +} + +int32_t SandboxManager::DoSandboxFileCommonFlagsPointHandle(const AppSpawningCtx *appProperty, nlohmann::json &wholeConfig) +{ + nlohmann::json& commonConfig = wholeConfig[g_commonPrefix][0]; + if (commonConfig.find(g_appResources) != commonConfig.end()) { + return HandleFlagsPoint(appProperty, commonConfig[g_appResources][0]); + } + + return 0; +} + +int32_t SandboxManager::DoSandboxFileCommonBind(const AppSpawningCtx *appProperty, nlohmann::json &wholeConfig) +{ + nlohmann::json& commonConfig = wholeConfig[g_commonPrefix][0]; + int ret = 0; + + if (commonConfig.find(g_appBase) != commonConfig.end()) { + ret = DoAllMntPointsMount(appProperty, commonConfig[g_appBase][0], nullptr, g_appBase); + if (ret) { + return ret; + } + } + + if (commonConfig.find(g_appResources) != commonConfig.end()) { + ret = DoAllMntPointsMount(appProperty, commonConfig[g_appResources][0], nullptr, g_appResources); + } + + return ret; +} + +int32_t SandboxManager::DoSandboxFileCommonSymlink(const AppSpawningCtx *appProperty, nlohmann::json &wholeConfig) +{ + nlohmann::json& commonConfig = wholeConfig[g_commonPrefix][0]; + int ret = 0; + + if (commonConfig.find(g_appBase) != commonConfig.end()) { + ret = DoAllSymlinkPointslink(appProperty, commonConfig[g_appBase][0]); + if (ret) { + return ret; + } + } + + if (commonConfig.find(g_appResources) != commonConfig.end()) { + ret = DoAllSymlinkPointslink(appProperty, commonConfig[g_appResources][0]); + } + + return ret; +} + +int32_t SandboxManager::SetPrivateAppSandboxProperty_(const AppSpawningCtx *appProperty, nlohmann::json &config) +{ + int ret = DoSandboxFilePrivateBind(appProperty, config); + APPSPAWN_CHECK(ret == 0, return ret, "DoSandboxFilePrivateBind failed"); + + ret = DoSandboxFilePrivateSymlink(appProperty, config); + APPSPAWN_CHECK_ONLY_LOG(ret == 0, "DoSandboxFilePrivateSymlink failed"); + + ret = DoSandboxFilePrivateFlagsPointHandle(appProperty, config); + APPSPAWN_CHECK_ONLY_LOG(ret == 0, "DoSandboxFilePrivateFlagsPointHandle failed"); + + return ret; +} + +int32_t SandboxManager::SetPermissionAppSandboxProperty_(AppSpawningCtx *appProperty, nlohmann::json &config) +{ + int ret = DoSandboxFilePermissionBind(appProperty, config); + APPSPAWN_CHECK(ret == 0, return ret, "DoSandboxFilePermissionBind failed"); + return ret; +} + +int32_t SandboxManager::SetRenderSandboxPropertyNweb(const AppSpawningCtx *appProperty, std::string &sandboxPackagePath) +{ + SandboxConfigType type = CheckAppMsgFlagsSet(appProperty, APP_FLAGS_ISOLATED_SANDBOX_TYPE) ? + SANBOX_ISOLATED_JSON_CONFIG : SANBOX_APP_JSON_CONFIG; + + for (auto& config : SandboxUtils::GetJsonConfig(type)) { + nlohmann::json& privateAppConfig = config[g_privatePrefix][0]; + char *processType = (char *)(GetAppSpawnMsgExtInfo(appProperty->message, MSG_EXT_NAME_PROCESS_TYPE, NULL)); + APPSPAWN_CHECK(processType != NULL, return -1, "Invalid processType data"); + + if (strcmp(processType, "render") == 0 && privateAppConfig.find(g_ohosRender) != privateAppConfig.end()) { + int ret = DoAllMntPointsMount(appProperty, privateAppConfig[g_ohosRender][0], nullptr, g_ohosRender); + APPSPAWN_CHECK(ret == 0, return ret, "DoAllMntPointsMount failed, %{public}s", + GetBundleName(appProperty)); + ret = DoAllSymlinkPointslink(appProperty, privateAppConfig[g_ohosRender][0]); + APPSPAWN_CHECK(ret == 0, return ret, "DoAllSymlinkPointslink failed, %{public}s", + GetBundleName(appProperty)); + ret = HandleFlagsPoint(appProperty, privateAppConfig[g_ohosRender][0]); + APPSPAWN_CHECK_ONLY_LOG(ret == 0, "HandleFlagsPoint for render-sandbox failed, %{public}s", + GetBundleName(appProperty)); + } else if (strcmp(processType, "gpu") == 0 && privateAppConfig.find(g_ohosGpu) != privateAppConfig.end()) { + int ret = DoAllMntPointsMount(appProperty, privateAppConfig[g_ohosGpu][0], nullptr, g_ohosGpu); + APPSPAWN_CHECK(ret == 0, return ret, "DoAllMntPointsMount failed, %{public}s", + GetBundleName(appProperty)); + ret = DoAllSymlinkPointslink(appProperty, privateAppConfig[g_ohosGpu][0]); + APPSPAWN_CHECK(ret == 0, return ret, "DoAllSymlinkPointslink failed, %{public}s", + GetBundleName(appProperty)); + ret = HandleFlagsPoint(appProperty, privateAppConfig[g_ohosGpu][0]); + APPSPAWN_CHECK_ONLY_LOG(ret == 0, "HandleFlagsPoint for render-sandbox failed, %{public}s", + GetBundleName(appProperty)); + } + } + return 0; +} + +int32_t SandboxManager::SetPrivateAppSandboxProperty(const AppSpawningCtx *appProperty) +{ + int ret = 0; + SandboxConfigType type = CheckAppMsgFlagsSet(appProperty, APP_FLAGS_ISOLATED_SANDBOX_TYPE) ? + SANBOX_ISOLATED_JSON_CONFIG : SANBOX_APP_JSON_CONFIG; + + for (auto& config : SandboxUtils::GetJsonConfig(type)) { + ret = SetPrivateAppSandboxProperty_(appProperty, config); + APPSPAWN_CHECK(ret == 0, return ret, "parse adddata-sandbox config failed"); + } + return ret; +} + +bool SandboxManager::GetSandboxPrivateSharedStatus(const string &bundleName, AppSpawningCtx *appProperty) +{ + bool result = false; + SandboxConfigType type = CheckAppMsgFlagsSet(appProperty, APP_FLAGS_ISOLATED_SANDBOX_TYPE) ? + SANBOX_ISOLATED_JSON_CONFIG : SANBOX_APP_JSON_CONFIG; + + for (auto& config : SandboxUtils::GetJsonConfig(type)) { + nlohmann::json& privateAppConfig = config[g_privatePrefix][0]; + if (privateAppConfig.find(bundleName) != privateAppConfig.end() && + privateAppConfig[bundleName][0].find(g_sandBoxShared) != + privateAppConfig[bundleName][0].end()) { + string sandboxSharedStatus = + privateAppConfig[bundleName][0][g_sandBoxShared].get(); + if (sandboxSharedStatus == g_statusCheck) { + result = true; + } + } + } + return result; +} + +int32_t SandboxManager::SetPermissionAppSandboxProperty(AppSpawningCtx *appProperty) +{ + int ret = 0; + SandboxConfigType type = CheckAppMsgFlagsSet(appProperty, APP_FLAGS_ISOLATED_SANDBOX_TYPE) ? + SANBOX_ISOLATED_JSON_CONFIG : SANBOX_APP_JSON_CONFIG; + + for (auto& config : SandboxUtils::GetJsonConfig(type)) { + ret = SetPermissionAppSandboxProperty_(appProperty, config); + APPSPAWN_CHECK(ret == 0, return ret, "parse adddata-sandbox config failed"); + } + return ret; +} + +int32_t SandboxManager::SetCommonAppSandboxProperty_(const AppSpawningCtx *appProperty, nlohmann::json &config) +{ + int rc = 0; + rc = DoSandboxFileCommonBind(appProperty, config); + APPSPAWN_CHECK(rc == 0, return rc, "DoSandboxFileCommonBind failed, %{public}s", GetBundleName(appProperty)); + + // if sandbox switch is off, don't do symlink work again + if (CheckAppSandboxSwitchStatus(appProperty) == true && (CheckTotalSandboxSwitchStatus(appProperty) == true)) { + rc = DoSandboxFileCommonSymlink(appProperty, config); + APPSPAWN_CHECK(rc == 0, return rc, "DoSandboxFileCommonSymlink failed, %{public}s", GetBundleName(appProperty)); + } + + rc = DoSandboxFileCommonFlagsPointHandle(appProperty, config); + APPSPAWN_CHECK_ONLY_LOG(rc == 0, "DoSandboxFilePrivateFlagsPointHandle failed"); + + return rc; +} + +int32_t SandboxManager::SetCommonAppSandboxProperty(const AppSpawningCtx *appProperty, std::string &sandboxPackagePath) +{ + int ret = 0; + SandboxConfigType type = CheckAppMsgFlagsSet(appProperty, APP_FLAGS_ISOLATED_SANDBOX_TYPE) ? + SANBOX_ISOLATED_JSON_CONFIG : SANBOX_APP_JSON_CONFIG; + + for (auto& jsonConfig : SandboxUtils::GetJsonConfig(type)) { + ret = SetCommonAppSandboxProperty_(appProperty, jsonConfig); + APPSPAWN_CHECK(ret == 0, return ret, + "parse appdata config for common failed, %{public}s", sandboxPackagePath.c_str()); + } + + ret = MountAllHsp(appProperty, sandboxPackagePath); + APPSPAWN_CHECK(ret == 0, return ret, "mount extraInfo failed, %{public}s", sandboxPackagePath.c_str()); + + ret = MountAllGroup(appProperty, sandboxPackagePath); + APPSPAWN_CHECK(ret == 0, return ret, "mount groupList failed, %{public}s", sandboxPackagePath.c_str()); + + AppSpawnMsgDomainInfo *info = + reinterpret_cast(GetAppProperty(appProperty, TLV_DOMAIN_INFO)); + APPSPAWN_CHECK(info != nullptr, return -1, "No domain info %{public}s", sandboxPackagePath.c_str()); + if (strcmp(info->apl, APL_SYSTEM_BASIC.data()) == 0 || strcmp(info->apl, APL_SYSTEM_CORE.data()) == 0 || + CheckAppMsgFlagsSet(appProperty, APP_FLAGS_ACCESS_BUNDLE_DIR)) { + // need permission check for system app here + std::string destbundlesPath = sandboxPackagePath + g_dataBundles; + SharedMountArgs arg = { + .srcPath = g_physicalAppInstallPath.c_str(), + .destPath = destbundlesPath.c_str() + }; + DoAppSandboxMountOnce(appProperty, &arg); + } + + return 0; +} + +int32_t SandboxManager::MountAllHsp(const AppSpawningCtx *appProperty, std::string &sandboxPackagePath) +{ + int ret = 0; + string hspListInfo = GetExtraInfoByType(appProperty, HSPLIST_SOCKET_TYPE); + if (hspListInfo.length() == 0) { + return ret; + } + + nlohmann::json hsps = nlohmann::json::parse(hspListInfo.c_str(), nullptr, false); + APPSPAWN_CHECK(!hsps.is_discarded() && hsps.contains(g_hspList_key_bundles) && hsps.contains(g_hspList_key_modules) + && hsps.contains(g_hspList_key_versions), return -1, "MountAllHsp: json parse failed"); + + nlohmann::json& bundles = hsps[g_hspList_key_bundles]; + nlohmann::json& modules = hsps[g_hspList_key_modules]; + nlohmann::json& versions = hsps[g_hspList_key_versions]; + APPSPAWN_CHECK(bundles.is_array() && modules.is_array() && versions.is_array() && bundles.size() == modules.size() + && bundles.size() == versions.size(), return -1, "MountAllHsp: value is not arrary or sizes are not same"); + + APPSPAWN_LOGV("MountAllHsp: app = %{public}s, cnt = %{public}lu", + GetBundleName(appProperty), static_cast(bundles.size())); + for (uint32_t i = 0; i < bundles.size(); i++) { + // elements in json arrary can be different type + APPSPAWN_CHECK(bundles[i].is_string() && modules[i].is_string() && versions[i].is_string(), + return -1, "MountAllHsp: element type error"); + + std::string libBundleName = bundles[i]; + std::string libModuleName = modules[i]; + std::string libVersion = versions[i]; + APPSPAWN_CHECK(CheckPath(libBundleName) && CheckPath(libModuleName) && CheckPath(libVersion), + return -1, "MountAllHsp: path error"); + + std::string libPhysicalPath = g_physicalAppInstallPath + libBundleName + "/" + libVersion + "/" + libModuleName; + std::string mntPath = sandboxPackagePath + g_sandboxHspInstallPath + libBundleName + "/" + libModuleName; + SharedMountArgs arg = { + .srcPath = libPhysicalPath.c_str(), + .destPath = mntPath.c_str() + }; + ret = DoAppSandboxMountOnce(appProperty, &arg); + APPSPAWN_CHECK(ret == 0, return ret, "mount library failed %{public}d", ret); + } + return ret; +} + +int32_t SandboxManager::DoSandboxRootFolderCreateAdapt(std::string &sandboxPackagePath) +{ +#ifndef APPSPAWN_TEST + int rc = mount(nullptr, "/", nullptr, MS_REC | MS_SLAVE, nullptr); + APPSPAWN_CHECK(rc == 0, return rc, "set propagation slave failed"); +#endif + MakeDirRecursive(sandboxPackagePath, FILE_MODE); + + // bind mount "/" to /mnt/sandbox// path + // rootfs: to do more resources bind mount here to get more strict resources constraints +#ifndef APPSPAWN_TEST + rc = mount("/", sandboxPackagePath.c_str(), nullptr, BASIC_MOUNT_FLAGS, nullptr); + APPSPAWN_CHECK(rc == 0, return rc, "mount bind / failed, %{public}d", errno); +#endif + return 0; +} + +int32_t SandboxManager::MountAllGroup(const AppSpawningCtx *appProperty, std::string &sandboxPackagePath) +{ + int ret = 0; + string dataGroupInfo = GetExtraInfoByType(appProperty, DATA_GROUP_SOCKET_TYPE); + if (dataGroupInfo.length() == 0) { + return ret; + } + + nlohmann::json groups = nlohmann::json::parse(dataGroupInfo.c_str(), nullptr, false); + if (groups.is_discarded() && groups.contains(g_groupList_key_dataGroupId) && groups.contains(g_groupList_key_dir) && + groups.contains(g_groupList_key_gid) && groups.contains(g_groupList_key_uuid)) { + APPSPAWN_LOGE("dataGroupJson is discarded"); + return APPSPAWN_ARG_INVALID; + } + + for (auto& item : groups) { + // elements in json arrary can be different type + APPSPAWN_CHECK(IsValidDataGroupItem(item), return -1, "MountAllGroup: data group item error"); + std::string srcPath = item[g_groupList_key_dir]; + APPSPAWN_CHECK(!CheckPath(srcPath), return -1, "MountAllGroup: path error"); + + int elxValue = GetElxInfoFromDir(srcPath.c_str()); + APPSPAWN_CHECK((elxValue >= EL2 && elxValue < ELX_MAX), return -1, "Get elx value failed"); + + const DataGroupSandboxPathTemplate *templateItem = GetDataGroupArgTemplate(elxValue); + APPSPAWN_CHECK(templateItem != nullptr, return -1, "Get data group arg template failed"); + + // If permission isn't null, need check permission flag + if (templateItem->permission != nullptr) { + int index = GetPermissionIndex(nullptr, templateItem->permission); + APPSPAWN_LOGV("mount dir no lock mount permission flag %{public}d", index); + if (CheckAppPermissionFlagSet(appProperty, static_cast(index)) == 0) { + continue; + } + } + + std::string dataGroupUuid = item[g_groupList_key_uuid]; + std::string mntPath = sandboxPackagePath + templateItem->sandboxPath + dataGroupUuid; + mode_t mountSharedFlag = MS_SLAVE; + if (CheckAppMsgFlagsSet(appProperty, APP_FLAGS_ISOLATED_SANDBOX)) { + mountSharedFlag |= MS_REMOUNT | MS_NODEV | MS_RDONLY | MS_BIND; + } + SharedMountArgs arg = { + .srcPath = srcPath.c_str(), + .destPath = mntPath.c_str(), + .mountSharedFlag = mountSharedFlag + }; + ret = DoAppSandboxMountOnce(appProperty, &arg); + if (ret != 0) { + APPSPAWN_LOGE("mount el%{public}d datagroup failed", elxValue); + } + } + return 0; +} + +int32_t SandboxManager::DoSandboxRootFolderCreate(const AppSpawningCtx *appProperty, std::string &sandboxPackagePath) +{ +#ifndef APPSPAWN_TEST + int rc = mount(nullptr, "/", nullptr, MS_REC | MS_SLAVE, nullptr); + if (rc) { + return rc; + } +#endif + SharedMountArgs arg = { + .srcPath = sandboxPackagePath.c_str(), + .destPath = sandboxPackagePath.c_str() + }; + DoAppSandboxMountOnce(appProperty, &arg); + + return 0; +} + +int32_t SandboxManager::SetOverlayAppSandboxProperty(const AppSpawningCtx *appProperty, std::string &sandboxPackagePath) +{ + int ret = 0; + if (!CheckAppMsgFlagsSet(appProperty, APP_FLAGS_OVERLAY)) { + return ret; + } + + string overlayInfo = GetExtraInfoByType(appProperty, OVERLAY_SOCKET_TYPE); + set mountedSrcSet; + vector splits = split(overlayInfo, g_overlayDecollator); + string sandboxOverlayPath = sandboxPackagePath + g_overlayPath; + for (auto hapPath : splits) { + size_t pathIndex = hapPath.find_last_of(g_fileSeparator); + if (pathIndex == string::npos) { + continue; + } + std::string srcPath = hapPath.substr(0, pathIndex); + if (mountedSrcSet.find(srcPath) != mountedSrcSet.end()) { + APPSPAWN_LOGV("%{public}s have mounted before, no need to mount twice.", srcPath.c_str()); + continue; + } + + auto bundleNameIndex = srcPath.find_last_of(g_fileSeparator); + string destPath = sandboxOverlayPath + srcPath.substr(bundleNameIndex + 1, srcPath.length()); + SharedMountArgs arg = { + .srcPath = srcPath.c_str(), + .destPath = destPath.c_str() + }; + int32_t retMount = DoAppSandboxMountOnce(appProperty, &arg); + if (retMount != 0) { + APPSPAWN_LOGE("fail to mount overlay path, src is %{public}s.", hapPath.c_str()); + ret = retMount; + } + + mountedSrcSet.emplace(srcPath); + } + return ret; +} + +int32_t SandboxManager::SetBundleResourceAppSandboxProperty(const AppSpawningCtx *appProperty, + std::string &sandboxPackagePath) +{ + if (!CheckAppMsgFlagsSet(appProperty, APP_FLAGS_BUNDLE_RESOURCES)) { + return 0; + } + + string destPath = sandboxPackagePath + g_bundleResourceDestPath; + SharedMountArgs arg = { + .srcPath = g_bundleResourceSrcPath.c_str(), + .destPath = destPath.c_str() + }; + return DoAppSandboxMountOnce(appProperty, &arg); +} + +int32_t SandboxManager::SetSandboxProperty(AppSpawningCtx *appProperty, std::string &sandboxPackagePath) +{ + int32_t ret = 0; + const std::string bundleName = GetBundleName(appProperty); + ret = SetCommonAppSandboxProperty(appProperty, sandboxPackagePath); + APPSPAWN_CHECK(ret == 0, return ret, "SetCommonAppSandboxProperty failed, packagename is %{public}s", + bundleName.c_str()); + if (CheckBundleNameForPrivate(bundleName)) { + ret = SetPrivateAppSandboxProperty(appProperty); + APPSPAWN_CHECK(ret == 0, return ret, "SetPrivateAppSandboxProperty failed, packagename is %{public}s", + bundleName.c_str()); + } + ret = SetPermissionAppSandboxProperty(appProperty); + APPSPAWN_CHECK(ret == 0, return ret, "SetPermissionAppSandboxProperty failed, packagename is %{public}s", + bundleName.c_str()); + + ret = SetOverlayAppSandboxProperty(appProperty, sandboxPackagePath); + APPSPAWN_CHECK(ret == 0, return ret, "SetOverlayAppSandboxProperty failed, packagename is %{public}s", + bundleName.c_str()); + + ret = SetBundleResourceAppSandboxProperty(appProperty, sandboxPackagePath); + APPSPAWN_CHECK(ret == 0, return ret, "SetBundleResourceAppSandboxProperty failed, packagename is %{public}s", + bundleName.c_str()); + APPSPAWN_LOGV("Set appsandbox property success"); + return ret; +} + +int32_t SandboxManager::ChangeCurrentDir(std::string &sandboxPackagePath, const std::string &bundleName, + bool sandboxSharedStatus) +{ + int32_t ret = 0; + ret = chdir(sandboxPackagePath.c_str()); + APPSPAWN_CHECK(ret == 0, return ret, "chdir failed, packagename is %{public}s, path is %{public}s", + bundleName.c_str(), sandboxPackagePath.c_str()); + + if (sandboxSharedStatus) { + ret = chroot(sandboxPackagePath.c_str()); + APPSPAWN_CHECK(ret == 0, return ret, "chroot failed, path is %{public}s errno is %{public}d", + sandboxPackagePath.c_str(), errno); + return ret; + } + + ret = syscall(SYS_pivot_root, sandboxPackagePath.c_str(), sandboxPackagePath.c_str()); + APPSPAWN_CHECK(ret == 0, return ret, "errno is %{public}d, pivot root failed, packagename is %{public}s", + errno, bundleName.c_str()); + + ret = umount2(".", MNT_DETACH); + APPSPAWN_CHECK(ret == 0, return ret, "MNT_DETACH failed, packagename is %{public}s", bundleName.c_str()); + return ret; +} + +int32_t SandboxManager::SetAppSandboxProperty(AppSpawningCtx *client, uint32_t sandboxNsFlags) +{ + APPSPAWN_CHECK(appProperty != nullptr, return -1, "Invalid appspwn client"); + if (CheckBundleName(GetBundleName(appProperty)) != 0) { + return -1; + } + AppSpawnMsgDacInfo *dacInfo = reinterpret_cast(GetAppProperty(appProperty, TLV_DAC_INFO)); + if (dacInfo == nullptr) { + return -1; + } + + const std::string bundleName = GetBundleName(appProperty); + nlohmann::json tmpJson = {}; + std::string sandboxPackagePath = GetSbxPathByConfig(appProperty, tmpJson); + MakeDirRecursiveWithClock(sandboxPackagePath.c_str(), FILE_MODE); + bool sandboxSharedStatus = GetSandboxPrivateSharedStatus(bundleName, appProperty) || + (CheckAppPermissionFlagSet(appProperty, static_cast(GetPermissionIndex(nullptr, + ACCESS_DLP_FILE_MODE.c_str()))) != 0); + + // add pid to a new mnt namespace + int rc = EnableSandboxNamespace(appProperty, sandboxNsFlags); + APPSPAWN_CHECK(rc == 0, return rc, "unshare failed, packagename is %{public}s", bundleName.c_str()); + if (UpdatePermissionFlags(appProperty) != 0) { + APPSPAWN_LOGW("Set app permission flag fail."); + return -1; + } + UpdateMsgFlagsWithPermission(appProperty); + // check app sandbox switch + if ((CheckTotalSandboxSwitchStatus(appProperty) == false) || + (CheckAppSandboxSwitchStatus(appProperty) == false)) { + rc = DoSandboxRootFolderCreateAdapt(sandboxPackagePath); + } else if (!sandboxSharedStatus) { + rc = DoSandboxRootFolderCreate(appProperty, sandboxPackagePath); + } + APPSPAWN_CHECK(rc == 0, return rc, "DoSandboxRootFolderCreate failed, %{public}s", bundleName.c_str()); + rc = SetSandboxProperty(appProperty, sandboxPackagePath); + APPSPAWN_CHECK(rc == 0, return rc, "SetSandboxProperty failed, %{public}s", bundleName.c_str()); + +#ifdef APPSPAWN_MOUNT_TMPSHM + MountDevShmPath(sandboxPackagePath); +#endif + +#ifndef APPSPAWN_TEST + rc = ChangeCurrentDir(sandboxPackagePath, bundleName, sandboxSharedStatus); + APPSPAWN_CHECK(rc == 0, return rc, "change current dir failed"); + APPSPAWN_LOGV("Change root dir success"); +#endif + SetDecWithDir(appProperty, dacInfo->uid / UID_BASE); + SetDecDenyWithDir(appProperty); + SetDecPolicy(); +#if defined(APPSPAWN_MOUNT_TMPSHM) && defined(WITH_SELINUX) + Restorecon(DEV_SHM_DIR); +#endif + return 0; +} + +int32_t SandboxManager::SetAppSandboxPropertyNweb(AppSpawningCtx *client, uint32_t sandboxNsFlags) +{ + APPSPAWN_CHECK(appProperty != nullptr, return -1, "Invalid appspwn client"); + if (CheckBundleName(GetBundleName(appProperty)) != 0) { + return -1; + } + std::string sandboxPackagePath = g_sandBoxRootDirNweb; + const std::string bundleName = GetBundleName(appProperty); + bool sandboxSharedStatus = GetSandboxPrivateSharedStatus(bundleName, appProperty); + sandboxPackagePath += bundleName; + MakeDirRecursiveWithClock(sandboxPackagePath.c_str(), FILE_MODE); + + // add pid to a new mnt namespace + int rc = EnableSandboxNamespace(appProperty, sandboxNsFlags); + APPSPAWN_CHECK(rc == 0, return rc, "unshare failed, packagename is %{public}s", bundleName.c_str()); + + // check app sandbox switch + if ((CheckTotalSandboxSwitchStatus(appProperty) == false) || + (CheckAppSandboxSwitchStatus(appProperty) == false)) { + rc = DoSandboxRootFolderCreateAdapt(sandboxPackagePath); + } else if (!sandboxSharedStatus) { + rc = DoSandboxRootFolderCreate(appProperty, sandboxPackagePath); + } + APPSPAWN_CHECK(rc == 0, return rc, "DoSandboxRootFolderCreate failed, %{public}s", bundleName.c_str()); + // rendering process can be created by different apps, + // and the bundle names of these apps are different, + // so we can't use the method SetPrivateAppSandboxProperty + // which mount dirs by using bundle name. + rc = SetRenderSandboxPropertyNweb(appProperty, sandboxPackagePath); + APPSPAWN_CHECK(rc == 0, return rc, "SetRenderSandboxPropertyNweb failed, packagename is %{public}s", + sandboxPackagePath.c_str()); + + rc = SetOverlayAppSandboxProperty(appProperty, sandboxPackagePath); + APPSPAWN_CHECK(rc == 0, return rc, "SetOverlayAppSandboxProperty failed, packagename is %{public}s", + bundleName.c_str()); + + rc = SetBundleResourceAppSandboxProperty(appProperty, sandboxPackagePath); + APPSPAWN_CHECK(rc == 0, return rc, "SetBundleResourceAppSandboxProperty failed, packagename is %{public}s", + bundleName.c_str()); + +#ifndef APPSPAWN_TEST + rc = chdir(sandboxPackagePath.c_str()); + APPSPAWN_CHECK(rc == 0, return rc, "chdir failed, packagename is %{public}s, path is %{public}s", + bundleName.c_str(), sandboxPackagePath.c_str()); + + if (sandboxSharedStatus) { + rc = chroot(sandboxPackagePath.c_str()); + APPSPAWN_CHECK(rc == 0, return rc, "chroot failed, path is %{public}s errno is %{public}d", + sandboxPackagePath.c_str(), errno); + return 0; + } + + rc = syscall(SYS_pivot_root, sandboxPackagePath.c_str(), sandboxPackagePath.c_str()); + APPSPAWN_CHECK(rc == 0, return rc, "errno is %{public}d, pivot root failed, packagename is %{public}s", + errno, bundleName.c_str()); + + rc = umount2(".", MNT_DETACH); + APPSPAWN_CHECK(rc == 0, return rc, "MNT_DETACH failed, packagename is %{public}s", bundleName.c_str()); +#endif + return 0; +} +} // namespace AppSpawn +} // namespace OHOS + +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 (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::SandboxUtils::SetAppSandboxPropertyNweb(property, sandboxNsFlags); + } else { + ret = OHOS::AppSpawn::SandboxUtils::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; +} + +#define USER_ID_SIZE 16 +#define DIR_MODE 0711 + +static int SpawnMountDirToShared(AppSpawnMgr *content, AppSpawningCtx *property) +{ +#ifndef APPSPAWN_SANDBOX_NEW + if (!IsNWebSpawnMode(content)) { + // mount dynamic directory + MountToShared(content, property); + } +#endif + return 0; +} + +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 != NULL, 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 != NULL && appInfo != NULL && 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; + 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, LoadAppSandboxConfig); + (void)AddAppSpawnHook(STAGE_PARENT_PRE_FORK, HOOK_PRIO_COMMON, SpawnMountDirToShared); + (void)AddAppSpawnHook(STAGE_CHILD_EXECUTE, HOOK_PRIO_SANDBOX, SetAppSandboxProperty); + (void)AddProcessMgrHook(STAGE_SERVER_APP_UMOUNT, HOOK_PRIO_SANDBOX, UmountSandboxPath); +} +#endif \ No newline at end of file diff --git a/modules/sandbox/sandbox_manager.h b/modules/sandbox/sandbox_manager.h new file mode 100644 index 00000000..cfc91c16 --- /dev/null +++ b/modules/sandbox/sandbox_manager.h @@ -0,0 +1,78 @@ +/* + * 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_MANAGER_H +#define SANDBOX_MANAGER_H + +#include +#include +#include +#include "sandbox_def.h" +#include "appspawn_msg.h" +#include "appspawn_server.h" +#include "appspawn_manager.h" +#include "sandbox_shared_mount.h" + +namespace OHOS { +namespace AppSpawn { + +class SandboxManager { +public: + static int32_t DoDlpAppMountStrategy(const AppSpawningCtx *appProperty, const std::string &srcPath, + const std::string &sandboxPath, const std::string &fsType, unsigned long mountFlags); + static int32_t HandleSpecialAppMount(const AppSpawningCtx *appProperty, const std::string &srcPath, + const std::string &sandboxPath, const std::string &fsType, unsigned long mountFlags); + static int32_t SetDecWithDir(const AppSpawningCtx *appProperty, uint32_t userId); + static int32_t SetDecPolicyWithPermission(const AppSpawningCtx *appProperty, SandboxMountConfig &mountConfig); + static void SetDecDenyWithDir(const AppSpawningCtx *appProperty); + static int DoAllMntPointsMount(const AppSpawningCtx *appProperty, nlohmann::json &appConfig, + const char *typeName, const std::string §ion = "app-base"); + static int32_t DoAddGid(AppSpawningCtx *appProperty, nlohmann::json &appConfig, + const char* permissionName, const std::string §ion); + static int DoAllSymlinkPointslink(const AppSpawningCtx *appProperty, nlohmann::json &appConfig); + static int32_t DoSandboxFilePrivateBind(const AppSpawningCtx *appProperty, nlohmann::json &wholeConfig); + static int32_t DoSandboxFilePermissionBind(AppSpawningCtx *appProperty, nlohmann::json &wholeConfig); + static int32_t DoSandboxFilePrivateSymlink(const AppSpawningCtx *appProperty, nlohmann::json &wholeConfig); + static int32_t HandleFlagsPoint(const AppSpawningCtx *appProperty, nlohmann::json &wholeConfig); + static int32_t DoSandboxFilePrivateFlagsPointHandle(const AppSpawningCtx *appProperty, nlohmann::json &wholeConfig); + static int32_t DoSandboxFileCommonFlagsPointHandle(const AppSpawningCtx *appProperty, nlohmann::json &wholeConfig); + static int32_t DoSandboxFileCommonBind(const AppSpawningCtx *appProperty, nlohmann::json &wholeConfig); + static int32_t DoSandboxFileCommonSymlink(const AppSpawningCtx *appProperty, nlohmann::json &wholeConfig); + static int32_t SetPrivateAppSandboxProperty_(const AppSpawningCtx *appProperty, nlohmann::json &config); + static int32_t SetPermissionAppSandboxProperty_(AppSpawningCtx *appProperty, nlohmann::json &config); + static int32_t SetRenderSandboxPropertyNweb(const AppSpawningCtx *appProperty, std::string &sandboxPackagePath); + static int32_t SetPrivateAppSandboxProperty(const AppSpawningCtx *appProperty); + static bool GetSandboxPrivateSharedStatus(const string &bundleName, AppSpawningCtx *appProperty); + static int32_t SetPermissionAppSandboxProperty(AppSpawningCtx *appProperty); + static int32_t SetCommonAppSandboxProperty_(const AppSpawningCtx *appProperty, nlohmann::json &config); + static int32_t SetCommonAppSandboxProperty(const AppSpawningCtx *appProperty, std::string &sandboxPackagePath); + static int32_t MountAllHsp(const AppSpawningCtx *appProperty, std::string &sandboxPackagePath); + static int32_t DoSandboxRootFolderCreateAdapt(std::string &sandboxPackagePath); + static int32_t MountAllGroup(const AppSpawningCtx *appProperty, std::string &sandboxPackagePath); + static int32_t DoSandboxRootFolderCreate(const AppSpawningCtx *appProperty, std::string &sandboxPackagePath); + static int32_t SetOverlayAppSandboxProperty(const AppSpawningCtx *appProperty, std::string &sandboxPackagePath); + static int32_t SetBundleResourceAppSandboxProperty(const AppSpawningCtx *appProperty, + std::string &sandboxPackagePath); + static int32_t SetSandboxProperty(AppSpawningCtx *appProperty, std::string &sandboxPackagePath); + static int32_t ChangeCurrentDir(std::string &sandboxPackagePath, const std::string &bundleName, + bool sandboxSharedStatus); + static int32_t SetAppSandboxProperty(AppSpawningCtx *client, uint32_t sandboxNsFlags = CLONE_NEWNS); + static int32_t SetAppSandboxPropertyNweb(AppSpawningCtx *client, uint32_t sandboxNsFlags = CLONE_NEWNS); +}; + +} // namespace AppSpawn +} // namespace OHOS + +#endif // SANDBOX_MANAGER_H \ No newline at end of file diff --git a/modules/sandbox/sandbox_utils.cpp b/modules/sandbox/sandbox_utils.cpp index 5fcefbc8..75e2ea47 100644 --- a/modules/sandbox/sandbox_utils.cpp +++ b/modules/sandbox/sandbox_utils.cpp @@ -75,9 +75,7 @@ namespace { const std::string APP_JSON_CONFIG("/appdata-sandbox.json"); const std::string APP_ISOLATED_JSON_CONFIG("/appdata-sandbox-isolated.json"); const std::string g_physicalAppInstallPath = "/data/app/el1/bundle/public/"; - const std::string g_sandboxGroupPath = "/data/storage/el2/group/"; const std::string g_sandboxHspInstallPath = "/data/storage/el1/bundle/"; - const std::string g_sandBoxAppInstallPath = "/data/accounts/account_0/applications/"; const std::string g_bundleResourceSrcPath = "/data/service/el1/public/bms/bundle_resources/"; const std::string g_bundleResourceDestPath = "/data/storage/bundle_resources/"; const std::string g_dataBundles = "/data/bundles/"; @@ -88,7 +86,7 @@ namespace { const std::string g_clonePackageName = ""; const std::string g_arkWebPackageName = ""; const std::string g_hostUserId = ""; - const std::string g_sandBoxDir = "/mnt/sandbox/"; + const std::string g_sandBoxRootDir = "/mnt/sandbox/"; const std::string g_statusCheck = "true"; const std::string g_sbxSwitchCheck = "ON"; const std::string g_dlpBundleName = "com.ohos.dlpmanager"; @@ -708,7 +706,7 @@ std::string SandboxUtils::GetSbxPathByConfig(const AppSpawningCtx *appProperty, variablePackageName << "+clone-" << bundleInfo->bundleIndex << "+" << bundleInfo->bundleName; tmpBundlePath = variablePackageName.str(); } - const std::string variableSandboxRoot = g_sandBoxDir + to_string(dacInfo->uid / UID_BASE) + + const std::string variableSandboxRoot = g_sandBoxRootDir + to_string(dacInfo->uid / UID_BASE) + "/" + isolatedFlagText.c_str() + tmpBundlePath; if (config.find(g_sandboxRootPrefix) != config.end()) { sandboxRoot = config[g_sandboxRootPrefix].get(); -- Gitee