使能应用沙箱可配置功能

Signed-off-by: Zheng Yongjun <zhengyongjun3@huawei.com>
This commit is contained in:
Zheng Yongjun 2022-04-28 15:42:14 +08:00
parent 542d4aeafc
commit 01ee17293a
12 changed files with 1072 additions and 302 deletions

View File

@ -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}"

View File

@ -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

View File

@ -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<std::string, std::string> mountMap;
mountMap[destDatabasePath] = oriDatabasePath;
mountMap[destInstallPath] = oriInstallPath;
mountMap[destel1DataPath] = oriel1DataPath;
mountMap[destel2DataPath] = oriel2DataPath;
std::map<std::string, std::string>::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<std::string> 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<std::string> 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<std::string> 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/<packagename>/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/<packageName> 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/<packageName> path mkdir
std::map<std::string, std::string> mountMap;
std::vector<std::string> 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/<packageName> path
std::map<std::string, std::string>::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/<packageName> path
// bin -> /system/bin
// d -> /sys/kernel/debug
// etc -> /system/etc
// init -> /system/bin/init
// lib -> /system/lib
// sdcard -> /storage/self/primary
std::map<std::string, std::string> 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/<packagename> path<74>?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/<packagename>/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);
}

189
appdata-sandbox.json Normal file
View File

@ -0,0 +1,189 @@
{
"common" : [{
"top-sandbox-switch": "ON",
"app-base" : [{
"sandbox-root" : "/mnt/sandbox/<PackageName>",
"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/<PackageName>",
"sandbox-path" : "/data/storage/el1/bundle",
"sandbox-flags" : [ "bind", "rec" ],
"check-action-status": "true"
}, {
"src-path" : "/data/app/el2/<currentUserId>/base/<PackageName>",
"sandbox-path" : "/data/storage/el2/base",
"sandbox-flags" : [ "bind", "rec" ],
"check-action-status": "true"
}, {
"src-path" : "/data/app/el2/<currentUserId>/database/<PackageName>",
"sandbox-path" : "/data/storage/el2/database",
"sandbox-flags" : [ "bind", "rec" ],
"check-action-status": "true"
}, {
"src-path" : "/data/app/el1/<currentUserId>/base/<PackageName>",
"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/<currentUserId>/account/merge_view/data/<PackageName>",
"sandbox-path" : "/data/storage/el2/distributedfiles",
"sandbox-flags" : [ "bind", "rec" ],
"check-action-status": "false"
}, {
"src-path" : "/mnt/hmdfs/<currentUserId>/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/<PackageName>",
"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/<PackageName>",
"mount-bind-paths" : [{
"src-path" : "/storage/media/<currentUserId>",
"sandbox-path" : "/storage/media",
"sandbox-flags" : [ "bind", "rec" ],
"check-action-status": "false"
}
],
"symbol-links" : []
}],
"com.ohos.launcher" : [{
"sandbox-switch": "ON",
"sandbox-root" : "/mnt/sandbox/<PackageName>",
"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/<PackageName>",
"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/<PackageName>",
"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" : []
}]
}]
}

View File

@ -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,

View File

@ -14,6 +14,7 @@
*/
#include "appspawn_service.h"
#include "appspawn_adapter.h"
#include <fcntl.h>
#include <sys/capability.h>
@ -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[])

View File

@ -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",
]
}

37
util/include/json_utils.h Normal file
View File

@ -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 <string>
#include <vector>
#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<std::string>& value);
static bool ParseObjVecFromJson(
const nlohmann::json& json, const std::string& key, std::vector<nlohmann::json>& value);
};
} // namespace AppSpawn
} // namespace OHOS
#endif // JSON_UTILS_H

View File

@ -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 <cstdint>
#include <list>
#include "parcel.h"
namespace OHOS {
namespace AppSpawn {
template<class T>
std::vector<T> TranslateListToVector(const std::list<T> &originList)
{
std::size_t len = originList.size();
std::vector<T> destVector(len);
std::copy(originList.begin(), originList.end(), destVector.begin());
return destVector;
}
template<class T>
std::list<T> TranslateVectorToList(const std::vector<T> &originVector)
{
int len = originVector.length();
std::list<T> destList(len);
std::copy(originVector.begin(), originVector.end(), destList.begin());
return destList;
}
} // namespace AppSpawn
} // namespace OHOS
#endif // PACEL_UTIL_H

View File

@ -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 <string>
#include <vector>
#include <sys/types.h>
#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<std::string> &vec);
private:
static nlohmann::json appSandboxConfig_;
};
} // namespace AppSpawn
} // namespace OHOS
#endif // SANDBOX_UTILS_H

119
util/src/json_utils.cpp Normal file
View File

@ -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 <fstream>
#include <sstream>
#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<std::string>();
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<int>();
return true;
}
return false;
}
bool JsonUtils::GetStringVecFromJson(const nlohmann::json &json, const std::string &key,
std::vector<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_array()) {
HiLog::Error(LABEL, "Find key[%{public}s] successful.", key.c_str());
value = json.at(key).get<std::vector<std::string>>();
return true;
}
return false;
}
bool JsonUtils::ParseObjVecFromJson(const nlohmann::json &json, const std::string &key,
std::vector<nlohmann::json> &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<std::vector<nlohmann::json>>();
return true;
}
return false;
}
} // namespace AppSpawn
} // namespace OHOS

579
util/src/sandbox_utils.cpp Normal file
View File

@ -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 <unistd.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <cerrno>
#include <dirent.h>
#include <dlfcn.h>
#include <fstream>
#include <sstream>
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 = "<currentUserId>";
const std::string PACKAGE_NAME = "<PackageName>";
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<std::string> split(std::string &str, const std::string &pattern)
{
std::string::size_type pos;
std::vector<std::string> 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<std::string, mode_t> 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<std::string> 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<std::string> &vec)
{
const std::map<std::string, mode_t> 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<std::string>();
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<std::string>();
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>());
std::string sandboxPath = sandboxRoot + ConvertToRealPath(appProperty,
mntPoint[SANDBOX_PATH].get<std::string>());
unsigned long mountFlags = GetMountFlagsFromConfig(mntPoint[SANDBOX_FLAGS].get<std::vector<std::string>>());
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>());
std::string linkName = sandboxRoot + ConvertToRealPath(appProperty, symPoint[LINK_NAME].get<std::string>());
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/<packageName> 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<std::string>();
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