Merge remote-tracking branch 'upstream/master'

This commit is contained in:
wangminmin 2023-08-03 20:45:17 +08:00
commit a89a0f0dac
23 changed files with 591 additions and 409 deletions

115
BUILD.gn
View File

@ -35,6 +35,7 @@ config("appspawn_config") {
"//foundation/communication/ipc/interfaces/innerkits/ipc_core/include",
"//foundation/arkui/napi",
"//third_party/libuv/include",
"//third_party/selinux/libselinux/include/",
]
if (build_selinux) {
@ -43,15 +44,30 @@ config("appspawn_config") {
}
ohos_executable("appspawn") {
defines = []
if (target_cpu == "arm64") {
defines += [ "webview_arm64" ]
}
if (target_cpu == "x86_64") {
defines += [ "webview_x86_64" ]
}
sources = [
"${appspawn_path}/adapter/appspawn_ace.cpp",
"${appspawn_path}/adapter/appspawn_nweb.cpp",
"${appspawn_path}/adapter/nwebspawn_lancher.cpp",
"${appspawn_path}/interfaces/innerkits/src/appspawn_mount_permission.cpp",
"${appspawn_path}/standard/main.c",
"${appspawn_path}/util/src/json_utils.cpp",
"${appspawn_path}/util/src/sandbox_utils.cpp",
]
if (asan_detector || is_asan) {
defines = [ "ASAN_DETECTOR" ]
defines += [ "ASAN_DETECTOR" ]
}
configs = [ ":appspawn_config" ]
deps = [ "${appspawn_path}:appspawn_server" ]
deps = [
"${appspawn_path}:appspawn_server",
"//third_party/selinux:libselinux",
]
external_deps = [
"ability_base:want",
"ability_runtime:app_manager",
@ -65,7 +81,9 @@ ohos_executable("appspawn") {
"init:libbegetutil",
"resource_management:global_resmgr",
]
if (build_selinux) {
external_deps += [ "selinux_adapter:libhap_restorecon" ]
}
install_enable = true
subsystem_name = "${subsystem_name}"
part_name = "${part_name}"
@ -95,6 +113,7 @@ ohos_shared_library("appspawn_helper") {
ohos_static_library("appspawn_server") {
sources = [
"${appspawn_path}/adapter/appspawn_adapter.cpp",
"${appspawn_path}/adapter/appspawn_nweb.cpp",
"${appspawn_path}/adapter/appspawn_sandbox.cpp",
"${appspawn_path}/common/appspawn_server.c",
"${appspawn_path}/interfaces/innerkits/src/appspawn_mount_permission.cpp",
@ -116,15 +135,16 @@ ohos_static_library("appspawn_server") {
ldflags = [ "-Wl,--dynamic-linker,/system/bin/linker64z" ]
deps = [
":asan.options",
"//foundation/communication/netmanager_base/services/netmanagernative/netsys_client:netsys_client",
"//third_party/selinux:libselinux",
]
external_deps = [
"access_token:libtoken_setproc",
"access_token:libtokenid_sdk",
"c_utils:utils",
"config_policy:configpolicy_util",
"hilog:libhilog",
"init:libbegetutil",
"init:libbegetutil",
"netmanager_base:netsys_client",
]
if (!defined(global_parts_info) ||
@ -159,86 +179,6 @@ ohos_prebuilt_etc("appspawn.rc") {
part_name = "${part_name}"
}
ohos_static_library("nwebspawn_server") {
sources = [
"${appspawn_path}/adapter/appspawn_adapter.cpp",
"${appspawn_path}/adapter/appspawn_sandbox.cpp",
"${appspawn_path}/common/appspawn_server.c",
"${appspawn_path}/interfaces/innerkits/src/appspawn_mount_permission.cpp",
"${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",
"INIT_AGENT",
"NWEB_SPAWN",
"APPSPAWN_CHECK_GID_UID",
"APPSPAWN_LABEL=\"NWEBSPAWN\"",
]
include_dirs = [ "//third_party/selinux/libselinux/include/" ]
configs = [ ":appspawn_config" ]
ldflags = [ "-Wl,--dynamic-linker,/system/bin/linker64z" ]
deps = [
"//foundation/communication/netmanager_base/services/netmanagernative/netsys_client:netsys_client",
"//third_party/selinux:libselinux",
]
external_deps = [
"access_token:libtoken_setproc",
"access_token:libtokenid_sdk",
"c_utils:utils",
"config_policy:configpolicy_util",
"hilog:libhilog",
"init:libbegetutil",
]
if (build_selinux) {
external_deps += [ "selinux_adapter:libhap_restorecon" ]
}
cflags = []
if (build_seccomp) {
cflags += [ "-DWITH_SECCOMP" ]
external_deps += [ "init:seccomp" ]
}
subsystem_name = "${subsystem_name}"
part_name = "${part_name}"
}
ohos_executable("nwebspawn") {
defines = [
"NWEB_SPAWN",
"APPSPAWN_LABEL=\"NWEBSPAWN\"",
]
if (target_cpu == "arm64") {
defines += [ "webview_arm64" ]
}
if (target_cpu == "x86_64") {
defines += [ "webview_x86_64" ]
}
sources = [
"${appspawn_path}/adapter/appspawn_nweb.cpp",
"${appspawn_path}/interfaces/innerkits/src/appspawn_mount_permission.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}:nwebspawn_server" ]
external_deps = [
"config_policy:configpolicy_util",
"hilog:libhilog",
]
if (build_selinux) {
external_deps += [ "selinux_adapter:libhap_restorecon" ]
}
install_enable = true
subsystem_name = "${subsystem_name}"
part_name = "${part_name}"
}
ohos_prebuilt_etc("nwebspawn.rc") {
source = "nwebspawn.cfg"
relative_install_dir = "init"
@ -249,9 +189,6 @@ ohos_prebuilt_etc("nwebspawn.rc") {
group("nweb") {
deps = []
if (appspawn_support_nweb) {
deps += [
":nwebspawn",
":nwebspawn.rc",
]
deps += [ ":nwebspawn.rc" ]
}
}

View File

@ -61,6 +61,7 @@ static void GetPreloadModules(const std::string &configName, std::set<std::strin
static void PreloadModule(void)
{
#ifndef APPSPAWN_TEST
OHOS::AbilityRuntime::Runtime::Options options;
options.lang = OHOS::AbilityRuntime::Runtime::Language::JS;
options.loadAce = true;
@ -71,6 +72,7 @@ static void PreloadModule(void)
APPSPAWN_LOGE("LoadExtendLib: Failed to create runtime");
return;
}
#endif
std::set<std::string> modules = {};
CfgFiles *files = GetCfgFiles("etc/appspawn");
if (files == nullptr) {
@ -89,10 +91,14 @@ static void PreloadModule(void)
FreeCfgFiles(files);
for (std::string moduleName : modules) {
APPSPAWN_LOGI("moduleName %{public}s", moduleName.c_str());
#ifndef APPSPAWN_TEST
runtime->PreloadSystemModule(moduleName);
#endif
}
#ifndef APPSPAWN_TEST
// Save preloaded runtime
OHOS::AbilityRuntime::Runtime::SavePreloaded(std::move(runtime));
#endif
}
void LoadExtendLib(AppSpawnContent *content)

View File

@ -17,9 +17,7 @@
#include <cerrno>
#ifdef NWEB_SPAWN
#include "selinux/selinux.h"
#endif
#include "appspawn_service.h"
#ifdef WITH_SELINUX
@ -33,28 +31,28 @@
const char* RENDERER_NAME = "renderer";
#endif
#ifdef NWEB_SPAWN
#include "tokenid_kit.h"
#include "access_token.h"
#define NWEBSPAWN_SERVER_NAME "nwebspawn"
using namespace OHOS::Security::AccessToken;
#endif
int SetAppAccessToken(struct AppSpawnContent_ *content, AppSpawnClient *client)
{
AppSpawnClientExt *appProperty = reinterpret_cast<AppSpawnClientExt *>(client);
#if NWEB_SPAWN
int32_t ret = 0;
uint64_t tokenId = 0;
if (content->isNweb) {
TokenIdKit tokenIdKit;
uint64_t tokenId = tokenIdKit.GetRenderTokenID(appProperty->property.accessTokenIdEx);
tokenId = tokenIdKit.GetRenderTokenID(appProperty->property.accessTokenIdEx);
if (tokenId == static_cast<uint64_t>(INVALID_TOKENID)) {
APPSPAWN_LOGE("AppSpawnServer::Failed to get render token id, renderTokenId =%{public}llu",
static_cast<unsigned long long>(tokenId));
return -1;
}
#else
uint64_t tokenId = appProperty->property.accessTokenIdEx;
#endif
int32_t ret = SetSelfTokenID(tokenId);
} else {
tokenId = appProperty->property.accessTokenIdEx;
}
ret = SetSelfTokenID(tokenId);
if (ret != 0) {
APPSPAWN_LOGE("AppSpawnServer::set access token id failed, ret = %{public}d", ret);
return -1;
@ -65,12 +63,12 @@ int SetAppAccessToken(struct AppSpawnContent_ *content, AppSpawnClient *client)
return 0;
}
void SetSelinuxCon(struct AppSpawnContent_ *content, AppSpawnClient *client)
int SetSelinuxCon(struct AppSpawnContent_ *content, AppSpawnClient *client)
{
#ifdef WITH_SELINUX
#ifdef NWEB_SPAWN
if (content->isNweb) {
setcon("u:r:isolated_render:s0");
#else
} else {
UNUSED(content);
AppSpawnClientExt *appProperty = reinterpret_cast<AppSpawnClientExt *>(client);
HapContext hapContext;
@ -85,25 +83,28 @@ void SetSelinuxCon(struct AppSpawnContent_ *content, AppSpawnClient *client)
if (ret != 0) {
APPSPAWN_LOGE("AppSpawnServer::Failed to hap domain set context, errno = %{public}d %{public}s",
errno, appProperty->property.apl);
return -1;
} else {
APPSPAWN_LOGV("AppSpawnServer::Success to hap domain set context, ret = %{public}d", ret);
}
}
#endif
#endif
return 0;
}
void SetUidGidFilter(struct AppSpawnContent_ *content)
{
#ifdef WITH_SECCOMP
#ifdef NWEB_SPAWN
bool ret = false;
if (content->isNweb) {
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
APPSPAWN_LOGE("Failed to set no new privs");
}
if (!SetSeccompPolicyWithName(INDIVIDUAL, NWEBSPAWN_NAME)) {
#else
if (!SetSeccompPolicyWithName(INDIVIDUAL, APPSPAWN_NAME)) {
#endif
ret = SetSeccompPolicyWithName(INDIVIDUAL, NWEBSPAWN_NAME);
} else {
ret = SetSeccompPolicyWithName(INDIVIDUAL, APPSPAWN_NAME);
}
if (!ret) {
APPSPAWN_LOGE("Failed to set APPSPAWN seccomp filter and exit");
#ifndef APPSPAWN_TEST
_exit(0x7f);
@ -117,13 +118,12 @@ void SetUidGidFilter(struct AppSpawnContent_ *content)
int SetSeccompFilter(struct AppSpawnContent_ *content, AppSpawnClient *client)
{
#ifdef WITH_SECCOMP
#ifdef NWEB_SPAWN
const char *appName = RENDERER_NAME;
SeccompFilterType type = INDIVIDUAL;
#else
const char *appName = APP_NAME;
SeccompFilterType type = APP;
#endif
if (content->isNweb) {
appName = RENDERER_NAME;
type = INDIVIDUAL;
}
if (!SetSeccompPolicyWithName(type, appName)) {
APPSPAWN_LOGE("Failed to set %{public}s seccomp filter and exit", appName);
#ifndef APPSPAWN_TEST

View File

@ -26,9 +26,11 @@ extern "C" {
int32_t SetAppSandboxProperty(struct AppSpawnContent_ *content, AppSpawnClient *client);
int SetAppAccessToken(struct AppSpawnContent_ *content, AppSpawnClient *client);
void SetSelinuxCon(struct AppSpawnContent_ *content, AppSpawnClient *client);
int SetSelinuxCon(struct AppSpawnContent_ *content, AppSpawnClient *client);
void LoadExtendLib(AppSpawnContent *content);
void LoadExtendLibNweb(AppSpawnContent *content);
void RunChildProcessor(AppSpawnContent *content, AppSpawnClient *client);
void RunChildProcessorNweb(AppSpawnContent *content, AppSpawnClient *client);
void LoadAppSandboxConfig(void);
void SetUidGidFilter(struct AppSpawnContent_ *content);
int SetSeccompFilter(struct AppSpawnContent_ *content, AppSpawnClient *client);

View File

@ -33,6 +33,8 @@
#include "appspawn_service.h"
#include "appspawn_adapter.h"
struct RenderProcessNode {
RenderProcessNode(time_t now, int exit):recordTime_(now), exitStatus_(exit) {}
time_t recordTime_;
@ -42,129 +44,63 @@ struct RenderProcessNode {
namespace {
constexpr int32_t RENDER_PROCESS_MAX_NUM = 16;
std::map<int32_t, RenderProcessNode> g_renderProcessMap;
void *g_nwebHandle = nullptr;
std::mutex g_mutex;
#if defined(webview_arm64)
const std::string RELATIVE_PATH_FOR_HAP = "NWeb.hap!/libs/arm64-v8a";
const std::string NWEB_HAP_LIB_PATH = "/data/storage/el1/bundle/nweb/libs/arm64";
#elif defined(webview_x86_64)
const std::string RELATIVE_PATH_FOR_HAP = "NWeb.hap!/libs/x86_64";
const std::string NWEB_HAP_LIB_PATH = "/data/storage/el1/bundle/nweb/libs/x86_64";
#else
const std::string RELATIVE_PATH_FOR_HAP = "NWeb.hap!/libs/armeabi-v7a";
const std::string NWEB_HAP_LIB_PATH = "/data/storage/el1/bundle/nweb/libs/arm";
#endif
const std::string NWEB_HAP_PATH = "/system/app/com.ohos.nweb/";
const std::string NWEB_HAP_PATH_1 = "/system/app/NWeb/";
}
std::string GetNWebHapLibsPath()
void LoadExtendLibNweb(AppSpawnContent *content)
{
std::string libPath;
if (access(NWEB_HAP_PATH.c_str(), F_OK) == 0) {
libPath = NWEB_HAP_PATH + RELATIVE_PATH_FOR_HAP;
APPSPAWN_LOGI("get fix path, %{public}s", libPath.c_str());
return libPath;
}
if (access(NWEB_HAP_PATH_1.c_str(), F_OK) == 0) {
libPath = NWEB_HAP_PATH_1 + RELATIVE_PATH_FOR_HAP;
APPSPAWN_LOGI("get fix path, %{public}s", libPath.c_str());
return libPath;
}
return "";
}
#ifdef __MUSL__
void *LoadWithRelroFile(const std::string &lib, const std::string &nsName,
const std::string &nsPath)
void RunChildProcessorNweb(AppSpawnContent *content, AppSpawnClient *client)
{
#ifdef webview_arm64
const std::string nwebRelroPath =
"/data/misc/shared_relro/libwebviewchromium64.relro";
size_t nwebReservedSize = 1 * 1024 * 1024 * 1024;
#else
const std::string nwebRelroPath =
"/data/misc/shared_relro/libwebviewchromium32.relro";
size_t nwebReservedSize = 130 * 1024 * 1024;
#endif
if (unlink(nwebRelroPath.c_str()) != 0 && errno != ENOENT) {
APPSPAWN_LOGI("LoadWithRelroFile unlink failed");
}
int relroFd =
open(nwebRelroPath.c_str(), O_RDWR | O_TRUNC | O_CLOEXEC | O_CREAT,
S_IRUSR | S_IRGRP | S_IROTH);
if (relroFd < 0) {
int tmpNo = errno;
APPSPAWN_LOGE("LoadWithRelroFile open failed, error=[%{public}s]", strerror(tmpNo));
return nullptr;
}
void *nwebReservedAddress = mmap(nullptr, nwebReservedSize, PROT_NONE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (nwebReservedAddress == MAP_FAILED) {
close(relroFd);
int tmpNo = errno;
APPSPAWN_LOGE("LoadWithRelroFile mmap failed, error=[%{public}s]", strerror(tmpNo));
return nullptr;
}
Dl_namespace dlns;
dlns_init(&dlns, nsName.c_str());
dlns_create(&dlns, nsPath.c_str());
dl_extinfo extinfo = {
.flag = DL_EXT_WRITE_RELRO | DL_EXT_RESERVED_ADDRESS_RECURSIVE |
DL_EXT_RESERVED_ADDRESS,
.relro_fd = relroFd,
.reserved_addr = nwebReservedAddress,
.reserved_size = nwebReservedSize,
};
void *result =
dlopen_ns_ext(&dlns, lib.c_str(), RTLD_NOW | RTLD_GLOBAL, &extinfo);
close(relroFd);
return result;
}
#endif
APPSPAWN_LOGI("RunChildProcessorNweb");
void *webEngineHandle = nullptr;
void *nwebRenderHandle = nullptr;
void LoadExtendLib(AppSpawnContent *content)
{
const std::string loadLibDir = GetNWebHapLibsPath();
#ifdef __MUSL__
Dl_namespace dlns;
dlns_init(&dlns, "nweb_ns");
dlns_create(&dlns, loadLibDir.c_str());
#if defined(webview_x86_64)
void *handle = dlopen_ns(&dlns, "libweb_engine.so", RTLD_NOW | RTLD_GLOBAL);
dlns_create(&dlns, NWEB_HAP_LIB_PATH.c_str());
// preload libweb_engine
webEngineHandle = dlopen_ns(&dlns, "libweb_engine.so", RTLD_NOW | RTLD_GLOBAL);
// load libnweb_render
nwebRenderHandle = dlopen_ns(&dlns, "libnweb_render.so", RTLD_NOW | RTLD_GLOBAL);
#else
void *handle = LoadWithRelroFile("libweb_engine.so", "nweb_ns", loadLibDir);
if (handle == nullptr) {
APPSPAWN_LOGE("dlopen_ns_ext failed, fallback to dlopen_ns");
handle = dlopen_ns(&dlns, "libweb_engine.so", RTLD_NOW | RTLD_GLOBAL);
}
// preload libweb_engine
const std::string engineLibDir = NWEB_HAP_LIB_PATH + "/libweb_engine.so";
webEngineHandle = dlopen(engineLibDir.c_str(), RTLD_NOW | RTLD_GLOBAL);
// load libnweb_render
const std::string renderLibDir = NWEB_HAP_LIB_PATH + "/libnweb_render.so";
nwebRenderHandle = dlopen(renderLibDir.c_str(), RTLD_NOW | RTLD_GLOBAL);
#endif
#else
const std::string engineLibDir = loadLibDir + "/libweb_engine.so";
void *handle = dlopen(engineLibDir.c_str(), RTLD_NOW | RTLD_GLOBAL);
#endif
if (handle == nullptr) {
if (webEngineHandle == nullptr) {
APPSPAWN_LOGE("Fail to dlopen libweb_engine.so, [%{public}s]", dlerror());
} else {
APPSPAWN_LOGI("Success to dlopen libweb_engine.so");
}
#ifdef __MUSL__
g_nwebHandle = dlopen_ns(&dlns, "libnweb_render.so", RTLD_NOW | RTLD_GLOBAL);
#else
const std::string renderLibDir = loadLibDir + "/libnweb_render.so";
g_nwebHandle = dlopen(renderLibDir.c_str(), RTLD_NOW | RTLD_GLOBAL);
#endif
if (g_nwebHandle == nullptr) {
if (nwebRenderHandle == nullptr) {
APPSPAWN_LOGE("Fail to dlopen libnweb_render.so, [%{public}s]", dlerror());
return;
} else {
APPSPAWN_LOGI("Success to dlopen libnweb_render.so");
}
}
void RunChildProcessor(AppSpawnContent *content, AppSpawnClient *client)
{
AppSpawnClientExt *appProperty = reinterpret_cast<AppSpawnClientExt *>(client);
using FuncType = void (*)(const char *cmd);
FuncType funcNWebRenderMain = reinterpret_cast<FuncType>(dlsym(g_nwebHandle, "NWebRenderMain"));
FuncType funcNWebRenderMain = reinterpret_cast<FuncType>(dlsym(nwebRenderHandle, "NWebRenderMain"));
if (funcNWebRenderMain == nullptr) {
APPSPAWN_LOGI("webviewspawn dlsym ERROR=%{public}s", dlerror());
return;

View File

@ -68,7 +68,13 @@ int32_t SetAppSandboxProperty(struct AppSpawnContent_ *content, AppSpawnClient *
if ((client->cloneFlags & CLONE_NEWNS) != CLONE_NEWNS) {
return 0;
}
int ret = SandboxUtils::SetAppSandboxProperty(client);
int ret = 0;
if (content->isNweb) {
ret = SandboxUtils::SetAppSandboxPropertyNweb(client);
} else {
ret = SandboxUtils::SetAppSandboxProperty(client);
}
// free HspList
if (clientExt->property.hspList.data != nullptr) {
free(clientExt->property.hspList.data);

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2021-2023 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 "nwebspawn_lancher.h"
#include "appspawn_server.h"
#define NWEB_UID 3081
#define NWEB_GID 3081
#define CAP_NUM 2
#define BITLEN32 32
pid_t NwebSpawnLanch()
{
pid_t ret = fork();
if (ret == 0) {
setcon("u:r:nwebspawn:s0");
struct __user_cap_header_struct capHeader;
capHeader.version = _LINUX_CAPABILITY_VERSION_3;
capHeader.pid = 0;
const uint64_t inheriTable = 0x2000c0;
const uint64_t permitted = 0x2000c0;
const uint64_t effective = 0x2000c0;
struct __user_cap_data_struct capData[CAP_NUM] = {};
for (int j = 0; j < CAP_NUM; ++j) {
capData[0].inheritable = (__u32)(inheriTable);
capData[1].inheritable = (__u32)(inheriTable >> BITLEN32);
capData[0].permitted = (__u32)(permitted);
capData[1].permitted = (__u32)(permitted >> BITLEN32);
capData[0].effective = (__u32)(effective);
capData[1].effective = (__u32)(effective >> BITLEN32);
}
capset(&capHeader, capData);
for (int i = 0; i <= CAP_LAST_CAP; ++i) {
prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0);
}
setuid(NWEB_UID);
setgid(NWEB_GID);
APPSPAWN_LOGI("nwebspawn fork success");
}
return ret;
}

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2021-2023 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 NWEBSPAWNLANCHER_CPP
#define NWEBSPAWNLANCHER_CPP
#include "selinux/selinux.h"
#include <sys/capability.h>
#include <sys/prctl.h>
#include <unistd.h>
#include <sched.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
pid_t NwebSpawnLanch();
#ifdef __cplusplus
}
#endif
#endif

View File

@ -73,6 +73,11 @@
"sandbox-path" : "/vendor/lib",
"sandbox-flags" : [ "bind", "rec" ],
"check-action-status": "false"
}, {
"src-path" : "/vendor/etc/vulkan",
"sandbox-path" : "/vendor/etc/vulkan",
"sandbox-flags" : [ "bind", "rec" ],
"check-action-status": "false"
}, {
"src-path" : "/data/app/el1/bundle/public/<PackageName>",
"sandbox-path" : "/data/storage/el1/bundle",
@ -335,6 +340,18 @@
],
"symbol-links" : []
}],
"com.ohos.amsdialog" : [{
"sandbox-switch": "ON",
"sandbox-root" : "/mnt/sandbox/<PackageName>",
"mount-paths" : [{
"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": "ON",
"sandbox-root" : "/mnt/sandbox/<PackageName>",
@ -366,6 +383,12 @@
"sandbox-root" : "/mnt/sandbox/<PackageName>",
"sandbox-shared" : "true",
"mount-paths" : [{
"src-path" : "/mnt/data/<currentUserId>",
"sandbox-path" : "/mnt/data",
"sandbox-flags" : [ "bind", "rec" ],
"mount-shared-flag" : "true",
"check-action-status": "true"
}, {
"src-path" : "/dev/fuse",
"sandbox-path" : "/mnt/data/fuse",
"sandbox-flags" : [ "MS_NOSUID", "MS_NODEV", "MS_NOEXEC", "MS_NOATIME", "MS_LAZYTIME" ],
@ -385,7 +408,7 @@
"check-action-status": "true"
},
{
"src-path" : "/mnt/external",
"src-path" : "/mnt/data/external",
"sandbox-path" : "/mnt/external",
"sandbox-flags" : [ "bind", "rec" ],
"check-action-status": "true"
@ -493,7 +516,7 @@
"sandbox-flags": [ "bind", "rec" ]
},
{
"src-path": "/mnt/external",
"src-path": "/mnt/data/external",
"sandbox-path": "/storage/External",
"sandbox-flags": [ "bind", "rec" ]
},
@ -514,7 +537,7 @@
{
"sandbox-switch": "ON",
"sandbox-root": "/mnt/sandbox/<PackageName>",
"gids": [],
"gids": [1008],
"mount-paths": [
{
"src-path": "/storage/media/<currentUserId>/local/files/.thumbs/Photo",

View File

@ -1,4 +1,12 @@
{
"jobs" : [{
"name" : "service:nwebspawn",
"cmds" : [
"mkdir /mnt/sandbox",
"mkdir /mnt/sandbox/com.ohos.render/ 0711 nwebspawn nwebspawn"
]
}
],
"services" : [{
"name" : "appspawn",
"path" : ["/system/bin/appspawn",
@ -11,6 +19,9 @@
"sandbox" : 0,
"start-mode" : "boot",
"secon" : "u:r:appspawn:s0",
"jobs" : {
"on-start" : "service:nwebspawn"
},
"bootevents" : "bootevent.appspawn.started"
}
]

View File

@ -42,7 +42,9 @@
"resource_management",
"hitrace",
"common_event_service",
"hisysevent"
"hisysevent",
"security_component",
"netmanager"
],
"third_party": [
"bounds_checking_function",

View File

@ -20,7 +20,7 @@
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <stdbool.h>
#include "beget_ext.h"
#include "hilog/log.h"
#include "securec.h"
@ -48,6 +48,7 @@ typedef struct AppSpawnClient_ {
typedef struct AppSpawnContent_ {
char *longProcName;
uint32_t longProcNameLen;
bool isNweb;
// system
void (*loadExtendLib)(struct AppSpawnContent_ *content);

View File

@ -23,7 +23,7 @@
extern "C" {
#endif
#if defined(__MUSL__) || defined(NWEB_SPAWN)
#if defined(__MUSL__)
#ifndef APPSPAWN_TEST
#define SOCKET_DIR "/dev/unix/socket/"
#else
@ -33,13 +33,12 @@ extern "C" {
#define SOCKET_DIR "/dev/socket/"
#endif
#ifdef NWEB_SPAWN
#define APPSPAWN_SOCKET_NAME "NWebSpawn"
#define APPSPAWN_SERVER_NAME "nwebspawn"
#else
#define NWEBSPAWN_SOCKET_NAME "NWebSpawn"
#define NWEBSPAWN_SERVER_NAME "nwebspawn"
#define APPSPAWN_SOCKET_NAME "AppSpawn"
#define APPSPAWN_SERVER_NAME "appspawn"
#endif
enum AppType {
APP_TYPE_DEFAULT = 0, // JavaScript app

View File

@ -1,18 +1,13 @@
{
"jobs" : [{
"name" : "service:nwebspawn",
"cmds" : [
"mkdir /mnt/sandbox",
"mkdir /mnt/sandbox/com.ohos.render/ 0711 nwebspawn nwebspawn"
]
}
],
"services" : [{
"name" : "nwebspawn",
"path" : ["/system/bin/nwebspawn",
"--process-name com.ohos.appspawn.startup --start-flags daemon --type standard ",
"--sandbox-switch on --bundle-name com.ohos.appspawn.startup --app-operate-type operate ",
"--render-command command --app-launch-type singleton --app-visible true"],
"uid" : "nwebspawn",
"gid" : ["nwebspawn"],
"caps" : ["SYS_ADMIN", "SETGID", "SETUID"],
"socket" : [{
"name" : "NWebSpawn",
"family" : "AF_LOCAL",
@ -24,13 +19,8 @@
"option" : [
]
}],
"uid" : "nwebspawn",
"gid" : ["nwebspawn"],
"caps" : ["SYS_ADMIN", "SETGID", "SETUID"],
"jobs" : {
"on-start" : "service:nwebspawn"
},
"ondemand" : true,
"disabled" : 1,
"secon" : "u:r:nwebspawn:s0"
}
]

View File

@ -157,7 +157,8 @@ static int SetCapabilities(struct AppSpawnContent_ *content, AppSpawnClient *cli
// set capabilities
isRet = capset(&cap_header, &cap_data[0]) == -1;
APPSPAWN_CHECK(!isRet, return -errno, "capset failed: %{public}d", errno);
SetSelinuxCon(content, client);
isRet = SetSelinuxCon(content, client) == -1;
APPSPAWN_CHECK(!isRet, return -EPERM, "Failed to set selinux context");
return 0;
}
@ -669,17 +670,17 @@ void SetContentFunction(AppSpawnContent *content)
content->setKeepCapabilities = SetKeepCapabilities;
content->setUidGid = SetUidGid;
content->setXpmRegion = SetXpmRegion;
content->setCapabilities = SetCapabilities;
content->setFileDescriptors = SetFileDescriptors;
content->setAppSandbox = SetAppSandboxProperty;
content->setAppAccessToken = SetAppAccessToken;
content->coldStartApp = ColdStartApp;
content->setAsanEnabledEnv = SetAsanEnabledEnv;
#ifdef ASAN_DETECTOR
content->getWrapBundleNameValue = GetWrapBundleNameValue;
#endif
content->setSeccompFilter = SetSeccompFilter;
content->setAppSandbox = SetAppSandboxProperty;
content->setCapabilities = SetCapabilities;
content->setUidGidFilter = SetUidGidFilter;
content->setSeccompFilter = SetSeccompFilter;
content->setAppAccessToken = SetAppAccessToken;
content->handleInternetPermission = HandleInternetPermission;
content->waitForDebugger = WaitForDebugger;
}

View File

@ -93,13 +93,6 @@ APPSPAWN_STATIC void AddAppInfo(pid_t pid, const char *processName)
APPSPAWN_LOGI("Add %{public}s, pid=%{public}d success", processName, pid);
}
APPSPAWN_STATIC void ProcessTimer(const TimerHandle taskHandle, void *context)
{
UNUSED(context);
APPSPAWN_LOGI("timeout stop appspawn");
LE_StopLoop(LE_GetDefaultLoop());
}
static AppInfo *GetAppInfo(pid_t pid)
{
HashNode *node = OH_HashMapGet(g_appSpawnContent->appMap, (const void *)&pid);
@ -116,13 +109,6 @@ static void RemoveAppInfo(pid_t pid)
if ((g_appSpawnContent->flags & FLAGS_ON_DEMAND) != FLAGS_ON_DEMAND) {
return;
}
if (g_appSpawnContent->timer == NULL && OH_HashMapIsEmpty(g_appSpawnContent->appMap) != 0) {
APPSPAWN_LOGI("Start time for appspawn");
int ret = LE_CreateTimer(LE_GetDefaultLoop(), &g_appSpawnContent->timer, ProcessTimer, NULL);
APPSPAWN_CHECK(ret == 0, return, "Failed to create time");
LE_StartTimer(LE_GetDefaultLoop(), g_appSpawnContent->timer, APPSPAWN_EXIT_TIME, 1); // 60000 60s
}
}
static void KillProcess(const HashNode *node, const void *context)
@ -196,11 +182,30 @@ static void HandleDiedPid(pid_t pid, uid_t uid, int status)
ReportProcessExitInfo(appInfo->name, pid, uid, status);
#endif
#ifdef NWEB_SPAWN
// delete app info
RemoveAppInfo(pid);
}
static void HandleDiedPidNweb(pid_t pid, uid_t uid, int status)
{
AppInfo *appInfo = GetAppInfo(pid);
APPSPAWN_CHECK(appInfo != NULL, return, "Can not find app info for %{public}d", pid);
if (WIFSIGNALED(status)) {
APPSPAWN_LOGW("%{public}s with pid %{public}d exit with signal:%{public}d",
appInfo->name, pid, WTERMSIG(status));
}
if (WIFEXITED(status)) {
APPSPAWN_LOGW("%{public}s with pid %{public}d exit with code:%{public}d",
appInfo->name, pid, WEXITSTATUS(status));
}
#ifdef REPORT_EVENT
ReportProcessExitInfo(appInfo->name, pid, uid, status);
#endif
// nwebspawn will invoke waitpid and remove appinfo at GetProcessTerminationStatusInner when
// GetProcessTerminationStatusInner is called before the parent process receives the SIGCHLD signal.
RecordRenderProcessExitedStatus(pid, status);
#endif
// delete app info
RemoveAppInfo(pid);
@ -229,6 +234,29 @@ APPSPAWN_STATIC void SignalHandler(const struct signalfd_siginfo *siginfo)
}
}
APPSPAWN_STATIC void SignalHandlerNweb(const struct signalfd_siginfo *siginfo)
{
APPSPAWN_LOGI("SignalHandler signum %{public}d", siginfo->ssi_signo);
switch (siginfo->ssi_signo) {
case SIGCHLD: { // delete pid from app map
pid_t pid;
int status;
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
HandleDiedPidNweb(pid, siginfo->ssi_uid, status);
}
break;
}
case SIGTERM: { // appswapn killed, use kill without parameter
OH_HashMapTraverse(g_appSpawnContent->appMap, KillProcess, NULL);
LE_StopLoop(LE_GetDefaultLoop());
break;
}
default:
APPSPAWN_LOGI("SigHandler, unsupported signal %{public}d.", siginfo->ssi_signo);
break;
}
}
static void HandleSpecial(AppSpawnClientExt *appProperty)
{
// special handle bundle name medialibrary and scanner
@ -239,8 +267,8 @@ static void HandleSpecial(AppSpawnClientExt *appProperty)
for (size_t i = 0; i < sizeof(specialBundleNames) / sizeof(specialBundleNames[0]); i++) {
if (strcmp(appProperty->property.bundleName, specialBundleNames[i]) == 0) {
if (appProperty->property.gidCount < APP_MAX_GIDS) {
appProperty->property.gidTable[appProperty->property.gidCount] = GID_USER_DATA_RW;
appProperty->property.gidCount++;
appProperty->property.gidTable[appProperty->property.gidCount++] = GID_USER_DATA_RW;
appProperty->property.gidTable[appProperty->property.gidCount++] = GID_FILE_ACCESS;
}
break;
@ -452,7 +480,7 @@ static void OnReceiveRequest(const TaskHandle taskHandle, const uint8_t *buffer,
return;
}
#ifdef NWEB_SPAWN
if (g_appSpawnContent->content.isNweb) {
// get render process termination status, only nwebspawn need this logic.
if (appProperty->property.code == GET_RENDER_TERMINATION_STATUS) {
int ret = GetProcessTerminationStatus(&appProperty->client);
@ -460,8 +488,7 @@ static void OnReceiveRequest(const TaskHandle taskHandle, const uint8_t *buffer,
SendResponse(appProperty, (char *)&ret, sizeof(ret));
return;
}
#endif
}
APPSPAWN_CHECK(appProperty->property.gidCount <= APP_MAX_GIDS && strlen(appProperty->property.processName) > 0,
LE_CloseTask(LE_GetDefaultLoop(), taskHandle);
return, "Invalid property %{public}u", appProperty->property.gidCount);
@ -593,7 +620,14 @@ static void AppSpawnRun(AppSpawnContent *content, int argc, char *const argv[])
AppSpawnContentExt *appSpawnContent = (AppSpawnContentExt *)content;
APPSPAWN_CHECK(appSpawnContent != NULL, return, "Invalid appspawn content");
LE_STATUS status = LE_CreateSignalTask(LE_GetDefaultLoop(), &appSpawnContent->sigHandler, SignalHandler);
LE_STATUS status;
if (content->isNweb) {
status = LE_CreateSignalTask(LE_GetDefaultLoop(), &appSpawnContent->sigHandler, SignalHandlerNweb);
} else {
status = LE_CreateSignalTask(LE_GetDefaultLoop(), &appSpawnContent->sigHandler, SignalHandler);
}
if (status == 0) {
(void)LE_AddSignal(LE_GetDefaultLoop(), appSpawnContent->sigHandler, SIGCHLD);
(void)LE_AddSignal(LE_GetDefaultLoop(), appSpawnContent->sigHandler, SIGTERM);
@ -651,7 +685,11 @@ static int CreateAppSpawnServer(AppSpawnContentExt *appSpawnContent, const char
ret = chmod(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
APPSPAWN_CHECK(ret == 0, return -1, "Failed to chmod %{public}s, err %{public}d. ", path, errno);
#ifndef APPSPAWN_CHECK_GID_UID
if (appSpawnContent->content.isNweb) {
ret = lchown(path, 3081, 3081); // 3081 is appspawn gid
} else {
ret = lchown(path, 0, 4000); // 4000 is appspawn gid
}
APPSPAWN_CHECK(ret == 0, return -1, "Failed to lchown %{public}s, err %{public}d. ", path, errno);
#endif
APPSPAWN_LOGI("CreateAppSpawnServer path %{public}s fd %{public}d",
@ -670,6 +708,11 @@ AppSpawnContent *AppSpawnCreateContent(const char *socketName, char *longProcNam
(void)memset_s(&appSpawnContent->content, sizeof(appSpawnContent->content), 0, sizeof(appSpawnContent->content));
appSpawnContent->content.longProcName = longProcName;
appSpawnContent->content.longProcNameLen = longProcNameLen;
if (strcmp(longProcName, NWEBSPAWN_SERVER_NAME) == 0) {
appSpawnContent->content.isNweb = true;
} else {
appSpawnContent->content.isNweb = false;
}
appSpawnContent->timer = NULL;
appSpawnContent->flags = 0;
appSpawnContent->server = NULL;

View File

@ -17,6 +17,7 @@
#define APPSPAWN_SERVICE_H
#include <unistd.h>
#include <stdbool.h>
#include "appspawn_msg.h"
#include "appspawn_server.h"
#include "init_hashmap.h"

View File

@ -21,7 +21,7 @@
#include "securec.h"
#include "init_param.h"
#include "syspara/parameter.h"
#include "nwebspawn_lancher.h"
#define APPSPAWN_PRELOAD "libappspawn_helper.z.so"
static void CheckPreload(char *const argv[])
@ -54,6 +54,7 @@ int main(int argc, char *const argv[])
(void)signal(SIGPIPE, SIG_IGN);
uint32_t argvSize = 0;
int mode = 0;
pid_t pid = 1;
if ((argc > PARAM_INDEX) && (strcmp(argv[START_INDEX], "cold-start") == 0)) {
argvSize = APP_LEN_PROC_NAME;
mode = 1;
@ -68,12 +69,30 @@ int main(int argc, char *const argv[])
if (argvSize > APP_MSG_MAX_SIZE) {
return -1;
}
pid = NwebSpawnLanch();
int isRet = memset_s(argv[0], argvSize, 0, (size_t)argvSize) != EOK;
APPSPAWN_CHECK(!isRet, return -EINVAL, "Failed to memset argv[0]");
if (pid == 0) {
isRet = strncpy_s(argv[0], argvSize, NWEBSPAWN_SERVER_NAME, strlen(NWEBSPAWN_SERVER_NAME)) != EOK;
} else {
isRet = strncpy_s(argv[0], argvSize, APPSPAWN_SERVER_NAME, strlen(APPSPAWN_SERVER_NAME)) != EOK;
}
APPSPAWN_CHECK(!isRet, return -EINVAL, "strncpy_s appspawn server name error: %{public}d", errno);
}
if (pid == 0) {
APPSPAWN_LOGI("NwebSpawnCreateContent argc %{public}d mode %{public}d %{public}u", argc, mode, argvSize);
AppSpawnContent *content = AppSpawnCreateContent(NWEBSPAWN_SOCKET_NAME, argv[0], argvSize, mode);
APPSPAWN_CHECK(content != NULL, return -1, "Invalid content for nwebspawn");
APPSPAWN_CHECK(content->initAppSpawn != NULL, return -1, "Invalid content for nwebspawn");
APPSPAWN_CHECK(content->runAppSpawn != NULL, return -1, "Invalid content for nwebspawn");
// set common operation
content->loadExtendLib = LoadExtendLibNweb;
content->runChildProcessor = RunChildProcessorNweb;
content->initAppSpawn(content);
content->runAppSpawn(content, argc, argv);
} else {
APPSPAWN_LOGI("AppSpawnCreateContent argc %{public}d mode %{public}d %{public}u", argc, mode, argvSize);
AppSpawnContent *content = AppSpawnCreateContent(APPSPAWN_SOCKET_NAME, argv[0], argvSize, mode);
APPSPAWN_CHECK(content != NULL, return -1, "Invalid content for appspawn");
@ -88,6 +107,7 @@ int main(int argc, char *const argv[])
SystemSetParameter("bootevent.appspawn.started", "true");
}
content->runAppSpawn(content, argc, argv);
}
return 0;
}

View File

@ -67,7 +67,7 @@ config("utest_config") {
ohos_unittest("AppSpawn_ut") {
module_out_path = "${module_output_path}"
deps = []
defines = [
"clone=CloneStub",
"bind=BindStub",
@ -92,6 +92,7 @@ ohos_unittest("AppSpawn_ut") {
sources = [
"${appspawn_path}/adapter/appspawn_ace.cpp",
"${appspawn_path}/adapter/appspawn_adapter.cpp",
"${appspawn_path}/adapter/appspawn_nweb.cpp",
"${appspawn_path}/adapter/appspawn_sandbox.cpp",
"${appspawn_path}/common/appspawn_server.c",
"${appspawn_path}/interfaces/innerkits/client/appspawn_socket.cpp",
@ -112,13 +113,14 @@ ohos_unittest("AppSpawn_ut") {
]
configs = [ "//base/startup/appspawn/test/unittest:utest_config" ]
deps += [ "//third_party/selinux:libselinux" ]
external_deps = [
"ability_base:want",
"ability_runtime:app_manager",
"ability_runtime:appkit_native",
"ability_runtime:runtime",
"access_token:libtoken_setproc",
"access_token:libtokenid_sdk",
"bundle_framework:appexecfwk_base",
"bundle_framework:appexecfwk_core",
"c_utils:utils",

View File

@ -1058,33 +1058,32 @@ HWTEST(AppSpawnSandboxTest, App_Spawn_Sandbox_33, TestSize.Level0)
m_appProperty->uid = 1000;
m_appProperty->gid = 1000;
const char *srcPath = "/data/app/el1";
std::string path = srcPath;
std::string path = "/data/app/el1";
OHOS::AppSpawn::SandboxUtils::CheckAndPrepareSrcPath(m_appProperty, path);
const char *srcPath1 = "/data/app/el2/100/base/ohos.test.bundle1";
std::string path1 = srcPath1;
std::string path1 = "/data/app/el2/100/base/ohos.test.bundle1";
OHOS::AppSpawn::SandboxUtils::CheckAndPrepareSrcPath(m_appProperty, path1);
const char *srcPath2 = "/data/app/el2/100/database/ohos.test.bundle2";
std::string path2 = srcPath2;
std::string path2 = "/data/app/el2/100/database/ohos.test.bundle2";
OHOS::AppSpawn::SandboxUtils::CheckAndPrepareSrcPath(m_appProperty, path2);
const char *srcPath3 = "/data/app/el2/100/test123/ohos.test.bundle3";
std::string path3 = srcPath3;
std::string path3 = "/data/app/el2/100/test123/ohos.test.bundle3";
OHOS::AppSpawn::SandboxUtils::CheckAndPrepareSrcPath(m_appProperty, path3);
const char *srcPath4 = "/data/serivce/el2/100/hmdfs/account/data/ohos.test.bundle4";
std::string path4 = srcPath4;
std::string path4 = "/data/serivce/el2/100/hmdfs/account/data/ohos.test.bundle4";
OHOS::AppSpawn::SandboxUtils::CheckAndPrepareSrcPath(m_appProperty, path4);
const char *srcPath5 = "/data/serivce/el2/100/hmdfs/non_account/data/ohos.test.bundle5";
std::string path5 = srcPath5;
std::string path5 = "/data/serivce/el2/100/hmdfs/non_account/data/ohos.test.bundle5";
OHOS::AppSpawn::SandboxUtils::CheckAndPrepareSrcPath(m_appProperty, path5);
const char *srcPath6 = "/data/serivce/el2/100/hmdfs/non_account/test/ohos.test.bundle6";
std::string path6 = srcPath6;
std::string path6 = "/data/serivce/el2/100/hmdfs/non_account/test/ohos.test.bundle6";
OHOS::AppSpawn::SandboxUtils::CheckAndPrepareSrcPath(m_appProperty, path6);
std::string path7 = "/data/app/el2/100/group/091a68a9-2cc9-4279-8849-28631b598975";
OHOS::AppSpawn::SandboxUtils::CheckAndPrepareSrcPath(m_appProperty, path7);
std::string path8 = "/data/app/el2/100/group/ce876162-fe69-45d3-aa8e-411a047af564";
OHOS::AppSpawn::SandboxUtils::CheckAndPrepareSrcPath(m_appProperty, path8);
SUCCEED();
}
@ -1411,4 +1410,48 @@ HWTEST(AppSpawnSandboxTest, App_Spawn_Sandbox_39, TestSize.Level0)
GTEST_LOG_(INFO) << "App_Spawn_Sandbox_39 end";
}
/**
* @tc.name: App_Spawn_Sandbox_40
* @tc.desc: load group info config SetAppSandboxProperty
* @tc.type: FUNC
* @tc.require:issueI7FUPV
* @tc.author:
*/
HWTEST(AppSpawnSandboxTest, App_Spawn_Sandbox_40, TestSize.Level0)
{
GTEST_LOG_(INFO) << "App_Spawn_Sandbox_40 start";
ClientSocket::AppProperty *m_appProperty = GetAppProperty();
m_appProperty->uid = 1100;
m_appProperty->gid = 1100;
m_appProperty->gidCount = 2;
m_appProperty->flags |= 0x100;
std::string sandboxPrefix = "/mnt/sandbox/testBundle";
if (strcpy_s(m_appProperty->bundleName, APP_LEN_BUNDLE_NAME, "testBundle") != 0) {
GTEST_LOG_(INFO) << "SetAppSandboxProperty set bundleName" << std::endl;
}
{ // totalLength is 0
m_appProperty->dataGroupInfoList = {};
int ret = OHOS::AppSpawn::SandboxUtils::MountAllGroup(m_appProperty, sandboxPrefix);
EXPECT_EQ(0, ret);
}
{ // data is nullptr
m_appProperty->dataGroupInfoList = {1, nullptr};
int ret = OHOS::AppSpawn::SandboxUtils::MountAllGroup(m_appProperty, sandboxPrefix);
EXPECT_EQ(0, ret);
}
{ // success
char dataGroupInfoListStr[] = "{ \
\"dataGroupId\":[\"1234abcd5678efgh\", \"abcduiop1234\"], \
\"dir\":[\"/data/app/el2/100/group/091a68a9-2cc9-4279-8849-28631b598975\", \
\"/data/app/el2/100/group/ce876162-fe69-45d3-aa8e-411a047af564\"], \
\"gid\":[\"20100001\", \"20100002\"] \
}";
m_appProperty->dataGroupInfoList = {strlen(dataGroupInfoListStr), dataGroupInfoListStr};
int ret = OHOS::AppSpawn::SandboxUtils::MountAllGroup(m_appProperty, sandboxPrefix);
EXPECT_EQ(0, ret);
}
m_appProperty->dataGroupInfoList = {};
GTEST_LOG_(INFO) << "App_Spawn_Sandbox_40 end";
}
} // namespace OHOS

View File

@ -52,7 +52,6 @@ TaskHandle AcceptClient(const LoopHandle loopHandle, const TaskHandle server, ui
bool ReceiveRequestData(const TaskHandle taskHandle, AppSpawnClientExt *appProperty,
const uint8_t *buffer, uint32_t buffLen);
void AddAppInfo(pid_t pid, const char *processName);
void ProcessTimer(const TimerHandle taskHandle, void *context);
void SignalHandler(const struct signalfd_siginfo *siginfo);
#ifdef __cplusplus
}
@ -123,6 +122,13 @@ static void CheckAndCreateDir(const char *fileName)
free(path);
}
static void ProcessTimer(const TimerHandle taskHandle, void *context)
{
UNUSED(context);
APPSPAWN_LOGI("timeout stop appspawn");
LE_StopLoop(LE_GetDefaultLoop());
}
namespace OHOS {
class AppSpawnStandardTest : public testing::Test {
public:
@ -157,69 +163,6 @@ static void FreeHspList(HspList &hspList)
hspList = {};
}
/**
* @tc.name: App_Spawn_Standard_002
* @tc.desc: fork app son process and set content.
* @tc.type: FUNC
* @tc.require:issueI5NTX6
* @tc.author:
*/
HWTEST(AppSpawnStandardTest, App_Spawn_Standard_002, TestSize.Level0)
{
CheckAndCreateDir("/data/appspawn_ut/dev/unix/socket/");
GTEST_LOG_(INFO) << "App_Spawn_Standard_002 start";
char longProcName[124] = "App_Spawn_Standard_002";
int64_t longProcNameLen = 124; // 124 is str length
AppSpawnClientExt* client = (AppSpawnClientExt*)malloc(sizeof(AppSpawnClientExt));
client->client.id = 8; // 8 is client id
client->client.flags = 0;
client->client.cloneFlags = CLONE_NEWNS;
client->fd[0] = 100; // 100 is fd
client->fd[1] = 200; // 200 is fd
client->property.uid = 10000; // 10000 is uid
client->property.gid = 1000; // 1000 is gid
client->property.gidCount = 1; // 1 is gidCount
if (strcpy_s(client->property.processName, APP_LEN_PROC_NAME, "xxx.xxx.xxx") != 0) {
GTEST_LOG_(INFO) << "strcpy_s failed";
}
if (strcpy_s(client->property.bundleName, APP_LEN_BUNDLE_NAME, "xxx.xxx.xxx") != 0) {
GTEST_LOG_(INFO) << "strcpy_s failed";
}
if (strcpy_s(client->property.soPath, APP_LEN_SO_PATH, "xxx") != 0) {
GTEST_LOG_(INFO) << "strcpy_s failed";
}
client->property.accessTokenId = 671201800; // 671201800 is accessTokenId
if (strcpy_s(client->property.apl, APP_APL_MAX_LEN, "xxx") != 0) {
GTEST_LOG_(INFO) << "strcpy_s failed";
}
if (strcpy_s(client->property.renderCmd, APP_RENDER_CMD_MAX_LEN, "xxx") != 0) {
GTEST_LOG_(INFO) << "strcpy_s failed";
}
client->property.hspList = {0, 0, nullptr};
AppSpawnContent *content = AppSpawnCreateContent("AppSpawn", longProcName, longProcNameLen, 1);
content->loadExtendLib = LoadExtendLib;
content->runChildProcessor = RunChildProcessor;
SetContentFunction(content);
content->clearEnvironment(content, &client->client);
EXPECT_EQ(content->setProcessName(content, &client->client, (char *)longProcName, longProcNameLen), 0);
EXPECT_EQ(content->setKeepCapabilities(content, &client->client), 0);
EXPECT_EQ(content->setUidGid(content, &client->client), 0);
EXPECT_EQ(content->setCapabilities(content, &client->client), 0);
EXPECT_EQ(content->setFileDescriptors(content, &client->client), 0);
// test invalid
EXPECT_NE(content->setProcessName(content, &client->client, nullptr, 0), 0);
content->setAppSandbox(content, &client->client);
int ret = content->setAppAccessToken(content, &client->client);
EXPECT_EQ(ret, 0);
EXPECT_NE(content->coldStartApp(content, &client->client), 0);
GTEST_LOG_(INFO) << "App_Spawn_Standard_002 end";
}
/**
* @tc.name: App_Spawn_Standard_003
* @tc.desc: Verify set Arg if GetAppSpawnClient succeed.
@ -421,6 +364,60 @@ HWTEST(AppSpawnStandardTest, App_Spawn_Standard_003_3, TestSize.Level0)
APPSPAWN_LOGI("App_Spawn_Standard_003_3 en");
}
/**
* @tc.name: App_Spawn_Standard_003_4
* @tc.desc: Verify set Arg if GetAppSpawnClient succeed, with dataGroupList
* @tc.type: FUNC
* @tc.require:issueI7FUPV
* @tc.author:
*/
HWTEST(AppSpawnStandardTest, App_Spawn_Standard_003_4, TestSize.Level0)
{
APPSPAWN_LOGI("App_Spawn_Standard_003_4 start");
AppSpawnClientExt client = {};
char arg1[] = "/system/bin/appspawn";
char arg2[] = "cold-start";
char arg3[] = "1";
char arg4[] = "1:1:1:1:1:1:1:1:1:2:1000:1000:ohos.samples:ohos.samples.ecg:"
"default:671201800:system_core:default:0:671201800";
char arg5[] = "0";
char arg6[] = "0";
char arg7[] = "0";
char arg8[] = "0";
{
char arg9[] = "10";
char arg10[] = "012345678";
char* argv[] = {arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10};
int argc = sizeof(argv)/sizeof(argv[0]);
EXPECT_EQ(0, GetAppSpawnClientFromArg(argc, argv, &client));
FreeHspList(client.property.hspList);
}
{ // dataGroupList length is 0
char arg9[] = "0";
char* argv[] = {arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, nullptr};
int argc = sizeof(argv)/sizeof(argv[0]);
EXPECT_EQ(-1, GetAppSpawnClientFromArg(argc, argv, &client));
}
{ // dataGroupList length is nullptr
char arg10[] = "0123456789";
char* argv[] = {arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, nullptr, arg10};
int argc = sizeof(argv)/sizeof(argv[0]);
EXPECT_EQ(-1, GetAppSpawnClientFromArg(argc, argv, &client));
}
{ // dataGroupList length is non-zero, but argc is 7
char arg9[] = "10";
char* argv[] = {arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9};
int argc = sizeof(argv)/sizeof(argv[0]);
EXPECT_EQ(-1, GetAppSpawnClientFromArg(argc, argv, &client));
}
{ // dataGroupList length is non-zero, but content is nullptr
char arg9[] = "10";
char* argv[] = {arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, nullptr};
int argc = sizeof(argv)/sizeof(argv[0]);
EXPECT_EQ(-1, GetAppSpawnClientFromArg(argc, argv, &client));
}
APPSPAWN_LOGI("App_Spawn_Standard_003_4 en");
}
/**
* @tc.name: App_Spawn_Standard_004
* @tc.desc: App cold start.
* @tc.type: FUNC
@ -505,6 +502,22 @@ HWTEST(AppSpawnStandardTest, App_Spawn_Standard_005, TestSize.Level0)
ret = SetAppSandboxProperty((AppSpawnContent_*)content, &clientExt->client);
EXPECT_EQ(ret, 0);
// APP_NO_SANDBOX
clientExt->property.flags |= APP_NO_SANDBOX;
ret = SetAppSandboxProperty((AppSpawnContent_*)content, &clientExt->client);
EXPECT_EQ(ret, 0);
clientExt->property.flags &= ~APP_NO_SANDBOX;
// bundle name
clientExt->property.hspList.data = strdup("{ \
\"bundles\":[\"test.bundle1\", \"test.bundle2\"], \
\"modules\":[\"module1\", \"module2\"], \
\"versions\":[\"v10001\", \"v10002\"] \
}");
clientExt->property.hspList.totalLength = strlen(clientExt->property.hspList.data);
ret = SetAppSandboxProperty((AppSpawnContent_*)content, &clientExt->client);
EXPECT_EQ(ret, 0);
free(content);
GTEST_LOG_(INFO) << "App_Spawn_Standard_005 end";
}
@ -560,6 +573,7 @@ static AppSpawnContentExt *TestClient(int flags,
AppOperateType code, const std::string &processName, const std::string &serverName)
{
char buffer[64] = {0}; // 64 buffer size
CheckAndCreateDir(SOCKET_DIR);
AppSpawnContentExt *content =
(AppSpawnContentExt *)AppSpawnCreateContent(serverName.c_str(), buffer, sizeof(buffer), 0);
if (content == nullptr) {
@ -649,7 +663,7 @@ HWTEST(AppSpawnStandardTest, App_Spawn_Standard_006_4, TestSize.Level0)
{
GTEST_LOG_(INFO) << "App_Spawn_Standard_006_4 start";
SetHapDomainSetcontextResult(-1);
SetParameter("const.appspawn.preload", "false");
AppSpawnContentExt *content = TestClient(APP_COLD_BOOT,
DEFAULT, "com.ohos.medialibrary.medialibrarydata", "test006_2");
ASSERT_TRUE(content != nullptr);

View File

@ -16,10 +16,12 @@
#ifndef SANDBOX_UTILS_H
#define SANDBOX_UTILS_H
#include <string>
#include <vector>
#include <set>
#include <string>
#include <sys/mount.h>
#include <sys/types.h>
#include <vector>
#include "nlohmann/json.hpp"
#include "client_socket.h"
#include "appspawn_server.h"
@ -33,13 +35,14 @@ public:
static void StoreJsonConfig(nlohmann::json &appSandboxConfig);
static std::vector<nlohmann::json> &GetJsonConfig();
static int32_t SetAppSandboxProperty(AppSpawnClient *client);
static int32_t SetAppSandboxPropertyNweb(AppSpawnClient *client);
static uint32_t GetNamespaceFlagsFromConfig(const char *bundleName);
static std::set<std::string> GetMountPermissionNames();
private:
static int32_t DoAppSandboxMountOnce(const char *originPath, const char *destinationPath,
const char *fsType, unsigned long mountFlags,
const char *options);
const char *options, mode_t mountSharedFlag = MS_SLAVE);
static int32_t DoSandboxFileCommonBind(const ClientSocket::AppProperty *appProperty, nlohmann::json &wholeConfig);
static int32_t DoSandboxFileCommonSymlink(const ClientSocket::AppProperty *appProperty,
nlohmann::json &wholeConfig);
@ -78,6 +81,8 @@ private:
nlohmann::json &config);
static int32_t SetRenderSandboxProperty(const ClientSocket::AppProperty *appProperty,
std::string &sandboxPackagePath);
static int32_t SetRenderSandboxPropertyNweb(const ClientSocket::AppProperty *appProperty,
std::string &sandboxPackagePath);
static int32_t SetOverlayAppSandboxProperty(const ClientSocket::AppProperty *appProperty,
std::string &sandboxPackagePath);
static int32_t DoSandboxFilePermissionBind(ClientSocket::AppProperty *appProperty,

View File

@ -104,17 +104,15 @@ namespace {
const char *g_topSandBoxSwitchPrefix = "top-sandbox-switch";
const char *g_targetName = "target-name";
const char *g_flagePoint = "flags-point";
const char *g_mountSharedFlag = "mount-shared-flag";
const char *g_flags = "flags";
const char *g_sandBoxNameSpace = "sandbox-namespace";
const char *g_sandBoxCloneFlags = "clone-flags";
const char* g_fileSeparator = "/";
const char* g_overlayDecollator = "|";
#ifndef NWEB_SPAWN
const std::string g_sandBoxRootDir = "/mnt/sandbox/";
#else
const std::string g_ohosRender = "__internal__.com.ohos.render";
const std::string g_sandBoxRootDir = "/mnt/sandbox/com.ohos.render/";
#endif
const std::string g_sandBoxRootDirNweb = "/mnt/sandbox/com.ohos.render/";
}
nlohmann::json SandboxUtils::appNamespaceConfig_;
@ -200,7 +198,7 @@ static void MakeDirRecursive(const std::string &path, mode_t mode)
int32_t SandboxUtils::DoAppSandboxMountOnce(const char *originPath, const char *destinationPath,
const char *fsType, unsigned long mountFlags,
const char *options)
const char *options, mode_t mountSharedFlag)
{
// To make sure destinationPath exist
MakeDirRecursive(destinationPath, FILE_MODE);
@ -213,7 +211,7 @@ int32_t SandboxUtils::DoAppSandboxMountOnce(const char *originPath, const char *
destinationPath);
return ret;
}
ret = mount(NULL, destinationPath, NULL, MS_SLAVE, NULL);
ret = mount(NULL, destinationPath, NULL, mountSharedFlag, NULL);
APPSPAWN_CHECK(ret == 0, return ret,
"errno is: %{public}d, private mount to %{public}s failed", errno, destinationPath);
#endif
@ -539,17 +537,16 @@ int SandboxUtils::DoAllMntPointsMount(const ClientSocket::AppProperty *appProper
mntPoint[g_sandBoxPath].get<std::string>());
unsigned long mountFlags = GetMountFlagsFromConfig(mntPoint[g_sandBoxFlags].get<std::vector<std::string>>());
std::string fsType = (mntPoint.find(g_fsType) != mntPoint.end()) ? mntPoint[g_fsType].get<std::string>() : "";
const char* fsTypePoint = fsType.empty() ? nullptr : fsType.c_str();
mode_t mountSharedFlag = (mntPoint.find(g_mountSharedFlag) != mntPoint.end()) ? MS_SHARED : MS_SLAVE;
/* check and prepare /data/app/el2 base and database package path to avoid BMS failed to create this folder */
CheckAndPrepareSrcPath(appProperty, srcPath);
/* if app mount failed for special strategy, we need deal with common mount config */
int ret = HandleSpecialAppMount(appProperty, srcPath, sandboxPath, fsType, mountFlags);
if (ret < 0) {
if (fsType.empty()) {
ret = DoAppSandboxMountOnce(srcPath.c_str(), sandboxPath.c_str(), nullptr, mountFlags, nullptr);
} else {
ret = DoAppSandboxMountOnce(srcPath.c_str(), sandboxPath.c_str(), fsType.c_str(), mountFlags, nullptr);
}
ret = DoAppSandboxMountOnce(srcPath.c_str(), sandboxPath.c_str(), fsTypePoint,
mountFlags, nullptr, mountSharedFlag);
}
if (ret) {
std::string actionStatus = g_statusCheck;
@ -804,7 +801,12 @@ int32_t SandboxUtils::SetPermissionAppSandboxProperty_(ClientSocket::AppProperty
int32_t SandboxUtils::SetRenderSandboxProperty(const ClientSocket::AppProperty *appProperty,
std::string &sandboxPackagePath)
{
#ifdef NWEB_SPAWN
return 0;
}
int32_t SandboxUtils::SetRenderSandboxPropertyNweb(const ClientSocket::AppProperty *appProperty,
std::string &sandboxPackagePath)
{
for (auto config : SandboxUtils::GetJsonConfig()) {
nlohmann::json privateAppConfig = config[g_privatePrefix][0];
@ -820,7 +822,6 @@ int32_t SandboxUtils::SetRenderSandboxProperty(const ClientSocket::AppProperty *
appProperty->bundleName);
}
}
#endif
return 0;
}
@ -995,7 +996,6 @@ int32_t SandboxUtils::MountAllGroup(const ClientSocket::AppProperty *appProperty
APPSPAWN_CHECK(dataGroupIds[i].is_string() && gids[i].is_string() && dirs[i].is_string(),
return -1, "MountAllGroup: element type error");
std::string gid = gids[i];
std::string libPhysicalPath = dirs[i];
APPSPAWN_CHECK(!CheckPath(libPhysicalPath), return -1, "MountAllGroup: path error");
@ -1150,7 +1150,6 @@ int32_t SandboxUtils::SetAppSandboxProperty(AppSpawnClient *client)
rc = DoSandboxRootFolderCreate(appProperty, sandboxPackagePath);
}
APPSPAWN_CHECK(rc == 0, return rc, "DoSandboxRootFolderCreate failed, %{public}s", bundleName.c_str());
#ifndef NWEB_SPAWN
rc = SetCommonAppSandboxProperty(appProperty, sandboxPackagePath);
APPSPAWN_CHECK(rc == 0, return rc, "SetCommonAppSandboxProperty failed, packagename is %{public}s",
bundleName.c_str());
@ -1162,15 +1161,69 @@ int32_t SandboxUtils::SetAppSandboxProperty(AppSpawnClient *client)
rc = SetPermissionAppSandboxProperty(appProperty);
APPSPAWN_CHECK(rc == 0, return rc, "SetPermissionAppSandboxProperty failed, packagename is %{public}s",
bundleName.c_str());
#else
rc = SetOverlayAppSandboxProperty(appProperty, sandboxPackagePath);
APPSPAWN_CHECK(rc == 0, return rc, "SetOverlayAppSandboxProperty failed, packagename is %s",
bundleName.c_str());
#ifndef APPSPAWN_TEST
rc = chdir(sandboxPackagePath.c_str());
APPSPAWN_CHECK(rc == 0, return rc, "chdir failed, packagename is %{public}s, path is %{public}s",
bundleName.c_str(), sandboxPackagePath.c_str());
if (sandboxSharedStatus) {
rc = chroot(sandboxPackagePath.c_str());
APPSPAWN_CHECK(rc == 0, return rc, "chroot failed, path is %{public}s errno is %{public}d",
sandboxPackagePath.c_str(), errno);
return 0;
}
rc = syscall(SYS_pivot_root, sandboxPackagePath.c_str(), sandboxPackagePath.c_str());
APPSPAWN_CHECK(rc == 0, return rc, "errno is %{public}d, pivot root failed, packagename is %{public}s",
errno, bundleName.c_str());
rc = umount2(".", MNT_DETACH);
APPSPAWN_CHECK(rc == 0, return rc, "MNT_DETACH failed, packagename is %{public}s", bundleName.c_str());
#endif
return 0;
}
int32_t SandboxUtils::SetAppSandboxPropertyNweb(AppSpawnClient *client)
{
APPSPAWN_CHECK(client != NULL, return -1, "Invalid appspwn client");
AppSpawnClientExt *clientExt = reinterpret_cast<AppSpawnClientExt *>(client);
ClientSocket::AppProperty *appProperty = &clientExt->property;
if (CheckBundleName(appProperty->bundleName) != 0) {
return -1;
}
std::string sandboxPackagePath = g_sandBoxRootDirNweb;
const std::string bundleName = appProperty->bundleName;
bool sandboxSharedStatus = GetSandboxPrivateSharedStatus(bundleName);
sandboxPackagePath += bundleName;
MakeDirRecursive(sandboxPackagePath.c_str(), FILE_MODE);
int rc = 0;
// when CLONE_NEWPID is enabled, CLONE_NEWNS must be enabled.
if (!(client->cloneFlags & CLONE_NEWPID)) {
// add pid to a new mnt namespace
rc = unshare(CLONE_NEWNS);
APPSPAWN_CHECK(rc == 0, return rc, "unshare failed, packagename is %{public}s", bundleName.c_str());
}
// check app sandbox switch
if ((CheckTotalSandboxSwitchStatus(appProperty) == false) ||
(CheckAppSandboxSwitchStatus(appProperty) == false)) {
rc = DoSandboxRootFolderCreateAdapt(sandboxPackagePath);
} else if (!sandboxSharedStatus) {
rc = DoSandboxRootFolderCreate(appProperty, sandboxPackagePath);
}
APPSPAWN_CHECK(rc == 0, return rc, "DoSandboxRootFolderCreate failed, %{public}s", bundleName.c_str());
// rendering process can be created by different apps,
// and the bundle names of these apps are different,
// so we can't use the method SetPrivateAppSandboxProperty
// which mount dirs by using bundle name.
rc = SetRenderSandboxProperty(appProperty, sandboxPackagePath);
APPSPAWN_CHECK(rc == 0, return rc, "SetRenderSandboxProperty failed, packagename is %{public}s",
rc = SetRenderSandboxPropertyNweb(appProperty, sandboxPackagePath);
APPSPAWN_CHECK(rc == 0, return rc, "SetRenderSandboxPropertyNweb failed, packagename is %{public}s",
sandboxPackagePath.c_str());
#endif
rc = SetOverlayAppSandboxProperty(appProperty, sandboxPackagePath);
APPSPAWN_CHECK(rc == 0, return rc, "SetOverlayAppSandboxProperty failed, packagename is %s",