diff --git a/BUILD.gn b/BUILD.gn index 034efc340a216ec5cb3b0eca40c095664ce2f974..103f4b365b993ef0d5b1447cbde91c9ebfd40fd5 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -22,6 +22,7 @@ config("appspawn_config") { "adapter", "interfaces/innerkits/include", "//utils/native/base/include", + "util/include", "${aafwk_path}/frameworks/kits/appkit/native/app/include", "${aafwk_path}/interfaces/innerkits/app_manager/include/appmgr", "${appexecfwk_path}/interfaces/innerkits/libeventhandler/include", @@ -42,6 +43,7 @@ config("appspawn_config") { "//base/startup/init_lite/interfaces/innerkits/include", "//base/startup/init_lite/interfaces/innerkits/sandbox/include", "//base/startup/syspara_lite/interfaces/innerkits/native/syspara/include", + "//third_party/json/include", ] if (build_selinux) { @@ -80,6 +82,8 @@ ohos_static_library("appspawn_server") { "${appspawn_path}/common/appspawn_server.c", "${appspawn_path}/standard/appspawn_process.c", "${appspawn_path}/standard/appspawn_service.c", + "${appspawn_path}/util/src/json_utils.cpp", + "${appspawn_path}/util/src/sandbox_utils.cpp", ] defines = [ "GRAPHIC_PERMISSION_CHECK", @@ -118,12 +122,15 @@ ohos_executable("nwebspawn") { sources = [ "${appspawn_path}/adapter/appspawn_nweb.cpp", "${appspawn_path}/standard/main.c", + "${appspawn_path}/util/src/json_utils.cpp", + "${appspawn_path}/util/src/sandbox_utils.cpp", ] configs = [ ":appspawn_config" ] deps = [ "${appspawn_path}:appspawn_server", "//base/startup/init_lite/interfaces/innerkits/sandbox:libsandbox", ] + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] install_enable = true subsystem_name = "${subsystem_name}" diff --git a/adapter/appspawn_adapter.h b/adapter/appspawn_adapter.h index 3e3636c282a38a00e3cc7e230d755d1cfe109e5a..22168570d45020df85daafaee8cc279f0930ac04 100644 --- a/adapter/appspawn_adapter.h +++ b/adapter/appspawn_adapter.h @@ -31,6 +31,7 @@ void RunChildProcessor(AppSpawnContent *content, AppSpawnClient *client); void RegisterAppSandbox(struct AppSpawnContent_ *content, AppSpawnClient *client); int GetRenderProcessTerminationStatus(int32_t pid, int *status); void RecordRenderProcessExitedStatus(pid_t pid, int status); +void LoadAppSandboxConfig(void); #ifdef __cplusplus } #endif diff --git a/adapter/appspawn_sandbox.cpp b/adapter/appspawn_sandbox.cpp index 51dcee01852bf70c9f5cd99afe0b50cd82c6ba6c..1e92b9e88e5b4629867b546174285354a63cf617 100644 --- a/adapter/appspawn_sandbox.cpp +++ b/adapter/appspawn_sandbox.cpp @@ -29,15 +29,33 @@ #include "sandbox.h" #include "sandbox_namespace.h" +#include "json_utils.h" +#include "sandbox_utils.h" +#include "hilog/log.h" + +using namespace std; +using namespace OHOS; +using namespace OHOS::HiviewDFX; +using namespace OHOS::AppSpawn; +static constexpr HiLogLabel LABEL = {LOG_CORE, 0, "AppSpawn_SandboxUtil"}; bool g_isPrivAppSandboxCreated = false; bool g_isAppSandboxCreated = false; -constexpr std::string_view APL_SYSTEM_CORE("system_core"); -constexpr std::string_view APL_SYSTEM_BASIC("system_basic"); -constexpr static int UID_BASE = 200000; -constexpr static mode_t FILE_MODE = 0711; -constexpr static mode_t NWEB_FILE_MODE = 0511; +namespace { + const std::string APP_JSON_CONFIG("/system/etc/sandbox/appdata-sandbox.json"); +} + +void LoadAppSandboxConfig(void) +{ + // load sandbox config + nlohmann::json appSandboxConfig; + bool rc = JsonUtils::GetJsonObjFromJson(appSandboxConfig, APP_JSON_CONFIG); + if (!rc) { + HiLog::Error(LABEL, "AppSpawnServer::Failed to load app private sandbox config"); + } + SandboxUtils::StoreJsonConfig(appSandboxConfig); +} static void RegisterSandbox(AppSpawnContentExt *appSpawnContent, const char *sandbox) { @@ -92,244 +110,6 @@ void RegisterAppSandbox(struct AppSpawnContent_ *content, AppSpawnClient *client } } -static int32_t DoAppSandboxMountOnce(const std::string originPath, const std::string destinationPath) -{ - int rc = 0; - - rc = mount(originPath.c_str(), destinationPath.c_str(), NULL, MS_BIND | MS_REC, NULL); - if (rc) { - APPSPAWN_LOGE("bind mount %s to %s failed %d", originPath.c_str(), - destinationPath.c_str(), errno); - return rc; - } - - rc = mount(NULL, destinationPath.c_str(), NULL, MS_PRIVATE, NULL); - if (rc) { - APPSPAWN_LOGE("private mount to %s failed %d", destinationPath.c_str(), errno); - return rc; - } - - return 0; -} - -static int32_t DoAppSandboxMount(const AppParameter &appProperty, std::string rootPath) -{ - std::string currentUserId = std::to_string(appProperty.uid / UID_BASE); - std::string oriInstallPath = "/data/app/el1/bundle/public/"; - std::string oriel1DataPath = "/data/app/el1/" + currentUserId + "/base/"; - std::string oriel2DataPath = "/data/app/el2/" + currentUserId + "/base/"; - std::string oriDatabasePath = "/data/app/el2/" + currentUserId + "/database/"; - std::string destDatabasePath = rootPath + "/data/storage/el2/database"; - std::string destInstallPath = rootPath + "/data/storage/el1/bundle"; - std::string destel1DataPath = rootPath + "/data/storage/el1/base"; - std::string destel2DataPath = rootPath + "/data/storage/el2/base"; - - int rc = 0; - - std::string bundleName = appProperty.bundleName; - oriInstallPath += bundleName; - oriel1DataPath += bundleName; - oriel2DataPath += bundleName; - oriDatabasePath += bundleName; - - std::map mountMap; - mountMap[destDatabasePath] = oriDatabasePath; - mountMap[destInstallPath] = oriInstallPath; - mountMap[destel1DataPath] = oriel1DataPath; - mountMap[destel2DataPath] = oriel2DataPath; - - std::map::iterator iter; - for (iter = mountMap.begin(); iter != mountMap.end(); ++iter) { - rc = DoAppSandboxMountOnce(iter->second.c_str(), iter->first.c_str()); - if (rc) { - return rc; - } - } - - // to create some useful dir when mount point created - std::vector mkdirInfo; - std::string dirPath; - mkdirInfo.push_back("/data/storage/el1/bundle/nweb"); - mkdirInfo.push_back("/data/storage/el1/bundle/ohos.global.systemres"); - - for (size_t i = 0; i < mkdirInfo.size(); i++) { - dirPath = rootPath + mkdirInfo[i]; - mkdir(dirPath.c_str(), FILE_MODE); - } - - return 0; -} - -static int32_t DoAppSandboxMountCustomized(const AppParameter &appProperty, const std::string &rootPath) -{ - std::string bundleName = appProperty.bundleName; - std::string currentUserId = std::to_string(appProperty.uid / UID_BASE); - std::string destInstallPath = rootPath + "/data/storage/el1/bundle"; - bool AuthFlag = false; - const std::vector AuthAppList = {"com.ohos.launcher", "com.ohos.permissionmanager"}; - if (std::find(AuthAppList.begin(), AuthAppList.end(), bundleName) != AuthAppList.end()) { - AuthFlag = true; - } - - if (strcmp(appProperty.apl, APL_SYSTEM_BASIC.data()) == 0 || - strcmp(appProperty.apl, APL_SYSTEM_CORE.data()) == 0 || AuthFlag) { - // account_0/applications/ dir can still access other packages' data now for compatibility purpose - std::string oriapplicationsPath = "/data/app/el1/bundle/public/"; - std::string destapplicationsPath = rootPath + "/data/accounts/account_0/applications/"; - DoAppSandboxMountOnce(oriapplicationsPath.c_str(), destapplicationsPath.c_str()); - - // need permission check for system app here - std::string destbundlesPath = rootPath + "/data/bundles/"; - DoAppSandboxMountOnce(oriapplicationsPath.c_str(), destbundlesPath.c_str()); - } - - std::string orimntHmdfsPath = "/mnt/hmdfs/"; - std::string destmntHmdfsPath = rootPath + orimntHmdfsPath; - DoAppSandboxMountOnce(orimntHmdfsPath.c_str(), destmntHmdfsPath.c_str()); - - // Add distributedfile module support, later reconstruct it - std::string oriDistributedPath = "/mnt/hmdfs/" + currentUserId + "/account/merge_view/data/" + bundleName; - std::string destDistributedPath = rootPath + "/data/storage/el2/distributedfiles"; - DoAppSandboxMountOnce(oriDistributedPath.c_str(), destDistributedPath.c_str()); - - std::string oriDistributedGroupPath = "/mnt/hmdfs/" + currentUserId + "/non_account/merge_view/data/" + bundleName; - std::string destDistributedGroupPath = rootPath + "/data/storage/el2/auth_groups"; - DoAppSandboxMountOnce(oriDistributedGroupPath.c_str(), destDistributedGroupPath.c_str()); - - // do nweb adaption - std::string orinwebPath = "/data/app/el1/bundle/public/com.ohos.nweb"; - std::string destnwebPath = destInstallPath + "/nweb"; - chmod(destnwebPath.c_str(), NWEB_FILE_MODE); - DoAppSandboxMountOnce(orinwebPath.c_str(), destnwebPath.c_str()); - - // do systemres adaption - std::string oriSysresPath = "/data/app/el1/bundle/public/ohos.global.systemres"; - std::string destSysresPath = destInstallPath + "/ohos.global.systemres"; - chmod(destSysresPath.c_str(), NWEB_FILE_MODE); - DoAppSandboxMountOnce(oriSysresPath.c_str(), destSysresPath.c_str()); - - if (bundleName.find("medialibrary") != std::string::npos) { - std::string oriMediaPath = "/storage/media/" + currentUserId; - std::string destMediaPath = rootPath + "/storage/media"; - DoAppSandboxMountOnce(oriMediaPath.c_str(), destMediaPath.c_str()); - } - - return 0; -} - -static void DoAppSandboxMkdir(const std::string &sandboxPackagePath, const AppParameter &appProperty) -{ - std::vector mkdirInfo; - std::string dirPath; - - mkdirInfo.push_back("/mnt/"); - mkdirInfo.push_back("/mnt/hmdfs/"); - mkdirInfo.push_back("/data/"); - mkdirInfo.push_back("/storage/"); - mkdirInfo.push_back("/storage/media"); - mkdirInfo.push_back("/data/storage"); - // to create /mnt/sandbox//data/storage/el1 related path, later should delete this code. - mkdirInfo.push_back("/data/storage/el1"); - mkdirInfo.push_back("/data/storage/el1/bundle"); - mkdirInfo.push_back("/data/storage/el1/base"); - mkdirInfo.push_back("/data/storage/el1/database"); - mkdirInfo.push_back("/data/storage/el2"); - mkdirInfo.push_back("/data/storage/el2/base"); - mkdirInfo.push_back("/data/storage/el2/database"); - mkdirInfo.push_back("/data/storage/el2/distributedfiles"); - mkdirInfo.push_back("/data/storage/el2/auth_groups"); - // create applications folder for compatibility purpose - mkdirInfo.push_back("/data/accounts"); - mkdirInfo.push_back("/data/accounts/account_0"); - mkdirInfo.push_back("/data/accounts/account_0/applications/"); - mkdirInfo.push_back("/data/bundles/"); - - for (size_t i = 0; i < mkdirInfo.size(); i++) { - dirPath = sandboxPackagePath + mkdirInfo[i]; - mkdir(dirPath.c_str(), FILE_MODE); - } -} - -static int32_t DoSandboxRootFolderCreateAdapt(const std::string &sandboxPackagePath) -{ - int rc = mount(nullptr, "/", nullptr, MS_REC | MS_SLAVE, nullptr); - if (rc) { - APPSPAWN_LOGE("set propagation slave failed"); - return rc; - } - - // bind mount "/" to /mnt/sandbox/ path - // rootfs: to do more resources bind mount here to get more strict resources constraints - rc = mount("/", sandboxPackagePath.c_str(), nullptr, MS_BIND | MS_REC, nullptr); - if (rc) { - APPSPAWN_LOGE("mount bind / failed"); - return rc; - } - - return 0; -} - -static int32_t DoSandboxRootFolderCreate(const std::string &sandboxPackagePath) -{ - int rc = mount(nullptr, "/", nullptr, MS_REC | MS_SLAVE, nullptr); - if (rc) { - return rc; - } - - // bind mount sandboxPackagePath to make it a mount point for pivot_root syscall - DoAppSandboxMountOnce(sandboxPackagePath.c_str(), sandboxPackagePath.c_str()); - - // do /mnt/sandbox/ path mkdir - std::map mountMap; - std::vector vecInfo; - std::string tmpDir = ""; - - vecInfo.push_back("/config"); - vecInfo.push_back("/dev"); - vecInfo.push_back("/proc"); - vecInfo.push_back("/sys"); - vecInfo.push_back("/sys_prod"); - vecInfo.push_back("/system"); - - for (size_t i = 0; i < vecInfo.size(); i++) { - tmpDir = sandboxPackagePath + vecInfo[i]; - mkdir(tmpDir.c_str(), FILE_MODE); - mountMap[vecInfo[i]] = tmpDir; - } - - // bind mount root folder to /mnt/sandbox/ path - std::map::iterator iter; - for (iter = mountMap.begin(); iter != mountMap.end(); ++iter) { - rc = DoAppSandboxMountOnce(iter->first.c_str(), iter->second.c_str()); - if (rc) { - APPSPAWN_LOGE("move root folder failed, %s", sandboxPackagePath.c_str()); - } - } - - // to create symlink at /mnt/sandbox/ path - // bin -> /system/bin - // d -> /sys/kernel/debug - // etc -> /system/etc - // init -> /system/bin/init - // lib -> /system/lib - // sdcard -> /storage/self/primary - std::map symlinkMap; - symlinkMap["/system/bin"] = sandboxPackagePath + "/bin"; - symlinkMap["/sys/kernel/debug"] = sandboxPackagePath + "/d"; - symlinkMap["/system/etc"] = sandboxPackagePath + "/etc"; - symlinkMap["/system/bin/init"] = sandboxPackagePath + "/init"; -#ifdef __aarch64__ - symlinkMap["/system/lib64"] = sandboxPackagePath + "/lib64"; -#else - symlinkMap["/system/lib"] = sandboxPackagePath + "/lib"; -#endif - - for (iter = symlinkMap.begin(); iter != symlinkMap.end(); ++iter) { - symlink(iter->first.c_str(), iter->second.c_str()); - } - return 0; -} - static void MatchSandbox(AppSpawnClientExt *appProperty) { if (appProperty == nullptr) { @@ -349,66 +129,9 @@ static void MatchSandbox(AppSpawnClientExt *appProperty) int32_t SetAppSandboxProperty(struct AppSpawnContent_ *content, AppSpawnClient *client) { - int rc = 0; APPSPAWN_CHECK(client != NULL, return -1, "Invalid appspwn client"); AppSpawnClientExt *appProperty = (AppSpawnClientExt *)client; MatchSandbox(appProperty); - // create /mnt/sandbox/ path�?later put it to rootfs module - std::string sandboxPackagePath = "/"; - sandboxPackagePath += appProperty->property.bundleName; - mkdir(sandboxPackagePath.c_str(), FILE_MODE); - - // add pid to a new mnt namespace - rc = unshare(CLONE_NEWNS); - if (rc) { - APPSPAWN_LOGE("unshare failed, packagename is %s", appProperty->property.processName); - return rc; - } - - // to make wargnar work - if (access("/3rdmodem", F_OK) == 0) { - rc = DoSandboxRootFolderCreateAdapt(sandboxPackagePath); - } else { - rc = DoSandboxRootFolderCreate(sandboxPackagePath); - } - if (rc) { - APPSPAWN_LOGE("DoSandboxRootFolderCreate failed, %s", appProperty->property.processName); - return rc; - } - - // to create /mnt/sandbox//data/storage related path - DoAppSandboxMkdir(sandboxPackagePath, appProperty->property); - - rc = DoAppSandboxMount(appProperty->property, sandboxPackagePath); - if (rc) { - APPSPAWN_LOGE("DoAppSandboxMount failed, packagename is %s", appProperty->property.processName); - return rc; - } - - rc = DoAppSandboxMountCustomized(appProperty->property, sandboxPackagePath); - if (rc) { - APPSPAWN_LOGE("DoAppSandboxMountCustomized failed, packagename is %s", appProperty->property.processName); - return rc; - } - - rc = chdir(sandboxPackagePath.c_str()); - if (rc) { - APPSPAWN_LOGE("chdir failed, packagename is %s, path is %s", \ - appProperty->property.processName, sandboxPackagePath.c_str()); - return rc; - } - - rc = syscall(SYS_pivot_root, sandboxPackagePath.c_str(), sandboxPackagePath.c_str()); - if (rc) { - APPSPAWN_LOGE("pivot root failed, packagename is %s, errno is %d", \ - appProperty->property.processName, errno); - return rc; - } - - rc = umount2(".", MNT_DETACH); - if (rc) { - APPSPAWN_LOGE("MNT_DETACH failed, packagename is %s", appProperty->property.processName); - return rc; - } - return 0; + + return SandboxUtils::SetAppSandboxProperty(&appProperty->property); } diff --git a/appdata-sandbox.json b/appdata-sandbox.json new file mode 100644 index 0000000000000000000000000000000000000000..b28a2b839a0298dec7c12fe200e388993eb4b64b --- /dev/null +++ b/appdata-sandbox.json @@ -0,0 +1,189 @@ +{ + "common" : [{ + "top-sandbox-switch": "ON", + "app-base" : [{ + "sandbox-root" : "/mnt/sandbox/", + "mount-bind-paths" : [{ + "src-path" : "/config", + "sandbox-path" : "/config", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "true" + }, { + "src-path" : "/dev", + "sandbox-path" : "/dev", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "true" + }, { + "src-path" : "/proc", + "sandbox-path" : "/proc", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "true" + }, { + "src-path" : "/sys", + "sandbox-path" : "/sys", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "true" + }, { + "src-path" : "/sys_prod", + "sandbox-path" : "/sys_prod", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "true" + }, { + "src-path" : "/system", + "sandbox-path" : "/system", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "true" + }, { + "src-path" : "/data/app/el1/bundle/public/", + "sandbox-path" : "/data/storage/el1/bundle", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "true" + }, { + "src-path" : "/data/app/el2//base/", + "sandbox-path" : "/data/storage/el2/base", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "true" + }, { + "src-path" : "/data/app/el2//database/", + "sandbox-path" : "/data/storage/el2/database", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "true" + }, { + "src-path" : "/data/app/el1//base/", + "sandbox-path" : "/data/storage/el1/base", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "true" + }, { + "src-path" : "/mnt/hmdfs/", + "sandbox-path" : "/mnt/hmdfs/", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "false" + }, { + "src-path" : "/mnt/hmdfs//account/merge_view/data/", + "sandbox-path" : "/data/storage/el2/distributedfiles", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "false" + }, { + "src-path" : "/mnt/hmdfs//non_account/merge_view/data/", + "sandbox-path" : "/data/storage/el2/auth_groups", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "false" + }, { + "src-path" : "/data/app/el1/bundle/public/com.ohos.nweb", + "sandbox-path" : "/data/storage/el1/bundle/nweb", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "false" + }, { + "src-path" : "/data/app/el1/bundle/public/ohos.global.systemres", + "sandbox-path" : "/data/storage/el1/bundle/ohos.global.systemres", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "false" + } + ], + "symbol-links" : [{ + "target-name" : "/system/bin", + "link-name" : "/bin", + "check-action-status": "true" + }, { + "target-name" : "/system/lib", + "link-name" : "/lib", + "check-action-status": "true" + }, { + "target-name" : "/system/etc", + "link-name" : "/etc", + "check-action-status": "true" + }, { + "target-name" : "/system/bin/init", + "link-name" : "/init", + "check-action-status": "true" + }, { + "target-name" : "/sys/kernel/debug", + "link-name" : "/d", + "check-action-status": "true" + } + ] + }], + "app-resources" : [{ + "sandbox-root" : "/mnt/sandbox/", + "mount-bind-paths" : [{ + "src-path" : "/data/app/el1/bundle/public/com.ohos.nweb", + "sandbox-path" : "/data/storage/el1/bundle/nweb", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "false" + }, { + "src-path" : "/data/app/el1/bundle/public/ohos.global.systemres", + "sandbox-path" : "/data/storage/el1/bundle/ohos.global.systemres", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "false" + } + ], + "symbol-links" : [ + ] + }] + }], + "individual" : [{ + "com.ohos.medialibrary.MediaLibraryDataA" : [{ + "sandbox-switch": "ON", + "sandbox-root" : "/mnt/sandbox/", + "mount-bind-paths" : [{ + "src-path" : "/storage/media/", + "sandbox-path" : "/storage/media", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "false" + } + ], + "symbol-links" : [] + }], + "com.ohos.launcher" : [{ + "sandbox-switch": "ON", + "sandbox-root" : "/mnt/sandbox/", + "mount-bind-paths" : [{ + "src-path" : "/data/app/el1/bundle/public/", + "sandbox-path" : "/data/accounts/account_0/applications/", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "true" + }, { + "src-path" : "/data/app/el1/bundle/public/", + "sandbox-path" : "/data/bundles/", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "true" + } + ], + "symbol-links" : [] + }], + "com.ohos.permissionmanager" : [{ + "sandbox-switch": "ON", + "sandbox-root" : "/mnt/sandbox/", + "mount-bind-paths" : [{ + "src-path" : "/data/app/el1/bundle/public/", + "sandbox-path" : "/data/accounts/account_0/applications/", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "true" + }, { + "src-path" : "/data/app/el1/bundle/public/", + "sandbox-path" : "/data/bundles/", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "true" + } + ], + "symbol-links" : [] + }], + "ohos.samples.ecg" : [{ + "sandbox-switch": "OFF", + "sandbox-root" : "/mnt/sandbox/", + "mount-bind-paths" : [{ + "src-path" : "/data/app/el1/bundle/public/", + "sandbox-path" : "/data/accounts/account_0/applications/", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "true" + }, { + "src-path" : "/data/app/el1/bundle/public/", + "sandbox-path" : "/data/bundles/", + "sandbox-flags" : [ "bind", "rec" ], + "check-action-status": "true" + } + ], + "symbol-links" : [] + }] + }] +} \ No newline at end of file diff --git a/standard/appspawn_process.c b/standard/appspawn_process.c index d0f00c70ab5e137d92840e363786ad69d5f5d91d..c17718b3595f637eb9852da9186f1afd1be5118a 100644 --- a/standard/appspawn_process.c +++ b/standard/appspawn_process.c @@ -32,6 +32,7 @@ #include "appspawn_adapter.h" #include "securec.h" + #define DEVICE_NULL_STR "/dev/null" static int SetProcessName(struct AppSpawnContent_ *content, AppSpawnClient *client, diff --git a/standard/appspawn_service.c b/standard/appspawn_service.c index 4f66dfd2291e3b510cff27cea571e0bc3d50481c..ebfc10c488655a259f9be9146d245a4ebb6df8c4 100644 --- a/standard/appspawn_service.c +++ b/standard/appspawn_service.c @@ -14,6 +14,7 @@ */ #include "appspawn_service.h" +#include "appspawn_adapter.h" #include #include @@ -352,6 +353,9 @@ static void AppSpawnInit(AppSpawnContent *content) content->notifyResToParent = NotifyResToParent; // set private function SetContentFunction(content); + + // load app sandbox config + LoadAppSandboxConfig(); } void AppSpawnColdRun(AppSpawnContent *content, int argc, char *const argv[]) diff --git a/test/BUILD.gn b/test/BUILD.gn index 30ab969b676b4fac3299c1508b07e7337385cb60..83f2b49eb5a05e497edcc88edb36abc715583bda 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -39,6 +39,7 @@ config("appspawn_test_config") { "${appspawn_path}/test/mock/include", "${appspawn_path}/common", "${appspawn_path}/interfaces/innerkits/include", + "${appspawn_path}/util/include", ] } diff --git a/util/include/json_utils.h b/util/include/json_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..938274fac566f8c66ffc00a8ef50ea69e00e193d --- /dev/null +++ b/util/include/json_utils.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2022 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 JSON_UTILS_H +#define JSON_UTILS_H + +#include +#include +#include "nlohmann/json.hpp" + +namespace OHOS { +namespace AppSpawn { +class JsonUtils { +public: + 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 bool GetIntFromJson(const nlohmann::json& json, const std::string& key, int& value); + static bool GetStringVecFromJson( + const nlohmann::json& json, const std::string& key, std::vector& value); + static bool ParseObjVecFromJson( + const nlohmann::json& json, const std::string& key, std::vector& value); +}; +} // namespace AppSpawn +} // namespace OHOS +#endif // JSON_UTILS_H \ No newline at end of file diff --git a/util/include/parcel_util.h b/util/include/parcel_util.h new file mode 100644 index 0000000000000000000000000000000000000000..594bf97028b61b47758b2d0b8061c1a7e8556584 --- /dev/null +++ b/util/include/parcel_util.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2022 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 PACEL_UTIL_H +#define PACEL_UTIL_H + +#include +#include +#include "parcel.h" + +namespace OHOS { +namespace AppSpawn { +template +std::vector TranslateListToVector(const std::list &originList) +{ + std::size_t len = originList.size(); + std::vector destVector(len); + std::copy(originList.begin(), originList.end(), destVector.begin()); + return destVector; +} + +template +std::list TranslateVectorToList(const std::vector &originVector) +{ + int len = originVector.length(); + std::list destList(len); + std::copy(originVector.begin(), originVector.end(), destList.begin()); + return destList; +} +} // namespace AppSpawn +} // namespace OHOS + +#endif // PACEL_UTIL_H \ No newline at end of file diff --git a/util/include/sandbox_utils.h b/util/include/sandbox_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..7632267ed738a383c46ec948d2821436d1946cd3 --- /dev/null +++ b/util/include/sandbox_utils.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2022 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_UTILS_H +#define SANDBOX_UTILS_H + +#include +#include +#include +#include "nlohmann/json.hpp" +#include "client_socket.h" + +namespace OHOS { +namespace AppSpawn { +class SandboxUtils { +public: + static void StoreJsonConfig(nlohmann::json &appSandboxConfig); + static nlohmann::json GetJsonConfig(); + static int32_t SetAppSandboxProperty(const ClientSocket::AppProperty *appProperty); + +private: + static void MakeDirRecursive(const std::string path, mode_t mode); + static int32_t DoAppSandboxMountOnce(const std::string originPath, const std::string destinationPath, + unsigned long mountFlags); + static int32_t DoSandboxFileCommonBind(const ClientSocket::AppProperty *appProperty, nlohmann::json &wholeConfig); + static int32_t DoSandboxFileCommonSymlink(const ClientSocket::AppProperty *appProperty, + nlohmann::json &wholeConfig); + static int32_t DoSandboxFilePrivateBind(const ClientSocket::AppProperty *appProperty, nlohmann::json &wholeConfig); + static int32_t DoSandboxFilePrivateSymlink(const ClientSocket::AppProperty *appProperty, + nlohmann::json &wholeConfig); + static int32_t SetPrivateAppSandboxProperty(const ClientSocket::AppProperty *appProperty); + static int32_t SetCommonAppSandboxProperty(const ClientSocket::AppProperty *appProperty, + std::string &sandboxPackagePath); + static int32_t DoSandboxRootFolderCreateAdapt(std::string &sandboxPackagePath); + static int32_t DoSandboxRootFolderCreate(const ClientSocket::AppProperty *appProperty, + std::string &sandboxPackagePath); + static void DoSandboxChmod(nlohmann::json jsonConfig, std::string &sandboxRoot); + static int DoAllMntPointsMount(const ClientSocket::AppProperty *appProperty, nlohmann::json &appConfig); + static int DoAllSymlinkPointslink(const ClientSocket::AppProperty *appProperty, nlohmann::json &appConfig); + static std::string ConvertToRealPath(const ClientSocket::AppProperty *appProperty, std::string sandboxRoot); + static std::string GetSbxPathByConfig(const ClientSocket::AppProperty *appProperty, nlohmann::json &config); + static bool CheckTotalSandboxSwitchStatus(const ClientSocket::AppProperty *appProperty); + static bool CheckAppSandboxSwitchStatus(const ClientSocket::AppProperty *appProperty); + static bool GetSbxSwitchStatusByConfig(nlohmann::json &config); + static unsigned long GetMountFlagsFromConfig(const std::vector &vec); + +private: + static nlohmann::json appSandboxConfig_; +}; +} // namespace AppSpawn +} // namespace OHOS +#endif // SANDBOX_UTILS_H \ No newline at end of file diff --git a/util/src/json_utils.cpp b/util/src/json_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..37111e28830910019e481e505a5934799b6f4691 --- /dev/null +++ b/util/src/json_utils.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2022 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 "json_utils.h" +#include +#include +#include "hilog/log.h" + +using namespace std; +using namespace OHOS; +using namespace OHOS::HiviewDFX; +static constexpr HiLogLabel LABEL = {LOG_CORE, 0, "AppSpawn_JsonUtil"}; + +namespace OHOS { +namespace AppSpawn { +bool JsonUtils::GetJsonObjFromJson(nlohmann::json &jsonObj, const std::string &jsonPath) +{ + if (jsonPath.length() > PATH_MAX) { + HiLog::Error(LABEL, "jsonPath is too long"); + return false; + } + + std::ifstream jsonFileStream; + jsonFileStream.open(jsonPath.c_str(), std::ios::in); + if (!jsonFileStream.is_open()) { + HiLog::Error(LABEL, "Open json file failed."); + 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); + if (!jsonObj.is_structured()) { + HiLog::Error(LABEL, "Parse json file into jsonObj failed."); + return false; + } + return true; +} + +bool JsonUtils::GetStringFromJson(const nlohmann::json &json, const std::string &key, std::string &value) +{ + if (!json.is_object()) { + HiLog::Error(LABEL, "json is not object."); + return false; + } + if (json.find(key) != json.end() && json.at(key).is_string()) { + HiLog::Error(LABEL, "Find key[%{public}s] successful.", key.c_str()); + value = json.at(key).get(); + return true; + } + + return false; +} + +bool JsonUtils::GetIntFromJson(const nlohmann::json &json, const std::string &key, int &value) +{ + if (!json.is_object()) { + HiLog::Error(LABEL, "json is not object."); + return false; + } + if (json.find(key) != json.end() && json.at(key).is_number()) { + HiLog::Error(LABEL, "Find key[%{public}s] successful.", key.c_str()); + value = json.at(key).get(); + return true; + } + + return false; +} + +bool JsonUtils::GetStringVecFromJson(const nlohmann::json &json, const std::string &key, + std::vector &value) +{ + if (!json.is_object()) { + HiLog::Error(LABEL, "json is not object."); + return false; + } + if (json.find(key) != json.end() && json.at(key).is_array()) { + HiLog::Error(LABEL, "Find key[%{public}s] successful.", key.c_str()); + value = json.at(key).get>(); + return true; + } + + return false; +} + +bool JsonUtils::ParseObjVecFromJson(const nlohmann::json &json, const std::string &key, + std::vector &value) +{ + if (!json.is_object()) { + HiLog::Error(LABEL, "json is not object."); + return false; + } + if (json.find(key) != json.end() && json.at(key).is_array()) { + HiLog::Error(LABEL, "Find key[%{public}s] successful.", key.c_str()); + value = json.at(key).get>(); + return true; + } + + return false; +} +} // namespace AppSpawn +} // namespace OHOS \ No newline at end of file diff --git a/util/src/sandbox_utils.cpp b/util/src/sandbox_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..564bb9a40cd9718e3290e6faa506648f5348119a --- /dev/null +++ b/util/src/sandbox_utils.cpp @@ -0,0 +1,579 @@ +/* + * Copyright (C) 2022 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_utils.h" +#include "json_utils.h" +#include "hilog/log.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace OHOS; +using namespace OHOS::HiviewDFX; +static constexpr HiLogLabel LABEL = {LOG_CORE, 0, "AppSpawn_SandboxUtil"}; + +namespace OHOS { +namespace AppSpawn { +namespace { + constexpr int32_t UID_BASE = 200000; + constexpr static mode_t FILE_MODE = 0711; + constexpr static mode_t BASIC_MOUNT_FLAGS = MS_REC | MS_BIND; + constexpr std::string_view APL_SYSTEM_CORE("system_core"); + constexpr std::string_view APL_SYSTEM_BASIC("system_basic"); + const std::string PHYSICAL_APP_INSTALL_PATH = "/data/app/el1/bundle/public/"; + const std::string SANDBOX_APP_INSTALL_PATH = "/data/accounts/account_0/applications/"; + const std::string DATA_BUNDLES = "/data/bundles/"; + const std::string USERID = ""; + const std::string PACKAGE_NAME = ""; + const std::string SANDBOX_DIR = "/mnt/sandbox/"; + const std::string STATUS_CHECK = "true"; + const std::string SBX_SWITCH_CHECK = "ON"; + const char *COMMON_PREFIX = "common"; + const char *PRIVATE_PREFIX = "individual"; + const char *SRC_PATH = "src-path"; + const char *SANDBOX_PATH = "sandbox-path"; + const char *SANDBOX_FLAGS = "sandbox-flags"; + const char *DEST_MODE = "dest-mode"; + const char *ACTION_STATUS = "check-action-status"; + const char *TARGET_NAME = "target-name"; + const char *LINK_NAME = "link-name"; + const char *MOUNT_PREFIX = "mount-bind-paths"; + const char *SANDBOX_SWITCH_PREFIX = "sandbox-switch"; + const char *TOP_SANDBOX_SWITCH_PREFIX = "top-sandbox-switch"; + const char *SYMLINK_PREFIX = "symbol-links"; + const char *SANDBOX_ROOT_PREFIX = "sandbox-root"; + const char *WARGNAR_DEVICE_PATH = "/3rdmodem"; + const char *APP_BASE = "app-base"; + const char *APP_RESOURCES = "app-resources"; +} + + +nlohmann::json SandboxUtils::appSandboxConfig_; + +void SandboxUtils::StoreJsonConfig(nlohmann::json &appSandboxConfig) +{ + SandboxUtils::appSandboxConfig_ = appSandboxConfig; +} + +nlohmann::json SandboxUtils::GetJsonConfig() +{ + return SandboxUtils::appSandboxConfig_; +} + +void SandboxUtils::MakeDirRecursive(const std::string path, mode_t mode) +{ + size_t size = path.size(); + if (size == 0) + return; + + 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); + if (access(dir.c_str(), F_OK) < 0 && mkdir(dir.c_str(), mode) < 0) { + HiLog::Error(LABEL, "mkdir %{public}s error", dir.c_str()); + return; + } + } while (index < size); +} + +int32_t SandboxUtils::DoAppSandboxMountOnce(const std::string originPath, const std::string destinationPath, + unsigned long mountFlags) +{ + int ret = 0; + + // To make sure destinationPath exist + MakeDirRecursive(destinationPath, FILE_MODE); + + ret = mount(originPath.c_str(), destinationPath.c_str(), NULL, mountFlags, NULL); + if (ret) { + HiLog::Error(LABEL, "bind mount %{public}s to %{public}s failed %{public}d", originPath.c_str(), + destinationPath.c_str(), errno); + return ret; + } + + ret = mount(NULL, destinationPath.c_str(), NULL, MS_PRIVATE, NULL); + if (ret) { + HiLog::Error(LABEL, "private mount to %{public}s failed %{public}d", destinationPath.c_str(), errno); + return ret; + } + + return 0; +} + +static std::string& replace_all(std::string& str, const std::string& old_value, const std::string& new_value) +{ + while (true) { + std::string::size_type pos(0); + if ((pos = str.find(old_value)) != std::string::npos) + str.replace(pos, old_value.length(), new_value); + else break; + } + return str; +} + +static std::vector split(std::string &str, const std::string &pattern) +{ + std::string::size_type pos; + std::vector result; + str += pattern; + size_t size = str.size(); + + for (int i = 0; i < int(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; +} + +void SandboxUtils::DoSandboxChmod(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 = JsonUtils::GetStringFromJson(jsonConfig, DEST_MODE, fileModeStr); + if (rc == false) { + return; + } + + std::vector modeVec = split(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 SandboxUtils::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}}; + 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; +} + +string SandboxUtils::ConvertToRealPath(const ClientSocket::AppProperty *appProperty, std::string path) +{ + if (path.find(PACKAGE_NAME) != -1) { + path = replace_all(path, PACKAGE_NAME, appProperty->bundleName); + } + + if (path.find(USERID) != -1) { + path = replace_all(path, USERID, std::to_string(appProperty->uid / UID_BASE)); + } + + return path; +} + +std::string SandboxUtils::GetSbxPathByConfig(const ClientSocket::AppProperty *appProperty, nlohmann::json &config) +{ + std::string sandboxRoot = ""; + if (config.find(SANDBOX_ROOT_PREFIX) != config.end()) { + sandboxRoot = config[SANDBOX_ROOT_PREFIX].get(); + sandboxRoot = ConvertToRealPath(appProperty, sandboxRoot); + } else { + sandboxRoot = SANDBOX_DIR + appProperty->bundleName; + HiLog::Error(LABEL, "read sandbox-root config failed, set sandbox-root to default root" + "app name is %{public}s", appProperty->bundleName); + } + + return sandboxRoot; +} + +bool SandboxUtils::GetSbxSwitchStatusByConfig(nlohmann::json &config) +{ + if (config.find(SANDBOX_SWITCH_PREFIX) != config.end()) { + std::string switchStatus = config[SANDBOX_SWITCH_PREFIX].get(); + if (switchStatus == SBX_SWITCH_CHECK) { + return true; + } else { + return false; + } + } + + // if not find sandbox-switch node, default switch status is true + return true; +} + +int SandboxUtils::DoAllMntPointsMount(const ClientSocket::AppProperty *appProperty, nlohmann::json &appConfig) +{ + if (appConfig.find(MOUNT_PREFIX) == appConfig.end()) { + HiLog::Debug(LABEL, "mount config is not found, maybe reuslt sandbox launch failed" + "app name is %{public}s", appProperty->bundleName); + return 0; + } + + nlohmann::json mountPoints = appConfig[MOUNT_PREFIX]; + std::string sandboxRoot = GetSbxPathByConfig(appProperty, appConfig); + int mountPointSize = mountPoints.size(); + + for (int i = 0; i < mountPointSize; i++) { + nlohmann::json mntPoint = mountPoints[i]; + + // Check the validity of the mount configuration + if (mntPoint.find(SRC_PATH) == mntPoint.end() || mntPoint.find(SANDBOX_PATH) == mntPoint.end() + || mntPoint.find(SANDBOX_FLAGS) == mntPoint.end()) { + HiLog::Error(LABEL, "read mount config failed, app name is %{public}s", appProperty->bundleName); + continue; + } + + std::string srcPath = ConvertToRealPath(appProperty, mntPoint[SRC_PATH].get()); + std::string sandboxPath = sandboxRoot + ConvertToRealPath(appProperty, + mntPoint[SANDBOX_PATH].get()); + unsigned long mountFlags = GetMountFlagsFromConfig(mntPoint[SANDBOX_FLAGS].get>()); + + int ret = DoAppSandboxMountOnce(srcPath.c_str(), sandboxPath.c_str(), mountFlags); + if (ret) { + HiLog::Error(LABEL, "DoAppSandboxMountOnce failed, %{public}s", sandboxPath.c_str()); + + std::string actionStatus = STATUS_CHECK; + (void)JsonUtils::GetStringFromJson(mntPoint, ACTION_STATUS, actionStatus); + if (actionStatus == STATUS_CHECK) { + return ret; + } + } + + DoSandboxChmod(mntPoint, sandboxRoot); + } + + return 0; +} + +int SandboxUtils::DoAllSymlinkPointslink(const ClientSocket::AppProperty *appProperty, nlohmann::json &appConfig) +{ + if (appConfig.find(SYMLINK_PREFIX) == appConfig.end()) { + HiLog::Debug(LABEL, "symlink config is not found, maybe reuslt sandbox launch failed" + "app name is %{public}s", appProperty->bundleName); + return 0; + } + + nlohmann::json symlinkPoints = appConfig[SYMLINK_PREFIX]; + std::string sandboxRoot = GetSbxPathByConfig(appProperty, appConfig); + int symlinkPointSize = symlinkPoints.size(); + + for (int i = 0; i < symlinkPointSize; i++) { + nlohmann::json symPoint = symlinkPoints[i]; + + // Check the validity of the symlink configuration + if (symPoint.find(TARGET_NAME) == symPoint.end() || symPoint.find(LINK_NAME) == symPoint.end()) { + HiLog::Error(LABEL, "read symlink config failed, app name is %{public}s", appProperty->bundleName); + continue; + } + + std::string targetName = ConvertToRealPath(appProperty, symPoint[TARGET_NAME].get()); + std::string linkName = sandboxRoot + ConvertToRealPath(appProperty, symPoint[LINK_NAME].get()); + HiLog::Debug(LABEL, "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) { + HiLog::Error(LABEL, "symlink failed, %{public}s, errno is %{public}d", linkName.c_str(), errno); + + std::string actionStatus = STATUS_CHECK; + (void)JsonUtils::GetStringFromJson(symPoint, ACTION_STATUS, actionStatus); + if (actionStatus == STATUS_CHECK) { + return ret; + } + } + + DoSandboxChmod(symPoint, sandboxRoot); + } + + return 0; +} + +int32_t SandboxUtils::DoSandboxFilePrivateBind(const ClientSocket::AppProperty *appProperty, + nlohmann::json &wholeConfig) +{ + nlohmann::json privateAppConfig = wholeConfig[PRIVATE_PREFIX][0]; + if (privateAppConfig.find(appProperty->bundleName) != privateAppConfig.end()) { + return DoAllMntPointsMount(appProperty, privateAppConfig[appProperty->bundleName][0]); + } + + return 0; +} + +int32_t SandboxUtils::DoSandboxFilePrivateSymlink(const ClientSocket::AppProperty *appProperty, + nlohmann::json &wholeConfig) +{ + nlohmann::json privateAppConfig = wholeConfig[PRIVATE_PREFIX][0]; + if (privateAppConfig.find(appProperty->bundleName) != privateAppConfig.end()) { + return DoAllSymlinkPointslink(appProperty, privateAppConfig[appProperty->bundleName][0]); + } + + return 0; +} + +int32_t SandboxUtils::DoSandboxFileCommonBind(const ClientSocket::AppProperty *appProperty, nlohmann::json &wholeConfig) +{ + nlohmann::json commonConfig = wholeConfig[COMMON_PREFIX][0]; + int ret = 0; + + if (commonConfig.find(APP_BASE) != commonConfig.end()) { + ret = DoAllMntPointsMount(appProperty, commonConfig[APP_BASE][0]); + if (ret) { + return ret; + } + } + + if (commonConfig.find(APP_RESOURCES) != commonConfig.end()) { + ret = DoAllMntPointsMount(appProperty, commonConfig[APP_RESOURCES][0]); + } + + return ret; +} + +int32_t SandboxUtils::DoSandboxFileCommonSymlink(const ClientSocket::AppProperty *appProperty, + nlohmann::json &wholeConfig) +{ + nlohmann::json commonConfig = wholeConfig[COMMON_PREFIX][0]; + int ret = 0; + + if (commonConfig.find(APP_BASE) != commonConfig.end()) { + ret = DoAllSymlinkPointslink(appProperty, commonConfig[APP_BASE][0]); + if (ret) { + return ret; + } + } + + if (commonConfig.find(APP_RESOURCES) != commonConfig.end()) { + ret = DoAllSymlinkPointslink(appProperty, commonConfig[APP_RESOURCES][0]); + } + + return ret; +} + +int32_t SandboxUtils::SetPrivateAppSandboxProperty(const ClientSocket::AppProperty *appProperty) +{ + nlohmann::json config = SandboxUtils::GetJsonConfig(); + int ret; + + ret = DoSandboxFilePrivateBind(appProperty, config); + if (ret) { + HiLog::Error(LABEL, "DoSandboxFilePrivateBind failed"); + return ret; + } + + ret = DoSandboxFilePrivateSymlink(appProperty, config); + if (ret) { + HiLog::Error(LABEL, "DoSandboxFilePrivateSymlink failed"); + return ret; + } + + return 0; +} + +int32_t SandboxUtils::SetCommonAppSandboxProperty(const ClientSocket::AppProperty *appProperty, + std::string &sandboxPackagePath) +{ + nlohmann::json jsonConfig = SandboxUtils::GetJsonConfig(); + + int rc = DoSandboxFileCommonBind(appProperty, jsonConfig); + if (rc) { + HiLog::Error(LABEL, "DoSandboxFileCommonBind failed, %{public}s", sandboxPackagePath.c_str()); + return rc; + } + + // if sandbox switch is off, don't do symlink work again + if (CheckAppSandboxSwitchStatus(appProperty) == true && (CheckTotalSandboxSwitchStatus(appProperty) == true)) { + rc = DoSandboxFileCommonSymlink(appProperty, jsonConfig); + if (rc) { + HiLog::Error(LABEL, "DoSandboxFileCommonSymlink failed, %{public}s", sandboxPackagePath.c_str()); + return rc; + } + } + + if (strcmp(appProperty->apl, APL_SYSTEM_BASIC.data()) == 0 || + strcmp(appProperty->apl, APL_SYSTEM_CORE.data()) == 0) { + // account_0/applications/ dir can still access other packages' data now for compatibility purpose + std::string destapplicationsPath = sandboxPackagePath + SANDBOX_APP_INSTALL_PATH; + DoAppSandboxMountOnce(PHYSICAL_APP_INSTALL_PATH.c_str(), destapplicationsPath.c_str(), BASIC_MOUNT_FLAGS); + + // need permission check for system app here + std::string destbundlesPath = sandboxPackagePath + DATA_BUNDLES; + DoAppSandboxMountOnce(PHYSICAL_APP_INSTALL_PATH.c_str(), destbundlesPath.c_str(), BASIC_MOUNT_FLAGS); + } + + return 0; +} + +int32_t SandboxUtils::DoSandboxRootFolderCreateAdapt(std::string &sandboxPackagePath) +{ + int rc = mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL); + if (rc) { + HiLog::Error(LABEL, "set propagation slave failed"); + return rc; + } + + MakeDirRecursive(sandboxPackagePath, FILE_MODE); + + // bind mount "/" to /mnt/sandbox/ path + // rootfs: to do more resources bind mount here to get more strict resources constraints + rc = mount("/", sandboxPackagePath.c_str(), NULL, BASIC_MOUNT_FLAGS, NULL); + if (rc) { + HiLog::Error(LABEL, "mount bind / failed, %{public}d", errno); + return rc; + } + + return 0; +} + +int32_t SandboxUtils::DoSandboxRootFolderCreate(const ClientSocket::AppProperty *appProperty, + std::string &sandboxPackagePath) +{ + int rc = mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL); + if (rc) { + return rc; + } + + DoAppSandboxMountOnce(sandboxPackagePath.c_str(), sandboxPackagePath.c_str(), BASIC_MOUNT_FLAGS); + + return 0; +} + +bool SandboxUtils::CheckTotalSandboxSwitchStatus(const ClientSocket::AppProperty *appProperty) +{ + nlohmann::json wholeConfig = SandboxUtils::GetJsonConfig(); + HiLog::Error(LABEL, "CheckAppSandboxSwitchStatus total start, %{public}s", appProperty->bundleName); + + nlohmann::json commonAppConfig = wholeConfig[COMMON_PREFIX][0]; + if (commonAppConfig.find(TOP_SANDBOX_SWITCH_PREFIX) != commonAppConfig.end()) { + std::string switchStatus = commonAppConfig[TOP_SANDBOX_SWITCH_PREFIX].get(); + if (switchStatus == SBX_SWITCH_CHECK) { + return true; + } else { + return false; + } + } + + // default sandbox switch is on + return true; +} + +bool SandboxUtils::CheckAppSandboxSwitchStatus(const ClientSocket::AppProperty *appProperty) +{ + nlohmann::json wholeConfig = SandboxUtils::GetJsonConfig(); + bool rc = true; + HiLog::Error(LABEL, "CheckAppSandboxSwitchStatus start, %{public}s", appProperty->bundleName); + + nlohmann::json privateAppConfig = wholeConfig[PRIVATE_PREFIX][0]; + if (privateAppConfig.find(appProperty->bundleName) != privateAppConfig.end()) { + nlohmann::json appConfig = privateAppConfig[appProperty->bundleName][0]; + rc = GetSbxSwitchStatusByConfig(appConfig); + HiLog::Error(LABEL, "CheckAppSandboxSwitchStatus middle, %{public}d", rc); + } + + // default sandbox switch is on + return rc; +} + +int32_t SandboxUtils::SetAppSandboxProperty(const ClientSocket::AppProperty *appProperty) +{ + std::string sandboxPackagePath = "/mnt/sandbox/"; + const std::string bundleName = appProperty->bundleName; + sandboxPackagePath += bundleName; + int rc = 0; + + // add pid to a new mnt namespace + rc = unshare(CLONE_NEWNS); + if (rc) { + HiLog::Error(LABEL, "unshare failed, packagename is %{public}s", bundleName.c_str()); + return rc; + } + + // to make wargnar work and check app sandbox switch + if (access(WARGNAR_DEVICE_PATH, F_OK) == 0 || (CheckTotalSandboxSwitchStatus(appProperty) == false) || + (CheckAppSandboxSwitchStatus(appProperty) == false)) { + rc = DoSandboxRootFolderCreateAdapt(sandboxPackagePath); + HiLog::Error(LABEL, "CheckAppSandboxSwitchStatus 1111, %{public}d", rc); + } else { + rc = DoSandboxRootFolderCreate(appProperty, sandboxPackagePath); + HiLog::Error(LABEL, "CheckAppSandboxSwitchStatus 2222, %{public}d", rc); + } + if (rc) { + HiLog::Error(LABEL, "DoSandboxRootFolderCreate failed, %{public}s", bundleName.c_str()); + return rc; + } + + rc = SetCommonAppSandboxProperty(appProperty, sandboxPackagePath); + if (rc) { + HiLog::Error(LABEL, "SetCommonAppSandboxProperty failed, packagename is %{public}s", bundleName.c_str()); + return rc; + } + + rc = SetPrivateAppSandboxProperty(appProperty); + if (rc) { + HiLog::Error(LABEL, "SetPrivateAppSandboxProperty failed, packagename is %{public}s", bundleName.c_str()); + return rc; + } + + rc = chdir(sandboxPackagePath.c_str()); + if (rc) { + HiLog::Error(LABEL, "chdir failed, packagename is %{public}s, path is %{public}s", \ + bundleName.c_str(), sandboxPackagePath.c_str()); + return rc; + } + + rc = syscall(SYS_pivot_root, sandboxPackagePath.c_str(), sandboxPackagePath.c_str()); + if (rc) { + HiLog::Error(LABEL, "pivot root failed, packagename is %{public}s, errno is %{public}d", \ + bundleName.c_str(), errno); + return rc; + } + + rc = umount2(".", MNT_DETACH); + if (rc) { + HiLog::Error(LABEL, "MNT_DETACH failed, packagename is %{public}s", bundleName.c_str()); + return rc; + } + + return 0; +} +} // namespace AppSpawn +} // namespace OHOS \ No newline at end of file