mirror of
https://gitee.com/openharmony/startup_appspawn
synced 2024-11-27 01:00:38 +00:00
Merge gitee.com:openharmony/startup_appspawn into 0401_change
This commit is contained in:
commit
07b93eb1b0
@ -21,6 +21,9 @@
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <malloc.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#undef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#include <sched.h>
|
||||
@ -207,6 +210,25 @@ static int CloneAppSpawn(void *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ForkProcess(AppSandboxArg *sandbox)
|
||||
{
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
ProcessExit(AppSpawnChild((void *)sandbox));
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
// after calling setns, new process will be in the same pid namespace of the input pid
|
||||
static int SetPidNamespace(int nsPidFd, int nsType)
|
||||
{
|
||||
if (setns(nsPidFd, nsType) < 0) {
|
||||
APPSPAWN_LOGE("set pid namespace nsType:%{pudblic}d failed", nsType);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AppSpawnProcessMsg(AppSandboxArg *sandbox, pid_t *childPid)
|
||||
{
|
||||
APPSPAWN_CHECK(sandbox != NULL && sandbox->content != NULL, return -1, "Invalid content for appspawn");
|
||||
@ -217,9 +239,12 @@ int AppSpawnProcessMsg(AppSandboxArg *sandbox, pid_t *childPid)
|
||||
if (sandbox->content->isNweb) {
|
||||
pid = clone(CloneAppSpawn, NULL, sandbox->client->cloneFlags | SIGCHLD, (void *)sandbox);
|
||||
} else {
|
||||
pid = fork();
|
||||
if (pid == 0) {
|
||||
ProcessExit(AppSpawnChild((void *)sandbox));
|
||||
if (sandbox->content->sandboxNsFlags & CLONE_NEWPID) {
|
||||
SetPidNamespace(sandbox->content->nsInitPidFd, CLONE_NEWPID); // pid_ns_init is the init process
|
||||
pid = ForkProcess(sandbox);
|
||||
SetPidNamespace(sandbox->content->nsSelfPidFd, 0); // go back to original pid namespace
|
||||
} else {
|
||||
pid = ForkProcess(sandbox);
|
||||
}
|
||||
}
|
||||
APPSPAWN_CHECK(pid >= 0, return -errno, "fork child process error: %{public}d", -errno);
|
||||
|
@ -50,7 +50,9 @@ typedef struct AppSpawnContent {
|
||||
uint32_t longProcNameLen;
|
||||
uint32_t sandboxNsFlags;
|
||||
bool isNweb;
|
||||
|
||||
int nsSelfPidFd; // ns pid fd of appspawn
|
||||
int nsInitPidFd; // ns pid fd of pid_ns_init
|
||||
|
||||
// system
|
||||
void (*loadExtendLib)(struct AppSpawnContent *content);
|
||||
int (*initAppSpawn)(struct AppSpawnContent *content);
|
||||
|
@ -37,6 +37,7 @@ if (!defined(ohos_lite)) {
|
||||
"${appspawn_path}/common",
|
||||
"${appspawn_path}/modules/sandbox",
|
||||
"${appspawn_path}/util/include",
|
||||
"${appspawn_path}/modules//module_engine//include",
|
||||
]
|
||||
|
||||
defines = [
|
||||
|
@ -1,25 +0,0 @@
|
||||
[
|
||||
{ "name": "AddPreloadHook" },
|
||||
{ "name": "AddAppChangeHook" },
|
||||
{ "name": "AddAppSpawnHook" },
|
||||
{ "name": "AppSpawnHookExecute" },
|
||||
{ "name": "AppSpawnEnvClear" },
|
||||
{ "name": "GetAppPropertyExt" },
|
||||
{ "name": "CheckAppPropertyFlags" },
|
||||
{ "name": "SetAppPropertyFlags" },
|
||||
{ "name": "IsNWebSpawnMode" },
|
||||
{ "name": "GetAppSpawnMsgType" },
|
||||
{ "name": "GetBundleName" },
|
||||
{ "name": "GetAppProperty" },
|
||||
{ "name": "GetProcessName" },
|
||||
{ "name": "RegChildLooper" },
|
||||
{ "name": "MakeDirRec" },
|
||||
{ "name": "SandboxMountPath" },
|
||||
{ "name": "IsDeveloperModeOn" },
|
||||
{ "name": "AddVariableReplaceHandler" },
|
||||
{ "name": "GetSpawnedProcess" },
|
||||
{ "name": "DumpNormalProperty" },
|
||||
{ "name": "AppSpawnDump" },
|
||||
{ "name": "RegisterExpandSandboxCfgHandler" },
|
||||
{ "name": "IsColdRunMode" }
|
||||
]
|
@ -25,7 +25,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct TagSandboxSection {
|
||||
typedef struct TagSandboxQueue {
|
||||
struct ListNode front;
|
||||
uint32_t type;
|
||||
} SandboxQueue;
|
||||
|
67
modules/ace_adapter/BUILD.gn
Executable file
67
modules/ace_adapter/BUILD.gn
Executable file
@ -0,0 +1,67 @@
|
||||
# Copyright (c) 2024 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.
|
||||
|
||||
import("//base/startup/appspawn/appspawn.gni")
|
||||
import("//build/ohos.gni")
|
||||
|
||||
ohos_shared_library("appspawn_ace") {
|
||||
sources = [
|
||||
"ace_adapter.cpp",
|
||||
"command_lexer.cpp",
|
||||
]
|
||||
include_dirs = [
|
||||
".",
|
||||
"${appspawn_path}/common",
|
||||
"${appspawn_path}/standard",
|
||||
"${appspawn_path}/util/include",
|
||||
]
|
||||
deps = [
|
||||
"${appspawn_path}/modules/module_engine:libappspawn_module_engine",
|
||||
"${appspawn_path}/util:libappspawn_util",
|
||||
"//third_party/cJSON:cjson",
|
||||
]
|
||||
defines = []
|
||||
if (asan_detector || is_asan) {
|
||||
defines += [ "ASAN_DETECTOR" ]
|
||||
}
|
||||
external_deps = [
|
||||
"ability_base:want",
|
||||
"ability_runtime:app_manager",
|
||||
"ability_runtime:appkit_native",
|
||||
"ability_runtime:runtime",
|
||||
"access_token:libtoken_setproc",
|
||||
"ace_engine:ace_forward_compatibility",
|
||||
"c_utils:utils",
|
||||
"common_event_service:cesfwk_innerkits",
|
||||
"config_policy:configpolicy_util",
|
||||
"eventhandler:libeventhandler",
|
||||
"hilog:libhilog",
|
||||
"hitrace:hitrace_meter",
|
||||
"init:libbegetutil",
|
||||
"ipc:ipc_single",
|
||||
"libuv:uv",
|
||||
"napi:ace_napi",
|
||||
"os_account:os_account_innerkits",
|
||||
"resource_management:global_resmgr",
|
||||
"selinux:libselinux",
|
||||
]
|
||||
subsystem_name = "${subsystem_name}"
|
||||
part_name = "${part_name}"
|
||||
install_enable = true
|
||||
if (target_cpu == "arm64" || target_cpu == "x86_64" ||
|
||||
target_cpu == "riscv64") {
|
||||
module_install_dir = "lib64/appspawn/appspawn"
|
||||
} else {
|
||||
module_install_dir = "lib/appspawn/appspawn"
|
||||
}
|
||||
}
|
204
modules/ace_adapter/ace_adapter.cpp
Executable file
204
modules/ace_adapter/ace_adapter.cpp
Executable file
@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright (c) 2024 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 <cerrno>
|
||||
#include <cstring>
|
||||
#include <dlfcn.h>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "appspawn_hook.h"
|
||||
#include "appspawn_server.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "command_lexer.h"
|
||||
#include "config_policy_utils.h"
|
||||
#include "hitrace_meter.h"
|
||||
#include "js_runtime.h"
|
||||
#include "json_utils.h"
|
||||
#include "parameters.h"
|
||||
#include "resource_manager.h"
|
||||
#ifndef APPSPAWN_TEST
|
||||
#include "ace_forward_compatibility.h"
|
||||
#include "foundation/ability/ability_runtime/interfaces/kits/native/appkit/app/main_thread.h"
|
||||
#include "runtime.h"
|
||||
#endif
|
||||
|
||||
using namespace OHOS::AppSpawn;
|
||||
using namespace OHOS::Global;
|
||||
|
||||
#ifdef ASAN_DETECTOR
|
||||
static const bool DEFAULT_PRELOAD_VALUE = false;
|
||||
#else
|
||||
static const bool DEFAULT_PRELOAD_VALUE = true;
|
||||
#endif
|
||||
static const std::string PRELOAD_JSON_CONFIG("/appspawn_preload.json");
|
||||
|
||||
typedef struct TagAppSpawnSandboxCfg {
|
||||
std::set<std::string> modules;
|
||||
} AppSpawnSandboxCfg;
|
||||
|
||||
static void GetModules(const cJSON *root, std::set<std::string> &modules)
|
||||
{
|
||||
// no config
|
||||
cJSON *modulesJson = cJSON_GetObjectItemCaseSensitive(root, "napi");
|
||||
if (modulesJson == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t moduleCount = cJSON_GetArraySize(modulesJson);
|
||||
for (uint32_t i = 0; i < moduleCount; ++i) {
|
||||
const char *moduleName = cJSON_GetStringValue(cJSON_GetArrayItem(modulesJson, i));
|
||||
if (moduleName == nullptr) {
|
||||
continue;
|
||||
}
|
||||
APPSPAWN_LOGV("moduleName %{public}s", moduleName);
|
||||
if (!modules.count(moduleName)) {
|
||||
modules.insert(moduleName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int GetModuleSet(const cJSON *root, AppSpawnSandboxCfg *context)
|
||||
{
|
||||
GetModules(root, context->modules);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void PreloadModule(void)
|
||||
{
|
||||
OHOS::AbilityRuntime::Runtime::Options options;
|
||||
options.lang = OHOS::AbilityRuntime::Runtime::Language::JS;
|
||||
options.loadAce = true;
|
||||
options.preload = true;
|
||||
|
||||
auto runtime = OHOS::AbilityRuntime::Runtime::Create(options);
|
||||
if (!runtime) {
|
||||
APPSPAWN_LOGE("LoadExtendLib: Failed to create runtime");
|
||||
return;
|
||||
}
|
||||
|
||||
AppSpawnSandboxCfg context = {};
|
||||
(void)ParseSandboxConfig("etc/appspawn", PRELOAD_JSON_CONFIG.c_str(), GetModuleSet, &context);
|
||||
for (std::string moduleName : context.modules) {
|
||||
APPSPAWN_LOGI("moduleName %{public}s", moduleName.c_str());
|
||||
runtime->PreloadSystemModule(moduleName);
|
||||
}
|
||||
// Save preloaded runtime
|
||||
OHOS::AbilityRuntime::Runtime::SavePreloaded(std::move(runtime));
|
||||
}
|
||||
|
||||
static void LoadExtendLib(void)
|
||||
{
|
||||
const char *acelibdir = OHOS::Ace::AceForwardCompatibility::GetAceLibName();
|
||||
APPSPAWN_LOGI("LoadExtendLib: Start calling dlopen acelibdir.");
|
||||
void *aceAbilityLib = dlopen(acelibdir, RTLD_NOW | RTLD_LOCAL);
|
||||
APPSPAWN_CHECK(aceAbilityLib != nullptr, return, "Fail to dlopen %{public}s, [%{public}s]", acelibdir, dlerror());
|
||||
APPSPAWN_LOGI("LoadExtendLib: Success to dlopen %{public}s", acelibdir);
|
||||
|
||||
OHOS::AppExecFwk::MainThread::PreloadExtensionPlugin();
|
||||
bool preload = OHOS::system::GetBoolParameter("persist.appspawn.preload", DEFAULT_PRELOAD_VALUE);
|
||||
if (!preload) {
|
||||
APPSPAWN_LOGI("LoadExtendLib: Do not preload JS VM");
|
||||
return;
|
||||
}
|
||||
|
||||
APPSPAWN_LOGI("LoadExtendLib: Start preload JS VM");
|
||||
SetTraceDisabled(true);
|
||||
PreloadModule();
|
||||
SetTraceDisabled(false);
|
||||
|
||||
Resource::ResourceManager *systemResMgr = Resource::GetSystemResourceManagerNoSandBox();
|
||||
APPSPAWN_CHECK(systemResMgr != nullptr, return, "Fail to get system resource manager");
|
||||
APPSPAWN_LOGI("LoadExtendLib: End preload JS VM");
|
||||
}
|
||||
|
||||
static int RunChildThread(const AppSpawnMgr *content, const AppSpawningCtx *property)
|
||||
{
|
||||
AppSpawnEnvClear((AppSpawnContent *)&content->content, (AppSpawnClient *)&property->client);
|
||||
std::string checkExit;
|
||||
if (OHOS::system::GetBoolParameter("persist.init.debug.checkexit", true)) {
|
||||
checkExit = std::to_string(getpid());
|
||||
}
|
||||
setenv(APPSPAWN_CHECK_EXIT, checkExit.c_str(), true);
|
||||
OHOS::AppExecFwk::MainThread::Start();
|
||||
unsetenv(APPSPAWN_CHECK_EXIT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int RunChildByRenderCmd(const AppSpawnMgr *content, const AppSpawningCtx *property)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
char *renderCmd = reinterpret_cast<char *>(GetAppPropertyExt(property, MSG_EXT_NAME_RENDER_CMD, &len));
|
||||
if (renderCmd == NULL || !IsDeveloperModeOn(property)) {
|
||||
APPSPAWN_LOGE("Denied launching a native process: not in developer mode");
|
||||
return -1;
|
||||
}
|
||||
APPSPAWN_LOGI("renderCmd %{public}s", renderCmd);
|
||||
std::vector<std::string> args;
|
||||
std::string command(renderCmd);
|
||||
CommandLexer lexer(command);
|
||||
if (!lexer.GetAllArguments(args)) {
|
||||
return -1;
|
||||
}
|
||||
if (args.empty()) {
|
||||
APPSPAWN_LOGE("Failed to run a native process: empty command %{public}s", renderCmd);
|
||||
return -1;
|
||||
}
|
||||
std::vector<char *> options;
|
||||
for (const auto &arg : args) {
|
||||
options.push_back(const_cast<char *>(arg.c_str()));
|
||||
}
|
||||
options.push_back(nullptr);
|
||||
// clear appspawn env, do not user any content and property
|
||||
AppSpawnEnvClear((AppSpawnContent *)&content->content, (AppSpawnClient *)&property->client);
|
||||
execvp(args[0].c_str(), options.data());
|
||||
// If it succeeds calling execvp, it never returns.
|
||||
int err = errno;
|
||||
APPSPAWN_LOGE("Failed to launch a native process with execvp: %{public}s", strerror(err));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int RunChildProcessor(AppSpawnContent *content, AppSpawnClient *client)
|
||||
{
|
||||
APPSPAWN_CHECK(client != NULL && content != NULL, return -1, "Invalid client");
|
||||
AppSpawningCtx *property = reinterpret_cast<AppSpawningCtx *>(client);
|
||||
int ret = 0;
|
||||
if (GetAppSpawnMsgType(property) == MSG_SPAWN_NATIVE_PROCESS) {
|
||||
ret = RunChildByRenderCmd(reinterpret_cast<AppSpawnMgr *>(content), property);
|
||||
} else {
|
||||
ret = RunChildThread(reinterpret_cast<AppSpawnMgr *>(content), property);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int PreLoadAppSpawn(AppSpawnMgr *content)
|
||||
{
|
||||
if (IsNWebSpawnMode(content)) {
|
||||
return 0;
|
||||
}
|
||||
// register
|
||||
RegChildLooper(&content->content, RunChildProcessor);
|
||||
LoadExtendLib();
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_CONSTRUCTOR(void)
|
||||
{
|
||||
APPSPAWN_LOGV("Load ace module ...");
|
||||
AddPreloadHook(HOOK_PRIO_HIGHEST, PreLoadAppSpawn);
|
||||
}
|
103
modules/ace_adapter/command_lexer.cpp
Executable file
103
modules/ace_adapter/command_lexer.cpp
Executable file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) 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 "appspawn_utils.h"
|
||||
#include "command_lexer.h"
|
||||
|
||||
using namespace OHOS::AppSpawn;
|
||||
|
||||
enum class ParsingState {
|
||||
INIT,
|
||||
IN_WHITESPACE,
|
||||
IN_ARGUMENT,
|
||||
IN_SINGLE_QUOTE,
|
||||
IN_DOUBLE_QUOTE,
|
||||
};
|
||||
|
||||
bool CommandLexer::GetAllArguments(std::vector<std::string> &args)
|
||||
{
|
||||
constexpr char singleQuote = '\'';
|
||||
constexpr char doubleQuote = '"';
|
||||
ParsingState state = ParsingState::INIT;
|
||||
std::string lastArg;
|
||||
|
||||
for (size_t i = 0; i < str_.size(); i++) {
|
||||
switch (state) {
|
||||
case ParsingState::INIT:
|
||||
if (isspace(str_[i])) {
|
||||
state = ParsingState::IN_WHITESPACE;
|
||||
} else if (str_[i] == singleQuote) {
|
||||
state = ParsingState::IN_SINGLE_QUOTE;
|
||||
} else if (str_[i] == doubleQuote) {
|
||||
state = ParsingState::IN_DOUBLE_QUOTE;
|
||||
} else {
|
||||
state = ParsingState::IN_ARGUMENT;
|
||||
lastArg += str_[i];
|
||||
}
|
||||
break;
|
||||
case ParsingState::IN_WHITESPACE:
|
||||
if (str_[i] == singleQuote) {
|
||||
state = ParsingState::IN_SINGLE_QUOTE;
|
||||
} else if (str_[i] == doubleQuote) {
|
||||
state = ParsingState::IN_DOUBLE_QUOTE;
|
||||
} else if (!isspace(str_[i])) {
|
||||
state = ParsingState::IN_ARGUMENT;
|
||||
lastArg += str_[i];
|
||||
}
|
||||
break;
|
||||
case ParsingState::IN_ARGUMENT:
|
||||
if (isspace(str_[i])) {
|
||||
args.push_back(std::move(lastArg));
|
||||
// Whether a moved string is empty depends on the
|
||||
// implementation of C++ std library, so clear() is called.
|
||||
lastArg.clear();
|
||||
state = ParsingState::IN_WHITESPACE;
|
||||
} else if (str_[i] == singleQuote) {
|
||||
state = ParsingState::IN_SINGLE_QUOTE;
|
||||
} else if (str_[i] == doubleQuote) {
|
||||
state = ParsingState::IN_DOUBLE_QUOTE;
|
||||
} else {
|
||||
lastArg += str_[i];
|
||||
}
|
||||
break;
|
||||
case ParsingState::IN_SINGLE_QUOTE:
|
||||
if (str_[i] == singleQuote) {
|
||||
state = ParsingState::IN_ARGUMENT;
|
||||
} else {
|
||||
lastArg += str_[i];
|
||||
}
|
||||
break;
|
||||
case ParsingState::IN_DOUBLE_QUOTE:
|
||||
if (str_[i] == doubleQuote) {
|
||||
state = ParsingState::IN_ARGUMENT;
|
||||
} else {
|
||||
lastArg += str_[i];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (state == ParsingState::IN_ARGUMENT) {
|
||||
args.push_back(std::move(lastArg));
|
||||
} else if (state == ParsingState::IN_SINGLE_QUOTE ||
|
||||
state == ParsingState::IN_DOUBLE_QUOTE) {
|
||||
APPSPAWN_LOGE("Parsing arguments failed: missing terminated quote");
|
||||
args.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
45
modules/ace_adapter/command_lexer.h
Executable file
45
modules/ace_adapter/command_lexer.h
Executable file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 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 COMMAND_LEXER_H
|
||||
#define COMMAND_LEXER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace OHOS {
|
||||
namespace AppSpawn {
|
||||
|
||||
class CommandLexer {
|
||||
public:
|
||||
explicit CommandLexer(const std::string &str) : str_(str) {}
|
||||
// Disable copy and move semantics to avoid extension of the lifecyle of the
|
||||
// resource not owned by this class.
|
||||
CommandLexer(const CommandLexer &other) = delete;
|
||||
CommandLexer(CommandLexer &&other) = delete;
|
||||
CommandLexer &operator=(const CommandLexer &other) = delete;
|
||||
CommandLexer &operator=(CommandLexer &&other) = delete;
|
||||
// Return true, and args will be populated with all argument. Otherwise,
|
||||
// false is returned, and args will be cleared.
|
||||
bool GetAllArguments(std::vector<std::string> &args);
|
||||
|
||||
private:
|
||||
const std::string &str_;
|
||||
};
|
||||
|
||||
} // namespace AppSpawn
|
||||
} // namespace OHOS
|
||||
|
||||
#endif // COMMAND_LEXER_H
|
46
modules/asan/BUILD.gn
Executable file
46
modules/asan/BUILD.gn
Executable file
@ -0,0 +1,46 @@
|
||||
# Copyright (c) 2024 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.
|
||||
|
||||
import("//base/startup/appspawn/appspawn.gni")
|
||||
import("//build/ohos.gni")
|
||||
|
||||
ohos_shared_library("appspawn_asan") {
|
||||
sources = [ "asan_detector.c" ]
|
||||
include_dirs = [
|
||||
".",
|
||||
"${appspawn_path}/common",
|
||||
"${appspawn_path}/standard",
|
||||
]
|
||||
defines = []
|
||||
deps = [ "${appspawn_path}/modules/module_engine:libappspawn_module_engine" ]
|
||||
if (is_asan) {
|
||||
defines += [ "APPSPAWN_ASAN" ]
|
||||
}
|
||||
if (asan_detector || is_asan) {
|
||||
defines += [ "ASAN_DETECTOR" ]
|
||||
}
|
||||
external_deps = [
|
||||
"c_utils:utils",
|
||||
"hilog:libhilog",
|
||||
"init:libbegetutil",
|
||||
]
|
||||
install_enable = true
|
||||
subsystem_name = "${subsystem_name}"
|
||||
part_name = "${part_name}"
|
||||
if (target_cpu == "arm64" || target_cpu == "x86_64" ||
|
||||
target_cpu == "riscv64") {
|
||||
module_install_dir = "lib64/appspawn"
|
||||
} else {
|
||||
module_install_dir = "lib/appspawn"
|
||||
}
|
||||
}
|
120
modules/asan/asan_detector.c
Executable file
120
modules/asan/asan_detector.c
Executable file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2024 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 "appspawn_hook.h"
|
||||
#include "appspawn_msg.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "parameter.h"
|
||||
#include "securec.h"
|
||||
|
||||
// for stub
|
||||
extern bool may_init_gwp_asan(bool forceInit);
|
||||
|
||||
// ide-asan
|
||||
static int SetAsanEnabledEnv(const AppSpawnMgr *content, const AppSpawningCtx *property)
|
||||
{
|
||||
const char *bundleName = GetBundleName(property);
|
||||
if (CheckAppMsgFlagsSet(property, APP_FLAGS_ASANENABLED)) {
|
||||
char *devPath = "/dev/asanlog";
|
||||
char logPath[PATH_MAX] = {0};
|
||||
int ret = snprintf_s(logPath, sizeof(logPath), sizeof(logPath) - 1,
|
||||
"/data/app/el1/100/base/%s/log", bundleName);
|
||||
APPSPAWN_CHECK(ret > 0, return -1, "Invalid snprintf_s");
|
||||
char asanOptions[PATH_MAX] = {0};
|
||||
ret = snprintf_s(asanOptions, sizeof(asanOptions), sizeof(asanOptions) - 1,
|
||||
"log_path=%s/asan.log:include=/system/etc/asan.options", devPath);
|
||||
APPSPAWN_CHECK(ret > 0, return -1, "Invalid snprintf_s");
|
||||
|
||||
#if defined(__aarch64__) || defined(__x86_64__)
|
||||
setenv("LD_PRELOAD", "/system/lib64/libclang_rt.asan.so", 1);
|
||||
#else
|
||||
setenv("LD_PRELOAD", "/system/lib/libclang_rt.asan.so", 1);
|
||||
#endif
|
||||
unsetenv("UBSAN_OPTIONS");
|
||||
setenv("ASAN_OPTIONS", asanOptions, 1);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void SetGwpAsanEnabled(const AppSpawnMgr *content, const AppSpawningCtx *property)
|
||||
{
|
||||
if (!(CheckAppMsgFlagsSet(property, APP_FLAGS_GWP_ENABLED_FORCE) ||
|
||||
CheckAppMsgFlagsSet(property, APP_FLAGS_GWP_ENABLED_NORMAL))) {
|
||||
return;
|
||||
}
|
||||
if (IsDeveloperModeOn(property)) {
|
||||
APPSPAWN_LOGV("SetGwpAsanEnabled with flags: %{public}d",
|
||||
CheckAppMsgFlagsSet(property, APP_FLAGS_GWP_ENABLED_FORCE));
|
||||
may_init_gwp_asan(CheckAppMsgFlagsSet(property, APP_FLAGS_GWP_ENABLED_FORCE));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ASAN_DETECTOR
|
||||
#define WRAP_VALUE_MAX_LENGTH 96
|
||||
static int CheckSupportColdStart(const char *bundleName)
|
||||
{
|
||||
char wrapBundleNameKey[WRAP_VALUE_MAX_LENGTH] = {0};
|
||||
char wrapBundleNameValue[WRAP_VALUE_MAX_LENGTH] = {0};
|
||||
|
||||
int len = sprintf_s(wrapBundleNameKey, WRAP_VALUE_MAX_LENGTH, "wrap.%s", bundleName);
|
||||
APPSPAWN_CHECK(len > 0 && (len < WRAP_VALUE_MAX_LENGTH), return -1, "Invalid to format wrapBundleNameKey");
|
||||
|
||||
int ret = GetParameter(wrapBundleNameKey, "", wrapBundleNameValue, WRAP_VALUE_MAX_LENGTH);
|
||||
APPSPAWN_CHECK(ret > 0 && (!strcmp(wrapBundleNameValue, "asan_wrapper")), return -1,
|
||||
"Not wrap %{public}s.", bundleName);
|
||||
APPSPAWN_LOGI("Asan: GetParameter %{public}s the value is %{public}s.", wrapBundleNameKey, wrapBundleNameValue);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int AsanSpawnGetSpawningFlag(AppSpawnMgr *content, AppSpawningCtx *property)
|
||||
{
|
||||
APPSPAWN_LOGV("Prepare spawn app %{public}s", GetProcessName(property));
|
||||
#ifdef ASAN_DETECTOR
|
||||
if (CheckSupportColdStart(GetBundleName(property)) == 0) {
|
||||
property->client.flags |= APP_COLD_START;
|
||||
property->client.flags |= APP_ASAN_DETECTOR;
|
||||
if (property->forkCtx.coldRunPath) {
|
||||
free(property->forkCtx.coldRunPath);
|
||||
}
|
||||
property->forkCtx.coldRunPath = strdup("/system/asan/bin/appspawn");
|
||||
if (property->forkCtx.coldRunPath == NULL) {
|
||||
APPSPAWN_LOGE("Failed to set asan exec path %{public}s", GetProcessName(property));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int AsanSpawnInitSpawningEnv(AppSpawnMgr *content, AppSpawningCtx *property)
|
||||
{
|
||||
if (GetAppSpawnMsgType(property) == MSG_SPAWN_NATIVE_PROCESS) {
|
||||
return 0;
|
||||
}
|
||||
int ret = SetAsanEnabledEnv(content, property);
|
||||
if (ret == 0) {
|
||||
APPSPAWN_LOGI("SetAsanEnabledEnv cold start app %{public}s", GetProcessName(property));
|
||||
property->client.flags |= APP_COLD_START;
|
||||
}
|
||||
(void)SetGwpAsanEnabled(content, property);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_CONSTRUCTOR(void)
|
||||
{
|
||||
APPSPAWN_LOGV("Load asan module ...");
|
||||
AddAppSpawnHook(STAGE_CHILD_PRE_COLDBOOT, HOOK_PRIO_COMMON, AsanSpawnInitSpawningEnv);
|
||||
AddAppSpawnHook(STAGE_PARENT_PRE_FORK, HOOK_PRIO_COMMON, AsanSpawnGetSpawningFlag);
|
||||
}
|
73
modules/common/BUILD.gn
Executable file
73
modules/common/BUILD.gn
Executable file
@ -0,0 +1,73 @@
|
||||
# Copyright (c) 2024 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.
|
||||
|
||||
import("//base/startup/appspawn/appspawn.gni")
|
||||
import("//build/ohos.gni")
|
||||
|
||||
ohos_shared_library("appspawn_common") {
|
||||
sources = [
|
||||
"appspawn_adapter.cpp",
|
||||
"appspawn_cgroup.c",
|
||||
"appspawn_common.c",
|
||||
]
|
||||
include_dirs = [
|
||||
".",
|
||||
"${appspawn_path}/common",
|
||||
"${appspawn_path}/standard",
|
||||
]
|
||||
cflags = []
|
||||
deps = [
|
||||
"${appspawn_path}/modules/module_engine:libappspawn_module_engine",
|
||||
"//third_party/cJSON:cjson",
|
||||
]
|
||||
defines = [ "GRAPHIC_PERMISSION_CHECK" ]
|
||||
external_deps = [
|
||||
"access_token:libtoken_setproc",
|
||||
"access_token:libtokenid_sdk",
|
||||
"c_utils:utils",
|
||||
"hilog:libhilog",
|
||||
"init:libbegetutil",
|
||||
"netmanager_base:netsys_client",
|
||||
]
|
||||
if (build_selinux) {
|
||||
defines += [ "WITH_SELINUX" ]
|
||||
deps += [ "//third_party/selinux:libselinux" ]
|
||||
external_deps += [ "selinux_adapter:libhap_restorecon" ]
|
||||
}
|
||||
if (build_seccomp) {
|
||||
defines += [ "WITH_SECCOMP" ]
|
||||
external_deps += [ "init:seccomp" ]
|
||||
}
|
||||
|
||||
if (!defined(global_parts_info) ||
|
||||
defined(global_parts_info.security_security_component_manager)) {
|
||||
defines += [ "SECURITY_COMPONENT_ENABLE" ]
|
||||
external_deps += [ "security_component_manager:libsecurity_component_sdk" ]
|
||||
}
|
||||
|
||||
if (!defined(global_parts_info) ||
|
||||
defined(global_parts_info.security_code_signature)) {
|
||||
defines += [ "CODE_SIGNATURE_ENABLE" ]
|
||||
external_deps += [ "code_signature:libcode_sign_attr_utils" ]
|
||||
}
|
||||
|
||||
subsystem_name = "${subsystem_name}"
|
||||
part_name = "${part_name}"
|
||||
install_enable = true
|
||||
if (target_cpu == "arm64" || target_cpu == "x86_64" ||
|
||||
target_cpu == "riscv64") {
|
||||
module_install_dir = "lib64/appspawn/common"
|
||||
} else {
|
||||
module_install_dir = "lib/appspawn/common"
|
||||
}
|
||||
}
|
168
modules/common/appspawn_adapter.cpp
Executable file
168
modules/common/appspawn_adapter.cpp
Executable file
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (c) 2024 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 "appspawn_adapter.h"
|
||||
|
||||
#include "access_token.h"
|
||||
#include "appspawn_hook.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "cJSON.h"
|
||||
#include "token_setproc.h"
|
||||
#include "tokenid_kit.h"
|
||||
|
||||
#ifdef WITH_SELINUX
|
||||
#include "hap_restorecon.h"
|
||||
#include "selinux/selinux.h"
|
||||
#endif
|
||||
#ifdef WITH_SECCOMP
|
||||
#include "seccomp_policy.h"
|
||||
#include <sys/prctl.h>
|
||||
const char *RENDERER_NAME = "renderer";
|
||||
#endif
|
||||
|
||||
#define NWEBSPAWN_SERVER_NAME "nwebspawn"
|
||||
using namespace OHOS::Security::AccessToken;
|
||||
|
||||
int SetAppAccessToken(const AppSpawnMgr *content, const AppSpawningCtx *property)
|
||||
{
|
||||
int32_t ret = 0;
|
||||
uint64_t tokenId = 0;
|
||||
AppSpawnMsgAccessToken *tokenInfo = (AppSpawnMsgAccessToken *)GetAppProperty(property, TLV_ACCESS_TOKEN_INFO);
|
||||
APPSPAWN_CHECK(tokenInfo != NULL, return APPSPAWN_MSG_INVALID,
|
||||
"No access token in msg %{public}s", GetProcessName(property));
|
||||
APPSPAWN_LOGV("AppSpawnServer::set access token %{public}" PRId64 " %{public}d",
|
||||
tokenInfo->accessTokenIdEx, IsNWebSpawnMode(content));
|
||||
|
||||
if (IsNWebSpawnMode(content)) {
|
||||
TokenIdKit tokenIdKit;
|
||||
tokenId = tokenIdKit.GetRenderTokenID(tokenInfo->accessTokenIdEx);
|
||||
} else {
|
||||
tokenId = tokenInfo->accessTokenIdEx;
|
||||
}
|
||||
ret = SetSelfTokenID(tokenId);
|
||||
APPSPAWN_CHECK(ret == 0, return APPSPAWN_ACCESS_TOKEN_INVALID,
|
||||
"set access token id failed, ret: %{public}d %{public}s", ret, GetProcessName(property));
|
||||
APPSPAWN_LOGV("SetAppAccessToken success for %{public}s", GetProcessName(property));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SetSelinuxCon(const AppSpawnMgr *content, const AppSpawningCtx *property)
|
||||
{
|
||||
#ifdef WITH_SELINUX
|
||||
APPSPAWN_LOGV("SetSelinuxCon IsDeveloperModeOn %{public}d", IsDeveloperModeOn(property));
|
||||
if (GetAppSpawnMsgType(property) == MSG_SPAWN_NATIVE_PROCESS) {
|
||||
if (!IsDeveloperModeOn(property)) {
|
||||
APPSPAWN_LOGE("Denied Launching a native process: not in developer mode");
|
||||
return APPSPAWN_NATIVE_NOT_SUPPORT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (IsNWebSpawnMode(content)) {
|
||||
setcon("u:r:isolated_render:s0");
|
||||
return 0;
|
||||
}
|
||||
AppSpawnMsgDomainInfo *msgDomainInfo = (AppSpawnMsgDomainInfo *)GetAppProperty(property, TLV_DOMAIN_INFO);
|
||||
APPSPAWN_CHECK(msgDomainInfo != NULL, return APPSPAWN_TLV_NONE,
|
||||
"No domain info in req form %{public}s", GetProcessName(property))
|
||||
HapContext hapContext;
|
||||
HapDomainInfo hapDomainInfo;
|
||||
hapDomainInfo.apl = msgDomainInfo->apl;
|
||||
hapDomainInfo.packageName = GetProcessName(property);
|
||||
hapDomainInfo.hapFlags = msgDomainInfo->hapFlags;
|
||||
if (CheckAppMsgFlagsSet(property, APP_FLAGS_DEBUGGABLE)) {
|
||||
hapDomainInfo.hapFlags |= SELINUX_HAP_DEBUGGABLE;
|
||||
}
|
||||
int32_t ret = hapContext.HapDomainSetcontext(hapDomainInfo);
|
||||
if (CheckAppMsgFlagsSet(property, APP_FLAGS_ASANENABLED)) {
|
||||
ret = 0;
|
||||
}
|
||||
APPSPAWN_CHECK(ret == 0, return APPSPAWN_ACCESS_TOKEN_INVALID,
|
||||
"Set domain context failed, ret: %{public}d %{public}s", ret, GetProcessName(property));
|
||||
APPSPAWN_LOGV("SetSelinuxCon success for %{public}s", GetProcessName(property));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SetUidGidFilter(const AppSpawnMgr *content)
|
||||
{
|
||||
#ifdef WITH_SECCOMP
|
||||
bool ret = false;
|
||||
if (IsNWebSpawnMode(content)) {
|
||||
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
|
||||
APPSPAWN_LOGE("Failed to set no new privs");
|
||||
}
|
||||
ret = SetSeccompPolicyWithName(INDIVIDUAL, NWEBSPAWN_NAME);
|
||||
} else {
|
||||
ret = SetSeccompPolicyWithName(INDIVIDUAL, APPSPAWN_NAME);
|
||||
}
|
||||
if (!ret) {
|
||||
APPSPAWN_LOGE("Failed to set APPSPAWN seccomp filter and exit");
|
||||
_exit(0x7f);
|
||||
}
|
||||
APPSPAWN_LOGV("SetUidGidFilter success");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SetSeccompFilter(const AppSpawnMgr *content, const AppSpawningCtx *property)
|
||||
{
|
||||
#ifdef WITH_SECCOMP
|
||||
const char *appName = APP_NAME;
|
||||
SeccompFilterType type = APP;
|
||||
if (IsNWebSpawnMode(content)) {
|
||||
return 0;
|
||||
}
|
||||
if (!SetSeccompPolicyWithName(type, appName)) {
|
||||
APPSPAWN_LOGE("Failed to set %{public}s seccomp filter and exit %{public}d", appName, errno);
|
||||
return -EINVAL;
|
||||
}
|
||||
APPSPAWN_LOGV("SetSeccompFilter success for %{public}s", GetProcessName(property));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SetInternetPermission(const AppSpawningCtx *property)
|
||||
{
|
||||
AppSpawnMsgInternetInfo *info = (AppSpawnMsgInternetInfo *)GetAppProperty(property, TLV_INTERNET_INFO);
|
||||
APPSPAWN_CHECK(info != NULL, return 0,
|
||||
"No tlv internet permission info in req form %{public}s", GetProcessName(property));
|
||||
APPSPAWN_LOGV("Set internet permission %{public}d %{public}d", info->setAllowInternet, info->allowInternet);
|
||||
if (info->setAllowInternet == 1 && info->allowInternet == 0) {
|
||||
DisallowInternet();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t SetEnvInfo(const AppSpawnMgr *content, const AppSpawningCtx *property)
|
||||
{
|
||||
uint32_t size = 0;
|
||||
char *envStr = reinterpret_cast<char *>(GetAppPropertyExt(property, "AppEnv", &size));
|
||||
if (size == 0 || envStr == NULL) {
|
||||
return 0;
|
||||
}
|
||||
int ret = 0;
|
||||
cJSON *root = cJSON_Parse(envStr);
|
||||
APPSPAWN_CHECK(root != nullptr, return -1, "SetEnvInfo: json parse failed %{public}s", envStr);
|
||||
cJSON *config = nullptr;
|
||||
cJSON_ArrayForEach(config, root) {
|
||||
const char *name = config->string;
|
||||
const char *value = cJSON_GetStringValue(config);
|
||||
APPSPAWN_LOGV("SetEnvInfo name: %{public}s value: %{public}s", name, value);
|
||||
ret = setenv(name, value, 1);
|
||||
APPSPAWN_CHECK(ret == 0, break, "setenv failed, errno: %{public}d", errno);
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
return ret;
|
||||
}
|
36
modules/common/appspawn_adapter.h
Executable file
36
modules/common/appspawn_adapter.h
Executable file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2021-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 APPSPAWN_ADPATER_CPP
|
||||
#define APPSPAWN_ADPATER_CPP
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int SetAppAccessToken(const AppSpawnMgr *content, const AppSpawningCtx *property);
|
||||
int SetSelinuxCon(const AppSpawnMgr *content, const AppSpawningCtx *property);
|
||||
|
||||
int SetUidGidFilter(const AppSpawnMgr *content);
|
||||
int SetSeccompFilter(const AppSpawnMgr *content, const AppSpawningCtx *property);
|
||||
int SetInternetPermission(const AppSpawningCtx *property);
|
||||
int32_t SetEnvInfo(const AppSpawnMgr *content, const AppSpawningCtx *property);
|
||||
|
||||
// stub for extend func
|
||||
void DisallowInternet(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
158
modules/common/appspawn_cgroup.c
Executable file
158
modules/common/appspawn_cgroup.c
Executable file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 2024 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 <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "appspawn_adapter.h"
|
||||
#include "appspawn_hook.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "securec.h"
|
||||
|
||||
APPSPAWN_STATIC int GetCgroupPath(const AppSpawnedProcessInfo *appInfo, char *buffer, uint32_t buffLen)
|
||||
{
|
||||
const int userId = appInfo->uid / UID_BASE;
|
||||
#ifdef APPSPAWN_TEST
|
||||
int ret = snprintf_s(buffer, buffLen, buffLen - 1, APPSPAWN_BASE_DIR "/dev/pids/testpids/%d/%s/%d/",
|
||||
userId, appInfo->name, appInfo->pid);
|
||||
#else
|
||||
int ret = snprintf_s(buffer, buffLen, buffLen - 1, "/dev/pids/%d/%s/app_%d/", userId, appInfo->name, appInfo->pid);
|
||||
#endif
|
||||
APPSPAWN_CHECK(ret > 0, return ret, "Failed to snprintf_s errno: %{public}d", errno);
|
||||
APPSPAWN_LOGV("Cgroup path %{public}s ", buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
APPSPAWN_STATIC int WriteToFile(const char *path, int truncated, pid_t pids[], uint32_t count)
|
||||
{
|
||||
char pidName[32] = {0}; // 32 max len
|
||||
int fd = open(path, O_RDWR | (truncated ? O_TRUNC : O_APPEND));
|
||||
APPSPAWN_CHECK(fd >= 0, return APPSPAWN_SYSTEM_ERROR,
|
||||
"Failed to open file errno: %{public}d path: %{public}s", errno, path);
|
||||
int ret = 0;
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
APPSPAWN_LOGV(" WriteToFile pid %{public}d ", pids[i]);
|
||||
ret = snprintf_s(pidName, sizeof(pidName), sizeof(pidName) - 1, "%d\n", pids[i]);
|
||||
APPSPAWN_CHECK(ret > 0, break, "Failed to snprintf_s errno: %{public}d", errno);
|
||||
ret = write(fd, pidName, strlen(pidName));
|
||||
APPSPAWN_CHECK(ret > 0, break,
|
||||
"Failed to write file errno: %{public}d path: %{public}s %{public}s", errno, path, pidName);
|
||||
ret = 0;
|
||||
}
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int WritePidMax(const char *path, uint32_t max)
|
||||
{
|
||||
char value[32] = {0}; // 32 max len
|
||||
int fd = open(path, O_RDWR | O_TRUNC);
|
||||
APPSPAWN_CHECK(fd >= 0, return -1,
|
||||
"Failed to open file errno: %{public}d path: %{public}s", errno, path);
|
||||
int ret = 0;
|
||||
do {
|
||||
ret = snprintf_s(value, sizeof(value), sizeof(value) - 1, "%u\n", max);
|
||||
APPSPAWN_CHECK(ret > 0, break, "Failed to snprintf_s errno: %{public}d", errno);
|
||||
ret = write(fd, value, strlen(value));
|
||||
APPSPAWN_CHECK(ret > 0, break,
|
||||
"Failed to write file errno: %{public}d path: %{public}s %{public}s %{public}d", errno, path, value, ret);
|
||||
ret = 0;
|
||||
} while (0);
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void KillProcessesByCGroup(const char *path, AppSpawnMgr *content, const AppSpawnedProcessInfo *appInfo)
|
||||
{
|
||||
FILE *file = fopen(path, "r");
|
||||
APPSPAWN_CHECK(file != NULL, return, "Open file fail %{public}s errno: %{public}d", path, errno);
|
||||
pid_t pid = 0;
|
||||
while (fscanf_s(file, "%d\n", &pid) == 1 && pid > 0) {
|
||||
APPSPAWN_LOGV(" KillProcessesByCGroup pid %{public}d ", pid);
|
||||
if (pid == appInfo->pid) {
|
||||
continue;
|
||||
}
|
||||
AppSpawnedProcessInfo *tmp = GetSpawnedProcess(pid);
|
||||
if (tmp != NULL) {
|
||||
APPSPAWN_LOGI("Got app %{public}s in same group for pid %{public}d.", tmp->name, pid);
|
||||
continue;
|
||||
}
|
||||
APPSPAWN_LOGI("Kill app pid %{public}d now ...", pid);
|
||||
#ifdef APPSPAWN_TEST
|
||||
kill(pid, SIGKILL);
|
||||
#endif
|
||||
}
|
||||
(void)fclose(file);
|
||||
}
|
||||
|
||||
static int ProcessMgrRemoveApp(const AppSpawnMgr *content, const AppSpawnedProcessInfo *appInfo)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != NULL, return -1);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(appInfo != NULL, return -1);
|
||||
if (IsNWebSpawnMode(content) || strcmp(appInfo->name, NWEBSPAWN_SERVER_NAME) == 0) {
|
||||
return 0;
|
||||
}
|
||||
char path[PATH_MAX] = {};
|
||||
APPSPAWN_LOGV("ProcessMgrRemoveApp %{public}d %{public}d to cgroup ", appInfo->pid, appInfo->uid);
|
||||
int ret = GetCgroupPath(appInfo, path, sizeof(path));
|
||||
APPSPAWN_CHECK(ret == 0, return -1, "Failed to get real path errno: %d", errno);
|
||||
ret = strcat_s(path, sizeof(path), "cgroup.procs");
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "Failed to strcat_s errno: %{public}d", errno);
|
||||
KillProcessesByCGroup(path, (AppSpawnMgr *)content, appInfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ProcessMgrAddApp(const AppSpawnMgr *content, const AppSpawnedProcessInfo *appInfo)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != NULL, return -1);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(appInfo != NULL, return -1);
|
||||
if (IsNWebSpawnMode(content)) {
|
||||
return 0;
|
||||
}
|
||||
char path[PATH_MAX] = {};
|
||||
APPSPAWN_LOGV("ProcessMgrAddApp %{public}d %{public}d to cgroup ", appInfo->pid, appInfo->uid);
|
||||
int ret = GetCgroupPath(appInfo, path, sizeof(path));
|
||||
APPSPAWN_CHECK(ret == 0, return -1, "Failed to get real path errno: %d", errno);
|
||||
(void)CreateSandboxDir(path, 0755); // 0755 default mode
|
||||
uint32_t pathLen = strlen(path);
|
||||
ret = strcat_s(path, sizeof(path), "cgroup.procs");
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "Failed to strcat_s errno: %{public}d", errno);
|
||||
ret = WriteToFile(path, 0, (pid_t *)&appInfo->pid, 1);
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "write pid to cgroup.procs fail %{public}s", path);
|
||||
if (appInfo->max != 0) {
|
||||
path[pathLen] = '\0';
|
||||
ret = strcat_s(path, sizeof(path), "pids.max");
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "Failed to strcat_s errno: %{public}d", errno);
|
||||
ret = WritePidMax(path, appInfo->max);
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "write max to pids.max fail %{public}s", path);
|
||||
}
|
||||
APPSPAWN_LOGV("Add app %{public}d to cgroup %{public}s success", appInfo->pid, path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_CONSTRUCTOR(void)
|
||||
{
|
||||
AddProcessMgrHook(STAGE_SERVER_APP_ADD, 0, ProcessMgrAddApp);
|
||||
AddProcessMgrHook(STAGE_SERVER_APP_DIED, 0, ProcessMgrRemoveApp);
|
||||
}
|
467
modules/common/appspawn_common.c
Executable file
467
modules/common/appspawn_common.c
Executable file
@ -0,0 +1,467 @@
|
||||
/*
|
||||
* Copyright (c) 2024 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 <fcntl.h>
|
||||
#include <grp.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <sys/capability.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#undef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#include <dlfcn.h>
|
||||
#include <malloc.h>
|
||||
#include <sched.h>
|
||||
|
||||
#include "appspawn_adapter.h"
|
||||
#include "appspawn_hook.h"
|
||||
#include "appspawn_msg.h"
|
||||
#include "init_param.h"
|
||||
#include "parameter.h"
|
||||
#include "securec.h"
|
||||
|
||||
#ifdef CODE_SIGNATURE_ENABLE // for xpm
|
||||
#include "code_sign_attr_utils.h"
|
||||
#endif
|
||||
#ifdef SECURITY_COMPONENT_ENABLE
|
||||
#include "sec_comp_enhance_kit_c.h"
|
||||
#endif
|
||||
#ifdef WITH_SELINUX
|
||||
#include "selinux/selinux.h"
|
||||
#endif
|
||||
|
||||
#define DEVICE_NULL_STR "/dev/null"
|
||||
#define BITLEN32 32
|
||||
#define PID_NS_INIT_UID 100000 // reserved for pid_ns_init process, avoid app, render proc, etc.
|
||||
#define PID_NS_INIT_GID 100000
|
||||
|
||||
static int SetProcessName(const AppSpawnMgr *content, const AppSpawningCtx *property)
|
||||
{
|
||||
const char *processName = GetProcessName(property);
|
||||
APPSPAWN_CHECK(processName != NULL, return -EINVAL, "Can not get process name");
|
||||
// 解析时已经检查
|
||||
size_t len = strlen(processName);
|
||||
char shortName[MAX_LEN_SHORT_NAME] = {0};
|
||||
// process short name max length 16 bytes.
|
||||
size_t copyLen = len;
|
||||
const char *pos = processName;
|
||||
if (len >= MAX_LEN_SHORT_NAME) {
|
||||
copyLen = MAX_LEN_SHORT_NAME - 1;
|
||||
pos += (len - copyLen);
|
||||
}
|
||||
bool isRet = strncpy_s(shortName, MAX_LEN_SHORT_NAME, pos, copyLen) != EOK;
|
||||
APPSPAWN_CHECK(!isRet, return EINVAL, "strncpy_s short name error: %{public}d", errno);
|
||||
|
||||
// set short name
|
||||
isRet = prctl(PR_SET_NAME, shortName) == -1;
|
||||
APPSPAWN_CHECK(!isRet, return errno, "prctl(PR_SET_NAME) error: %{public}d", errno);
|
||||
|
||||
// reset longProcName
|
||||
isRet = memset_s(content->content.longProcName,
|
||||
(size_t)content->content.longProcNameLen, 0, (size_t)content->content.longProcNameLen) != EOK;
|
||||
APPSPAWN_CHECK(!isRet, return EINVAL, "Failed to memset long process name");
|
||||
|
||||
// set long process name
|
||||
isRet = strncpy_s(content->content.longProcName, content->content.longProcNameLen, processName, len) != EOK;
|
||||
APPSPAWN_CHECK(!isRet, return EINVAL,
|
||||
"strncpy_s long name error: %{public}d longProcNameLen %{public}u", errno, content->content.longProcNameLen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int SetKeepCapabilities(const AppSpawnMgr *content, const AppSpawningCtx *property)
|
||||
{
|
||||
AppSpawnMsgDacInfo *dacInfo = (AppSpawnMsgDacInfo *)GetAppProperty(property, TLV_DAC_INFO);
|
||||
APPSPAWN_CHECK(dacInfo != NULL, return APPSPAWN_TLV_NONE,
|
||||
"No tlv %{public}d in msg %{public}s", TLV_DOMAIN_INFO, GetProcessName(property));
|
||||
|
||||
// set keep capabilities when user not root.
|
||||
if (dacInfo->uid != 0) {
|
||||
bool isRet = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1;
|
||||
APPSPAWN_CHECK(!isRet, return errno, "set keepcaps failed: %{public}d", errno);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int SetCapabilities(const AppSpawnMgr *content, const AppSpawningCtx *property)
|
||||
{
|
||||
// init cap
|
||||
struct __user_cap_header_struct capHeader;
|
||||
|
||||
bool isRet = memset_s(&capHeader, sizeof(capHeader), 0, sizeof(capHeader)) != EOK;
|
||||
APPSPAWN_CHECK(!isRet, return -EINVAL, "Failed to memset cap header");
|
||||
|
||||
capHeader.version = _LINUX_CAPABILITY_VERSION_3;
|
||||
capHeader.pid = 0;
|
||||
|
||||
struct __user_cap_data_struct capData[2]; // 2 is data number
|
||||
isRet = memset_s(&capData, sizeof(capData), 0, sizeof(capData)) != EOK;
|
||||
APPSPAWN_CHECK(!isRet, return -EINVAL, "Failed to memset cap data");
|
||||
|
||||
// init inheritable permitted effective zero
|
||||
#ifdef GRAPHIC_PERMISSION_CHECK
|
||||
const uint64_t inheriTable = 0;
|
||||
const uint64_t permitted = 0;
|
||||
const uint64_t effective = 0;
|
||||
#else
|
||||
const uint64_t inheriTable = 0x3fffffffff;
|
||||
const uint64_t permitted = 0x3fffffffff;
|
||||
const uint64_t effective = 0x3fffffffff;
|
||||
#endif
|
||||
|
||||
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);
|
||||
|
||||
// set capabilities
|
||||
isRet = capset(&capHeader, &capData[0]) != 0;
|
||||
APPSPAWN_CHECK(!isRet, return -errno, "Failed to capset errno: %{public}d", errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void InitDebugParams(const AppSpawnMgr *content, const AppSpawningCtx *property)
|
||||
{
|
||||
#if defined(__aarch64__) || defined(__x86_64__)
|
||||
const char *debugSoPath = "/system/lib64/libhidebug.so";
|
||||
#else
|
||||
const char *debugSoPath = "/system/lib/libhidebug.so";
|
||||
#endif
|
||||
const char *processName = GetProcessName(property);
|
||||
APPSPAWN_CHECK(processName != NULL, return, "Can not get process name ");
|
||||
|
||||
bool isRet = access(debugSoPath, F_OK) != 0;
|
||||
APPSPAWN_CHECK(!isRet, return,
|
||||
"access failed, errno: %{public}d debugSoPath: %{public}s", errno, debugSoPath);
|
||||
|
||||
void *handle = dlopen(debugSoPath, RTLD_LAZY);
|
||||
APPSPAWN_CHECK(handle != NULL, return, "Failed to dlopen libhidebug.so errno: %{public}s", dlerror());
|
||||
|
||||
bool (*initParam)(const char *name);
|
||||
initParam = (bool (*)(const char *name))dlsym(handle, "InitEnvironmentParam");
|
||||
APPSPAWN_CHECK(initParam != NULL, dlclose(handle);
|
||||
return, "Failed to dlsym errno: %{public}s", dlerror());
|
||||
(*initParam)(processName);
|
||||
dlclose(handle);
|
||||
}
|
||||
|
||||
static void ClearEnvironment(const AppSpawnMgr *content, const AppSpawningCtx *property)
|
||||
{
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGCHLD);
|
||||
sigaddset(&mask, SIGTERM);
|
||||
sigprocmask(SIG_UNBLOCK, &mask, NULL);
|
||||
// close child fd
|
||||
close(property->forkCtx.fd[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
static int SetXpmConfig(const AppSpawnMgr *content, const AppSpawningCtx *property)
|
||||
{
|
||||
#ifdef CODE_SIGNATURE_ENABLE
|
||||
// nwebspawn no permission set xpm config
|
||||
if (IsNWebSpawnMode(content)) {
|
||||
return 0;
|
||||
}
|
||||
AppSpawnMsgOwnerId *ownerInfo = (AppSpawnMsgOwnerId *)GetAppProperty(property, TLV_OWNER_INFO);
|
||||
int ret = InitXpmRegion();
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "init xpm region failed: %{public}d", ret);
|
||||
|
||||
if (CheckAppMsgFlagsSet(property, APP_FLAGS_DEBUGGABLE)) {
|
||||
ret = SetXpmOwnerId(PROCESS_OWNERID_DEBUG, NULL);
|
||||
} else if (ownerInfo == NULL) {
|
||||
ret = SetXpmOwnerId(PROCESS_OWNERID_COMPAT, NULL);
|
||||
} else {
|
||||
ret = SetXpmOwnerId(PROCESS_OWNERID_APP, ownerInfo->ownerId);
|
||||
}
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "set xpm region failed: %{public}d", ret);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int SetUidGid(const AppSpawnMgr *content, const AppSpawningCtx *property)
|
||||
{
|
||||
AppSpawnMsgDacInfo *dacInfo = (AppSpawnMsgDacInfo *)GetAppProperty(property, TLV_DAC_INFO);
|
||||
APPSPAWN_CHECK(dacInfo != NULL, return APPSPAWN_TLV_NONE,
|
||||
"No tlv %{public}d in msg %{public}s", TLV_DAC_INFO, GetProcessName(property));
|
||||
|
||||
// set gids
|
||||
int ret = setgroups(dacInfo->gidCount, (const gid_t *)(&dacInfo->gidTable[0]));
|
||||
APPSPAWN_CHECK(ret == 0, return errno,
|
||||
"setgroups failed: %{public}d, gids.size=%{public}u", errno, dacInfo->gidCount);
|
||||
|
||||
// set gid
|
||||
ret = setresgid(dacInfo->gid, dacInfo->gid, dacInfo->gid);
|
||||
APPSPAWN_CHECK(ret == 0, return errno,
|
||||
"setgid(%{public}u) failed: %{public}d", dacInfo->gid, errno);
|
||||
|
||||
ret = SetSeccompFilter(content, property);
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "Failed to set setSeccompFilter");
|
||||
|
||||
/* If the effective user ID is changed from 0 to nonzero,
|
||||
* then all capabilities are cleared from the effective set
|
||||
*/
|
||||
ret = setresuid(dacInfo->uid, dacInfo->uid, dacInfo->uid);
|
||||
APPSPAWN_CHECK(ret == 0, return errno,
|
||||
"setuid(%{public}u) failed: %{public}d", dacInfo->uid, errno);
|
||||
|
||||
if (CheckAppMsgFlagsSet(property, APP_FLAGS_DEBUGGABLE) && IsDeveloperModeOn(property)) {
|
||||
setenv("HAP_DEBUGGABLE", "true", 1);
|
||||
if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) {
|
||||
APPSPAWN_LOGE("Failed to set app dumpable: %{public}s", strerror(errno));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t SetFileDescriptors(const AppSpawnMgr *content, const AppSpawningCtx *property)
|
||||
{
|
||||
#ifndef APPSPAWN_TEST
|
||||
// close stdin stdout stderr
|
||||
close(STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
// redirect to /dev/null
|
||||
int devNullFd = open(DEVICE_NULL_STR, O_RDWR);
|
||||
if (devNullFd == -1) {
|
||||
APPSPAWN_LOGE("open dev_null error: %{public}d", errno);
|
||||
return (-errno);
|
||||
}
|
||||
|
||||
// stdin
|
||||
if (dup2(devNullFd, STDIN_FILENO) == -1) {
|
||||
APPSPAWN_LOGE("dup2 STDIN error: %{public}d", errno);
|
||||
return (-errno);
|
||||
};
|
||||
|
||||
// stdout
|
||||
if (dup2(devNullFd, STDOUT_FILENO) == -1) {
|
||||
APPSPAWN_LOGE("dup2 STDOUT error: %{public}d", errno);
|
||||
return (-errno);
|
||||
};
|
||||
// stderr
|
||||
if (dup2(devNullFd, STDERR_FILENO) == -1) {
|
||||
APPSPAWN_LOGE("dup2 STDERR error: %{public}d", errno);
|
||||
return (-errno);
|
||||
};
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t CheckTraceStatus(void)
|
||||
{
|
||||
int fd = open("/proc/self/status", O_RDONLY);
|
||||
APPSPAWN_CHECK(fd >= 0, return errno, "Failed to open /proc/self/status error: %{public}d", errno);
|
||||
|
||||
char data[1024] = {0}; // 1024 is data length
|
||||
ssize_t dataNum = read(fd, data, sizeof(data));
|
||||
(void)close(fd);
|
||||
APPSPAWN_CHECK(dataNum > 0, return -1, "Failed to read file /proc/self/status error: %{public}d", errno);
|
||||
|
||||
const char *tracerPid = "TracerPid:\t";
|
||||
char *traceStr = strstr(data, tracerPid);
|
||||
APPSPAWN_CHECK(traceStr != NULL, return -1, "Not found %{public}s", tracerPid);
|
||||
|
||||
char *separator = strchr(traceStr, '\n');
|
||||
APPSPAWN_CHECK(separator != NULL, return -1, "Not found %{public}s", "\n");
|
||||
|
||||
int len = separator - traceStr - strlen(tracerPid);
|
||||
char pid = *(traceStr + strlen(tracerPid));
|
||||
if (len > 1 || pid != '0') {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int32_t WaitForDebugger(const AppSpawningCtx *property)
|
||||
{
|
||||
// wait for debugger only debugging is required and process is debuggable
|
||||
if (CheckAppMsgFlagsSet(property, APP_FLAGS_NATIVEDEBUG) && CheckAppMsgFlagsSet(property, APP_FLAGS_DEBUGGABLE)) {
|
||||
uint32_t count = 0;
|
||||
while (CheckTraceStatus() != 0) {
|
||||
#ifndef APPSPAWN_TEST
|
||||
usleep(1000 * 100); // sleep 1000 * 100 microsecond
|
||||
#else
|
||||
if (count > 0) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
count++;
|
||||
// remind users to connect to the debugger every 60 * 10 times
|
||||
if (count % (10 * 60) == 0) {
|
||||
count = 0;
|
||||
APPSPAWN_LOGI("wait for debugger, please attach the process");
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int SpawnInitSpawningEnv(AppSpawnMgr *content, AppSpawningCtx *property)
|
||||
{
|
||||
APPSPAWN_LOGV("Spawning: clear env");
|
||||
int ret = SetProcessName(content, property);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
// close socket id and signal for child
|
||||
ClearEnvironment(content, property);
|
||||
|
||||
ResetParamSecurityLabel();
|
||||
|
||||
ret = SetAppAccessToken(content, property);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int SpawnEnableCache(AppSpawnMgr *content, AppSpawningCtx *property)
|
||||
{
|
||||
APPSPAWN_LOGV("Spawning: enable cache for app process");
|
||||
// enable cache for app process
|
||||
mallopt(M_OHOS_CONFIG, M_TCACHE_PERFORMANCE_MODE);
|
||||
mallopt(M_OHOS_CONFIG, M_ENABLE_OPT_TCACHE);
|
||||
mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_ENABLE);
|
||||
mallopt(M_DELAYED_FREE, M_DELAYED_FREE_ENABLE);
|
||||
|
||||
int ret = SetInternetPermission(property);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int SpawnSetProperties(AppSpawnMgr *content, AppSpawningCtx *property)
|
||||
{
|
||||
APPSPAWN_LOGV("Spawning: set child property");
|
||||
(void)umask(DEFAULT_UMASK);
|
||||
int ret = SetKeepCapabilities(content, property);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
|
||||
ret = SetXpmConfig(content, property);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
|
||||
// 这里是否有必要
|
||||
ret = SetProcessName(content, property);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
|
||||
ret = SetUidGid(content, property);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
|
||||
ret = SetFileDescriptors(content, property);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
|
||||
ret = SetCapabilities(content, property);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
|
||||
ret = SetSelinuxCon(content, property) == -1;
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
|
||||
ret = SetEnvInfo(content, property);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
|
||||
ret = WaitForDebugger(property);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
|
||||
#ifdef SECURITY_COMPONENT_ENABLE
|
||||
InitSecCompClientEnhance();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int PreLoadSetSeccompFilter(AppSpawnMgr *content)
|
||||
{
|
||||
// set uid gid filetr
|
||||
int ret = SetUidGidFilter(content);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int SpawnComplete(AppSpawnMgr *content, AppSpawningCtx *property)
|
||||
{
|
||||
InitDebugParams(content, property);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int CheckEnabled(const char *param, const char *value)
|
||||
{
|
||||
char tmp[32] = {0}; // 32 max
|
||||
int ret = GetParameter(param, "", tmp, sizeof(tmp));
|
||||
APPSPAWN_LOGV("CheckEnabled key %{public}s ret %{public}d result: %{public}s", param, ret, tmp);
|
||||
int enabled = (ret > 0 && strcmp(tmp, value) == 0);
|
||||
return enabled;
|
||||
}
|
||||
|
||||
static int SpawnGetSpawningFlag(AppSpawnMgr *content, AppSpawningCtx *property)
|
||||
{
|
||||
APPSPAWN_LOGV("Spawning: prepare app %{public}s", GetProcessName(property));
|
||||
if (CheckAppMsgFlagsSet(property, APP_FLAGS_COLD_BOOT)) {
|
||||
// check cold start
|
||||
property->client.flags |= CheckEnabled("startup.appspawn.cold.boot", "true") ? APP_COLD_START : 0;
|
||||
}
|
||||
// check developer mode
|
||||
property->client.flags |= CheckEnabled("const.security.developermode.state", "true") ? APP_DEVELOPER_MODE : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int PreLoadEnablePidNs(AppSpawnMgr *content)
|
||||
{
|
||||
APPSPAWN_LOGI("Enable pid namespace %{public}d %{public}d sandboxNsFlags: %{public}x",
|
||||
IsNWebSpawnMode(content), IsColdRunMode(content), content->content.sandboxNsFlags);
|
||||
if (IsNWebSpawnMode(content) || IsColdRunMode(content)) {
|
||||
return 0;
|
||||
}
|
||||
if (!(content->content.sandboxNsFlags & CLONE_NEWPID)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = unshare(CLONE_NEWPID);
|
||||
APPSPAWN_CHECK(ret == 0, return -1, "unshare CLONE_NWEPID failed, errno=%{public}d", errno);
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
setuid(PID_NS_INIT_UID);
|
||||
setgid(PID_NS_INIT_GID);
|
||||
#ifdef WITH_SELINUX
|
||||
setcon("u:r:pid_ns_init:s0");
|
||||
#endif
|
||||
char *argv[] = {"/system/bin/pid_ns_init", NULL};
|
||||
execve("/system/bin/pid_ns_init", argv, NULL);
|
||||
_exit(0x7f);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_CONSTRUCTOR(void)
|
||||
{
|
||||
APPSPAWN_LOGV("Load common module ...");
|
||||
AddPreloadHook(HOOK_PRIO_COMMON, PreLoadSetSeccompFilter);
|
||||
AddPreloadHook(HOOK_PRIO_LOWEST, PreLoadEnablePidNs);
|
||||
|
||||
AddAppSpawnHook(STAGE_PARENT_PRE_FORK, HOOK_PRIO_HIGHEST, SpawnGetSpawningFlag);
|
||||
AddAppSpawnHook(STAGE_CHILD_PRE_COLDBOOT, HOOK_PRIO_HIGHEST, SpawnInitSpawningEnv);
|
||||
AddAppSpawnHook(STAGE_CHILD_EXECUTE, HOOK_PRIO_HIGHEST, SpawnEnableCache);
|
||||
AddAppSpawnHook(STAGE_CHILD_EXECUTE, HOOK_PRIO_PROPERTY, SpawnSetProperties);
|
||||
AddAppSpawnHook(STAGE_CHILD_POST_RELY, HOOK_PRIO_HIGHEST, SpawnComplete);
|
||||
}
|
2
interfaces/innerkits_new/module_engine/BUILD.gn → modules/module_engine/BUILD.gn
Normal file → Executable file
2
interfaces/innerkits_new/module_engine/BUILD.gn → modules/module_engine/BUILD.gn
Normal file → Executable file
@ -23,7 +23,7 @@ config("appspawn_module_engine_exported_config") {
|
||||
visibility += [ "include" ]
|
||||
include_dirs = [
|
||||
"${appspawn_innerkits_path}/include",
|
||||
"${appspawn_innerkits_path}/module_engine/include",
|
||||
"${appspawn_path}/modules/module_engine/include",
|
||||
"${appspawn_path}/util/include",
|
||||
]
|
||||
}
|
90
interfaces/innerkits_new/module_engine/include/appspawn_hook.h → modules/module_engine/include/appspawn_hook.h
Normal file → Executable file
90
interfaces/innerkits_new/module_engine/include/appspawn_hook.h → modules/module_engine/include/appspawn_hook.h
Normal file → Executable file
@ -35,7 +35,7 @@ typedef struct TagAppSpawnMgr AppSpawnMgr;
|
||||
typedef struct TagAppSpawningCtx AppSpawningCtx;
|
||||
typedef struct AppSpawnContent AppSpawnContent;
|
||||
typedef struct AppSpawnClient AppSpawnClient;
|
||||
typedef struct TagAppSpawnedProcess AppSpawnedProcess;
|
||||
typedef struct TagAppSpawnedProcess AppSpawnedProcessInfo;
|
||||
|
||||
typedef enum {
|
||||
EXT_DATA_SANDBOX
|
||||
@ -44,76 +44,48 @@ typedef enum {
|
||||
struct TagAppSpawnExtData;
|
||||
typedef void (*AppSpawnExtDataFree)(struct TagAppSpawnExtData *data);
|
||||
typedef void (*AppSpawnExtDataDump)(struct TagAppSpawnExtData *data);
|
||||
typedef void (*AppSpawnExtDataClear)(struct TagAppSpawnExtData *data);
|
||||
typedef struct TagAppSpawnExtData {
|
||||
ListNode node;
|
||||
uint32_t dataId;
|
||||
AppSpawnExtDataFree freeNode;
|
||||
AppSpawnExtDataClear clearNode;
|
||||
AppSpawnExtDataDump dumpNode;
|
||||
} AppSpawnExtData;
|
||||
|
||||
typedef enum TagAppSpawnHookStage {
|
||||
// run in init
|
||||
HOOK_PRELOAD = 10,
|
||||
STAGE_SERVER_PRELOAD = 10,
|
||||
STAGE_SERVER_APP_ADD,
|
||||
STAGE_SERVER_APP_DIED,
|
||||
|
||||
// run before fork
|
||||
HOOK_SPAWN_PREPARE = 20,
|
||||
STAGE_PARENT_PRE_FORK = 20,
|
||||
STAGE_PARENT_PRE_RELY = 21,
|
||||
STAGE_PARENT_POST_RELY = 22,
|
||||
|
||||
// run in child process
|
||||
HOOK_SPAWN_CLEAR_ENV = 30, // clear env, set token HOOK_SPAWN_CLEAR_ENV
|
||||
HOOK_SPAWN_SET_CHILD_PROPERTY,
|
||||
HOOK_SPAWN_COMPLETED,
|
||||
HOOK_SPAWN_POST = 40,
|
||||
// for app change
|
||||
HOOK_APP_ADD = 50,
|
||||
HOOK_APP_DIED,
|
||||
STAGE_CHILD_PRE_COLDBOOT = 30, // clear env, set token before cold boot
|
||||
STAGE_CHILD_EXECUTE,
|
||||
STAGE_CHILD_PRE_RELY,
|
||||
STAGE_CHILD_POST_RELY,
|
||||
STAGE_CHILD_PRE_RUN
|
||||
} AppSpawnHookStage;
|
||||
|
||||
typedef enum TagAppSpawnHookPrio {
|
||||
HOOK_PRIO_HIGHEST = 1000,
|
||||
HOOK_PRIO_COMMON = 2000,
|
||||
HOOK_PRIO_SANDBOX = 3000,
|
||||
HOOK_PRIO_PROPERTY = 4000,
|
||||
HOOK_PRIO_LOWEST = 5000,
|
||||
} AppSpawnHookPrio;
|
||||
|
||||
typedef int (*PreloadHook)(AppSpawnMgr *content);
|
||||
typedef int (*AppSpawnHook)(AppSpawnMgr *content, AppSpawningCtx *property);
|
||||
typedef int (*ProcessChangeHook)(const AppSpawnMgr *content, const AppSpawnedProcess *appInfo);
|
||||
typedef int (*ProcessChangeHook)(const AppSpawnMgr *content, const AppSpawnedProcessInfo *appInfo);
|
||||
int AddPreloadHook(int prio, PreloadHook hook);
|
||||
int AddAppSpawnHook(AppSpawnHookStage stage, int prio, AppSpawnHook hook);
|
||||
int AddAppChangeHook(AppSpawnHookStage stage, int prio, ProcessChangeHook hook);
|
||||
|
||||
int IsNWebSpawnMode(const AppSpawnMgr *content);
|
||||
int IsColdRunMode(const AppSpawnMgr *content);
|
||||
|
||||
int GetAppSpawnMsgType(const AppSpawningCtx *property);
|
||||
const char *GetBundleName(const AppSpawningCtx *property);
|
||||
void *GetAppProperty(const AppSpawningCtx *property, uint32_t type);
|
||||
const char *GetProcessName(const AppSpawningCtx *property);
|
||||
|
||||
/**
|
||||
* @brief Get the App Property Ex info
|
||||
*
|
||||
* @param property app 属性信息
|
||||
* @param name 变量名
|
||||
* @param len 返回变量长度
|
||||
* @return uint8_t* 返回变量值
|
||||
*/
|
||||
uint8_t *GetAppPropertyExt(const AppSpawningCtx *property, const char *name, uint32_t *len);
|
||||
|
||||
/**
|
||||
* @brief 检查app属性参数的flags是否设置
|
||||
*
|
||||
* @param property app 属性信息
|
||||
* @param type TLV_MSG_FLAGS or TLV_PERMISSION
|
||||
* @param index flags index
|
||||
* @return int
|
||||
*/
|
||||
int CheckAppPropertyFlags(const AppSpawningCtx *property, uint32_t type, uint32_t index);
|
||||
int SetAppPropertyFlags(const AppSpawningCtx *property, uint32_t type, uint32_t index);
|
||||
|
||||
__attribute__((always_inline)) inline int TestAppMsgFlagsSet(const AppSpawningCtx *property, uint32_t index)
|
||||
{
|
||||
return CheckAppPropertyFlags(property, TLV_MSG_FLAGS, index);
|
||||
}
|
||||
__attribute__((always_inline)) inline int TestAppPermissionFlags(const AppSpawningCtx *property, uint32_t index)
|
||||
{
|
||||
return CheckAppPropertyFlags(property, TLV_PERMISSION, index);
|
||||
}
|
||||
__attribute__((always_inline)) inline int SetAppPermissionFlags(const AppSpawningCtx *property, uint32_t index)
|
||||
{
|
||||
return SetAppPropertyFlags(property, TLV_PERMISSION, index);
|
||||
}
|
||||
int AddProcessMgrHook(AppSpawnHookStage stage, int prio, ProcessChangeHook hook);
|
||||
|
||||
typedef int (*ChildLoop)(AppSpawnContent *content, AppSpawnClient *client);
|
||||
/**
|
||||
@ -133,7 +105,7 @@ void RegChildLooper(AppSpawnContent *content, ChildLoop loop);
|
||||
* @return int 结果
|
||||
*/
|
||||
int MakeDirRec(const char *path, mode_t mode, int lastPath);
|
||||
__attribute__((always_inline)) inline int MakeDirRecursive(const char *path, mode_t mode)
|
||||
__attribute__((always_inline)) inline int CreateSandboxDir(const char *path, mode_t mode)
|
||||
{
|
||||
return MakeDirRec(path, mode, 1);
|
||||
}
|
||||
@ -148,12 +120,12 @@ typedef struct {
|
||||
} MountArg;
|
||||
|
||||
int SandboxMountPath(const MountArg *arg);
|
||||
int IsDeveloperModeOn(const AppSpawningCtx *property);
|
||||
|
||||
// 扩展变量
|
||||
typedef struct TagSandboxContext SandboxContext;
|
||||
typedef struct TagVarExtraData VarExtraData;
|
||||
typedef int (*ReplaceVarHandler)(const SandboxContext *context,
|
||||
const uint8_t *buffer, uint32_t bufferLen, uint32_t *realLen, int permission);
|
||||
const char *buffer, uint32_t bufferLen, uint32_t *realLen, const VarExtraData *extraData);
|
||||
/**
|
||||
* @brief 注册变量替换处理函数
|
||||
*
|
||||
@ -163,9 +135,9 @@ typedef int (*ReplaceVarHandler)(const SandboxContext *context,
|
||||
*/
|
||||
int AddVariableReplaceHandler(const char *name, ReplaceVarHandler handler);
|
||||
|
||||
typedef struct TagAppSpawnSandbox AppSpawnSandbox;
|
||||
typedef struct TagAppSpawnSandboxCfg AppSpawnSandboxCfg;
|
||||
typedef int (*ProcessExpandSandboxCfg)(const SandboxContext *context,
|
||||
const AppSpawnSandbox *appSandBox, const char *name);
|
||||
const AppSpawnSandboxCfg *appSandBox, const char *name);
|
||||
#define EXPAND_CFG_HANDLER_PRIO_START 3
|
||||
|
||||
/**
|
0
interfaces/innerkits_new/module_engine/include/appspawn_msg.h → modules/module_engine/include/appspawn_msg.h
Normal file → Executable file
0
interfaces/innerkits_new/module_engine/include/appspawn_msg.h → modules/module_engine/include/appspawn_msg.h
Normal file → Executable file
0
interfaces/innerkits_new/module_engine/stub/libappspawn.stub.empty.json → modules/module_engine/stub/libappspawn.stub.empty.json
Normal file → Executable file
0
interfaces/innerkits_new/module_engine/stub/libappspawn.stub.empty.json → modules/module_engine/stub/libappspawn.stub.empty.json
Normal file → Executable file
19
modules/module_engine/stub/libappspawn.stub.json
Executable file
19
modules/module_engine/stub/libappspawn.stub.json
Executable file
@ -0,0 +1,19 @@
|
||||
[
|
||||
{ "name": "AddPreloadHook" },
|
||||
{ "name": "AddProcessMgrHook" },
|
||||
{ "name": "AddAppSpawnHook" },
|
||||
{ "name": "AppSpawnHookExecute" },
|
||||
{ "name": "AppSpawnEnvClear" },
|
||||
{ "name": "GetAppSpawnMsgInfo" },
|
||||
{ "name": "GetAppSpawnMsgExtInfo" },
|
||||
{ "name": "CheckAppSpawnMsgFlag" },
|
||||
{ "name": "SetAppSpawnMsgFlag" },
|
||||
{ "name": "RegChildLooper" },
|
||||
{ "name": "MakeDirRec" },
|
||||
{ "name": "SandboxMountPath" },
|
||||
{ "name": "AddVariableReplaceHandler" },
|
||||
{ "name": "GetSpawnedProcess" },
|
||||
{ "name": "DumpAppSpawnMsg" },
|
||||
{ "name": "AppSpawnDump" },
|
||||
{ "name": "RegisterExpandSandboxCfgHandler" }
|
||||
]
|
260
modules/modulemgr/appspawn_modulemgr.c
Executable file
260
modules/modulemgr/appspawn_modulemgr.c
Executable file
@ -0,0 +1,260 @@
|
||||
/*
|
||||
* Copyright (c) 2024 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 "appspawn_modulemgr.h"
|
||||
|
||||
#include "appspawn_hook.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "hookmgr.h"
|
||||
#include "modulemgr.h"
|
||||
|
||||
typedef struct {
|
||||
const AppSpawnContent *content;
|
||||
const AppSpawnedProcessInfo *appInfo;
|
||||
} AppSpawnAppArg;
|
||||
|
||||
static struct {
|
||||
MODULE_MGR *moduleMgr;
|
||||
AppSpawnModuleType type;
|
||||
const char *moduleName;
|
||||
} g_moduleMgr[MODULE_MAX] = {
|
||||
{NULL, MODULE_DEFAULT, "appspawn"},
|
||||
{NULL, MODULE_APPSPAWN, "appspawn/appspawn"},
|
||||
{NULL, MODULE_NWEBSPAWN, "appspawn/nwebspawn"},
|
||||
{NULL, MODULE_COMMON, "appspawn/common"},
|
||||
};
|
||||
static HOOK_MGR *g_appspawnHookMgr = NULL;
|
||||
|
||||
int AppSpawnModuleMgrInstall(const char *moduleName)
|
||||
{
|
||||
if (moduleName == NULL) {
|
||||
return -1;
|
||||
}
|
||||
int type = MODULE_DEFAULT;
|
||||
if (g_moduleMgr[type].moduleMgr == NULL) {
|
||||
g_moduleMgr[type].moduleMgr = ModuleMgrCreate(g_moduleMgr[type].moduleName);
|
||||
}
|
||||
if (g_moduleMgr[type].moduleMgr == NULL) {
|
||||
return -1;
|
||||
}
|
||||
#ifndef APPSPAWN_TEST
|
||||
return ModuleMgrInstall(g_moduleMgr[type].moduleMgr, moduleName, 0, NULL);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void AppSpawnModuleMgrUnInstall(int type)
|
||||
{
|
||||
if (type >= MODULE_MAX) {
|
||||
return;
|
||||
}
|
||||
if (g_moduleMgr[type].moduleMgr == NULL) {
|
||||
return;
|
||||
}
|
||||
ModuleMgrDestroy(g_moduleMgr[type].moduleMgr);
|
||||
g_moduleMgr[type].moduleMgr = NULL;
|
||||
}
|
||||
|
||||
int AppSpawnLoadAutoRunModules(int type)
|
||||
{
|
||||
if (type >= MODULE_MAX) {
|
||||
return -1;
|
||||
}
|
||||
if (g_moduleMgr[type].moduleMgr != NULL) {
|
||||
return 0;
|
||||
}
|
||||
APPSPAWN_LOGI("AppSpawnLoadAutoRunModules: %{public}d moduleName: %{public}s", type, g_moduleMgr[type].moduleName);
|
||||
#ifndef APPSPAWN_TEST
|
||||
g_moduleMgr[type].moduleMgr = ModuleMgrScan(g_moduleMgr[type].moduleName);
|
||||
return g_moduleMgr[type].moduleMgr == NULL ? -1 : 0;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
HOOK_MGR *GetAppSpawnHookMgr(void)
|
||||
{
|
||||
if (g_appspawnHookMgr != NULL) {
|
||||
return g_appspawnHookMgr;
|
||||
}
|
||||
g_appspawnHookMgr = HookMgrCreate("appspawn");
|
||||
return g_appspawnHookMgr;
|
||||
}
|
||||
|
||||
void DeleteAppSpawnHookMgr(void)
|
||||
{
|
||||
HookMgrDestroy(g_appspawnHookMgr);
|
||||
g_appspawnHookMgr = NULL;
|
||||
}
|
||||
|
||||
static int PreloadHookRun(const HOOK_INFO *hookInfo, void *executionContext)
|
||||
{
|
||||
AppSpawnHookArg *arg = (AppSpawnHookArg *)executionContext;
|
||||
PreloadHook realHook = (PreloadHook)hookInfo->hookCookie;
|
||||
return realHook((void *)arg->content);
|
||||
}
|
||||
|
||||
static void PreHookExec(const HOOK_INFO *hookInfo, void *executionContext)
|
||||
{
|
||||
AppSpawnHookArg *arg = (AppSpawnHookArg *)executionContext;
|
||||
AppSpawnMgr *spawnMgr = (AppSpawnMgr *)arg->content;
|
||||
clock_gettime(CLOCK_MONOTONIC, &spawnMgr->perLoadStart);
|
||||
APPSPAWN_LOGI("Hook stage: %{public}d prio: %{public}d start", hookInfo->stage, hookInfo->prio);
|
||||
}
|
||||
|
||||
static void PostHookExec(const HOOK_INFO *hookInfo, void *executionContext, int executionRetVal)
|
||||
{
|
||||
AppSpawnHookArg *arg = (AppSpawnHookArg *)executionContext;
|
||||
AppSpawnMgr *spawnMgr = (AppSpawnMgr *)arg->content;
|
||||
clock_gettime(CLOCK_MONOTONIC, &spawnMgr->perLoadEnd);
|
||||
uint64_t diff = DiffTime(&spawnMgr->perLoadStart, &spawnMgr->perLoadEnd);
|
||||
APPSPAWN_LOGI("Hook stage: %{public}d prio: %{public}d end time %{public}" PRId64 " ns result: %{public}d",
|
||||
hookInfo->stage, hookInfo->prio, diff, executionRetVal);
|
||||
}
|
||||
|
||||
int PreloadHookExecute(AppSpawnContent *content)
|
||||
{
|
||||
AppSpawnHookArg arg;
|
||||
arg.content = content;
|
||||
arg.client = NULL;
|
||||
HOOK_EXEC_OPTIONS options;
|
||||
options.flags = TRAVERSE_STOP_WHEN_ERROR;
|
||||
options.preHook = PreHookExec;
|
||||
options.postHook = PostHookExec;
|
||||
int ret = HookMgrExecute(GetAppSpawnHookMgr(), STAGE_SERVER_PRELOAD, (void *)(&arg), &options);
|
||||
APPSPAWN_LOGI("Execute hook [%{public}d] result %{public}d", STAGE_SERVER_PRELOAD, ret);
|
||||
return ret == ERR_NO_HOOK_STAGE ? 0 : ret;
|
||||
}
|
||||
|
||||
int AddPreloadHook(int prio, PreloadHook hook)
|
||||
{
|
||||
APPSPAWN_CHECK(hook != NULL, return APPSPAWN_ARG_INVALID, "Invalid hook");
|
||||
HOOK_INFO info;
|
||||
info.stage = STAGE_SERVER_PRELOAD;
|
||||
info.prio = prio;
|
||||
info.hook = PreloadHookRun;
|
||||
info.hookCookie = (void *)hook;
|
||||
APPSPAWN_LOGI("AddPreloadHook prio: %{public}d", prio);
|
||||
return HookMgrAddEx(GetAppSpawnHookMgr(), &info);
|
||||
}
|
||||
|
||||
static int AppSpawnHookRun(const HOOK_INFO *hookInfo, void *executionContext)
|
||||
{
|
||||
AppSpawnForkArg *arg = (AppSpawnForkArg *)executionContext;
|
||||
AppSpawnHook realHook = (AppSpawnHook)hookInfo->hookCookie;
|
||||
return realHook((AppSpawnMgr *)arg->content, (AppSpawningCtx *)arg->client);
|
||||
}
|
||||
|
||||
static void PreAppSpawnHookExec(const HOOK_INFO *hookInfo, void *executionContext)
|
||||
{
|
||||
AppSpawnHookArg *arg = (AppSpawnHookArg *)executionContext;
|
||||
clock_gettime(CLOCK_MONOTONIC, &arg->tmStart);
|
||||
APPSPAWN_LOGI("Hook stage: %{public}d prio: %{public}d start", hookInfo->stage, hookInfo->prio);
|
||||
}
|
||||
|
||||
static void PostAppSpawnHookExec(const HOOK_INFO *hookInfo, void *executionContext, int executionRetVal)
|
||||
{
|
||||
AppSpawnHookArg *arg = (AppSpawnHookArg *)executionContext;
|
||||
clock_gettime(CLOCK_MONOTONIC, &arg->tmEnd);
|
||||
uint64_t diff = DiffTime(&arg->tmStart, &arg->tmEnd);
|
||||
APPSPAWN_LOGI("Hook stage: %{public}d prio: %{public}d end time %{public}" PRId64 " ns result: %{public}d",
|
||||
hookInfo->stage, hookInfo->prio, diff, executionRetVal);
|
||||
}
|
||||
|
||||
int AppSpawnHookExecute(AppSpawnHookStage stage, uint32_t flags, AppSpawnContent *content, AppSpawnClient *client)
|
||||
{
|
||||
APPSPAWN_LOGV("Execute hook [%{public}d] for app: %{public}s", stage, GetProcessName((AppSpawningCtx *)client));
|
||||
AppSpawnHookArg forkArg;
|
||||
forkArg.client = client;
|
||||
forkArg.content = content;
|
||||
HOOK_EXEC_OPTIONS options;
|
||||
options.flags = flags; // TRAVERSE_STOP_WHEN_ERROR : 0;
|
||||
options.preHook = PreAppSpawnHookExec;
|
||||
options.postHook = PostAppSpawnHookExec;
|
||||
int ret = HookMgrExecute(GetAppSpawnHookMgr(), stage, (void *)(&forkArg), &options);
|
||||
return ret == ERR_NO_HOOK_STAGE ? 0 : ret;
|
||||
}
|
||||
|
||||
int AppSpawnExecuteClearEnvHook(AppSpawnContent *content, AppSpawnClient *client)
|
||||
{
|
||||
return AppSpawnHookExecute(STAGE_CHILD_PRE_COLDBOOT, HOOK_STOP_WHEN_ERROR, content, client);
|
||||
}
|
||||
|
||||
int AppSpawnExecuteSpawningHook(AppSpawnContent *content, AppSpawnClient *client)
|
||||
{
|
||||
return AppSpawnHookExecute(STAGE_CHILD_EXECUTE, HOOK_STOP_WHEN_ERROR, content, client);
|
||||
}
|
||||
|
||||
int AppSpawnExecutePostReplyHook(AppSpawnContent *content, AppSpawnClient *client)
|
||||
{
|
||||
return AppSpawnHookExecute(STAGE_CHILD_POST_RELY, HOOK_STOP_WHEN_ERROR, content, client);
|
||||
}
|
||||
|
||||
int AppSpawnExecutePreReplyHook(AppSpawnContent *content, AppSpawnClient *client)
|
||||
{
|
||||
return AppSpawnHookExecute(STAGE_CHILD_PRE_RELY, HOOK_STOP_WHEN_ERROR, content, client);
|
||||
}
|
||||
|
||||
void AppSpawnEnvClear(AppSpawnContent *content, AppSpawnClient *client)
|
||||
{
|
||||
(void)AppSpawnHookExecute(STAGE_CHILD_PRE_RUN, 0, content, client);
|
||||
}
|
||||
|
||||
int AddAppSpawnHook(AppSpawnHookStage stage, int prio, AppSpawnHook hook)
|
||||
{
|
||||
APPSPAWN_CHECK(hook != NULL, return APPSPAWN_ARG_INVALID, "Invalid hook");
|
||||
HOOK_INFO info;
|
||||
info.stage = stage;
|
||||
info.prio = prio;
|
||||
info.hook = AppSpawnHookRun;
|
||||
info.hookCookie = (void *)hook;
|
||||
APPSPAWN_LOGI("AddAppSpawnHook stage: %{public}d prio: %{public}d", stage, prio);
|
||||
return HookMgrAddEx(GetAppSpawnHookMgr(), &info);
|
||||
}
|
||||
|
||||
int ProcessMgrHookExecute(AppSpawnHookStage stage, const AppSpawnContent *content,
|
||||
const AppSpawnedProcessInfo *appInfo)
|
||||
{
|
||||
AppSpawnAppArg arg;
|
||||
arg.appInfo = appInfo;
|
||||
arg.content = content;
|
||||
int ret = HookMgrExecute(GetAppSpawnHookMgr(), stage, (void *)(&arg), NULL);
|
||||
return ret == ERR_NO_HOOK_STAGE ? 0 : ret;
|
||||
}
|
||||
|
||||
static int ProcessMgrHookRun(const HOOK_INFO *hookInfo, void *executionContext)
|
||||
{
|
||||
AppSpawnAppArg *arg = (AppSpawnAppArg *)executionContext;
|
||||
ProcessChangeHook realHook = (ProcessChangeHook)hookInfo->hookCookie;
|
||||
return realHook((AppSpawnMgr *)arg->content, arg->appInfo);
|
||||
}
|
||||
|
||||
int AddProcessMgrHook(AppSpawnHookStage stage, int prio, ProcessChangeHook hook)
|
||||
{
|
||||
APPSPAWN_CHECK(hook != NULL, return APPSPAWN_ARG_INVALID, "Invalid hook");
|
||||
HOOK_INFO info;
|
||||
info.stage = stage;
|
||||
info.prio = prio;
|
||||
info.hook = ProcessMgrHookRun;
|
||||
info.hookCookie = hook;
|
||||
return HookMgrAddEx(GetAppSpawnHookMgr(), &info);
|
||||
}
|
||||
|
||||
void RegChildLooper(struct AppSpawnContent *content, ChildLoop loop)
|
||||
{
|
||||
APPSPAWN_CHECK(content != NULL && loop != NULL, return, "Invalid content for RegChildLooper");
|
||||
content->runChildProcessor = loop;
|
||||
}
|
58
modules/modulemgr/appspawn_modulemgr.h
Executable file
58
modules/modulemgr/appspawn_modulemgr.h
Executable file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2024 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 APPSPAWN_MODULE_MGR_H
|
||||
#define APPSPAWN_MODULE_MGR_H
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "hookmgr.h"
|
||||
#include "modulemgr.h"
|
||||
#include "appspawn_hook.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HOOK_STOP_WHEN_ERROR 0x2
|
||||
|
||||
typedef enum {
|
||||
MODULE_DEFAULT,
|
||||
MODULE_APPSPAWN,
|
||||
MODULE_NWEBSPAWN,
|
||||
MODULE_COMMON,
|
||||
MODULE_MAX
|
||||
} AppSpawnModuleType;
|
||||
|
||||
typedef struct {
|
||||
AppSpawnContent *content;
|
||||
AppSpawnClient *client;
|
||||
struct timespec tmStart;
|
||||
struct timespec tmEnd;
|
||||
} AppSpawnHookArg;
|
||||
|
||||
int AppSpawnModuleMgrInstall(const char *mgrName);
|
||||
int AppSpawnLoadAutoRunModules(int type);
|
||||
void AppSpawnModuleMgrUnInstall(int type);
|
||||
void DeleteAppSpawnHookMgr(void);
|
||||
int PreloadHookExecute(AppSpawnContent *content);
|
||||
int ProcessMgrHookExecute(AppSpawnHookStage stage, const AppSpawnContent *content, const AppSpawnedProcessInfo *appInfo);
|
||||
int AppSpawnHookExecute(AppSpawnHookStage stage, uint32_t flags, AppSpawnContent *content, AppSpawnClient *client);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // APPSPAWN_MODULE_MGR_H
|
53
modules/nweb_adapter/BUILD.gn
Executable file
53
modules/nweb_adapter/BUILD.gn
Executable file
@ -0,0 +1,53 @@
|
||||
# Copyright (c) 2024 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.
|
||||
|
||||
import("//base/startup/appspawn/appspawn.gni")
|
||||
import("//build/ohos.gni")
|
||||
|
||||
ohos_shared_library("appspawn_nweb") {
|
||||
sources = [ "nwebspawn_adapter.cpp" ]
|
||||
include_dirs = [
|
||||
".",
|
||||
"${appspawn_path}/common",
|
||||
"${appspawn_path}/standard",
|
||||
]
|
||||
|
||||
defines = []
|
||||
cflags = []
|
||||
deps = [ "${appspawn_path}/modules/module_engine:libappspawn_module_engine" ]
|
||||
if (target_cpu == "arm64") {
|
||||
defines += [ "webview_arm64" ]
|
||||
}
|
||||
if (target_cpu == "x86_64") {
|
||||
defines += [ "webview_x86_64" ]
|
||||
}
|
||||
|
||||
external_deps = [
|
||||
"c_utils:utils",
|
||||
"hilog:libhilog",
|
||||
"init:libbegetutil",
|
||||
]
|
||||
if (build_seccomp) {
|
||||
cflags += [ "-DWITH_SECCOMP" ]
|
||||
external_deps += [ "init:seccomp" ]
|
||||
}
|
||||
subsystem_name = "${subsystem_name}"
|
||||
part_name = "${part_name}"
|
||||
install_enable = true
|
||||
if (target_cpu == "arm64" || target_cpu == "x86_64" ||
|
||||
target_cpu == "riscv64") {
|
||||
module_install_dir = "lib64/appspawn/nwebspawn"
|
||||
} else {
|
||||
module_install_dir = "lib/appspawn/nwebspawn"
|
||||
}
|
||||
}
|
133
modules/nweb_adapter/nwebspawn_adapter.cpp
Executable file
133
modules/nweb_adapter/nwebspawn_adapter.cpp
Executable file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) 2024 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 <algorithm>
|
||||
#include <cerrno>
|
||||
#include <ctime>
|
||||
#include <dlfcn.h>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
#ifdef __MUSL__
|
||||
#include <cerrno>
|
||||
#include <dlfcn_ext.h>
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include "appspawn_hook.h"
|
||||
|
||||
#ifdef WITH_SECCOMP
|
||||
#include "seccomp_policy.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
#if defined(webview_arm64)
|
||||
const std::string NWEB_HAP_LIB_PATH = "/data/storage/el1/bundle/nweb/libs/arm64";
|
||||
#elif defined(webview_x86_64)
|
||||
const std::string NWEB_HAP_LIB_PATH = "/data/storage/el1/bundle/nweb/libs/x86_64";
|
||||
#else
|
||||
const std::string NWEB_HAP_LIB_PATH = "/data/storage/el1/bundle/nweb/libs/arm";
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
static bool SetSeccompPolicyForRenderer(void *nwebRenderHandle)
|
||||
{
|
||||
#ifdef WITH_SECCOMP
|
||||
if (IsEnableSeccomp()) {
|
||||
using SeccompFuncType = bool (*)(void);
|
||||
SeccompFuncType funcSetRendererSeccompPolicy =
|
||||
reinterpret_cast<SeccompFuncType>(dlsym(nwebRenderHandle, "SetRendererSeccompPolicy"));
|
||||
if (funcSetRendererSeccompPolicy != nullptr && funcSetRendererSeccompPolicy()) {
|
||||
return true;
|
||||
}
|
||||
APPSPAWN_LOGE("SetRendererSeccompPolicy dlsym errno: %{public}d", errno);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
static int RunChildProcessor(AppSpawnContent *content, AppSpawnClient *client)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
char *renderCmd = reinterpret_cast<char *>(GetAppPropertyExt(
|
||||
reinterpret_cast<AppSpawningCtx *>(client), MSG_EXT_NAME_RENDER_CMD, &len));
|
||||
if (renderCmd == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
std::string renderStr(renderCmd);
|
||||
void *webEngineHandle = nullptr;
|
||||
void *nwebRenderHandle = nullptr;
|
||||
#ifdef __MUSL__
|
||||
Dl_namespace dlns;
|
||||
dlns_init(&dlns, "nweb_ns");
|
||||
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
|
||||
// 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
|
||||
if (webEngineHandle == nullptr) {
|
||||
APPSPAWN_LOGE("Fail to dlopen libweb_engine.so, errno: %{public}d", errno);
|
||||
}
|
||||
|
||||
if (nwebRenderHandle == nullptr) {
|
||||
APPSPAWN_LOGE("Fail to dlopen libnweb_render.so, errno: %{public}d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!SetSeccompPolicyForRenderer(nwebRenderHandle)) {
|
||||
return -1;
|
||||
}
|
||||
using FuncType = void (*)(const char *cmd);
|
||||
|
||||
FuncType funcNWebRenderMain = reinterpret_cast<FuncType>(dlsym(nwebRenderHandle, "NWebRenderMain"));
|
||||
if (funcNWebRenderMain == nullptr) {
|
||||
APPSPAWN_LOGE("webviewspawn dlsym errno: %{public}d", errno);
|
||||
return -1;
|
||||
}
|
||||
AppSpawnEnvClear(content, client);
|
||||
funcNWebRenderMain(renderStr.c_str());
|
||||
APPSPAWN_LOGI("RunChildProcessorNweb %{public}s", renderStr.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int PreLoadNwebSpawn(AppSpawnMgr *content)
|
||||
{
|
||||
APPSPAWN_LOGI("PreLoadNwebSpawn %{public}d", IsNWebSpawnMode(content));
|
||||
if (!IsNWebSpawnMode(content)) {
|
||||
return 0;
|
||||
}
|
||||
// register
|
||||
RegChildLooper(&content->content, RunChildProcessor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_CONSTRUCTOR(void)
|
||||
{
|
||||
APPSPAWN_LOGI("Load nweb module ...");
|
||||
AddPreloadHook(HOOK_PRIO_HIGHEST, PreLoadNwebSpawn);
|
||||
}
|
58
modules/sandbox/BUILD.gn
Executable file
58
modules/sandbox/BUILD.gn
Executable file
@ -0,0 +1,58 @@
|
||||
# Copyright (c) 2024 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.
|
||||
|
||||
import("//base/startup/appspawn/appspawn.gni")
|
||||
import("//build/ohos.gni")
|
||||
|
||||
ohos_shared_library("appspawn_sandbox") {
|
||||
sources = [
|
||||
"appspawn_mount_template.c",
|
||||
"appspawn_permission.c",
|
||||
"appspawn_sandbox.c",
|
||||
"sandbox_cfgvar.c",
|
||||
"sandbox_expand.c",
|
||||
"sandbox_load.c",
|
||||
"sandbox_manager.c",
|
||||
]
|
||||
|
||||
include_dirs = [
|
||||
".",
|
||||
"${appspawn_path}/common",
|
||||
"${appspawn_path}/standard",
|
||||
"${appspawn_path}/modules//module_engine//include",
|
||||
]
|
||||
|
||||
configs = [ "${appspawn_path}:appspawn_config" ]
|
||||
|
||||
defines = []
|
||||
deps = [
|
||||
"${appspawn_path}/modules/module_engine:libappspawn_module_engine",
|
||||
"${appspawn_path}/util:libappspawn_util",
|
||||
"//third_party/cJSON:cjson",
|
||||
]
|
||||
external_deps = [
|
||||
"c_utils:utils",
|
||||
"hilog:libhilog",
|
||||
"init:libbegetutil",
|
||||
]
|
||||
subsystem_name = "${subsystem_name}"
|
||||
part_name = "${part_name}"
|
||||
install_enable = true
|
||||
if (target_cpu == "arm64" || target_cpu == "x86_64" ||
|
||||
target_cpu == "riscv64") {
|
||||
defines += [ "APPSPAWN_64" ]
|
||||
module_install_dir = "lib64/appspawn/common"
|
||||
} else {
|
||||
module_install_dir = "lib/appspawn/common"
|
||||
}
|
||||
}
|
187
modules/sandbox/appspawn_mount_template.c
Executable file
187
modules/sandbox/appspawn_mount_template.c
Executable file
@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (c) 2024 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 <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sched.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "appspawn_sandbox.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "securec.h"
|
||||
|
||||
/*
|
||||
名称 fs-type flags options 说明
|
||||
default MS_BIND MS_REC 默认可读写
|
||||
rdonly MS_NODEV MS_RDONLY 只读挂载
|
||||
epfs epfs MS_NODEV 待讨论
|
||||
dac_override MS_NODEV MS_RDONLY "support_overwrite=1"
|
||||
开启const.filemanager.full_mount.enable fuse fuse MS_NOSUID MS_NODEV MS_NOEXEC MS_NOATIME MS_LAZYTIME
|
||||
dlp_fuse fuse MS_NOSUID MS_NODEV MS_NOEXEC MS_NOATIME MS_LAZYTIME 为dlpmanager管理应用专用的挂载参数
|
||||
shared MS_BIND MS_REC root
|
||||
namespace上是MS_SHARED方式挂载
|
||||
|
||||
*/
|
||||
/**
|
||||
"dac-override-sensitive": "true", 默认值:false。使能后直接使用默认值
|
||||
"sandbox-flags-customized": [ "MS_NODEV", "MS_RDONLY" ],
|
||||
"fs-type": "sharefs",
|
||||
"options": "support_overwrite=1"
|
||||
*/
|
||||
#define FUSE_MOUNT_FLAGS (MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME | MS_LAZYTIME)
|
||||
#define FUSE_MOUNT_OPTIONS \
|
||||
"fd=%d, rootmode=40000,user_id=%d,group_id=%d,allow_other," \
|
||||
"context=\"u:object_r:dlp_fuse_file:s0\", fscontext=u:object_r:dlp_fuse_file:s0"
|
||||
|
||||
static const MountArgTemplate DEF_MOUNT_ARG_TMP[MOUNT_TMP_MAX] = {
|
||||
{"default", MOUNT_TMP_DEFAULT, NULL, MS_BIND | MS_REC, NULL, MS_SLAVE},
|
||||
{"rdonly", MOUNT_TMP_RDONLY, NULL, MS_NODEV | MS_RDONLY, NULL, MS_SLAVE},
|
||||
{"epfs", MOUNT_TMP_EPFS, "epfs", MS_NODEV, NULL, MS_SLAVE},
|
||||
{"dac_override", MOUNT_TMP_DAC_OVERRIDE, "sharefs", MS_NODEV | MS_RDONLY, "support_overwrite=1", MS_SLAVE},
|
||||
{"fuse", MOUNT_TMP_FUSE, "fuse", FUSE_MOUNT_FLAGS, FUSE_MOUNT_OPTIONS, MS_SHARED},
|
||||
{"dlp_fuse", MOUNT_TMP_DLP_FUSE, "fuse", FUSE_MOUNT_FLAGS, FUSE_MOUNT_OPTIONS, MS_SHARED},
|
||||
{"shared", MOUNT_TMP_SHRED, NULL, MS_BIND | MS_REC, NULL, MS_SHARED},
|
||||
};
|
||||
|
||||
static const SandboxFlagInfo MOUNT_FLAGS_MAP[] = {
|
||||
{"rec", MS_REC}, {"MS_REC", MS_REC},
|
||||
{"bind", MS_BIND}, {"MS_BIND", MS_BIND}, {"move", MS_MOVE}, {"MS_MOVE", MS_MOVE},
|
||||
{"slave", MS_SLAVE}, {"MS_SLAVE", MS_SLAVE}, {"rdonly", MS_RDONLY}, {"MS_RDONLY", MS_RDONLY},
|
||||
{"shared", MS_SHARED}, {"MS_SHARED", MS_SHARED}, {"unbindable", MS_UNBINDABLE},
|
||||
{"MS_UNBINDABLE", MS_UNBINDABLE}, {"remount", MS_REMOUNT}, {"MS_REMOUNT", MS_REMOUNT},
|
||||
{"nosuid", MS_NOSUID}, {"MS_NOSUID", MS_NOSUID}, {"nodev", MS_NODEV}, {"MS_NODEV", MS_NODEV},
|
||||
{"noexec", MS_NOEXEC}, {"MS_NOEXEC", MS_NOEXEC}, {"noatime", MS_NOATIME}, {"MS_NOATIME", MS_NOATIME},
|
||||
{"lazytime", MS_LAZYTIME}, {"MS_LAZYTIME", MS_LAZYTIME}
|
||||
};
|
||||
|
||||
static const SandboxFlagInfo PATH_MODE_MAP[] = {
|
||||
{"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}
|
||||
};
|
||||
|
||||
uint32_t GetMountCategory(const char *name)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(name != NULL, return MOUNT_TMP_DEFAULT);
|
||||
uint32_t count = ARRAY_LENGTH(DEF_MOUNT_ARG_TMP);
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (strcmp(DEF_MOUNT_ARG_TMP[i].name, name) == 0) {
|
||||
return DEF_MOUNT_ARG_TMP[i].category;
|
||||
}
|
||||
}
|
||||
return MOUNT_TMP_DEFAULT;
|
||||
}
|
||||
|
||||
const MountArgTemplate *GetMountArgTemplate(uint32_t category)
|
||||
{
|
||||
uint32_t count = ARRAY_LENGTH(DEF_MOUNT_ARG_TMP);
|
||||
if (category > count) {
|
||||
return NULL;
|
||||
}
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (DEF_MOUNT_ARG_TMP[i].category == category) {
|
||||
return &DEF_MOUNT_ARG_TMP[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const SandboxFlagInfo *GetSandboxFlagInfo(const char *key, const SandboxFlagInfo *flagsInfos, uint32_t count)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(key != NULL, return NULL);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(flagsInfos != NULL, return NULL);
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (strcmp(flagsInfos[i].name, key) == 0) {
|
||||
return &flagsInfos[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int GetPathMode(const char *name)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(name != NULL, return 0);
|
||||
const SandboxFlagInfo *info = GetSandboxFlagInfo(name, PATH_MODE_MAP, ARRAY_LENGTH(PATH_MODE_MAP));
|
||||
if (info != NULL) {
|
||||
return info->flags;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void DumpSandboxFlags(char *buffer, uint32_t bufferSize, unsigned long flags,
|
||||
const SandboxFlagInfo *flagsInfos, uint32_t count)
|
||||
{
|
||||
bool first = true;
|
||||
size_t currLen = 0;
|
||||
int len = 0;
|
||||
unsigned long tmp = flags;
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if ((flagsInfos[i].flags & tmp) == 0) {
|
||||
continue;
|
||||
}
|
||||
tmp &= ~(flagsInfos[i].flags);
|
||||
if (!first) {
|
||||
len = sprintf_s(buffer + currLen, bufferSize - currLen - 1, " %s ", "|");
|
||||
APPSPAWN_CHECK_ONLY_EXPER(len > 0, return);
|
||||
currLen += len;
|
||||
}
|
||||
first = false;
|
||||
len = sprintf_s(buffer + currLen, bufferSize - currLen, "%s", flagsInfos[i].name);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(len > 0, return);
|
||||
currLen += len;
|
||||
}
|
||||
}
|
||||
|
||||
static void DumpMode(const char *info, mode_t mode)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(info != NULL, return);
|
||||
char buffer[64] = {0}; // 64 to show flags
|
||||
DumpSandboxFlags(buffer, sizeof(buffer), mode, PATH_MODE_MAP, ARRAY_LENGTH(PATH_MODE_MAP));
|
||||
APPSPAPWN_DUMP("%{public}s[0x%{public}x] %{public}s", info, (uint32_t)(mode), buffer);
|
||||
}
|
||||
|
||||
static void DumpMountFlags(const char *info, unsigned long mountFlags)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(info != NULL, return);
|
||||
char buffer[128] = {0}; // 64 to show flags
|
||||
DumpSandboxFlags(buffer, sizeof(buffer), mountFlags, MOUNT_FLAGS_MAP, ARRAY_LENGTH(MOUNT_FLAGS_MAP));
|
||||
APPSPAPWN_DUMP("%{public}s[0x%{public}x] %{public}s", info, (uint32_t)(mountFlags), buffer);
|
||||
}
|
||||
|
||||
void DumpMountPathMountNode(const PathMountNode *pathNode)
|
||||
{
|
||||
const MountArgTemplate *tmp = GetMountArgTemplate(pathNode->category);
|
||||
if (tmp == NULL) {
|
||||
return;
|
||||
}
|
||||
APPSPAPWN_DUMP(" sandbox node category: %{public}u(%{public}s)", tmp->category, tmp->name);
|
||||
DumpMountFlags(" sandbox node mountFlags: ", tmp->mountFlags);
|
||||
APPSPAPWN_DUMP(" sandbox node mountSharedFlag: %{public}s",
|
||||
tmp->mountSharedFlag == MS_SLAVE ? "MS_SLAVE" : "MS_SHARED");
|
||||
APPSPAPWN_DUMP(" sandbox node options: %{public}s", tmp->options ? tmp->options : "null");
|
||||
APPSPAPWN_DUMP(" sandbox node fsType: %{public}s", tmp->fsType ? tmp->fsType : "null");
|
||||
DumpMode(" sandbox node destMode: ", pathNode->destMode);
|
||||
APPSPAPWN_DUMP(" sandbox node mountSharedFlag: %{public}s",
|
||||
pathNode->mountSharedFlag ? "MS_SHARED" : "MS_SLAVE");
|
||||
}
|
@ -13,10 +13,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "appspawn_permission.h"
|
||||
#include "appspawn_utils.h"
|
||||
#ifdef APPSPAWN_CLIENT
|
||||
#include "appspawn_mount_permission.h"
|
||||
#else
|
||||
#include "appspawn_sandbox.h"
|
||||
#endif
|
||||
#include "appspawn_msg.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "securec.h"
|
||||
#include "interfaces/innerkits_new/permission/appspawn_mount_permission.h"
|
||||
|
||||
static int PermissionNodeCompareIndex(ListNode *node, void *data)
|
||||
{
|
||||
@ -27,18 +31,35 @@ static int PermissionNodeCompareIndex(ListNode *node, void *data)
|
||||
static int PermissionNodeCompareName(ListNode *node, void *data)
|
||||
{
|
||||
SandboxPermissionNode *permissionNode = (SandboxPermissionNode *)ListEntry(node, SandboxMountNode, node);
|
||||
#ifdef APPSPAWN_CLIENT
|
||||
return strcmp(permissionNode->name, (char *)data);
|
||||
#else
|
||||
return strcmp(permissionNode->section.name, (char *)data);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int PermissionNodeCompareProc(ListNode *node, ListNode *newNode)
|
||||
{
|
||||
SandboxPermissionNode *permissionNode = (SandboxPermissionNode *)ListEntry(node, SandboxMountNode, node);
|
||||
SandboxPermissionNode *newPermissionNode = (SandboxPermissionNode *)ListEntry(newNode, SandboxMountNode, node);
|
||||
#ifdef APPSPAWN_CLIENT
|
||||
return strcmp(permissionNode->name, newPermissionNode->name);
|
||||
#else
|
||||
return strcmp(permissionNode->section.name, newPermissionNode->section.name);
|
||||
#endif
|
||||
}
|
||||
|
||||
int AddSandboxPermissionNode(const char *name, SandboxQueue *queue)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(name != NULL && queue != NULL, return APPSPAWN_ARG_INVALID);
|
||||
#ifndef APPSPAWN_CLIENT
|
||||
size_t len = sizeof(SandboxPermissionNode);
|
||||
SandboxPermissionNode *node = (SandboxPermissionNode *)CreateSandboxSection(
|
||||
name, len, SANDBOX_TAG_PERMISSION);
|
||||
APPSPAWN_CHECK(node != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to create permission node");
|
||||
node->permissionIndex = 0;
|
||||
OH_ListAddWithOrder(&queue->front, &node->section.sandboxNode.node, PermissionNodeCompareProc);
|
||||
#else
|
||||
size_t len = APPSPAWN_ALIGN(strlen(name) + 1) + sizeof(SandboxPermissionNode);
|
||||
SandboxPermissionNode *node = (SandboxPermissionNode *)calloc(1, len);
|
||||
APPSPAWN_CHECK(node != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to create permission node");
|
||||
@ -48,18 +69,25 @@ int AddSandboxPermissionNode(const char *name, SandboxQueue *queue)
|
||||
APPSPAWN_CHECK(ret == 0, free(node);
|
||||
return APPSPAWN_SYSTEM_ERROR, "Failed to copy name");
|
||||
OH_ListAddWithOrder(&queue->front, &node->sandboxNode.node, PermissionNodeCompareProc);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t PermissionRenumber(SandboxQueue *queue)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(queue != NULL, return -1);
|
||||
ListNode *node = queue->front.next;
|
||||
int index = -1;
|
||||
while (node != &queue->front) {
|
||||
SandboxPermissionNode *permissionNode = (SandboxPermissionNode *)ListEntry(node, SandboxMountNode, node);
|
||||
permissionNode->permissionIndex = ++index;
|
||||
#ifdef APPSPAWN_CLIENT
|
||||
APPSPAWN_LOGV("Permission index %{public}d name %{public}s",
|
||||
permissionNode->permissionIndex, permissionNode->name);
|
||||
#else
|
||||
APPSPAWN_LOGV("Permission index %{public}d name %{public}s",
|
||||
permissionNode->permissionIndex, permissionNode->section.name);
|
||||
#endif
|
||||
node = node->next;
|
||||
}
|
||||
return index + 1;
|
||||
@ -85,6 +113,7 @@ const SandboxPermissionNode *GetPermissionNodeInQueueByIndex(SandboxQueue *queue
|
||||
|
||||
int32_t GetPermissionIndexInQueue(SandboxQueue *queue, const char *permission)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(queue != NULL && permission != NULL, return INVALID_PERMISSION_INDEX);
|
||||
const SandboxPermissionNode *permissionNode = GetPermissionNodeInQueue(queue, permission);
|
||||
return permissionNode == NULL ? INVALID_PERMISSION_INDEX : permissionNode->permissionIndex;
|
||||
}
|
@ -26,14 +26,15 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#define APP_SANDBOX_FILE_NAME "/appdata-sandbox.json"
|
||||
typedef struct TagSandboxSection SandboxQueue;
|
||||
#define WEB_SANDBOX_FILE_NAME "/appdata-sandbox-nweb.json"
|
||||
|
||||
typedef struct TagSandboxQueue SandboxQueue;
|
||||
typedef struct TagPermissionNode SandboxPermissionNode;
|
||||
|
||||
int32_t AddSandboxPermissionNode(const char *name, SandboxQueue *queue);
|
||||
int32_t GetPermissionIndexInQueue(SandboxQueue *queue, const char *permission);
|
||||
const SandboxPermissionNode *GetPermissionNodeInQueue(SandboxQueue *queue, const char *permission);
|
||||
const SandboxPermissionNode *GetPermissionNodeInQueueByIndex(SandboxQueue *queue, int32_t index);
|
||||
const SandboxPermissionNode *GetPermissionNode(const char *permission);
|
||||
int32_t PermissionRenumber(SandboxQueue *queue);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
824
modules/sandbox/appspawn_sandbox.c
Executable file
824
modules/sandbox/appspawn_sandbox.c
Executable file
@ -0,0 +1,824 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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 "appspawn_sandbox.h"
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sched.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "appspawn_msg.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "init_utils.h"
|
||||
#include "parameter.h"
|
||||
#include "securec.h"
|
||||
|
||||
static inline bool CheckSpawningMsgFlagSet(const SandboxContext *context, uint32_t index)
|
||||
{
|
||||
APPSPAWN_CHECK(context->message != NULL, return false, "Invalid property for type %{public}u", TLV_MSG_FLAGS);
|
||||
return CheckAppSpawnMsgFlag(context->message, TLV_MSG_FLAGS, index);
|
||||
}
|
||||
|
||||
static inline bool CheckSpawningPermissionFlagSet(const SandboxContext *context, uint32_t index)
|
||||
{
|
||||
APPSPAWN_CHECK(context != NULL && context->message != NULL,
|
||||
return NULL, "Invalid property for type %{public}u", TLV_PERMISSION);
|
||||
return CheckAppSpawnMsgFlag(context->message, TLV_PERMISSION, index);
|
||||
}
|
||||
|
||||
static SandboxContext *g_sandboxContext = NULL;
|
||||
|
||||
SandboxContext *GetSandboxContext(void)
|
||||
{
|
||||
if (g_sandboxContext == NULL) {
|
||||
SandboxContext *context = calloc(1, MAX_SANDBOX_BUFFER * MAX_BUFFER + sizeof(SandboxContext));
|
||||
APPSPAWN_CHECK(context != NULL, return NULL, "Failed to get mem");
|
||||
char *buffer = (char *)(context + 1);
|
||||
for (int i = 0; i < MAX_BUFFER; i++) {
|
||||
context->buffer[i].bufferLen = MAX_SANDBOX_BUFFER;
|
||||
context->buffer[i].current = 0;
|
||||
context->buffer[i].buffer = buffer + MAX_SANDBOX_BUFFER * i;
|
||||
}
|
||||
context->bundleName = NULL;
|
||||
context->bundleHasWps = 0;
|
||||
context->dlpBundle = 0;
|
||||
context->appFullMountEnable = 0;
|
||||
context->dlpUiExtType = 0;
|
||||
context->sandboxSwitch = 1;
|
||||
context->sandboxShared = false;
|
||||
context->message = NULL;
|
||||
context->rootPath = NULL;
|
||||
context->sandboxPackagePath = NULL;
|
||||
|
||||
g_sandboxContext = context;
|
||||
}
|
||||
return g_sandboxContext;
|
||||
}
|
||||
|
||||
void DeleteSandboxContext(SandboxContext *context)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(context != NULL, return);
|
||||
if (context->rootPath) {
|
||||
free(context->rootPath);
|
||||
context->rootPath = NULL;
|
||||
}
|
||||
if (context->sandboxPackagePath) {
|
||||
free(context->sandboxPackagePath);
|
||||
context->sandboxPackagePath = NULL;
|
||||
}
|
||||
if (context == g_sandboxContext) {
|
||||
g_sandboxContext = NULL;
|
||||
}
|
||||
free(context);
|
||||
}
|
||||
|
||||
static int InitSandboxContext(SandboxContext *context,
|
||||
const AppSpawnSandboxCfg *sandbox, const AppSpawningCtx *property, int nwebspawn)
|
||||
{
|
||||
AppSpawnMsgFlags *msgFlags = (AppSpawnMsgFlags *)GetAppProperty(property, TLV_MSG_FLAGS);
|
||||
APPSPAWN_CHECK(msgFlags != NULL, return APPSPAWN_TLV_NONE,
|
||||
"No msg flags in msg %{public}s", GetProcessName(property));
|
||||
context->nwebspawn = nwebspawn;
|
||||
context->bundleName = GetBundleName(property);
|
||||
context->bundleHasWps = strstr(context->bundleName, "wps") != NULL;
|
||||
context->dlpBundle = strstr(context->bundleName, "com.ohos.dlpmanager") != NULL;
|
||||
context->appFullMountEnable = sandbox->appFullMountEnable;
|
||||
context->dlpUiExtType = strstr(GetProcessName(property), "sys/commonUI") != NULL;
|
||||
|
||||
context->sandboxSwitch = 1;
|
||||
context->sandboxShared = false;
|
||||
SandboxPackageNameNode *packageNode = (SandboxPackageNameNode *)GetSandboxSection(
|
||||
&sandbox->packageNameQueue, context->bundleName);
|
||||
if (packageNode) {
|
||||
context->sandboxShared = packageNode->section.sandboxShared;
|
||||
}
|
||||
context->message = property->message;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static VarExtraData *GetVarExtraData(const SandboxContext *context, const SandboxSection *section)
|
||||
{
|
||||
static VarExtraData extraData;
|
||||
(void)memset_s(&extraData, sizeof(extraData), 0, sizeof(extraData));
|
||||
extraData.sandboxTag = GetSectionType(section);
|
||||
if (extraData.sandboxTag == SANDBOX_TAG_NAME_GROUP) {
|
||||
SandboxNameGroupNode *groupNode = (SandboxNameGroupNode *)section;
|
||||
extraData.data.depNode = groupNode->depNode;
|
||||
}
|
||||
return &extraData;
|
||||
}
|
||||
|
||||
static int BuildPackagePath(SandboxContext *sandboxContext, const AppSpawnSandboxCfg *sandbox)
|
||||
{
|
||||
const char *packagePath = GetSandboxRealVar(sandboxContext, BUFFER_FOR_SOURCE, sandbox->rootPath, NULL, NULL);
|
||||
if (packagePath) {
|
||||
sandboxContext->sandboxPackagePath = strdup(packagePath);
|
||||
}
|
||||
APPSPAWN_CHECK(sandboxContext->sandboxPackagePath != NULL,
|
||||
return APPSPAWN_SYSTEM_ERROR, "Failed to format path app: %{public}s", sandboxContext->bundleName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int BuildRootPath(SandboxContext *context, const AppSpawnSandboxCfg *sandbox, const SandboxSection *section)
|
||||
{
|
||||
const char *rootPath = GetSandboxRealVar(context, BUFFER_FOR_SOURCE, sandbox->rootPath, NULL, NULL);
|
||||
if (rootPath) {
|
||||
context->rootPath = strdup(rootPath);
|
||||
}
|
||||
APPSPAWN_CHECK(context->rootPath != NULL, return -1,
|
||||
"Failed to build root path app: %{public}s", context->bundleName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t GetMountArgs(const SandboxContext *context, const PathMountNode *sandboxNode, MountArg *args)
|
||||
{
|
||||
uint32_t category = sandboxNode->category;
|
||||
if ((category == MOUNT_TMP_DLP_FUSE) && !context->appFullMountEnable) { // use default
|
||||
category = MOUNT_TMP_DEFAULT;
|
||||
}
|
||||
const MountArgTemplate *tmp = GetMountArgTemplate(category);
|
||||
if (tmp == 0) {
|
||||
return MOUNT_TMP_DEFAULT;
|
||||
}
|
||||
args->mountFlags = tmp->mountFlags;
|
||||
args->fsType = tmp->fsType;
|
||||
args->options = tmp->options;
|
||||
args->mountSharedFlag = (sandboxNode->mountSharedFlag) ? MS_SHARED : tmp->mountSharedFlag;
|
||||
return category;
|
||||
}
|
||||
|
||||
static int CheckSandboxMountNode(const SandboxContext *context,
|
||||
const SandboxSection *section, const PathMountNode *sandboxNode)
|
||||
{
|
||||
if (sandboxNode->source == NULL || sandboxNode->target == NULL) {
|
||||
APPSPAWN_LOGW("Invalid mount config section %{public}s", section->name);
|
||||
return 0;
|
||||
}
|
||||
// special handle wps and don't use /data/app/xxx/<Package> config
|
||||
if (GetSectionType(section) == SANDBOX_TAG_SPAWN_FLAGS) { // flags-point
|
||||
if (context->bundleHasWps &&
|
||||
(strstr(sandboxNode->source, "/data/app") != NULL) &&
|
||||
(strstr(sandboxNode->source, "/base") != NULL || strstr(sandboxNode->source, "/database") != NULL) &&
|
||||
(strstr(sandboxNode->source, PARAMETER_PACKAGE_NAME) != NULL)) {
|
||||
APPSPAWN_LOGW("Invalid mount source %{public}s section %{public}s",
|
||||
sandboxNode->source, section->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// check apl
|
||||
AppSpawnMsgDomainInfo *msgDomainInfo = (AppSpawnMsgDomainInfo *)GetSpawningMsgInfo(context, TLV_DOMAIN_INFO);
|
||||
if (msgDomainInfo != NULL && sandboxNode->appAplName != NULL) {
|
||||
if (!strcmp(sandboxNode->appAplName, msgDomainInfo->apl)) {
|
||||
APPSPAWN_LOGW("Invalid mount app apl %{public}s %{public}s section %{public}s",
|
||||
sandboxNode->appAplName, msgDomainInfo->apl, section->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int32_t DoDlpAppMountStrategy(const SandboxContext *context, const MountArg *args)
|
||||
{
|
||||
AppSpawnMsgDacInfo *info = (AppSpawnMsgDacInfo *)GetSpawningMsgInfo(context, TLV_DAC_INFO);
|
||||
APPSPAWN_CHECK(info != NULL, return APPSPAWN_TLV_NONE,
|
||||
"No tlv %{public}d in msg %{public}s", TLV_DAC_INFO, context->bundleName);
|
||||
|
||||
// umount fuse path, make sure that sandbox path is not a mount point
|
||||
umount2(args->destinationPath, MNT_DETACH);
|
||||
|
||||
int fd = open("/dev/fuse", O_RDWR);
|
||||
APPSPAWN_CHECK(fd != -1, return -EINVAL,
|
||||
"open /dev/fuse failed, errno: %{public}d sandbox path %{public}s", errno, args->destinationPath);
|
||||
|
||||
char options[FUSE_OPTIONS_MAX_LEN];
|
||||
(void)sprintf_s(options, sizeof(options), "fd=%d,"
|
||||
"rootmode=40000,user_id=%d,group_id=%d,allow_other,"
|
||||
"context=\"u:object_r:dlp_fuse_file:s0\","
|
||||
"fscontext=u:object_r:dlp_fuse_file:s0", fd, info->uid, info->gid);
|
||||
|
||||
// To make sure destinationPath exist
|
||||
CreateSandboxDir(args->destinationPath, FILE_MODE);
|
||||
MountArg mountArg = {args->originPath, args->destinationPath, args->fsType, args->mountFlags, options, MS_SHARED};
|
||||
int ret = SandboxMountPath(&mountArg);
|
||||
if (ret != 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
/* close DLP_FUSE_FD and dup FD to it */
|
||||
close(DLP_FUSE_FD);
|
||||
ret = dup2(fd, DLP_FUSE_FD);
|
||||
APPSPAWN_CHECK_ONLY_LOG(ret != -1, "dup fuse fd %{public}d failed, errno: %{public}d", fd, errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void CheckAndCreateSandboxFile(const char *file)
|
||||
{
|
||||
if (access(file, F_OK) == 0) {
|
||||
APPSPAWN_LOGI("file %{public}s already exist", file);
|
||||
return;
|
||||
}
|
||||
MakeDirRec(file, FILE_MODE, 0);
|
||||
int fd = open(file, O_CREAT, FILE_MODE);
|
||||
if (fd < 0) {
|
||||
APPSPAWN_LOGW("failed create %{public}s, err=%{public}d", file, errno);
|
||||
} else {
|
||||
close(fd);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static int DoSandboxPathNodeMount(const SandboxContext *context,
|
||||
const SandboxSection *section, const PathMountNode *sandboxNode, int operation)
|
||||
{
|
||||
if (CheckSandboxMountNode(context, section, sandboxNode) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
MountArg args = {};
|
||||
uint32_t category = GetMountArgs(context, sandboxNode, &args);
|
||||
|
||||
args.originPath = GetSandboxRealVar(context, BUFFER_FOR_SOURCE, sandboxNode->source, NULL, NULL);
|
||||
// only destinationPath
|
||||
VarExtraData *extraData = GetVarExtraData(context, section);
|
||||
args.destinationPath = GetSandboxRealVar(context,
|
||||
BUFFER_FOR_TARGET, sandboxNode->target, context->rootPath, extraData);
|
||||
APPSPAWN_CHECK(args.originPath != NULL && args.destinationPath != NULL,
|
||||
return APPSPAWN_ARG_INVALID, "Invalid path %{public}s %{public}s", args.originPath, args.destinationPath);
|
||||
|
||||
if (sandboxNode->sandboxNode.type == SANDBOX_TAG_MOUNT_FILE) {
|
||||
CheckAndCreateSandboxFile(args.destinationPath);
|
||||
} else {
|
||||
CreateSandboxDir(args.destinationPath, FILE_MODE);
|
||||
}
|
||||
APPSPAWN_LOGV("Bind mount category %{public}u op %{public}x \n "
|
||||
"mount arg: %{public}s %{public}s %{public}x %{public}s \n %{public}s => %{public}s",
|
||||
category, operation, args.fsType, args.mountSharedFlag == MS_SHARED ? "MS_SHARED" : "MS_SLAVE",
|
||||
(uint32_t)args.mountFlags, args.options, args.originPath, args.destinationPath);
|
||||
|
||||
if ((operation & MOUNT_PATH_OP_UNMOUNT) == MOUNT_PATH_OP_UNMOUNT) {
|
||||
// unmount this deps
|
||||
APPSPAWN_LOGV("DoSandboxPathNodeMount umount2 %{public}s", args.destinationPath);
|
||||
umount2(args.destinationPath, MNT_DETACH);
|
||||
}
|
||||
int ret = 0;
|
||||
if (category == MOUNT_TMP_DLP_FUSE || category == MOUNT_TMP_DLP_FUSE) {
|
||||
ret = DoDlpAppMountStrategy(context, &args);
|
||||
} else {
|
||||
ret = SandboxMountPath(&args);
|
||||
}
|
||||
if (ret != 0 && sandboxNode->checkErrorFlag) {
|
||||
APPSPAWN_LOGE("Failed to mount config, section: %{public}s result: %{public}d category: %{public}d",
|
||||
section->name, ret, category);
|
||||
return ret;
|
||||
}
|
||||
if (sandboxNode->destMode != 0) {
|
||||
chmod(context->rootPath, sandboxNode->destMode);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int DoSandboxPathSymLink(const SandboxContext *context,
|
||||
const SandboxSection *section, const SymbolLinkNode *sandboxNode)
|
||||
{
|
||||
// Check the validity of the symlink configuration
|
||||
if (sandboxNode->linkName == NULL || sandboxNode->target == NULL) {
|
||||
APPSPAWN_LOGW("Invalid symlink config, section %{public}s", section->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *target = GetSandboxRealVar(context, BUFFER_FOR_SOURCE, sandboxNode->target, NULL, NULL);
|
||||
const char *linkName = GetSandboxRealVar(context, BUFFER_FOR_TARGET,
|
||||
sandboxNode->linkName, context->rootPath, NULL);
|
||||
APPSPAWN_LOGV("symlink, from %{public}s to %{public}s", target, linkName);
|
||||
int ret = symlink(target, linkName);
|
||||
if (ret && errno != EEXIST) {
|
||||
if (sandboxNode->checkErrorFlag) {
|
||||
APPSPAWN_LOGE("symlink failed, errno: %{public}d link info %{public}s %{public}s",
|
||||
errno, sandboxNode->target, sandboxNode->linkName);
|
||||
return errno;
|
||||
}
|
||||
APPSPAWN_LOGV("symlink failed, errno: %{public}d link info %{public}s %{public}s",
|
||||
errno, sandboxNode->target, sandboxNode->linkName);
|
||||
}
|
||||
if (sandboxNode->destMode != 0) {
|
||||
chmod(context->rootPath, sandboxNode->destMode);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int DoSandboxNodeMount(const SandboxContext *context, const SandboxSection *section, int operation)
|
||||
{
|
||||
APPSPAWN_LOGV("DoSandboxNodeMount section %{public}s operation %{public}x", section->name, operation);
|
||||
ListNode *node = section->front.next;
|
||||
while (node != §ion->front) {
|
||||
int ret = 0;
|
||||
SandboxMountNode *sandboxNode = (SandboxMountNode *)ListEntry(node, SandboxMountNode, node);
|
||||
switch (sandboxNode->type) {
|
||||
case SANDBOX_TAG_MOUNT_PATH:
|
||||
case SANDBOX_TAG_MOUNT_FILE:
|
||||
ret = DoSandboxPathNodeMount(context, section, (PathMountNode *)sandboxNode, operation);
|
||||
break;
|
||||
case SANDBOX_TAG_SYMLINK:
|
||||
if ((operation & MOUNT_PATH_OP_NO_SYMLINK) == MOUNT_PATH_OP_NO_SYMLINK) {
|
||||
break;
|
||||
}
|
||||
ret = DoSandboxPathSymLink(context, section, (SymbolLinkNode *)sandboxNode);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int UpdateMountPathDepsPath(const SandboxContext *context, SandboxNameGroupNode *groupNode)
|
||||
{
|
||||
PathMountNode *depNode = groupNode->depNode;
|
||||
const char *srcPath = GetSandboxRealVar(context, BUFFER_FOR_SOURCE, depNode->source, NULL, NULL);
|
||||
const char *sandboxPath = GetSandboxRealVar(context, BUFFER_FOR_TARGET, depNode->target, NULL, NULL);
|
||||
if (srcPath == NULL || sandboxPath == NULL) {
|
||||
APPSPAWN_LOGE("Failed to get real path %{public}s ", groupNode->section.name);
|
||||
return APPSPAWN_SANDBOX_MOUNT_FAIL;
|
||||
}
|
||||
free(depNode->source);
|
||||
depNode->source = strdup(srcPath);
|
||||
free(depNode->target);
|
||||
depNode->target = strdup(sandboxPath);
|
||||
if (depNode->source == NULL || depNode->target == NULL) {
|
||||
APPSPAWN_LOGE("Failed to get real path %{public}s ", groupNode->section.name);
|
||||
if (depNode->source) {
|
||||
free(depNode->source);
|
||||
depNode->source = NULL;
|
||||
}
|
||||
if (depNode->target) {
|
||||
free(depNode->target);
|
||||
depNode->target = NULL;
|
||||
}
|
||||
return APPSPAWN_SANDBOX_MOUNT_FAIL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool CheckAndCreateDepPath(const SandboxContext *context, const SandboxNameGroupNode *sandboxNode)
|
||||
{
|
||||
if (sandboxNode->mountMode != MOUNT_MODE_NOT_EXIST) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PathMountNode *mountNode = (PathMountNode *)GetFirstSandboxMountNode(&sandboxNode->section);
|
||||
if (mountNode == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *srcPath = GetSandboxRealVar(context, BUFFER_FOR_SOURCE, mountNode->source, NULL, NULL);
|
||||
if (srcPath == NULL) {
|
||||
return false;
|
||||
}
|
||||
APPSPAWN_LOGV("Mount depended to check src: %{public}s", srcPath);
|
||||
if (access(srcPath, F_OK) == 0) {
|
||||
return true;
|
||||
}
|
||||
// 这里已经是实际路径了,不需要转化
|
||||
APPSPAWN_LOGV("Mount depended source: %{public}s", sandboxNode->depNode->source);
|
||||
CreateSandboxDir(sandboxNode->depNode->source, FILE_MODE);
|
||||
return false;
|
||||
}
|
||||
|
||||
static int MountNameGroupPath(const SandboxContext *context,
|
||||
const AppSpawnSandboxCfg *sandbox, const SandboxNameGroupNode *sandboxNode)
|
||||
{
|
||||
int ret = 0;
|
||||
APPSPAWN_LOGV("Set name-group: '%{public}s' root path: '%{public}s' global %{public}s",
|
||||
sandboxNode->section.name, context->rootPath, sandbox->rootPath);
|
||||
|
||||
ret = DoSandboxNodeMount(context, &sandboxNode->section, 0);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"Mount name group %{public}s fail result: %{public}d", sandboxNode->section.name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int MountSandboxConfig(const SandboxContext *context,
|
||||
const AppSpawnSandboxCfg *sandbox, const SandboxSection *section, int operation)
|
||||
{
|
||||
// if sandbox switch is off, don't do symlink work again
|
||||
operation |= !(context->sandboxSwitch && sandbox->topSandboxSwitch) ? MOUNT_PATH_OP_NO_SYMLINK : 0;
|
||||
APPSPAWN_LOGV("Set config section: %{public}s root path: '%{public}s' symlinkDo: %{public}x",
|
||||
section->name, context->rootPath, operation);
|
||||
|
||||
int ret = DoSandboxNodeMount(context, section, operation);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"Mount sandbox config fail result: %{public}d, app: %{public}s", ret, context->bundleName);
|
||||
|
||||
if (section->nameGroups == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < section->number; i++) {
|
||||
if (section->nameGroups[i] == NULL) {
|
||||
continue;
|
||||
}
|
||||
SandboxNameGroupNode *groupNode = (SandboxNameGroupNode *)section->nameGroups[i];
|
||||
MountNameGroupPath(context, sandbox, groupNode);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int SetExpandSandboxConfig(const SandboxContext *context, const AppSpawnSandboxCfg *sandbox)
|
||||
{
|
||||
int ret = ProcessExpandAppSandboxConfig(context, sandbox, "HspList");
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"Set HspList config fail result: %{public}d, app: %{public}s", ret, context->bundleName);
|
||||
ret = ProcessExpandAppSandboxConfig(context, sandbox, "DataGroup");
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"Set DataGroup config fail result: %{public}d, app: %{public}s", ret, context->bundleName);
|
||||
|
||||
bool mountDestBundlePath = false;
|
||||
AppSpawnMsgDomainInfo *msgDomainInfo = (AppSpawnMsgDomainInfo *)GetSpawningMsgInfo(context, TLV_DOMAIN_INFO);
|
||||
if (msgDomainInfo != NULL) {
|
||||
mountDestBundlePath = (strcmp(msgDomainInfo->apl, APL_SYSTEM_BASIC) == 0) ||
|
||||
(strcmp(msgDomainInfo->apl, APL_SYSTEM_CORE) == 0);
|
||||
}
|
||||
if (mountDestBundlePath || (CheckSpawningMsgFlagSet(context, APP_FLAGS_ACCESS_BUNDLE_DIR) != 0)) {
|
||||
// need permission check for system app here
|
||||
const char *destBundlesPath = GetSandboxRealVar(context,
|
||||
BUFFER_FOR_TARGET, "/data/bundles/", context->sandboxPackagePath, NULL);
|
||||
CreateSandboxDir(destBundlesPath, FILE_MODE);
|
||||
MountArg mountArg = {PHYSICAL_APP_INSTALL_PATH, destBundlesPath, NULL, MS_REC | MS_BIND, NULL, MS_SLAVE};
|
||||
ret = SandboxMountPath(&mountArg);
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "mount library failed %{public}d", ret);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int SetSandboxPackageNameConfig(const SandboxContext *context, const AppSpawnSandboxCfg *sandbox)
|
||||
{
|
||||
SandboxPackageNameNode *sandboxNode =
|
||||
(SandboxPackageNameNode *)GetSandboxSection(&sandbox->packageNameQueue, context->bundleName);
|
||||
if (sandboxNode != NULL) {
|
||||
int ret = MountSandboxConfig(context, sandbox, &sandboxNode->section, 0);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int SetSandboxSpawnFlagsConfig(const SandboxContext *context, const AppSpawnSandboxCfg *sandbox)
|
||||
{
|
||||
APPSPAWN_LOGV("Set spawning flags config");
|
||||
ListNode *node = sandbox->spawnFlagsQueue.front.next;
|
||||
while (node != &sandbox->spawnFlagsQueue.front) {
|
||||
SandboxFlagsNode *sandboxNode = (SandboxFlagsNode *)ListEntry(node, SandboxMountNode, node);
|
||||
if (!CheckSpawningMsgFlagSet(context, sandboxNode->flagIndex)) { // match flags point
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
int ret = MountSandboxConfig(context, sandbox, &sandboxNode->section, 0);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
node = node->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int SetSandboxPermissionConfig(const SandboxContext *context, const AppSpawnSandboxCfg *sandbox)
|
||||
{
|
||||
APPSPAWN_LOGV("Set permission config");
|
||||
ListNode *node = sandbox->permissionQueue.front.next;
|
||||
while (node != &sandbox->permissionQueue.front) {
|
||||
SandboxPermissionNode *permissionNode = (SandboxPermissionNode *)ListEntry(node, SandboxMountNode, node);
|
||||
if (!CheckSpawningPermissionFlagSet(context, permissionNode->permissionIndex)) {
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
APPSPAWN_LOGV("SetSandboxPermissionConfig permission %{public}s", permissionNode->section.name);
|
||||
int ret = MountSandboxConfig(context, sandbox, &permissionNode->section, 0);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
node = node->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int SetOverlayAppSandboxConfig(const SandboxContext *context, const AppSpawnSandboxCfg *sandbox)
|
||||
{
|
||||
if (!CheckSpawningMsgFlagSet(context, APP_FLAGS_OVERLAY)) {
|
||||
return 0;
|
||||
}
|
||||
int ret = ProcessExpandAppSandboxConfig(context, sandbox, "Overlay");
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int SetBundleResourceSandboxConfig(const SandboxContext *context, const AppSpawnSandboxCfg *sandbox)
|
||||
{
|
||||
if (!CheckSpawningMsgFlagSet(context, APP_FLAGS_BUNDLE_RESOURCES)) {
|
||||
return 0;
|
||||
}
|
||||
const char *destPath = GetSandboxRealVar(context,
|
||||
BUFFER_FOR_TARGET, "/data/storage/bundle_resources/", context->sandboxPackagePath, NULL);
|
||||
CreateSandboxDir(destPath, FILE_MODE);
|
||||
MountArg mountArg = {
|
||||
"/data/service/el1/public/bms/bundle_resources/", destPath, NULL, MS_REC | MS_BIND, NULL, MS_SLAVE
|
||||
};
|
||||
int ret = SandboxMountPath(&mountArg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int32_t ChangeCurrentDir(const SandboxContext *context)
|
||||
{
|
||||
int32_t ret = 0;
|
||||
ret = chdir(context->sandboxPackagePath);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"chdir failed, app: %{public}s, path: %{public}s errno: %{public}d",
|
||||
context->bundleName, context->sandboxPackagePath, errno);
|
||||
|
||||
if (context->sandboxShared) {
|
||||
ret = chroot(context->sandboxPackagePath);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"chroot failed, path: %{public}s errno: %{public}d", context->sandboxPackagePath, errno);
|
||||
return ret;
|
||||
}
|
||||
ret = syscall(SYS_pivot_root, context->sandboxPackagePath, context->sandboxPackagePath);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"pivot root failed, path: %{public}s errno: %{public}d", context->sandboxPackagePath, errno);
|
||||
ret = umount2(".", MNT_DETACH);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"MNT_DETACH failed, path: %{public}s errno: %{public}d", context->sandboxPackagePath, errno);
|
||||
APPSPAWN_LOGV("ChangeCurrentDir %{public}s ", context->sandboxPackagePath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int SandboxRootFolderCreateNoShare(
|
||||
const SandboxContext *context, const AppSpawnSandboxCfg *sandbox, bool remountProc)
|
||||
{
|
||||
APPSPAWN_LOGV("SandboxRootFolderCreateNoShare %{public}s ", context->sandboxPackagePath);
|
||||
int ret = mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"set propagation slave failed, app: %{public}s errno: %{public}d", context->sandboxPackagePath, errno);
|
||||
|
||||
MountArg arg = {context->sandboxPackagePath, context->sandboxPackagePath, NULL, BASIC_MOUNT_FLAGS, NULL, MS_SLAVE};
|
||||
ret = SandboxMountPath(&arg);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"mount path failed, app: %{public}s errno: %{public}d", context->sandboxPackagePath, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int SandboxRootFolderCreate(const SandboxContext *context, const AppSpawnSandboxCfg *sandbox)
|
||||
{
|
||||
APPSPAWN_LOGV("topSandboxSwitch %{public}d sandboxSwitch: %{public}d sandboxShared: %{public}d \n",
|
||||
sandbox->topSandboxSwitch, context->sandboxSwitch, context->sandboxShared);
|
||||
|
||||
int ret = 0;
|
||||
if (sandbox->topSandboxSwitch == 0 || context->sandboxSwitch == 0) {
|
||||
ret = mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"set propagation slave failed, app: %{public}s errno: %{public}d", context->sandboxPackagePath, errno);
|
||||
// bind mount "/" to /mnt/sandbox/<packageName> path
|
||||
// rootfs: to do more resources bind mount here to get more strict resources constraints
|
||||
ret = mount("/", context->sandboxPackagePath, NULL, BASIC_MOUNT_FLAGS, NULL);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"mount bind / failed, app: %{public}s errno: %{public}d", context->sandboxPackagePath, errno);
|
||||
} else if (!context->sandboxShared) {
|
||||
bool remountProc = !context->nwebspawn && ((sandbox->sandboxNsFlags & CLONE_NEWPID) == CLONE_NEWPID);
|
||||
ret = SandboxRootFolderCreateNoShare(context, sandbox, remountProc);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int DumpCurrentDir(SandboxContext *context, const char *dirPath)
|
||||
{
|
||||
DIR *pDir = opendir(dirPath);
|
||||
APPSPAWN_CHECK(pDir != NULL, return -1, "Read dir :%{public}s failed.%{public}d", dirPath, errno);
|
||||
|
||||
struct dirent *dp;
|
||||
while ((dp = readdir(pDir)) != NULL) {
|
||||
if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) {
|
||||
continue;
|
||||
}
|
||||
if (dp->d_type == DT_DIR) {
|
||||
APPSPAWN_LOGV(" Current path %{public}s/%{public}s ", dirPath, dp->d_name);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(snprintf_s(context->buffer[1].buffer, context->buffer[1].bufferLen, context->buffer[1].bufferLen - 1,
|
||||
"%s/%s", dirPath, dp->d_name) != -1, return -1);
|
||||
char *path = strdup(context->buffer[1].buffer);
|
||||
DumpCurrentDir(context, path);
|
||||
free(path);
|
||||
}
|
||||
}
|
||||
closedir(pDir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MountSandboxConfigs(const AppSpawnSandboxCfg *sandbox, const AppSpawningCtx *property, int nwebspawn)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != NULL, return -1);
|
||||
APPSPAWN_CHECK(sandbox != NULL, return -1, "Failed to get sandbox for %{public}s", GetProcessName(property));
|
||||
|
||||
SandboxContext *context = GetSandboxContext();
|
||||
APPSPAWN_CHECK_ONLY_EXPER(context != NULL, return APPSPAWN_SYSTEM_ERROR);
|
||||
int ret = InitSandboxContext(context, sandbox, property, nwebspawn);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
|
||||
do {
|
||||
ret = BuildRootPath((SandboxContext *)context, sandbox, NULL);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
ret = BuildPackagePath(context, sandbox);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
APPSPAWN_LOGV("Set sandbox config %{public}s", context->sandboxPackagePath);
|
||||
|
||||
ret = StagedMountPreUnShare(context, sandbox);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
|
||||
CreateSandboxDir(context->sandboxPackagePath, FILE_MODE);
|
||||
// add pid to a new mnt namespace
|
||||
ret = unshare(CLONE_NEWNS);
|
||||
APPSPAWN_CHECK(ret == 0, break,
|
||||
"unshare failed, app: %{public}s errno: %{public}d", context->bundleName, errno);
|
||||
|
||||
ret = SandboxRootFolderCreate(context, sandbox);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
|
||||
ret = StagedMountPostUnshare(context, sandbox);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
|
||||
ret = SetOverlayAppSandboxConfig(context, sandbox);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
ret = SetBundleResourceSandboxConfig(context, sandbox);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
|
||||
ret = ChangeCurrentDir(context);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, break);
|
||||
APPSPAWN_LOGV("Change root dir success %{public}s ", context->sandboxPackagePath);
|
||||
} while (0);
|
||||
|
||||
if (getcwd(context->buffer[0].buffer, context->buffer[0].bufferLen) != NULL) {
|
||||
APPSPAWN_LOGE("current_path %{public}s\n", context->buffer[0].buffer);
|
||||
}
|
||||
APPSPAWN_LOGV("current_path %{public}s \n", context->buffer[0].buffer);
|
||||
DumpCurrentDir(context, "/data");
|
||||
DeleteSandboxContext(context);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int StagedMountSystemConst(const AppSpawnSandboxCfg *sandbox, const AppSpawningCtx *property, int nwebspawn)
|
||||
{
|
||||
APPSPAWN_CHECK(sandbox != NULL, return -1, "Failed to get sandbox for %{public}s", GetProcessName(property));
|
||||
/**
|
||||
* system-const 处理逻辑
|
||||
* root-dir "/mnt/sandbox/app-root/<currentUserId>"
|
||||
* 遍历system-const, 处理mount path -- 可以清除配置
|
||||
* src = mount-path.src-path
|
||||
* dst = root-dir + mount-path.sandbox-path
|
||||
*
|
||||
* 遍历name-groups,处理mount path
|
||||
* 检查type,必须是 system-const
|
||||
* 如果存在 mount-paths-deps
|
||||
* src = mount-path.src-path
|
||||
* dst = root-dir + mount-paths-deps.sandbox-path + mount-path.sandbox-path
|
||||
* 否则:
|
||||
* src = mount-path.src-path
|
||||
* dst = root-dir + mount-path.sandbox-path
|
||||
*/
|
||||
SandboxContext *context = GetSandboxContext();
|
||||
APPSPAWN_CHECK_ONLY_EXPER(context != NULL, return APPSPAWN_SYSTEM_ERROR);
|
||||
int ret = InitSandboxContext(context, sandbox, property, nwebspawn);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
BuildRootPath((SandboxContext *)context, sandbox, NULL);
|
||||
|
||||
SandboxSection *section = GetSandboxSection(&sandbox->requiredQueue, "system-const");
|
||||
if (section != NULL) {
|
||||
ret = MountSandboxConfig(context, sandbox, section, 0);
|
||||
}
|
||||
DeleteSandboxContext(context);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int StagedMountPreUnShare(const SandboxContext *context, const AppSpawnSandboxCfg *sandbox)
|
||||
{
|
||||
APPSPAWN_CHECK(sandbox != NULL && context != NULL, return -1, "Invalid sandbox or context");
|
||||
APPSPAWN_LOGV("Set sandbox config before unshare group count %{public}d", sandbox->depNodeCount);
|
||||
|
||||
/**
|
||||
* 在unshare前处理mount-paths-deps 处理逻辑
|
||||
* root-dir global.sandbox-root
|
||||
* src-dir "/mnt/sandbox/app-common/<currentUserId>"
|
||||
* 遍历mount-paths-deps,处理mount-paths-deps
|
||||
* src = mount-paths-deps.src-path
|
||||
* dst = mount-paths-deps.sandbox-path
|
||||
* 如果设置no-exist,检查mount-paths 的src(实际路径) 是否不存在,
|
||||
则安mount-paths-deps.src-path 创建。 按shared方式挂载mount-paths-deps
|
||||
* 如果是 always,按shared方式挂载mount-paths-deps
|
||||
* 不配置 按always 处理
|
||||
*
|
||||
*/
|
||||
int ret = 0;
|
||||
for (uint32_t i = 0; i < sandbox->depNodeCount; i++) {
|
||||
SandboxNameGroupNode *groupNode = sandbox->depGroupNodes[i];
|
||||
if (groupNode == NULL || groupNode->depNode == NULL) {
|
||||
continue;
|
||||
}
|
||||
APPSPAWN_LOGV("Set sandbox deps config %{public}s ", groupNode->section.name);
|
||||
// change source and target to real path
|
||||
ret = UpdateMountPathDepsPath(context, groupNode);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"Failed to update deps path name group %{public}s", groupNode->section.name);
|
||||
|
||||
if (CheckAndCreateDepPath(context, groupNode)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = DoSandboxPathNodeMount(context, &groupNode->section, groupNode->depNode, 0);
|
||||
if (ret != 0) {
|
||||
APPSPAWN_LOGE("Mount deps root fail %{public}s", groupNode->section.name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (groupNode->destType == SANDBOX_TAG_SYSTEM_CONST) {
|
||||
ret = MountSandboxConfig(context, sandbox, &groupNode->section, MOUNT_PATH_OP_UNMOUNT);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"Set system-const config fail result: %{public}d, app: %{public}s", ret, context->bundleName);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int StagedMountPostUnshare(const SandboxContext *context, const AppSpawnSandboxCfg *sandbox)
|
||||
{
|
||||
APPSPAWN_CHECK(sandbox != NULL && context != NULL, return -1, "Invalid sandbox or context");
|
||||
APPSPAWN_LOGV("Set sandbox config after unshare ");
|
||||
/**
|
||||
* app-variable 处理逻辑
|
||||
* root-dir global.sandbox-root
|
||||
* app-variabl, 处理mount path
|
||||
* src = mount-path.src-path
|
||||
* dst = root-dir + mount-path.sandbox-path
|
||||
* 遍历name-groups,处理mount path
|
||||
* 如果存在 mount-paths-deps
|
||||
* src = mount-path.src-path
|
||||
* dst = root-dir + mount-paths-deps.sandbox-path + mount-path.sandbox-path
|
||||
* 否则:
|
||||
* src = mount-path.src-path
|
||||
* dst = root-dir + mount-path.sandbox-path
|
||||
*/
|
||||
int ret = 0;
|
||||
SandboxSection *section = GetSandboxSection(&sandbox->requiredQueue, "app-variable");
|
||||
if (section != NULL) {
|
||||
ret = MountSandboxConfig(context, sandbox, section, 0);
|
||||
APPSPAWN_CHECK(ret == 0, return ret,
|
||||
"Set app-variable config fail result: %{public}d, app: %{public}s", ret, context->bundleName);
|
||||
}
|
||||
if (!context->nwebspawn) {
|
||||
ret = SetExpandSandboxConfig(context, sandbox);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
}
|
||||
|
||||
ret = SetSandboxSpawnFlagsConfig(context, sandbox);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
|
||||
ret = SetSandboxPackageNameConfig(context, sandbox);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
|
||||
ret = SetSandboxPermissionConfig(context, sandbox);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int UnmountSandboxConfigs(const AppSpawnSandboxCfg *sandbox)
|
||||
{
|
||||
APPSPAWN_CHECK(sandbox != NULL, return -1, "Invalid sandbox or context");
|
||||
for (uint32_t i = 0; i < sandbox->depNodeCount; i++) {
|
||||
SandboxNameGroupNode *groupNode = sandbox->depGroupNodes[i];
|
||||
if (groupNode == NULL || groupNode->depNode == NULL) {
|
||||
continue;
|
||||
}
|
||||
APPSPAWN_LOGV("Unmount sandbox config sandbox path %{public}s ", groupNode->depNode->target);
|
||||
// unmount this deps
|
||||
umount2(groupNode->depNode->target, MNT_DETACH);
|
||||
}
|
||||
return 0;
|
||||
}
|
325
modules/sandbox/appspawn_sandbox.h
Executable file
325
modules/sandbox/appspawn_sandbox.h
Executable file
@ -0,0 +1,325 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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 APPSPAWN_SANDBOX_H
|
||||
#define APPSPAWN_SANDBOX_H
|
||||
|
||||
#include <limits.h>
|
||||
#include ""
|
||||
#include "appspawn.h"
|
||||
#include "appspawn_hook.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "list.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define JSON_FLAGS_INTERNAL "__internal__"
|
||||
#define SANDBOX_NWEBSPAWN_ROOT_PATH APPSPAWN_BASE_DIR "/mnt/sandbox/com.ohos.render/"
|
||||
#define OHOS_RENDER "__internal__.com.ohos.render"
|
||||
|
||||
#define PHYSICAL_APP_INSTALL_PATH "/data/app/el1/bundle/public/"
|
||||
#define APL_SYSTEM_CORE "system_core"
|
||||
#define APL_SYSTEM_BASIC "system_basic"
|
||||
#define MODULE_TEST_BUNDLE_NAME "moduleTestProcessName"
|
||||
#define DEFAULT_NWEB_SANDBOX_SEC_PATH "/data/app/el1/bundle/public/com.ohos.nweb" // persist.nweb.sandbox.src_path
|
||||
|
||||
#define PARAMETER_PACKAGE_NAME "<PackageName>"
|
||||
#define PARAMETER_USER_ID "<currentUserId>"
|
||||
#define PARAMETER_PACKAGE_INDEX "<PackageName_index>"
|
||||
|
||||
#define FILE_MODE 0711
|
||||
#define MAX_SANDBOX_BUFFER 256
|
||||
#define FUSE_OPTIONS_MAX_LEN 256
|
||||
#define DLP_FUSE_FD 1000
|
||||
#define APP_FLAGS_SECTION 0x80000000
|
||||
#define BASIC_MOUNT_FLAGS (MS_REC | MS_BIND)
|
||||
#define INVALID_UID ((uint32_t)-1)
|
||||
|
||||
#ifdef APPSPAWN_64
|
||||
#define APPSPAWN_LIB_NAME "lib64"
|
||||
#else
|
||||
#define APPSPAWN_LIB_NAME "lib"
|
||||
#endif
|
||||
|
||||
#define MOUNT_MODE_NONE 0 // "none"
|
||||
#define MOUNT_MODE_ALWAYS 1 // "always"
|
||||
#define MOUNT_MODE_NOT_EXIST 2 // "not-exists"
|
||||
|
||||
#define MOUNT_PATH_OP_NO_SYMLINK 0x01
|
||||
#define MOUNT_PATH_OP_UNMOUNT 0x02
|
||||
|
||||
#define FILE_CROSS_APP_MODE "ohos.permission.FILE_CROSS_APP"
|
||||
|
||||
typedef enum SandboxTag {
|
||||
SANDBOX_TAG_MOUNT_PATH = 0,
|
||||
SANDBOX_TAG_MOUNT_FILE,
|
||||
SANDBOX_TAG_SYMLINK,
|
||||
SANDBOX_TAG_PERMISSION,
|
||||
SANDBOX_TAG_PACKAGE_NAME,
|
||||
SANDBOX_TAG_SPAWN_FLAGS,
|
||||
SANDBOX_TAG_NAME_GROUP,
|
||||
SANDBOX_TAG_SYSTEM_CONST,
|
||||
SANDBOX_TAG_APP_VARIABLE,
|
||||
SANDBOX_TAG_APP_CONST,
|
||||
SANDBOX_TAG_REQUIRED,
|
||||
SANDBOX_TAG_INVALID
|
||||
} SandboxNodeType;
|
||||
|
||||
typedef struct {
|
||||
struct ListNode node;
|
||||
uint32_t type;
|
||||
} SandboxMountNode;
|
||||
|
||||
typedef struct TagSandboxQueue {
|
||||
struct ListNode front;
|
||||
uint32_t type;
|
||||
} SandboxQueue;
|
||||
|
||||
typedef struct TagPathMountNode {
|
||||
SandboxMountNode sandboxNode;
|
||||
char *source; // source 目录,一般是全局的fs 目录
|
||||
char *target; // 沙盒化后的目录
|
||||
mode_t destMode; // "dest-mode": "S_IRUSR | S_IWOTH | S_IRWXU " 默认值:0
|
||||
uint32_t mountSharedFlag : 1; // "mount-shared-flag" : "true", 默认值:false
|
||||
uint32_t checkErrorFlag : 1;
|
||||
uint32_t category;
|
||||
char *appAplName;
|
||||
} PathMountNode;
|
||||
|
||||
typedef struct TagSymbolLinkNode {
|
||||
SandboxMountNode sandboxNode;
|
||||
char *target;
|
||||
char *linkName;
|
||||
mode_t destMode; // "dest-mode": "S_IRUSR | S_IWOTH | S_IRWXU "
|
||||
uint32_t checkErrorFlag : 1;
|
||||
} SymbolLinkNode;
|
||||
|
||||
typedef struct TagSandboxSection {
|
||||
SandboxMountNode sandboxNode;
|
||||
struct ListNode front; // mount-path
|
||||
char *name;
|
||||
uint32_t number : 16;
|
||||
uint32_t gidCount : 16;
|
||||
gid_t *gidTable; // "gids": [1006, 1008],
|
||||
uint32_t sandboxSwitch : 1; // "sandbox-switch": "ON",
|
||||
uint32_t sandboxShared : 1; // "sandbox-switch": "ON",
|
||||
SandboxMountNode **nameGroups;
|
||||
} SandboxSection;
|
||||
|
||||
typedef struct {
|
||||
SandboxSection section;
|
||||
} SandboxPackageNameNode;
|
||||
|
||||
typedef struct {
|
||||
SandboxSection section;
|
||||
uint32_t flagIndex;
|
||||
} SandboxFlagsNode;
|
||||
|
||||
typedef struct TagSandboxGroupNode {
|
||||
SandboxSection section;
|
||||
uint32_t caps; // "caps": [ "shared" ],
|
||||
uint32_t destType;
|
||||
PathMountNode *depNode;
|
||||
uint32_t mountMode;
|
||||
} SandboxNameGroupNode;
|
||||
|
||||
typedef struct TagPermissionNode {
|
||||
SandboxSection section;
|
||||
int32_t permissionIndex;
|
||||
} SandboxPermissionNode;
|
||||
|
||||
typedef struct TagAppSpawnSandboxCfg {
|
||||
AppSpawnExtData extData;
|
||||
SandboxQueue requiredQueue;
|
||||
SandboxQueue permissionQueue;
|
||||
SandboxQueue packageNameQueue; // SandboxSection
|
||||
SandboxQueue spawnFlagsQueue;
|
||||
SandboxQueue nameGroupsQueue;
|
||||
uint32_t depNodeCount;
|
||||
SandboxNameGroupNode **depGroupNodes;
|
||||
int32_t maxPermissionIndex;
|
||||
uint32_t sandboxNsFlags; // "sandbox-ns-flags": [ "pid", "net" ], // for appspawn and newspawn
|
||||
// for comm section
|
||||
uint32_t topSandboxSwitch : 1; // "top-sandbox-switch": "ON",
|
||||
uint32_t appFullMountEnable : 1;
|
||||
uint32_t pidNamespaceSupport : 1;
|
||||
uint32_t systemUids[10];
|
||||
char *rootPath;
|
||||
} AppSpawnSandboxCfg;
|
||||
|
||||
enum {
|
||||
BUFFER_FOR_SOURCE,
|
||||
BUFFER_FOR_TARGET,
|
||||
MAX_BUFFER
|
||||
};
|
||||
|
||||
typedef struct TagSandboxBuffer {
|
||||
uint32_t bufferLen;
|
||||
uint32_t current;
|
||||
char *buffer;
|
||||
} SandboxBuffer;
|
||||
|
||||
typedef struct TagSandboxContext {
|
||||
SandboxBuffer buffer[MAX_BUFFER];
|
||||
const char *bundleName;
|
||||
const AppSpawnMsgNode *message; // 修改成操作消息
|
||||
uint32_t sandboxSwitch : 1;
|
||||
uint32_t sandboxShared : 1;
|
||||
uint32_t bundleHasWps : 1;
|
||||
uint32_t dlpBundle : 1;
|
||||
uint32_t dlpUiExtType : 1;
|
||||
uint32_t appFullMountEnable : 1;
|
||||
uint32_t nwebspawn : 1;
|
||||
char *rootPath;
|
||||
char *sandboxPackagePath;
|
||||
} SandboxContext;
|
||||
|
||||
/**
|
||||
* @brief AppSpawnSandboxCfg op
|
||||
*
|
||||
* @return AppSpawnSandboxCfg*
|
||||
*/
|
||||
AppSpawnSandboxCfg *CreateAppSpawnSandbox(void);
|
||||
AppSpawnSandboxCfg *GetAppSpawnSandbox(const AppSpawnMgr *content);
|
||||
void DeleteAppSpawnSandbox(AppSpawnSandboxCfg *sandbox);
|
||||
int LoadAppSandboxConfig(AppSpawnSandboxCfg *sandbox, int nwebSpawn);
|
||||
void DumpAppSpawnSandboxCfg(AppSpawnSandboxCfg *sandbox);
|
||||
|
||||
/**
|
||||
* @brief SandboxSection op
|
||||
*
|
||||
*/
|
||||
SandboxSection *CreateSandboxSection(const char *name, uint32_t dataLen, uint32_t type);
|
||||
SandboxSection *GetSandboxSection(const SandboxQueue *queue, const char *name);
|
||||
void AddSandboxSection(SandboxSection *node, SandboxQueue *queue);
|
||||
void DeleteSandboxSection(SandboxSection *node);
|
||||
__attribute__((always_inline)) inline uint32_t GetSectionType(const SandboxSection *section)
|
||||
{
|
||||
return section != NULL ? section->sandboxNode.type : SANDBOX_TAG_INVALID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SandboxMountNode op
|
||||
*
|
||||
*/
|
||||
SandboxMountNode *CreateSandboxMountNode(uint32_t dataLen, uint32_t type);
|
||||
SandboxMountNode *GetFirstSandboxMountNode(const SandboxSection *section);
|
||||
void DeleteSandboxMountNode(SandboxMountNode *mountNode);
|
||||
void AddSandboxMountNode(SandboxMountNode *node, SandboxSection *section);
|
||||
|
||||
/**
|
||||
* @brief sandbox mount interface
|
||||
*
|
||||
*/
|
||||
int MountSandboxConfigs(const AppSpawnSandboxCfg *sandbox, const AppSpawningCtx *property, int nwebspawn);
|
||||
int StagedMountSystemConst(const AppSpawnSandboxCfg *sandbox, const AppSpawningCtx *property, int nwebspawn);
|
||||
int StagedMountPreUnShare(const SandboxContext *context, const AppSpawnSandboxCfg *sandbox);
|
||||
int StagedMountPostUnshare(const SandboxContext *context, const AppSpawnSandboxCfg *sandbox);
|
||||
int UnmountSandboxConfigs(const AppSpawnSandboxCfg *sandbox);
|
||||
|
||||
/**
|
||||
* @brief Variable op
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
struct ListNode node;
|
||||
ReplaceVarHandler replaceVar;
|
||||
char name[0];
|
||||
} AppSandboxVarNode;
|
||||
|
||||
typedef struct TagVarExtraData {
|
||||
uint32_t sandboxTag;
|
||||
union {
|
||||
PathMountNode *depNode;
|
||||
} data;
|
||||
} VarExtraData;
|
||||
|
||||
void ClearVariable(void);
|
||||
void AddDefaultVariable(void);
|
||||
const char *GetSandboxRealVar(const SandboxContext *context,
|
||||
uint32_t bufferType, const char *source, const char *prefix, const VarExtraData *extraData);
|
||||
|
||||
/**
|
||||
* @brief expand config
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
struct ListNode node;
|
||||
ProcessExpandSandboxCfg cfgHandle;
|
||||
int prio;
|
||||
char name[0];
|
||||
} AppSandboxExpandAppCfgNode;
|
||||
int ProcessExpandAppSandboxConfig(const SandboxContext *context,
|
||||
const AppSpawnSandboxCfg *appSandBox, const char *name);
|
||||
void AddDefaultExpandAppSandboxConfigHandle(void);
|
||||
void ClearExpandAppSandboxConfigHandle(void);
|
||||
|
||||
__attribute__((always_inline)) inline void *GetSpawningMsgInfo(const SandboxContext *context, uint32_t type)
|
||||
{
|
||||
APPSPAWN_CHECK(context->message != NULL,
|
||||
return NULL, "Invalid property for type %{public}u", type);
|
||||
return GetAppSpawnMsgInfo(context->message, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sandbox Context op
|
||||
*
|
||||
* @return SandboxContext*
|
||||
*/
|
||||
SandboxContext *GetSandboxContext(void);
|
||||
void DeleteSandboxContext(SandboxContext *context);
|
||||
|
||||
/**
|
||||
* @brief defineMount Arg Template and operation
|
||||
*
|
||||
*/
|
||||
enum {
|
||||
MOUNT_TMP_DEFAULT,
|
||||
MOUNT_TMP_RDONLY,
|
||||
MOUNT_TMP_EPFS,
|
||||
MOUNT_TMP_DAC_OVERRIDE,
|
||||
MOUNT_TMP_FUSE,
|
||||
MOUNT_TMP_DLP_FUSE,
|
||||
MOUNT_TMP_SHRED,
|
||||
MOUNT_TMP_MAX
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
uint32_t category;
|
||||
const char *fsType;
|
||||
unsigned long mountFlags;
|
||||
const char *options;
|
||||
mode_t mountSharedFlag;
|
||||
} MountArgTemplate;
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
unsigned long flags;
|
||||
} SandboxFlagInfo;
|
||||
|
||||
uint32_t GetMountCategory(const char *name);
|
||||
const MountArgTemplate *GetMountArgTemplate(uint32_t category);
|
||||
const SandboxFlagInfo *GetSandboxFlagInfo(const char *key, const SandboxFlagInfo *flagsInfos, uint32_t count);
|
||||
int GetPathMode(const char *name);
|
||||
|
||||
void DumpMountPathMountNode(const PathMountNode *pathNode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // APPSPAWN_SANDBOX_H
|
247
modules/sandbox/sandbox_cfgvar.c
Executable file
247
modules/sandbox/sandbox_cfgvar.c
Executable file
@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright (c) 2024 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 "appspawn_sandbox.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "modulemgr.h"
|
||||
#include "parameter.h"
|
||||
#include "securec.h"
|
||||
|
||||
struct ListNode g_sandboxVarList = {&g_sandboxVarList, &g_sandboxVarList};
|
||||
|
||||
static int VarPackageNameIndexReplace(const SandboxContext *context,
|
||||
const char *buffer, uint32_t bufferLen, uint32_t *realLen, const VarExtraData *extraData)
|
||||
{
|
||||
AppSpawnMsgBundleInfo *bundleInfo = (
|
||||
AppSpawnMsgBundleInfo *)GetSpawningMsgInfo(context, TLV_BUNDLE_INFO);
|
||||
APPSPAWN_CHECK(bundleInfo != NULL, return APPSPAWN_TLV_NONE,
|
||||
"No bundle info in msg %{public}s", context->bundleName);
|
||||
int len = 0;
|
||||
if (bundleInfo->bundleIndex > 0) {
|
||||
len = sprintf_s((char *)buffer, bufferLen, "%s_%d", bundleInfo->bundleName, bundleInfo->bundleIndex);
|
||||
} else {
|
||||
len = sprintf_s((char *)buffer, bufferLen, "%s", bundleInfo->bundleName);
|
||||
}
|
||||
APPSPAWN_CHECK(len > 0 && ((uint32_t)len < bufferLen),
|
||||
return -1, "Failed to format path app: %{public}s", context->bundleName);
|
||||
*realLen = (uint32_t)len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int VarPackageNameReplace(const SandboxContext *context,
|
||||
const char *buffer, uint32_t bufferLen, uint32_t *realLen, const VarExtraData *extraData)
|
||||
{
|
||||
int len = sprintf_s((char *)buffer, bufferLen, "%s", context->bundleName);
|
||||
APPSPAWN_CHECK(len > 0 && ((uint32_t)len < bufferLen),
|
||||
return -1, "Failed to format path app: %{public}s", context->bundleName);
|
||||
*realLen = (uint32_t)len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int VarCurrentUseIdReplace(const SandboxContext *context,
|
||||
const char *buffer, uint32_t bufferLen, uint32_t *realLen, const VarExtraData *extraData)
|
||||
{
|
||||
AppSpawnMsgDacInfo *info = (AppSpawnMsgDacInfo *)GetSpawningMsgInfo(context, TLV_DAC_INFO);
|
||||
APPSPAWN_CHECK(info != NULL, return APPSPAWN_TLV_NONE,
|
||||
"No tlv %{public}d in msg %{public}s", TLV_DAC_INFO, context->bundleName);
|
||||
int len = 0;
|
||||
if (extraData == NULL || extraData->sandboxTag != SANDBOX_TAG_PERMISSION) {
|
||||
len = sprintf_s((char *)buffer, bufferLen, "%u", info->uid / UID_BASE);
|
||||
} else if (context->appFullMountEnable && strlen(info->userName) > 0) {
|
||||
len = sprintf_s((char *)buffer, bufferLen, "%s", info->userName);
|
||||
} else {
|
||||
len = sprintf_s((char *)buffer, bufferLen, "%s", "currentUser");
|
||||
}
|
||||
APPSPAWN_CHECK(len > 0 && ((uint32_t)len < bufferLen),
|
||||
return -1, "Failed to format path app: %{public}s", context->bundleName);
|
||||
*realLen = (uint32_t)len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int VariableNodeCompareName(ListNode *node, void *data)
|
||||
{
|
||||
AppSandboxVarNode *varNode = (AppSandboxVarNode *)ListEntry(node, AppSandboxVarNode, node);
|
||||
return strcmp((char *)data, varNode->name);
|
||||
}
|
||||
|
||||
static AppSandboxVarNode *GetAppSandboxVarNode(const char *name)
|
||||
{
|
||||
ListNode *node = OH_ListFind(&g_sandboxVarList, (void *)name, VariableNodeCompareName);
|
||||
if (node == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return (AppSandboxVarNode *)ListEntry(node, AppSandboxVarNode, node);
|
||||
}
|
||||
|
||||
static int ReplaceVariableByParameter(const char *varData, SandboxBuffer *sandboxBuffer)
|
||||
{
|
||||
// "<param:persist.nweb.sandbox.src_path>"
|
||||
int len = GetParameter(varData + sizeof("<param:") - 1,
|
||||
DEFAULT_NWEB_SANDBOX_SEC_PATH, sandboxBuffer->buffer + sandboxBuffer->current,
|
||||
sandboxBuffer->bufferLen - sandboxBuffer->current - 1);
|
||||
APPSPAWN_CHECK(len > 0, return -1, "Failed to get param for var %{public}s", varData);
|
||||
sandboxBuffer->current += len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ReplaceVariableForDeps(const SandboxContext *context,
|
||||
SandboxBuffer *sandboxBuffer, const VarExtraData *extraData)
|
||||
{
|
||||
APPSPAWN_CHECK(extraData != NULL, return -1, "Invalid extra data ");
|
||||
uint32_t len = strlen(extraData->data.depNode->target);
|
||||
int ret = memcpy_s(sandboxBuffer->buffer + sandboxBuffer->current,
|
||||
sandboxBuffer->bufferLen - sandboxBuffer->current, extraData->data.depNode->target, len);
|
||||
APPSPAWN_CHECK(ret == 0, return -1, "Failed to copy real data");
|
||||
sandboxBuffer->current += len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int GetVariableName(char *varData, uint32_t len, const char *varStart, uint32_t *varLen)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
uint32_t sourceLen = strlen(varStart);
|
||||
for (; i < sourceLen; i++) {
|
||||
if (i > len) {
|
||||
return -1;
|
||||
}
|
||||
varData[i] = *(varStart + i);
|
||||
if (varData[i] == '>') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
varData[i + 1] = '\0';
|
||||
*varLen = i + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ReplaceVariable(const SandboxContext *context,
|
||||
const char *varStart, SandboxBuffer *sandboxBuffer, uint32_t *varLen, const VarExtraData *extraData)
|
||||
{
|
||||
char varData[128] = {0}; // 128 max len for var
|
||||
int ret = GetVariableName(varData, sizeof(varData), varStart, varLen);
|
||||
APPSPAWN_CHECK(ret == 0, return -1, "Failed to get variable name");
|
||||
|
||||
uint32_t valueLen = 0;
|
||||
AppSandboxVarNode *node = GetAppSandboxVarNode(varData);
|
||||
if (node != NULL) {
|
||||
ret = node->replaceVar(context, sandboxBuffer->buffer + sandboxBuffer->current,
|
||||
sandboxBuffer->bufferLen - sandboxBuffer->current - 1, &valueLen, extraData);
|
||||
APPSPAWN_CHECK(ret == 0 && valueLen < (sandboxBuffer->bufferLen - sandboxBuffer->current),
|
||||
return -1, "Failed to fill real data");
|
||||
sandboxBuffer->current += valueLen;
|
||||
return 0;
|
||||
}
|
||||
// "<param:persist.nweb.sandbox.src_path>"
|
||||
if (strncmp(varData, "<param:", sizeof("<param:") - 1) == 0) { // retry param:
|
||||
varData[*varLen - 1] = '\0'; // erase last >
|
||||
return ReplaceVariableByParameter(varData, sandboxBuffer);
|
||||
}
|
||||
if (strncmp(varData, "<lib>", sizeof("<lib>") - 1) == 0) { // retry lib
|
||||
ret = memcpy_s(sandboxBuffer->buffer + sandboxBuffer->current,
|
||||
sandboxBuffer->bufferLen - sandboxBuffer->current, APPSPAWN_LIB_NAME, strlen(APPSPAWN_LIB_NAME));
|
||||
APPSPAWN_CHECK(ret == 0, return -1, "Failed to copy real data");
|
||||
sandboxBuffer->current += strlen(APPSPAWN_LIB_NAME);
|
||||
return 0;
|
||||
}
|
||||
// <deps-sandbox-path>
|
||||
if (strncmp(varData, "<deps-sandbox-path>", sizeof("<deps-sandbox-path>") - 1) == 0) {
|
||||
return ReplaceVariableForDeps(context, sandboxBuffer, extraData);
|
||||
}
|
||||
// no match revered origin data
|
||||
APPSPAWN_LOGE("ReplaceVariable var '%{public}s' no match variable", varData);
|
||||
ret = memcpy_s(sandboxBuffer->buffer + sandboxBuffer->current,
|
||||
sandboxBuffer->bufferLen - sandboxBuffer->current, varData, *varLen);
|
||||
APPSPAWN_CHECK(ret == 0, return -1, "Failed to copy real data");
|
||||
sandboxBuffer->current += *varLen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int HandleVariableReplace(const SandboxContext *context, SandboxBuffer *sandboxBuffer,
|
||||
const char *source, const VarExtraData *extraData)
|
||||
{
|
||||
size_t sourceLen = strlen(source);
|
||||
for (size_t i = 0; i < sourceLen; i++) {
|
||||
if ((sandboxBuffer->current + 1) >= sandboxBuffer->bufferLen) {
|
||||
return -1;
|
||||
}
|
||||
if (*(source + i) != '<') { // copy source
|
||||
*(sandboxBuffer->buffer + sandboxBuffer->current) = *(source + i);
|
||||
sandboxBuffer->current++;
|
||||
continue;
|
||||
}
|
||||
uint32_t varLen = 0;
|
||||
int ret = ReplaceVariable(context, source + i, sandboxBuffer, &varLen, extraData);
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "Failed to fill real data");
|
||||
i += (varLen - 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *GetSandboxRealVar(const SandboxContext *context,
|
||||
uint32_t bufferType, const char *source, const char *prefix, const VarExtraData *extraData)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(context != NULL, return NULL);
|
||||
APPSPAWN_CHECK(bufferType < ARRAY_LENGTH(context->buffer), return NULL, "Invalid index for buffer");
|
||||
SandboxBuffer *sandboxBuffer = &((SandboxContext *)context)->buffer[bufferType];
|
||||
const char *tmp = source;
|
||||
int ret = 0;
|
||||
if (prefix != NULL) { // copy prefix data
|
||||
ret = HandleVariableReplace(context, sandboxBuffer, prefix, extraData);
|
||||
APPSPAWN_CHECK(ret == 0, return NULL, "Failed to replace source %{public}s ", prefix);
|
||||
|
||||
if (tmp != NULL && sandboxBuffer->buffer[sandboxBuffer->current - 1] == '/' && *tmp == '/') {
|
||||
tmp = source + 1;
|
||||
}
|
||||
}
|
||||
if (tmp != NULL) { // copy source data
|
||||
ret = HandleVariableReplace(context, sandboxBuffer, tmp, extraData);
|
||||
APPSPAWN_CHECK(ret == 0, return NULL, "Failed to replace source %{public}s ", source);
|
||||
}
|
||||
sandboxBuffer->buffer[sandboxBuffer->current] = '\0';
|
||||
// restore buffer
|
||||
sandboxBuffer->current = 0;
|
||||
return sandboxBuffer->buffer;
|
||||
}
|
||||
|
||||
int AddVariableReplaceHandler(const char *name, ReplaceVarHandler handler)
|
||||
{
|
||||
APPSPAWN_CHECK(name != NULL && handler != NULL, return APPSPAWN_ARG_INVALID, "Invalid arg ");
|
||||
if (GetAppSandboxVarNode(name) != NULL) {
|
||||
return APPSPAWN_NODE_EXIST;
|
||||
}
|
||||
|
||||
size_t len = APPSPAWN_ALIGN(strlen(name) + 1);
|
||||
AppSandboxVarNode *node = (AppSandboxVarNode *)malloc(sizeof(AppSandboxVarNode) + len);
|
||||
APPSPAWN_CHECK(node != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to create sandbox");
|
||||
OH_ListInit(&node->node);
|
||||
node->replaceVar = handler;
|
||||
int ret = strcpy_s(node->name, len, name);
|
||||
APPSPAWN_CHECK(ret == 0, free(node);
|
||||
return -1, "Failed to copy name %{public}s", name);
|
||||
OH_ListAddTail(&g_sandboxVarList, &node->node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AddDefaultVariable(void)
|
||||
{
|
||||
AddVariableReplaceHandler(PARAMETER_PACKAGE_NAME, VarPackageNameReplace);
|
||||
AddVariableReplaceHandler(PARAMETER_USER_ID, VarCurrentUseIdReplace);
|
||||
AddVariableReplaceHandler(PARAMETER_PACKAGE_INDEX, VarPackageNameIndexReplace);
|
||||
}
|
||||
|
||||
void ClearVariable(void)
|
||||
{
|
||||
OH_ListRemoveAll(&g_sandboxVarList, NULL);
|
||||
}
|
298
modules/sandbox/sandbox_expand.c
Executable file
298
modules/sandbox/sandbox_expand.c
Executable file
@ -0,0 +1,298 @@
|
||||
/*
|
||||
* Copyright (c) 2024 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 <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "appspawn_msg.h"
|
||||
#include "appspawn_sandbox.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "json_utils.h"
|
||||
#include "securec.h"
|
||||
|
||||
#define SANDBOX_GROUP_PATH "/data/storage/el2/group/"
|
||||
#define SANDBOX_INSTALL_PATH "/data/storage/el2/group/"
|
||||
#define SANDBOX_OVERLAY_PATH "/data/storage/overlay/"
|
||||
|
||||
static inline bool CheckPath(const char *name)
|
||||
{
|
||||
return name != NULL && strcmp(name, ".") != 0 && strcmp(name, "..") != 0 && strstr(name, "/") == NULL;
|
||||
}
|
||||
|
||||
static int MountAllHsp(const SandboxContext *context, const cJSON *hsps)
|
||||
{
|
||||
APPSPAWN_CHECK(context != NULL && hsps != NULL, return -1, "Invalid context or hsps");
|
||||
|
||||
int ret = 0;
|
||||
cJSON *bundles = cJSON_GetObjectItemCaseSensitive(hsps, "bundles");
|
||||
cJSON *modules = cJSON_GetObjectItemCaseSensitive(hsps, "modules");
|
||||
cJSON *versions = cJSON_GetObjectItemCaseSensitive(hsps, "versions");
|
||||
APPSPAWN_CHECK(bundles != NULL && cJSON_IsArray(bundles), return -1, "MountAllHsp: invalid bundles");
|
||||
APPSPAWN_CHECK(modules != NULL && cJSON_IsArray(modules), return -1, "MountAllHsp: invalid modules");
|
||||
APPSPAWN_CHECK(versions != NULL && cJSON_IsArray(versions), return -1, "MountAllHsp: invalid versions");
|
||||
int count = cJSON_GetArraySize(bundles);
|
||||
APPSPAWN_CHECK(count == cJSON_GetArraySize(modules), return -1, "MountAllHsp: sizes are not same");
|
||||
APPSPAWN_CHECK(count == cJSON_GetArraySize(versions), return -1, "MountAllHsp: sizes are not same");
|
||||
|
||||
APPSPAWN_LOGI("MountAllHsp app: %{public}s, count: %{public}d", context->bundleName, count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
char *libBundleName = cJSON_GetStringValue(cJSON_GetArrayItem(bundles, i));
|
||||
char *libModuleName = cJSON_GetStringValue(cJSON_GetArrayItem(modules, i));
|
||||
char *libVersion = cJSON_GetStringValue(cJSON_GetArrayItem(versions, i));
|
||||
APPSPAWN_CHECK(CheckPath(libBundleName) && CheckPath(libModuleName) && CheckPath(libVersion),
|
||||
return -1, "MountAllHsp: path error");
|
||||
|
||||
// src path
|
||||
int len = sprintf_s(context->buffer[0].buffer, context->buffer[0].bufferLen, "%s%s/%s/%s",
|
||||
PHYSICAL_APP_INSTALL_PATH, libBundleName, libVersion, libModuleName);
|
||||
APPSPAWN_CHECK(len > 0, return -1, "Failed to format install path");
|
||||
// sandbox path
|
||||
len = sprintf_s(context->buffer[1].buffer, context->buffer[1].bufferLen, "%s%s%s/%s",
|
||||
context->sandboxPackagePath, SANDBOX_INSTALL_PATH, libBundleName, libModuleName);
|
||||
APPSPAWN_CHECK(len > 0, return -1, "Failed to format install path");
|
||||
|
||||
CreateSandboxDir(context->buffer[1].buffer, FILE_MODE);
|
||||
MountArg mountArg = {
|
||||
context->buffer[0].buffer, context->buffer[1].buffer, NULL, MS_REC | MS_BIND, NULL, MS_SLAVE
|
||||
};
|
||||
ret = SandboxMountPath(&mountArg);
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "mount library failed %{public}d", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline char *GetLastPath(const char *libPhysicalPath)
|
||||
{
|
||||
char *tmp = GetLastStr(libPhysicalPath, "/");
|
||||
return tmp + 1;
|
||||
}
|
||||
|
||||
static int MountAllGroup(const SandboxContext *context, const cJSON *groups)
|
||||
{
|
||||
APPSPAWN_CHECK(context != NULL && groups != NULL, return -1, "Invalid context or group");
|
||||
int ret = 0;
|
||||
cJSON *dataGroupIds = cJSON_GetObjectItemCaseSensitive(groups, "dataGroupId");
|
||||
cJSON *gids = cJSON_GetObjectItemCaseSensitive(groups, "gid");
|
||||
cJSON *dirs = cJSON_GetObjectItemCaseSensitive(groups, "dir");
|
||||
APPSPAWN_CHECK(dataGroupIds != NULL && cJSON_IsArray(dataGroupIds),
|
||||
return -1, "MountAllGroup: invalid dataGroupIds");
|
||||
APPSPAWN_CHECK(gids != NULL && cJSON_IsArray(gids), return -1, "MountAllGroup: invalid gids");
|
||||
APPSPAWN_CHECK(dirs != NULL && cJSON_IsArray(dirs), return -1, "MountAllGroup: invalid dirs");
|
||||
int count = cJSON_GetArraySize(dataGroupIds);
|
||||
APPSPAWN_CHECK(count == cJSON_GetArraySize(gids), return -1, "MountAllGroup: sizes are not same");
|
||||
APPSPAWN_CHECK(count == cJSON_GetArraySize(dirs), return -1, "MountAllGroup: sizes are not same");
|
||||
|
||||
APPSPAWN_LOGI("MountAllGroup: app: %{public}s, count: %{public}d", context->bundleName, count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
cJSON *dirJson = cJSON_GetArrayItem(dirs, i);
|
||||
APPSPAWN_CHECK(dirJson != NULL && cJSON_IsString(dirJson), return -1, "MountAllGroup: invalid dirJson");
|
||||
const char *libPhysicalPath = cJSON_GetStringValue(dirJson);
|
||||
APPSPAWN_CHECK(!CheckPath(libPhysicalPath), return -1, "MountAllGroup: path error");
|
||||
|
||||
char *dataGroupUuid = GetLastPath(libPhysicalPath);
|
||||
int len = sprintf_s(context->buffer[0].buffer, context->buffer[0].bufferLen, "%s%s%s",
|
||||
context->sandboxPackagePath, SANDBOX_GROUP_PATH, dataGroupUuid);
|
||||
APPSPAWN_CHECK(len > 0, return -1, "Failed to format install path");
|
||||
APPSPAWN_LOGV("MountAllGroup src: '%{public}s' =>'%{public}s'", libPhysicalPath, context->buffer[0].buffer);
|
||||
|
||||
CreateSandboxDir(context->buffer[0].buffer, FILE_MODE);
|
||||
MountArg mountArg = {libPhysicalPath, context->buffer[0].buffer, NULL, MS_REC | MS_BIND, NULL, MS_SLAVE};
|
||||
ret = SandboxMountPath(&mountArg);
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "mount library failed %{public}d", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const SandboxContext *sandboxContext;
|
||||
uint32_t srcSetLen;
|
||||
char *mountedSrcSet;
|
||||
} OverlayContext;
|
||||
|
||||
static int SetOverlayAppPath(const char *hapPath, void *context)
|
||||
{
|
||||
APPSPAWN_LOGV("SetOverlayAppPath '%{public}s'", hapPath);
|
||||
OverlayContext *overlayContext = (OverlayContext *)context;
|
||||
const SandboxContext *sandboxContext = overlayContext->sandboxContext;
|
||||
|
||||
// src path
|
||||
char *tmp = GetLastStr(hapPath, "/");
|
||||
if (tmp == NULL) {
|
||||
return 0;
|
||||
}
|
||||
int ret = strncpy_s(sandboxContext->buffer[0].buffer,
|
||||
sandboxContext->buffer[0].bufferLen, hapPath, tmp - (char *)hapPath);
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "mount library failed %{public}d", ret);
|
||||
|
||||
if (strstr(overlayContext->mountedSrcSet, sandboxContext->buffer[0].buffer) != NULL) {
|
||||
APPSPAWN_LOGV("%{public}s have mounted before, no need to mount twice.", sandboxContext->buffer[0].buffer);
|
||||
return 0;
|
||||
}
|
||||
ret = strcat_s(overlayContext->mountedSrcSet, overlayContext->srcSetLen, "|");
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "Fail to add src path to set %{public}s", "|");
|
||||
ret = strcat_s(overlayContext->mountedSrcSet, overlayContext->srcSetLen, sandboxContext->buffer[0].buffer);
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "Fail to add src path to set %{public}s", sandboxContext->buffer[0].buffer);
|
||||
|
||||
// sandbox path
|
||||
tmp = GetLastStr(sandboxContext->buffer[0].buffer, "/");
|
||||
if (tmp == NULL) {
|
||||
return 0;
|
||||
}
|
||||
int len = sprintf_s(sandboxContext->buffer[1].buffer, sandboxContext->buffer[1].bufferLen, "%s%s",
|
||||
sandboxContext->sandboxPackagePath, SANDBOX_OVERLAY_PATH);
|
||||
APPSPAWN_CHECK(len > 0, return -1, "Failed to format install path");
|
||||
ret = strcat_s(sandboxContext->buffer[1].buffer, sandboxContext->buffer[1].bufferLen - len, tmp + 1);
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "mount library failed %{public}d", ret);
|
||||
APPSPAWN_LOGV("SetOverlayAppPath path: '%{public}s' => '%{public}s'",
|
||||
sandboxContext->buffer[0].buffer, sandboxContext->buffer[1].buffer);
|
||||
|
||||
MountArg mountArg = {
|
||||
sandboxContext->buffer[0].buffer, sandboxContext->buffer[1].buffer, NULL, MS_REC | MS_BIND, NULL, MS_SHARED
|
||||
};
|
||||
int retMount = SandboxMountPath(&mountArg);
|
||||
if (retMount != 0) {
|
||||
APPSPAWN_LOGE("Fail to mount overlay path, src is %{public}s.", hapPath);
|
||||
ret = retMount;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int SetOverlayAppSandboxConfig(const SandboxContext *context, const char *overlayInfo)
|
||||
{
|
||||
APPSPAWN_CHECK(context != NULL && overlayInfo != NULL, return -1, "Invalid context or overlayInfo");
|
||||
OverlayContext overlayContext;
|
||||
overlayContext.sandboxContext = context;
|
||||
overlayContext.srcSetLen = strlen(overlayInfo);
|
||||
overlayContext.mountedSrcSet = (char *)calloc(1, overlayContext.srcSetLen + 1);
|
||||
APPSPAWN_CHECK(overlayContext.mountedSrcSet != NULL, return -1, "Failed to create mountedSrcSet");
|
||||
*(overlayContext.mountedSrcSet + overlayContext.srcSetLen) = '\0';
|
||||
int ret = StringSplit(overlayInfo, "|", (void *)&overlayContext, SetOverlayAppPath);
|
||||
APPSPAWN_LOGV("overlayContext->mountedSrcSet: '%{public}s'", overlayContext.mountedSrcSet);
|
||||
free(overlayContext.mountedSrcSet);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline cJSON *GetJsonObjFromProperty(const SandboxContext *context, const char *name)
|
||||
{
|
||||
uint32_t size = 0;
|
||||
char *extInfo = (char *)(GetAppSpawnMsgExtInfo(context->message, name, &size));
|
||||
if (size == 0 || extInfo == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
APPSPAWN_LOGV("Get json name %{public}s value %{public}s", name, extInfo);
|
||||
cJSON *root = cJSON_Parse(extInfo);
|
||||
APPSPAWN_CHECK(root != NULL, return NULL, "Invalid ext info %{public}s for %{public}s", extInfo, name);
|
||||
return root;
|
||||
}
|
||||
|
||||
static int ProcessHSPListConfig(const SandboxContext *context, const AppSpawnSandboxCfg *appSandBox, const char *name)
|
||||
{
|
||||
cJSON *root = GetJsonObjFromProperty(context, name);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(root != NULL, return 0);
|
||||
int ret = MountAllHsp(context, root);
|
||||
cJSON_Delete(root);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ProcessDataGroupConfig(const SandboxContext *context, const AppSpawnSandboxCfg *appSandBox, const char *name)
|
||||
{
|
||||
cJSON *root = GetJsonObjFromProperty(context, name);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(root != NULL, return 0);
|
||||
int ret = MountAllGroup(context, root);
|
||||
cJSON_Delete(root);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ProcessOverlayAppConfig(const SandboxContext *context,
|
||||
const AppSpawnSandboxCfg *appSandBox, const char *name)
|
||||
{
|
||||
uint32_t size = 0;
|
||||
char *extInfo = (char *)GetAppSpawnMsgExtInfo(context->message, name, &size);
|
||||
if (size == 0 || extInfo == NULL) {
|
||||
return 0;
|
||||
}
|
||||
APPSPAWN_LOGV("ProcessOverlayAppConfig name %{public}s value %{public}s", name, extInfo);
|
||||
return SetOverlayAppSandboxConfig(context, extInfo);
|
||||
}
|
||||
|
||||
struct ListNode g_sandboxExpandCfgList = {&g_sandboxExpandCfgList, &g_sandboxExpandCfgList};
|
||||
static int AppSandboxExpandAppCfgCompareName(ListNode *node, void *data)
|
||||
{
|
||||
AppSandboxExpandAppCfgNode *varNode = ListEntry(node, AppSandboxExpandAppCfgNode, node);
|
||||
return strncmp((char *)data, varNode->name, strlen(varNode->name));
|
||||
}
|
||||
|
||||
static int AppSandboxExpandAppCfgComparePrio(ListNode *node1, ListNode *node2)
|
||||
{
|
||||
AppSandboxExpandAppCfgNode *varNode1 = ListEntry(node1, AppSandboxExpandAppCfgNode, node);
|
||||
AppSandboxExpandAppCfgNode *varNode2 = ListEntry(node2, AppSandboxExpandAppCfgNode, node);
|
||||
return varNode1->prio - varNode2->prio;
|
||||
}
|
||||
|
||||
static const AppSandboxExpandAppCfgNode *GetAppSandboxExpandAppCfg(const char *name)
|
||||
{
|
||||
ListNode *node = OH_ListFind(&g_sandboxExpandCfgList, (void *)name, AppSandboxExpandAppCfgCompareName);
|
||||
if (node == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return ListEntry(node, AppSandboxExpandAppCfgNode, node);
|
||||
}
|
||||
|
||||
int RegisterExpandSandboxCfgHandler(const char *name, int prio, ProcessExpandSandboxCfg handleExpandCfg)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(name != NULL && handleExpandCfg != NULL, return APPSPAWN_ARG_INVALID);
|
||||
if (GetAppSandboxExpandAppCfg(name) != NULL) {
|
||||
return APPSPAWN_NODE_EXIST;
|
||||
}
|
||||
|
||||
size_t len = APPSPAWN_ALIGN(strlen(name) + 1);
|
||||
AppSandboxExpandAppCfgNode *node = (AppSandboxExpandAppCfgNode *)(malloc(sizeof(AppSandboxExpandAppCfgNode) + len));
|
||||
APPSPAWN_CHECK(node != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to create sandbox");
|
||||
// ext data init
|
||||
OH_ListInit(&node->node);
|
||||
node->cfgHandle = handleExpandCfg;
|
||||
node->prio = prio;
|
||||
int ret = strcpy_s(node->name, len, name);
|
||||
APPSPAWN_CHECK(ret == 0, free(node);
|
||||
return -1, "Failed to copy name %{public}s", name);
|
||||
OH_ListAddWithOrder(&g_sandboxExpandCfgList, &node->node, AppSandboxExpandAppCfgComparePrio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ProcessExpandAppSandboxConfig(const SandboxContext *context, const AppSpawnSandboxCfg *appSandBox, const char *name)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(context != NULL && appSandBox != NULL, return APPSPAWN_ARG_INVALID);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(name != NULL, return APPSPAWN_ARG_INVALID);
|
||||
APPSPAWN_LOGV("ProcessExpandAppSandboxConfig %{public}s.", name);
|
||||
const AppSandboxExpandAppCfgNode *node = GetAppSandboxExpandAppCfg(name);
|
||||
if (node != NULL && node->cfgHandle != NULL) {
|
||||
return node->cfgHandle(context, appSandBox, name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AddDefaultExpandAppSandboxConfigHandle(void)
|
||||
{
|
||||
RegisterExpandSandboxCfgHandler("HspList", 0, ProcessHSPListConfig);
|
||||
RegisterExpandSandboxCfgHandler("DataGroup", 1, ProcessDataGroupConfig);
|
||||
RegisterExpandSandboxCfgHandler("Overlay", 2, ProcessOverlayAppConfig); // 2 priority
|
||||
}
|
||||
|
||||
void ClearExpandAppSandboxConfigHandle(void)
|
||||
{
|
||||
OH_ListRemoveAll(&g_sandboxExpandCfgList, NULL);
|
||||
}
|
578
modules/sandbox/sandbox_load.c
Executable file
578
modules/sandbox/sandbox_load.c
Executable file
@ -0,0 +1,578 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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 <ctype.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/mount.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "appspawn_msg.h"
|
||||
#include "appspawn_permission.h"
|
||||
#include "appspawn_sandbox.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "cJSON.h"
|
||||
#include "init_utils.h"
|
||||
#include "json_utils.h"
|
||||
#include "parameter.h"
|
||||
#include "securec.h"
|
||||
|
||||
static const SandboxFlagInfo NAMESPACE_FLAGS_MAP[] = {
|
||||
{"pid", CLONE_NEWPID}, {"net", CLONE_NEWNET}
|
||||
};
|
||||
|
||||
static const SandboxFlagInfo FLAGE_POINT_MAP[] = {
|
||||
{"0", 0},
|
||||
{"START_FLAGS_BACKUP", (unsigned long)APP_FLAGS_BACKUP_EXTENSION},
|
||||
{"DLP_MANAGER", (unsigned long)APP_FLAGS_DLP_MANAGER}
|
||||
};
|
||||
|
||||
static const SandboxFlagInfo MOUNT_MODE_MAP[] = {
|
||||
{"not-exists", (unsigned long)MOUNT_MODE_NOT_EXIST},
|
||||
{"always", (unsigned long)MOUNT_MODE_ALWAYS}
|
||||
};
|
||||
|
||||
static const SandboxFlagInfo NAME_GROUP_TYPE_MAP[] = {
|
||||
{"system-const", (unsigned long)SANDBOX_TAG_SYSTEM_CONST},
|
||||
{"app-variable", (unsigned long)SANDBOX_TAG_APP_VARIABLE}
|
||||
};
|
||||
|
||||
static inline PathMountNode *CreatePathMountNode(uint32_t type)
|
||||
{
|
||||
return (PathMountNode *)CreateSandboxMountNode(sizeof(PathMountNode), type);
|
||||
}
|
||||
|
||||
static inline SymbolLinkNode *CreateSymbolLinkNode(void)
|
||||
{
|
||||
return (SymbolLinkNode *)CreateSandboxMountNode(sizeof(SymbolLinkNode), SANDBOX_TAG_SYMLINK);
|
||||
}
|
||||
|
||||
static inline SandboxPackageNameNode *CreateSandboxPackageNameNode(const char *name)
|
||||
{
|
||||
return (SandboxPackageNameNode *)CreateSandboxSection(name,
|
||||
sizeof(SandboxPackageNameNode), SANDBOX_TAG_PACKAGE_NAME);
|
||||
}
|
||||
|
||||
static inline SandboxFlagsNode *CreateSandboxFlagsNode(const char *name)
|
||||
{
|
||||
return (SandboxFlagsNode *)CreateSandboxSection(name, sizeof(SandboxFlagsNode), SANDBOX_TAG_SPAWN_FLAGS);
|
||||
}
|
||||
|
||||
static inline SandboxNameGroupNode *CreateSandboxNameGroupNode(const char *name)
|
||||
{
|
||||
return (SandboxNameGroupNode *)CreateSandboxSection(name,
|
||||
sizeof(SandboxNameGroupNode), SANDBOX_TAG_NAME_GROUP);
|
||||
}
|
||||
|
||||
static inline SandboxPermissionNode *CreateSandboxPermissionNode(const char *name)
|
||||
{
|
||||
size_t len = sizeof(SandboxPermissionNode);
|
||||
SandboxPermissionNode *node = (SandboxPermissionNode *)
|
||||
CreateSandboxSection(name, len, SANDBOX_TAG_PERMISSION);
|
||||
APPSPAWN_CHECK(node != NULL, return NULL, "Failed to create permission node");
|
||||
node->permissionIndex = 0;
|
||||
return node;
|
||||
}
|
||||
|
||||
static inline bool GetBoolParameter(const char *param, bool value)
|
||||
{
|
||||
char tmp[32] = {0}; // 32 max
|
||||
int ret = GetParameter(param, "", tmp, sizeof(tmp));
|
||||
APPSPAWN_LOGV("GetBoolParameter key %{public}s ret %{public}d result: %{public}s", param, ret, tmp);
|
||||
return (ret > 0 && (strcmp(tmp, "true") == 0 || strcmp(tmp, "on") == 0 || strcmp(tmp, "1") == 0));
|
||||
}
|
||||
|
||||
static inline bool AppSandboxPidNsIsSupport(void)
|
||||
{
|
||||
return GetBoolParameter("const.sandbox.pidns.support", true);
|
||||
}
|
||||
|
||||
static inline bool CheckAppFullMountEnable(void)
|
||||
{
|
||||
return GetBoolParameter("const.filemanager.full_mount.enable", false);
|
||||
}
|
||||
|
||||
static unsigned long GetMountModeFromConfig(const cJSON *config, const char *key, unsigned long def)
|
||||
{
|
||||
char *value = cJSON_GetStringValue(cJSON_GetObjectItemCaseSensitive(config, key));
|
||||
if (value == NULL) {
|
||||
return def;
|
||||
}
|
||||
const SandboxFlagInfo *info = GetSandboxFlagInfo(value, MOUNT_MODE_MAP, ARRAY_LENGTH(MOUNT_MODE_MAP));
|
||||
if (info != NULL) {
|
||||
return info->flags;
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
static uint32_t GetNameGroupTypeFromConfig(const cJSON *config, const char *key, unsigned long def)
|
||||
{
|
||||
char *value = cJSON_GetStringValue(cJSON_GetObjectItemCaseSensitive(config, key));
|
||||
if (value == NULL) {
|
||||
return def;
|
||||
}
|
||||
const SandboxFlagInfo *info = GetSandboxFlagInfo(value, NAME_GROUP_TYPE_MAP, ARRAY_LENGTH(NAME_GROUP_TYPE_MAP));
|
||||
if (info != NULL) {
|
||||
return (uint32_t)info->flags;
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
static uint32_t GetSandboxNsFlags(const cJSON *appConfig)
|
||||
{
|
||||
uint32_t nsFlags = 0;
|
||||
cJSON *obj = cJSON_GetObjectItemCaseSensitive(appConfig, "sandbox-ns-flags");
|
||||
if (obj == NULL || !cJSON_IsArray(obj)) {
|
||||
return nsFlags;
|
||||
}
|
||||
int count = cJSON_GetArraySize(obj);
|
||||
for (int i = 0; i < count; i++) {
|
||||
char *value = cJSON_GetStringValue(cJSON_GetArrayItem(obj, i));
|
||||
const SandboxFlagInfo *info = GetSandboxFlagInfo(value, NAMESPACE_FLAGS_MAP, ARRAY_LENGTH(NAMESPACE_FLAGS_MAP));
|
||||
if (info != NULL) {
|
||||
nsFlags |= info->flags;
|
||||
}
|
||||
}
|
||||
return nsFlags;
|
||||
}
|
||||
|
||||
static int SetMode(const char *str, void *context)
|
||||
{
|
||||
mode_t *mode = (mode_t *)context;
|
||||
*mode |= GetPathMode(str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static mode_t GetChmodFromJson(const cJSON *config)
|
||||
{
|
||||
mode_t mode = 0;
|
||||
char *modeStrs = GetStringFromJsonObj(config, "dest-mode");
|
||||
if (modeStrs == NULL) {
|
||||
return mode;
|
||||
}
|
||||
(void)StringSplit(modeStrs, "|", (void *)&mode, SetMode);
|
||||
return mode;
|
||||
}
|
||||
|
||||
static uint32_t GetFlagIndexFromJson(const cJSON *config)
|
||||
{
|
||||
char *flagStr = GetStringFromJsonObj(config, "name");
|
||||
if (flagStr == NULL) {
|
||||
return 0;
|
||||
}
|
||||
const SandboxFlagInfo *info = GetSandboxFlagInfo(flagStr, FLAGE_POINT_MAP, ARRAY_LENGTH(FLAGE_POINT_MAP));
|
||||
if (info != NULL) {
|
||||
return info->flags;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PathMountNode *DecodeMountPathConfig(const cJSON *config, uint32_t type)
|
||||
{
|
||||
char *srcPath = GetStringFromJsonObj(config, "src-path");
|
||||
char *dstPath = GetStringFromJsonObj(config, "sandbox-path");
|
||||
if (srcPath == NULL || dstPath == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PathMountNode *sandboxNode = CreatePathMountNode(type);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(sandboxNode != NULL, return NULL);
|
||||
sandboxNode->source = strdup(srcPath);
|
||||
sandboxNode->target = strdup(dstPath);
|
||||
|
||||
sandboxNode->destMode = GetChmodFromJson(config);
|
||||
sandboxNode->mountSharedFlag = GetBoolValueFromJsonObj(config, "mount-shared-flag", false);
|
||||
sandboxNode->checkErrorFlag = GetBoolValueFromJsonObj(config, "check-action-status", false);
|
||||
|
||||
sandboxNode->category = GetMountCategory(GetStringFromJsonObj(config, "category"));
|
||||
const char *value = GetStringFromJsonObj(config, "app-apl-name");
|
||||
if (value != NULL) {
|
||||
sandboxNode->appAplName = strdup(value);
|
||||
}
|
||||
|
||||
if (sandboxNode->source == NULL || sandboxNode->target == NULL) {
|
||||
APPSPAWN_LOGE("Failed to get sourc or target path");
|
||||
DeleteSandboxMountNode((SandboxMountNode *)sandboxNode);
|
||||
return NULL;
|
||||
}
|
||||
return sandboxNode;
|
||||
}
|
||||
|
||||
static int ParseMountPathsConfig(AppSpawnSandboxCfg *sandbox,
|
||||
const cJSON *mountConfigs, SandboxSection *section, uint32_t type)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(mountConfigs != NULL && cJSON_IsArray(mountConfigs), return -1);
|
||||
|
||||
uint32_t mountPointSize = cJSON_GetArraySize(mountConfigs);
|
||||
for (uint32_t i = 0; i < mountPointSize; i++) {
|
||||
cJSON *mntJson = cJSON_GetArrayItem(mountConfigs, i);
|
||||
if (mntJson == NULL) {
|
||||
continue;
|
||||
}
|
||||
PathMountNode *sandboxNode = DecodeMountPathConfig(mntJson, type);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(sandboxNode != NULL, continue);
|
||||
AddSandboxMountNode(&sandboxNode->sandboxNode, section);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SymbolLinkNode *DecodeSymbolLinksConfig(const cJSON *config)
|
||||
{
|
||||
const char *target = GetStringFromJsonObj(config, "target-name");
|
||||
const char *linkName = GetStringFromJsonObj(config, "link-name");
|
||||
if (target == NULL || linkName == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SymbolLinkNode *node = CreateSymbolLinkNode();
|
||||
APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return NULL);
|
||||
node->destMode = GetChmodFromJson(config);
|
||||
node->checkErrorFlag = GetBoolValueFromJsonObj(config, "check-action-status", false);
|
||||
node->target = strdup(target);
|
||||
node->linkName = strdup(linkName);
|
||||
if (node->target == NULL || node->linkName == NULL) {
|
||||
APPSPAWN_LOGE("Failed to get sourc or target path");
|
||||
DeleteSandboxMountNode((SandboxMountNode *)node);
|
||||
return NULL;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static int ParseSymbolLinksConfig(AppSpawnSandboxCfg *sandbox,
|
||||
const cJSON *symbolLinkConfigs, SandboxSection *section)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(symbolLinkConfigs != NULL && cJSON_IsArray(symbolLinkConfigs), return -1);
|
||||
uint32_t symlinkPointSize = cJSON_GetArraySize(symbolLinkConfigs);
|
||||
for (uint32_t i = 0; i < symlinkPointSize; i++) {
|
||||
cJSON *symConfig = cJSON_GetArrayItem(symbolLinkConfigs, i);
|
||||
if (symConfig == NULL) {
|
||||
continue;
|
||||
}
|
||||
SymbolLinkNode *node = DecodeSymbolLinksConfig(symConfig);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return -1);
|
||||
AddSandboxMountNode(&node->sandboxNode, section);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ParseGidTableConfig(AppSpawnSandboxCfg *sandbox, const cJSON *configs, SandboxSection *section)
|
||||
{
|
||||
APPSPAWN_CHECK(cJSON_IsArray(configs), return 0, "json is not array.");
|
||||
uint32_t arrayLen = (uint32_t)cJSON_GetArraySize(configs);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(arrayLen > 0, return 0);
|
||||
APPSPAWN_CHECK(arrayLen < APP_MAX_GIDS, arrayLen = APP_MAX_GIDS, "More gid in gids json.");
|
||||
|
||||
section->gidTable = (gid_t *)calloc(1, sizeof(gid_t) * arrayLen);
|
||||
APPSPAWN_CHECK(section->gidTable != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to alloc memory.");
|
||||
|
||||
for (uint32_t i = 0; i < arrayLen; i++) {
|
||||
char *value = cJSON_GetStringValue(cJSON_GetArrayItem(configs, i));
|
||||
gid_t gid = DecodeGid(value);
|
||||
if (gid <= 0) {
|
||||
continue;
|
||||
}
|
||||
section->gidTable[section->gidCount++] = gid;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ParseMountGroupsConfig(AppSpawnSandboxCfg *sandbox, const cJSON *groupConfig, SandboxSection *section)
|
||||
{
|
||||
APPSPAWN_CHECK(cJSON_IsArray(groupConfig),
|
||||
return APPSPAWN_SANDBOX_INVALID, "Invalid mount-groups config %{public}s", section->name);
|
||||
|
||||
uint32_t count = (uint32_t)cJSON_GetArraySize(groupConfig);
|
||||
section->nameGroups = (SandboxMountNode **)malloc(sizeof(SandboxMountNode *) * count);
|
||||
APPSPAWN_CHECK(section->nameGroups != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to alloc memory for group name");
|
||||
|
||||
SandboxNameGroupNode *mountNode = NULL;
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
section->nameGroups[i] = NULL;
|
||||
char *name = cJSON_GetStringValue(cJSON_GetArrayItem(groupConfig, i));
|
||||
mountNode = (SandboxNameGroupNode *)GetSandboxSection(&sandbox->nameGroupsQueue, name);
|
||||
if (mountNode == NULL) {
|
||||
APPSPAWN_LOGE("Can not find name-group %{public}s", name);
|
||||
continue;
|
||||
}
|
||||
// check type
|
||||
if (strcmp(section->name, "system-const") == 0 && mountNode->destType != SANDBOX_TAG_SYSTEM_CONST) {
|
||||
APPSPAWN_LOGE("Invalid name-group %{public}s", name);
|
||||
continue;
|
||||
}
|
||||
section->nameGroups[section->number++] = (SandboxMountNode *)mountNode;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ParseBaseConfig(AppSpawnSandboxCfg *sandbox, SandboxSection *section, const cJSON *configs)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(configs != NULL, return 0);
|
||||
APPSPAWN_CHECK(cJSON_IsObject(configs),
|
||||
return APPSPAWN_SANDBOX_INVALID, "Invalid config %{public}s", section->name);
|
||||
APPSPAWN_LOGV("Parse sandbox %{public}s", section->name);
|
||||
// "sandbox-switch": "ON", default sandbox switch is on
|
||||
section->sandboxSwitch = GetBoolValueFromJsonObj(configs, "sandbox-switch", true);
|
||||
// "sandbox-shared"
|
||||
section->sandboxShared = GetBoolValueFromJsonObj(configs, "sandbox-shared", false);
|
||||
|
||||
int ret = 0;
|
||||
cJSON *gidTabJson = cJSON_GetObjectItemCaseSensitive(configs, "gids");
|
||||
if (gidTabJson) {
|
||||
ret = ParseGidTableConfig(sandbox, gidTabJson, section);
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "Parse gids for %{public}s", section->name);
|
||||
}
|
||||
cJSON *pathConfigs = cJSON_GetObjectItemCaseSensitive(configs, "mount-paths");
|
||||
if (pathConfigs != NULL) { // mount-paths
|
||||
ret = ParseMountPathsConfig(sandbox, pathConfigs, section, SANDBOX_TAG_MOUNT_PATH);
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "Parse mount-paths for %{public}s", section->name);
|
||||
}
|
||||
pathConfigs = cJSON_GetObjectItemCaseSensitive(configs, "mount-files");
|
||||
if (pathConfigs != NULL) { // mount-files
|
||||
ret = ParseMountPathsConfig(sandbox, pathConfigs, section, SANDBOX_TAG_MOUNT_FILE);
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "Parse mount-paths for %{public}s", section->name);
|
||||
}
|
||||
pathConfigs = cJSON_GetObjectItemCaseSensitive(configs, "symbol-links");
|
||||
if (pathConfigs != NULL) { // symbol-links
|
||||
ret = ParseSymbolLinksConfig(sandbox, pathConfigs, section);
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "Parse symbol-links for %{public}s", section->name);
|
||||
}
|
||||
cJSON *groupConfig = cJSON_GetObjectItemCaseSensitive(configs, "mount-groups");
|
||||
if (groupConfig != NULL) {
|
||||
ret = ParseMountGroupsConfig(sandbox, groupConfig, section);
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "Parse mount-groups for %{public}s", section->name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ParsePackageNameConfig(AppSpawnSandboxCfg *sandbox, const char *name, const cJSON *packageNameConfigs)
|
||||
{
|
||||
APPSPAWN_LOGV("Parse package-name config %{public}s", name);
|
||||
SandboxPackageNameNode *node = CreateSandboxPackageNameNode(name);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return -1);
|
||||
|
||||
int ret = ParseBaseConfig(sandbox, &node->section, packageNameConfigs);
|
||||
if (ret != 0) {
|
||||
DeleteSandboxSection((SandboxSection *)node);
|
||||
return ret;
|
||||
}
|
||||
// success, insert section
|
||||
AddSandboxSection(&node->section, &sandbox->packageNameQueue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ParseSpawnFlagsConfig(AppSpawnSandboxCfg *sandbox, const char *name, const cJSON *flagsConfig)
|
||||
{
|
||||
uint32_t flagIndex = GetFlagIndexFromJson(flagsConfig);
|
||||
APPSPAWN_LOGV("Parse spawn-flags config %{public}s flagIndex %{public}u", name, flagIndex);
|
||||
|
||||
SandboxFlagsNode *node = CreateSandboxFlagsNode(name);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return -1);
|
||||
node->flagIndex = flagIndex;
|
||||
|
||||
int ret = ParseBaseConfig(sandbox, &node->section, flagsConfig);
|
||||
if (ret != 0) {
|
||||
DeleteSandboxSection((SandboxSection *)node);
|
||||
return ret;
|
||||
}
|
||||
// success, insert section
|
||||
AddSandboxSection(&node->section, &sandbox->spawnFlagsQueue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ParsePermissionConfig(AppSpawnSandboxCfg *sandbox, const char *name, const cJSON *permissionConfig)
|
||||
{
|
||||
APPSPAWN_LOGV("Parse permission config %{public}s", name);
|
||||
SandboxPermissionNode *node = CreateSandboxPermissionNode(name);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return -1);
|
||||
|
||||
int ret = ParseBaseConfig(sandbox, &node->section, permissionConfig);
|
||||
if (ret != 0) {
|
||||
DeleteSandboxSection((SandboxSection *)node);
|
||||
return ret;
|
||||
}
|
||||
// success, insert section
|
||||
AddSandboxSection(&node->section, &sandbox->permissionQueue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SandboxNameGroupNode *ParseNameGroup(AppSpawnSandboxCfg *sandbox, const cJSON *groupConfig)
|
||||
{
|
||||
int ret = 0;
|
||||
char *name = GetStringFromJsonObj(groupConfig, "name");
|
||||
APPSPAWN_CHECK(name != NULL, return NULL, "No name in name group config");
|
||||
APPSPAWN_LOGV("Parse name-group config %{public}s", name);
|
||||
SandboxNameGroupNode *node = CreateSandboxNameGroupNode(name);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return NULL);
|
||||
|
||||
cJSON *obj = cJSON_GetObjectItemCaseSensitive(groupConfig, "mount-paths-deps");
|
||||
if (obj) {
|
||||
node->depNode = DecodeMountPathConfig(obj, SANDBOX_TAG_MOUNT_PATH);
|
||||
if (node->depNode == NULL) {
|
||||
DeleteSandboxSection((SandboxSection *)node);
|
||||
return NULL;
|
||||
}
|
||||
// "mount-mode": "not-exists"
|
||||
node->mountMode = GetMountModeFromConfig(obj, "mount-mode", MOUNT_MODE_ALWAYS);
|
||||
}
|
||||
|
||||
ret = ParseBaseConfig(sandbox, &node->section, groupConfig);
|
||||
if (ret != 0) {
|
||||
DeleteSandboxSection((SandboxSection *)node);
|
||||
return NULL;
|
||||
}
|
||||
// "type": "system-const",
|
||||
// "caps": ["shared"],
|
||||
node->destType = GetNameGroupTypeFromConfig(groupConfig, "type", SANDBOX_TAG_INVALID);
|
||||
// success, insert section
|
||||
AddSandboxSection(&node->section, &sandbox->nameGroupsQueue);
|
||||
return node;
|
||||
}
|
||||
|
||||
static int ParseNameGroupsConfig(AppSpawnSandboxCfg *sandbox, const cJSON *root)
|
||||
{
|
||||
APPSPAWN_CHECK(root != NULL, return APPSPAWN_SANDBOX_INVALID, "Invalid config ");
|
||||
cJSON *configs = cJSON_GetObjectItemCaseSensitive(root, "name-groups");
|
||||
APPSPAWN_CHECK_ONLY_EXPER(configs != NULL, return 0);
|
||||
APPSPAWN_CHECK(cJSON_IsArray(configs), return APPSPAWN_SANDBOX_INVALID, "Invalid config ");
|
||||
int count = cJSON_GetArraySize(configs);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(count > 0, return 0);
|
||||
|
||||
sandbox->depGroupNodes = (SandboxNameGroupNode **)calloc(1, sizeof(SandboxNameGroupNode *) * count);
|
||||
APPSPAWN_CHECK(sandbox->depGroupNodes != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed alloc memory ");
|
||||
sandbox->depNodeCount = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
cJSON *json = cJSON_GetArrayItem(configs, i);
|
||||
if (json == NULL) {
|
||||
continue;
|
||||
}
|
||||
SandboxNameGroupNode *node = ParseNameGroup(sandbox, json);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(node != NULL, return APPSPAWN_SANDBOX_INVALID);
|
||||
if (node->depNode) {
|
||||
sandbox->depGroupNodes[sandbox->depNodeCount++] = node;
|
||||
}
|
||||
}
|
||||
APPSPAWN_LOGV("ParseNameGroupsConfig depNodeCount %{public}d", sandbox->depNodeCount);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ParseConditionalConfig(AppSpawnSandboxCfg *sandbox, const cJSON *configs, const char *configName,
|
||||
int (*parseConfig)(AppSpawnSandboxCfg *sandbox, const char *name, const cJSON *configs))
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(configs != NULL, return 0);
|
||||
APPSPAWN_CHECK(cJSON_IsArray(configs),
|
||||
return APPSPAWN_SANDBOX_INVALID, "Invalid config %{public}s", configName);
|
||||
int ret = 0;
|
||||
int count = cJSON_GetArraySize(configs);
|
||||
for (int i = 0; i < count; i++) {
|
||||
cJSON *json = cJSON_GetArrayItem(configs, i);
|
||||
if (json == NULL) {
|
||||
continue;
|
||||
}
|
||||
char *name = GetStringFromJsonObj(json, "name");
|
||||
if (name == NULL) {
|
||||
APPSPAWN_LOGE("No name in %{public}s configs", configName);
|
||||
continue;
|
||||
}
|
||||
ret = parseConfig(sandbox, name, json);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ParseGlobalSandboxConfig(AppSpawnSandboxCfg *sandbox, const cJSON *root)
|
||||
{
|
||||
cJSON *json = cJSON_GetObjectItemCaseSensitive(root, "global");
|
||||
if (json) {
|
||||
sandbox->sandboxNsFlags = GetSandboxNsFlags(json);
|
||||
char *rootPath = GetStringFromJsonObj(json, "sandbox-root");
|
||||
APPSPAWN_CHECK(rootPath != NULL, return APPSPAWN_SYSTEM_ERROR, "No root path in config");
|
||||
sandbox->rootPath = strdup(rootPath);
|
||||
APPSPAWN_CHECK(sandbox->rootPath != NULL, return APPSPAWN_SYSTEM_ERROR, "Failed to copy root path");
|
||||
sandbox->topSandboxSwitch = GetBoolValueFromJsonObj(json, "top-sandbox-switch", true);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
APPSPAWN_STATIC int ParseAppSandboxConfig(const cJSON *root, AppSpawnSandboxCfg *sandbox)
|
||||
{
|
||||
APPSPAWN_CHECK(root != NULL && sandbox, return APPSPAWN_SYSTEM_ERROR, "Invalid json");
|
||||
int ret = ParseGlobalSandboxConfig(sandbox, root); // "global":
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return APPSPAWN_SANDBOX_INVALID);
|
||||
ret = ParseNameGroupsConfig(sandbox, root); // name-groups
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return APPSPAWN_SANDBOX_INVALID);
|
||||
|
||||
// "required"
|
||||
cJSON *required = cJSON_GetObjectItemCaseSensitive(root, "required");
|
||||
if (required) {
|
||||
cJSON *config = NULL;
|
||||
cJSON_ArrayForEach(config, required) {
|
||||
APPSPAWN_LOGI("Sandbox required config: %{public}s", config->string);
|
||||
SandboxSection *section = CreateSandboxSection(config->string, sizeof(SandboxSection),
|
||||
SANDBOX_TAG_REQUIRED);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(section != NULL, return -1);
|
||||
|
||||
int ret = ParseBaseConfig(sandbox, section, config);
|
||||
if (ret != 0) {
|
||||
DeleteSandboxSection(section);
|
||||
return ret;
|
||||
}
|
||||
// success, insert section
|
||||
AddSandboxSection(section, &sandbox->requiredQueue);
|
||||
}
|
||||
}
|
||||
|
||||
// conditional
|
||||
cJSON *json = cJSON_GetObjectItemCaseSensitive(root, "conditional");
|
||||
if (json != NULL) {
|
||||
// permission
|
||||
cJSON *config = cJSON_GetObjectItemCaseSensitive(json, "permission");
|
||||
ret = ParseConditionalConfig(sandbox, config, "permission", ParsePermissionConfig);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
// spawn-flag
|
||||
config = cJSON_GetObjectItemCaseSensitive(json, "spawn-flag");
|
||||
ret = ParseConditionalConfig(sandbox, config, "spawn-flag", ParseSpawnFlagsConfig);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
// package-name
|
||||
config = cJSON_GetObjectItemCaseSensitive(json, "package-name");
|
||||
ret = ParseConditionalConfig(sandbox, config, "package-name", ParsePackageNameConfig);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int LoadAppSandboxConfig(AppSpawnSandboxCfg *sandbox, int nwebSpawn)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(sandbox != NULL, return APPSPAWN_ARG_INVALID);
|
||||
const char *sandboxName = nwebSpawn ? WEB_SANDBOX_FILE_NAME : APP_SANDBOX_FILE_NAME;
|
||||
int ret = ParseSandboxConfig("etc/sandbox", sandboxName, ParseAppSandboxConfig, sandbox);
|
||||
if (ret == APPSPAWN_SANDBOX_NONE) {
|
||||
APPSPAWN_LOGW("No sandbox config");
|
||||
ret = 0;
|
||||
}
|
||||
APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
|
||||
sandbox->pidNamespaceSupport = AppSandboxPidNsIsSupport();
|
||||
sandbox->appFullMountEnable = CheckAppFullMountEnable();
|
||||
APPSPAWN_LOGI("Sandbox pidNamespaceSupport: %{public}d appFullMountEnable: %{public}d",
|
||||
sandbox->pidNamespaceSupport, sandbox->appFullMountEnable);
|
||||
return 0;
|
||||
}
|
544
modules/sandbox/sandbox_manager.c
Executable file
544
modules/sandbox/sandbox_manager.c
Executable file
@ -0,0 +1,544 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.
|
||||
*/
|
||||
|
||||
#undef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#include <sched.h>
|
||||
|
||||
#include "appspawn_permission.h"
|
||||
#include "appspawn_sandbox.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "modulemgr.h"
|
||||
#include "parameter.h"
|
||||
#include "securec.h"
|
||||
|
||||
static void FreePathMountNode(SandboxMountNode *node)
|
||||
{
|
||||
PathMountNode *sandboxNode = (PathMountNode *)node;
|
||||
if (sandboxNode->source) {
|
||||
free(sandboxNode->source);
|
||||
sandboxNode->source = NULL;
|
||||
}
|
||||
if (sandboxNode->target) {
|
||||
free(sandboxNode->target);
|
||||
sandboxNode->target = NULL;
|
||||
}
|
||||
if (sandboxNode->appAplName) {
|
||||
free(sandboxNode->appAplName);
|
||||
sandboxNode->appAplName = NULL;
|
||||
}
|
||||
free(sandboxNode);
|
||||
}
|
||||
|
||||
static void FreeSymbolLinkNode(SandboxMountNode *node)
|
||||
{
|
||||
SymbolLinkNode *sandboxNode = (SymbolLinkNode *)node;
|
||||
if (sandboxNode->target) {
|
||||
free(sandboxNode->target);
|
||||
sandboxNode->target = NULL;
|
||||
}
|
||||
if (sandboxNode->linkName) {
|
||||
free(sandboxNode->linkName);
|
||||
sandboxNode->linkName = NULL;
|
||||
}
|
||||
free(sandboxNode);
|
||||
}
|
||||
|
||||
static int SandboxNodeCompareProc(ListNode *node, ListNode *newNode)
|
||||
{
|
||||
SandboxMountNode *sandbox1 = (SandboxMountNode *)ListEntry(node, SandboxMountNode, node);
|
||||
SandboxMountNode *sandbox2 = (SandboxMountNode *)ListEntry(newNode, SandboxMountNode, node);
|
||||
return sandbox1->type - sandbox2->type;
|
||||
}
|
||||
|
||||
SandboxMountNode *CreateSandboxMountNode(uint32_t dataLen, uint32_t type)
|
||||
{
|
||||
APPSPAWN_CHECK(dataLen >= sizeof(SandboxMountNode) && dataLen <= sizeof(PathMountNode),
|
||||
return NULL, "Invalid dataLen %{public}u", dataLen);
|
||||
SandboxMountNode *node = (SandboxMountNode *)calloc(1, dataLen);
|
||||
APPSPAWN_CHECK(node != NULL, return NULL, "Failed to create mount node %{public}u", type);
|
||||
OH_ListInit(&node->node);
|
||||
node->type = type;
|
||||
return node;
|
||||
}
|
||||
|
||||
void AddSandboxMountNode(SandboxMountNode *node, SandboxSection *queue)
|
||||
{
|
||||
OH_ListAddWithOrder(&queue->front, &node->node, SandboxNodeCompareProc);
|
||||
}
|
||||
|
||||
void DeleteSandboxMountNode(SandboxMountNode *sandboxNode)
|
||||
{
|
||||
switch (sandboxNode->type) {
|
||||
case SANDBOX_TAG_MOUNT_PATH:
|
||||
case SANDBOX_TAG_MOUNT_FILE:
|
||||
FreePathMountNode(sandboxNode);
|
||||
break;
|
||||
case SANDBOX_TAG_SYMLINK:
|
||||
FreeSymbolLinkNode(sandboxNode);
|
||||
break;
|
||||
default:
|
||||
APPSPAWN_LOGE("Invalid type %{public}u", sandboxNode->type);
|
||||
free(sandboxNode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SandboxMountNode *GetFirstSandboxMountNode(const SandboxSection *section)
|
||||
{
|
||||
if (ListEmpty(section->front)) {
|
||||
return NULL;
|
||||
}
|
||||
return (SandboxMountNode *)ListEntry(section->front.next, SandboxMountNode, node);
|
||||
}
|
||||
|
||||
void DumpSandboxMountNode(const SandboxMountNode *sandboxNode, uint32_t index)
|
||||
{
|
||||
switch (sandboxNode->type) {
|
||||
case SANDBOX_TAG_MOUNT_PATH:
|
||||
case SANDBOX_TAG_MOUNT_FILE: {
|
||||
PathMountNode *pathNode = (PathMountNode *)sandboxNode;
|
||||
APPSPAPWN_DUMP(" ****************************** %{public}u", index);
|
||||
APPSPAPWN_DUMP(" sandbox node source: %{public}s", pathNode->source ? pathNode->source : "null");
|
||||
APPSPAPWN_DUMP(" sandbox node target: %{public}s", pathNode->target ? pathNode->target : "null");
|
||||
DumpMountPathMountNode(pathNode);
|
||||
APPSPAPWN_DUMP(" sandbox node apl: %{public}s",
|
||||
pathNode->appAplName ? pathNode->appAplName : "null");
|
||||
APPSPAPWN_DUMP(" sandbox node checkErrorFlag: %{public}s",
|
||||
pathNode->checkErrorFlag ? "true" : "false");
|
||||
break;
|
||||
}
|
||||
case SANDBOX_TAG_SYMLINK: {
|
||||
SymbolLinkNode *linkNode = (SymbolLinkNode *)sandboxNode;
|
||||
APPSPAPWN_DUMP(" ***********************************");
|
||||
APPSPAPWN_DUMP(" sandbox node target: %{public}s", linkNode->target ? linkNode->target : "null");
|
||||
APPSPAPWN_DUMP(" sandbox node linkName: %{public}s",
|
||||
linkNode->linkName ? linkNode->linkName : "null");
|
||||
APPSPAPWN_DUMP(" sandbox node destMode: %{public}x", linkNode->destMode);
|
||||
APPSPAPWN_DUMP(" sandbox node checkErrorFlag: %{public}s",
|
||||
linkNode->checkErrorFlag ? "true" : "false");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void InitSandboxSection(SandboxSection *section, int type)
|
||||
{
|
||||
OH_ListInit(§ion->front);
|
||||
section->sandboxSwitch = 0;
|
||||
section->sandboxShared = 0;
|
||||
section->number = 0;
|
||||
section->gidCount = 0;
|
||||
section->gidTable = NULL;
|
||||
section->nameGroups = NULL;
|
||||
section->name = NULL;
|
||||
OH_ListInit(§ion->sandboxNode.node);
|
||||
section->sandboxNode.type = type;
|
||||
}
|
||||
|
||||
static void ClearSandboxSection(SandboxSection *section)
|
||||
{
|
||||
if (section->gidTable) {
|
||||
free(section->gidTable);
|
||||
section->gidTable = NULL;
|
||||
}
|
||||
// free name group
|
||||
if (section->nameGroups) {
|
||||
free(section->nameGroups);
|
||||
section->nameGroups = NULL;
|
||||
}
|
||||
|
||||
// free mount path
|
||||
ListNode *node = section->front.next;
|
||||
while (node != §ion->front) {
|
||||
SandboxMountNode *sandboxNode = ListEntry(node, SandboxMountNode, node);
|
||||
// delete node
|
||||
OH_ListRemove(&sandboxNode->node);
|
||||
OH_ListInit(&sandboxNode->node);
|
||||
DeleteSandboxMountNode(sandboxNode);
|
||||
// get next
|
||||
node = section->front.next;
|
||||
}
|
||||
}
|
||||
|
||||
static void DumpSandboxQueue(const ListNode *front,
|
||||
void (*dumpSandboxMountNode)(const SandboxMountNode *node, uint32_t count))
|
||||
{
|
||||
uint32_t count = 0;
|
||||
ListNode *node = front->next;
|
||||
while (node != front) {
|
||||
SandboxMountNode *sandboxNode = (SandboxMountNode *)ListEntry(node, SandboxMountNode, node);
|
||||
count++;
|
||||
dumpSandboxMountNode(sandboxNode, count);
|
||||
// get next
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void DumpSandboxSection(const SandboxSection *section)
|
||||
{
|
||||
APPSPAPWN_DUMP(" ========================================= ");
|
||||
APPSPAPWN_DUMP(" Section %{public}s", section->name);
|
||||
APPSPAPWN_DUMP(" sandboxSwitch %{public}s", section->sandboxSwitch ? "true" : "false");
|
||||
APPSPAPWN_DUMP(" sandboxShared %{public}s", section->sandboxShared ? "true" : "false");
|
||||
APPSPAPWN_DUMP(" gidCount: %{public}u", section->gidCount);
|
||||
for (uint32_t index = 0; index < section->gidCount; index++) {
|
||||
APPSPAPWN_DUMP(" gidTable[%{public}u]: %{public}u", index, section->gidTable[index]);
|
||||
}
|
||||
APPSPAPWN_DUMP(" mount group count: %{public}u", section->number);
|
||||
for (uint32_t i = 0; i < section->number; i++) {
|
||||
if (section->nameGroups[i]) {
|
||||
SandboxNameGroupNode *groupNode = (SandboxNameGroupNode *)section->nameGroups[i];
|
||||
APPSPAPWN_DUMP(" name[%{public}d] %{public}s", i, groupNode->section.name);
|
||||
}
|
||||
}
|
||||
APPSPAPWN_DUMP(" mount-paths: ");
|
||||
DumpSandboxQueue(§ion->front, DumpSandboxMountNode);
|
||||
}
|
||||
|
||||
SandboxSection *CreateSandboxSection(const char *name, uint32_t dataLen, uint32_t type)
|
||||
{
|
||||
APPSPAWN_CHECK(name != NULL, return NULL, "Invalid name %{public}u", type);
|
||||
APPSPAWN_CHECK(dataLen >= sizeof(SandboxSection), return NULL, "Invalid dataLen %{public}u", dataLen);
|
||||
APPSPAWN_CHECK(dataLen <= sizeof(SandboxNameGroupNode), return NULL, "Invalid dataLen %{public}u", dataLen);
|
||||
SandboxSection *section = (SandboxSection *)calloc(1, dataLen);
|
||||
APPSPAWN_CHECK(section != NULL, return NULL, "Failed to create base node");
|
||||
InitSandboxSection(section, type);
|
||||
section->name = strdup(name);
|
||||
if (section->name == NULL) {
|
||||
ClearSandboxSection(section);
|
||||
free(section);
|
||||
return NULL;
|
||||
}
|
||||
return section;
|
||||
}
|
||||
|
||||
static int SandboxConditionalNodeCompareName(ListNode *node, void *data)
|
||||
{
|
||||
SandboxSection *tmpNode = (SandboxSection *)ListEntry(node, SandboxMountNode, node);
|
||||
return strcmp(tmpNode->name, (char *)data);
|
||||
}
|
||||
|
||||
static int SandboxConditionalNodeCompareNode(ListNode *node, ListNode *newNode)
|
||||
{
|
||||
SandboxSection *tmpNode = (SandboxSection *)ListEntry(node, SandboxMountNode, node);
|
||||
SandboxSection *tmpNewNode = (SandboxSection *)ListEntry(newNode, SandboxMountNode, node);
|
||||
return strcmp(tmpNode->name, tmpNewNode->name);
|
||||
}
|
||||
|
||||
SandboxSection *GetSandboxSection(const SandboxQueue *queue, const char *name)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(name != NULL && queue != NULL, return NULL);
|
||||
ListNode *node = OH_ListFind(&queue->front, (void *)name, SandboxConditionalNodeCompareName);
|
||||
if (node == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return (SandboxSection *)ListEntry(node, SandboxMountNode, node);
|
||||
}
|
||||
|
||||
void AddSandboxSection(SandboxSection *node, SandboxQueue *queue)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(node != NULL && queue != NULL, return);
|
||||
OH_ListAddWithOrder(&queue->front, &node->sandboxNode.node, SandboxConditionalNodeCompareNode);
|
||||
}
|
||||
|
||||
void DeleteSandboxSection(SandboxSection *section)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(section != NULL, return);
|
||||
// delete node
|
||||
OH_ListRemove(§ion->sandboxNode.node);
|
||||
OH_ListInit(§ion->sandboxNode.node);
|
||||
ClearSandboxSection(section);
|
||||
free(section);
|
||||
}
|
||||
|
||||
static void SandboxQueueClear(SandboxQueue *queue)
|
||||
{
|
||||
ListNode *node = queue->front.next;
|
||||
while (node != &queue->front) {
|
||||
SandboxSection *sandboxNode = (SandboxSection *)ListEntry(node, SandboxMountNode, node);
|
||||
DeleteSandboxSection(sandboxNode);
|
||||
// get first
|
||||
node = queue->front.next;
|
||||
}
|
||||
}
|
||||
|
||||
static int AppSpawnExtDataCompareDataId(ListNode *node, void *data)
|
||||
{
|
||||
AppSpawnExtData *extData = (AppSpawnExtData *)ListEntry(node, AppSpawnExtData, node);
|
||||
return extData->dataId - *(uint32_t *)data;
|
||||
}
|
||||
|
||||
AppSpawnSandboxCfg *GetAppSpawnSandbox(const AppSpawnMgr *content)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != NULL, return NULL);
|
||||
uint32_t dataId = EXT_DATA_SANDBOX;
|
||||
ListNode *node = OH_ListFind(&content->extData, (void *)&dataId, AppSpawnExtDataCompareDataId);
|
||||
if (node == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return (AppSpawnSandboxCfg *)ListEntry(node, AppSpawnSandboxCfg, extData);
|
||||
}
|
||||
|
||||
void DeleteAppSpawnSandbox(AppSpawnSandboxCfg *sandbox)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(sandbox != NULL, return);
|
||||
APPSPAWN_LOGV("DeleteAppSpawnSandbox");
|
||||
OH_ListRemove(&sandbox->extData.node);
|
||||
OH_ListInit(&sandbox->extData.node);
|
||||
|
||||
// delete all queue
|
||||
SandboxQueueClear(&sandbox->requiredQueue);
|
||||
SandboxQueueClear(&sandbox->permissionQueue);
|
||||
SandboxQueueClear(&sandbox->packageNameQueue);
|
||||
SandboxQueueClear(&sandbox->spawnFlagsQueue);
|
||||
SandboxQueueClear(&sandbox->nameGroupsQueue);
|
||||
free(sandbox->depGroupNodes);
|
||||
sandbox->depGroupNodes = NULL;
|
||||
|
||||
free(sandbox);
|
||||
sandbox = NULL;
|
||||
}
|
||||
|
||||
static void DumpSandboxSectionNode(const SandboxMountNode *node, uint32_t index)
|
||||
{
|
||||
SandboxPermissionNode *permissionNode = (SandboxPermissionNode *)node;
|
||||
DumpSandboxSection(&permissionNode->section);
|
||||
}
|
||||
|
||||
static void DumpSandbox(struct TagAppSpawnExtData *data)
|
||||
{
|
||||
AppSpawnSandboxCfg *sandbox = (AppSpawnSandboxCfg *)data;
|
||||
DumpAppSpawnSandboxCfg(sandbox);
|
||||
}
|
||||
|
||||
static inline void InitSandboxQueue(SandboxQueue *queue, uint32_t type)
|
||||
{
|
||||
OH_ListInit(&queue->front);
|
||||
queue->type = type;
|
||||
}
|
||||
|
||||
static void FreeAppSpawnSandbox(struct TagAppSpawnExtData *data)
|
||||
{
|
||||
AppSpawnSandboxCfg *sandbox = ListEntry(data, AppSpawnSandboxCfg, extData);
|
||||
UnmountSandboxConfigs(sandbox);
|
||||
// delete all var
|
||||
DeleteAppSpawnSandbox(sandbox);
|
||||
}
|
||||
|
||||
static void ClearAppSpawnSandbox(struct TagAppSpawnExtData *data)
|
||||
{
|
||||
// clear no use sand box config
|
||||
}
|
||||
|
||||
AppSpawnSandboxCfg *CreateAppSpawnSandbox(void)
|
||||
{
|
||||
// create sandbox
|
||||
AppSpawnSandboxCfg *sandbox = (AppSpawnSandboxCfg *)calloc(1, sizeof(AppSpawnSandboxCfg));
|
||||
APPSPAWN_CHECK(sandbox != NULL, return NULL, "Failed to create sandbox");
|
||||
|
||||
// ext data init
|
||||
OH_ListInit(&sandbox->extData.node);
|
||||
sandbox->extData.dataId = EXT_DATA_SANDBOX;
|
||||
sandbox->extData.freeNode = FreeAppSpawnSandbox;
|
||||
sandbox->extData.clearNode = ClearAppSpawnSandbox;
|
||||
sandbox->extData.dumpNode = DumpSandbox;
|
||||
|
||||
// queue
|
||||
InitSandboxQueue(&sandbox->requiredQueue, SANDBOX_TAG_REQUIRED);
|
||||
InitSandboxQueue(&sandbox->permissionQueue, SANDBOX_TAG_PERMISSION);
|
||||
InitSandboxQueue(&sandbox->packageNameQueue, SANDBOX_TAG_PACKAGE_NAME);
|
||||
InitSandboxQueue(&sandbox->spawnFlagsQueue, SANDBOX_TAG_SPAWN_FLAGS);
|
||||
InitSandboxQueue(&sandbox->nameGroupsQueue, SANDBOX_TAG_NAME_GROUP);
|
||||
|
||||
sandbox->topSandboxSwitch = 0;
|
||||
sandbox->appFullMountEnable = 0;
|
||||
sandbox->topSandboxSwitch = 0;
|
||||
sandbox->pidNamespaceSupport = 0;
|
||||
sandbox->sandboxNsFlags = 0;
|
||||
sandbox->maxPermissionIndex = -1;
|
||||
sandbox->depNodeCount = 0;
|
||||
sandbox->depGroupNodes = NULL;
|
||||
|
||||
for (uint32_t i = 0; i < ARRAY_LENGTH(sandbox->systemUids); i++) {
|
||||
sandbox->systemUids[i] = INVALID_UID;
|
||||
}
|
||||
|
||||
AddDefaultVariable();
|
||||
AddDefaultExpandAppSandboxConfigHandle();
|
||||
return sandbox;
|
||||
}
|
||||
|
||||
void DumpAppSpawnSandboxCfg(AppSpawnSandboxCfg *sandbox)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(sandbox != NULL, return);
|
||||
APPSPAPWN_DUMP("Sandbox sandboxNsFlags: %{public}x ", sandbox->sandboxNsFlags);
|
||||
APPSPAPWN_DUMP("Sandbox topSandboxSwitch: %{public}s", sandbox->topSandboxSwitch ? "true" : "false");
|
||||
APPSPAPWN_DUMP("Sandbox appFullMountEnable: %{public}s", sandbox->appFullMountEnable ? "true" : "false");
|
||||
APPSPAPWN_DUMP("Sandbox pidNamespaceSupport: %{public}s", sandbox->pidNamespaceSupport ? "true" : "false");
|
||||
APPSPAPWN_DUMP("Sandbox common info: ");
|
||||
|
||||
DumpSandboxQueue(&sandbox->requiredQueue.front, DumpSandboxSectionNode);
|
||||
DumpSandboxQueue(&sandbox->packageNameQueue.front, DumpSandboxSectionNode);
|
||||
DumpSandboxQueue(&sandbox->permissionQueue.front, DumpSandboxSectionNode);
|
||||
DumpSandboxQueue(&sandbox->spawnFlagsQueue.front, DumpSandboxSectionNode);
|
||||
DumpSandboxQueue(&sandbox->nameGroupsQueue.front, DumpSandboxSectionNode);
|
||||
}
|
||||
|
||||
static int PreLoadSandboxCfg(AppSpawnMgr *content)
|
||||
{
|
||||
AppSpawnSandboxCfg *sandbox = GetAppSpawnSandbox(content);
|
||||
APPSPAWN_CHECK(sandbox == NULL, return 0, "Sandbox has been load");
|
||||
|
||||
sandbox = CreateAppSpawnSandbox();
|
||||
APPSPAWN_CHECK_ONLY_EXPER(sandbox != NULL, return APPSPAWN_SYSTEM_ERROR);
|
||||
OH_ListAddTail(&sandbox->extData.node, &content->extData);
|
||||
|
||||
// load app sandbox config
|
||||
LoadAppSandboxConfig(sandbox, IsNWebSpawnMode(content));
|
||||
sandbox->maxPermissionIndex = PermissionRenumber(&sandbox->permissionQueue);
|
||||
|
||||
content->content.sandboxNsFlags = 0;
|
||||
if (IsNWebSpawnMode(content) || sandbox->pidNamespaceSupport) {
|
||||
content->content.sandboxNsFlags = sandbox->sandboxNsFlags;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SpawnBuildSandboxEnv(AppSpawnMgr *content, AppSpawningCtx *property)
|
||||
{
|
||||
AppSpawnSandboxCfg *appSandbox = GetAppSpawnSandbox(content);
|
||||
APPSPAWN_CHECK(appSandbox != NULL, return -1, "Failed to get sandbox for %{public}s", GetProcessName(property));
|
||||
// CLONE_NEWPID 0x20000000
|
||||
// CLONE_NEWNET 0x40000000
|
||||
if ((content->content.sandboxNsFlags & CLONE_NEWPID) == CLONE_NEWPID) {
|
||||
int ret = getprocpid();
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
int ret = MountSandboxConfigs(appSandbox, property, IsNWebSpawnMode(content));
|
||||
// for module test do not create sandbox
|
||||
if (strncmp(GetBundleName(property), MODULE_TEST_BUNDLE_NAME, strlen(MODULE_TEST_BUNDLE_NAME)) == 0) {
|
||||
return 0;
|
||||
}
|
||||
return ret == 0 ? 0 : APPSPAWN_SANDBOX_MOUNT_FAIL;
|
||||
}
|
||||
|
||||
static int AppendPermissionGid(const AppSpawnSandboxCfg *sandbox, AppSpawningCtx *property)
|
||||
{
|
||||
AppSpawnMsgDacInfo *dacInfo = (AppSpawnMsgDacInfo *)GetAppProperty(property, TLV_DAC_INFO);
|
||||
APPSPAWN_CHECK(dacInfo != NULL, return APPSPAWN_TLV_NONE,
|
||||
"No tlv %{public}d in msg %{public}s", TLV_DAC_INFO, GetProcessName(property));
|
||||
|
||||
ListNode *node = sandbox->permissionQueue.front.next;
|
||||
while (node != &sandbox->permissionQueue.front) {
|
||||
SandboxPermissionNode *permissionNode = (SandboxPermissionNode *)ListEntry(node, SandboxMountNode, node);
|
||||
if (!CheckAppPermissionFlagSet(property, (uint32_t)permissionNode->permissionIndex)) {
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
if (permissionNode->section.gidCount == 0) {
|
||||
node = node->next;
|
||||
continue;
|
||||
}
|
||||
APPSPAWN_LOGV("Append permission gid %{public}s to %{public}s permission: %{public}u message: %{public}u",
|
||||
permissionNode->section.name, GetProcessName(property), permissionNode->section.gidCount,
|
||||
dacInfo->gidCount);
|
||||
size_t copyLen = permissionNode->section.gidCount;
|
||||
if ((permissionNode->section.gidCount + dacInfo->gidCount) > APP_MAX_GIDS) {
|
||||
APPSPAWN_LOGW("More gid for %{public}s msg count %{public}u permission %{public}u",
|
||||
GetProcessName(property), dacInfo->gidCount, permissionNode->section.gidCount);
|
||||
copyLen = APP_MAX_GIDS - dacInfo->gidCount;
|
||||
}
|
||||
int ret = memcpy_s(&dacInfo->gidTable[dacInfo->gidCount], sizeof(gid_t) * copyLen,
|
||||
permissionNode->section.gidTable, sizeof(gid_t) * copyLen);
|
||||
if (ret != EOK) {
|
||||
APPSPAWN_LOGW("Failed to append permission %{public}s gid to %{public}s",
|
||||
permissionNode->section.name, GetProcessName(property));
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool IsSystemConstMounted(const AppSpawnSandboxCfg *sandbox, AppSpawnMsgDacInfo *info)
|
||||
{
|
||||
uid_t uid = info->uid / UID_BASE;
|
||||
for (uint32_t i = 0; i < ARRAY_LENGTH(sandbox->systemUids); i++) {
|
||||
if (sandbox->systemUids[i] == uid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int SetSystemConstMounted(AppSpawnSandboxCfg *sandbox, AppSpawnMsgDacInfo *info)
|
||||
{
|
||||
uid_t uid = info->uid / UID_BASE;
|
||||
for (uint32_t i = 0; i < ARRAY_LENGTH(sandbox->systemUids); i++) {
|
||||
if (sandbox->systemUids[i] == INVALID_UID) {
|
||||
sandbox->systemUids[i] = uid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SpawnPrepareSandboxCfg(AppSpawnMgr *content, AppSpawningCtx *property)
|
||||
{
|
||||
APPSPAWN_CHECK_ONLY_EXPER(content != NULL, return -1);
|
||||
APPSPAWN_CHECK_ONLY_EXPER(property != NULL, return -1);
|
||||
APPSPAWN_LOGV("Prepare sandbox config %{public}s", GetProcessName(property));
|
||||
AppSpawnSandboxCfg *sandbox = GetAppSpawnSandbox(content);
|
||||
APPSPAWN_CHECK(sandbox != NULL, return -1, "Failed to get sandbox for %{public}s", GetProcessName(property));
|
||||
|
||||
if (sandbox->appFullMountEnable) {
|
||||
int index = GetPermissionIndexInQueue(&sandbox->permissionQueue, FILE_CROSS_APP_MODE);
|
||||
if (index > 0) {
|
||||
SetAppPermissionFlags(property, index);
|
||||
}
|
||||
}
|
||||
int ret = AppendPermissionGid(sandbox, property);
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "Failed to add gid for %{public}s", GetProcessName(property));
|
||||
|
||||
AppSpawnMsgDacInfo *info = (AppSpawnMsgDacInfo *)GetAppProperty(property, TLV_DAC_INFO);
|
||||
APPSPAWN_CHECK(info != NULL, return APPSPAWN_TLV_NONE,
|
||||
"No tlv %{public}d in msg %{public}s", TLV_DAC_INFO, GetProcessName(property));
|
||||
if (!IsSystemConstMounted(sandbox, info)) {
|
||||
ret = StagedMountSystemConst(sandbox, property, IsNWebSpawnMode(content));
|
||||
APPSPAWN_CHECK(ret == 0, return ret, "Failed to mount system-const for %{public}s", GetProcessName(property));
|
||||
SetSystemConstMounted(sandbox, info);
|
||||
} else {
|
||||
APPSPAWN_LOGW("System-const config [uid: %{public}u] has been set", info->uid / UID_BASE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_CONSTRUCTOR(void)
|
||||
{
|
||||
APPSPAWN_LOGV("Load sandbox module ...");
|
||||
AddPreloadHook(HOOK_PRIO_SANDBOX, PreLoadSandboxCfg);
|
||||
AddAppSpawnHook(STAGE_PARENT_PRE_FORK, HOOK_PRIO_SANDBOX, SpawnPrepareSandboxCfg);
|
||||
AddAppSpawnHook(STAGE_CHILD_EXECUTE, HOOK_PRIO_SANDBOX, SpawnBuildSandboxEnv);
|
||||
}
|
||||
|
||||
MODULE_DESTRUCTOR(void)
|
||||
{
|
||||
ClearVariable();
|
||||
ClearExpandAppSandboxConfigHandle();
|
||||
}
|
38
modules/sysevent/BUILD.gn
Executable file
38
modules/sysevent/BUILD.gn
Executable file
@ -0,0 +1,38 @@
|
||||
# Copyright (c) 2024 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.
|
||||
import("//base/startup/appspawn/appspawn.gni")
|
||||
import("//build/ohos.gni")
|
||||
|
||||
ohos_shared_library("event_reporter") {
|
||||
sources = [ "event_reporter.cpp" ]
|
||||
include_dirs = [
|
||||
".",
|
||||
"${appspawn_path}/common",
|
||||
"${appspawn_path}/standard",
|
||||
]
|
||||
external_deps = [
|
||||
"hilog:libhilog",
|
||||
"hisysevent:libhisysevent",
|
||||
"init:libbegetutil",
|
||||
]
|
||||
deps = [ "${appspawn_path}/modules/module_engine:libappspawn_module_engine" ]
|
||||
subsystem_name = "${subsystem_name}"
|
||||
part_name = "${part_name}"
|
||||
install_enable = true
|
||||
if (target_cpu == "arm64" || target_cpu == "x86_64" ||
|
||||
target_cpu == "riscv64") {
|
||||
module_install_dir = "lib64/appspawn/common"
|
||||
} else {
|
||||
module_install_dir = "lib/appspawn/common"
|
||||
}
|
||||
}
|
55
modules/sysevent/event_reporter.cpp
Executable file
55
modules/sysevent/event_reporter.cpp
Executable file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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 <hisysevent.h>
|
||||
|
||||
#include "appspawn_hook.h"
|
||||
#include "appspawn_manager.h"
|
||||
#include "appspawn_utils.h"
|
||||
|
||||
using namespace OHOS::HiviewDFX;
|
||||
namespace OHOS {
|
||||
namespace system {
|
||||
constexpr char KEY_PROCESS_EXIT[] = "PROCESS_EXIT";
|
||||
constexpr char KEY_NAME[] = "PROCESS_NAME";
|
||||
constexpr char KEY_PID[] = "PID";
|
||||
constexpr char KEY_UID[] = "UID";
|
||||
constexpr char KEY_STATUS[] = "STATUS";
|
||||
constexpr int32_t MAX_NAME_LENGTH = 1024;
|
||||
|
||||
void ProcessMgrRemoveApp(const char* processName, int pid, int uid, int status)
|
||||
{
|
||||
std::string pname = "Unknown";
|
||||
if ((processName != NULL) && (strlen(processName) <= MAX_NAME_LENGTH)) {
|
||||
pname = std::string(processName, strlen(processName));
|
||||
}
|
||||
|
||||
HiSysEventWrite(HiSysEvent::Domain::STARTUP, KEY_PROCESS_EXIT, HiSysEvent::EventType::BEHAVIOR,
|
||||
KEY_NAME, pname, KEY_PID, pid, KEY_UID, uid, KEY_STATUS, status);
|
||||
}
|
||||
} // namespace system
|
||||
} // namespace OHOS
|
||||
|
||||
static int ProcessMgrRemoveApp(const AppSpawnMgr *content, const AppSpawnedProcessInfo *appInfo)
|
||||
{
|
||||
OHOS::system::ProcessMgrRemoveApp(appInfo->name, appInfo->pid, appInfo->uid, appInfo->exitStatus);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_CONSTRUCTOR(void)
|
||||
{
|
||||
APPSPAWN_LOGV("Load sys event module ...");
|
||||
AddProcessMgrHook(STAGE_SERVER_APP_DIED, 0, ProcessMgrRemoveApp);
|
||||
}
|
@ -22,7 +22,7 @@
|
||||
|
||||
#include "interfaces/innerkits/include/appspawn_msg.h"
|
||||
#include "interfaces/innerkits_new/include/appspawn.h"
|
||||
#include "interfaces/innerkits_new/module_engine/include/appspawn_msg.h"
|
||||
#include "modules/module_engine/include/appspawn_msg.h"
|
||||
#include "appspawn_service.h"
|
||||
#include "appspawn_utils.h"
|
||||
#include "securec.h"
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <sched.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "securec.h"
|
||||
#include "selinux/selinux.h"
|
||||
@ -605,6 +606,79 @@ int GetAppSpawnClientFromArg(int argc, char *const argv[], AppSpawnClientExt *cl
|
||||
return ret;
|
||||
}
|
||||
|
||||
static pid_t GetPidByName(const char *name)
|
||||
{
|
||||
int pid = -1; // initial pid set to -1
|
||||
DIR *dir = opendir("/proc");
|
||||
if (dir == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct dirent *entry;
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
if (entry->d_type != DT_DIR) {
|
||||
continue;
|
||||
}
|
||||
long pidNum = strtol(entry->d_name, NULL, 10); // pid will not exceed a 10-digit decimal number
|
||||
if (pidNum <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char path[32]; // path that contains the process name
|
||||
if (snprintf_s(path, sizeof(path), sizeof(path) - 1, "/proc/%s/comm", entry->d_name) < 0) {
|
||||
continue;
|
||||
}
|
||||
FILE *file = fopen(path, "r");
|
||||
if (file == NULL) {
|
||||
continue;
|
||||
}
|
||||
char buffer[32]; // read the process name
|
||||
if (fgets(buffer, sizeof(buffer), file) == NULL) {
|
||||
(void)fclose(file);
|
||||
continue;
|
||||
}
|
||||
buffer[strcspn(buffer, "\n")] = 0;
|
||||
if (strcmp(buffer, name) != 0) {
|
||||
(void)fclose(file);
|
||||
continue;
|
||||
}
|
||||
|
||||
APPSPAWN_LOGI("get pid of %{public}s success", name);
|
||||
pid = (int)pidNum;
|
||||
(void)fclose(file);
|
||||
break;
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
return pid;
|
||||
}
|
||||
|
||||
static int NsInitFunc()
|
||||
{
|
||||
setuid(PID_NS_INIT_UID);
|
||||
setgid(PID_NS_INIT_GID);
|
||||
setcon("u:r:pid_ns_init:s0");
|
||||
char* argv[] = {"/system/bin/pid_ns_init", NULL};
|
||||
execve("/system/bin/pid_ns_init", argv, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int GetNsPidFd(pid_t pid)
|
||||
{
|
||||
char nsPath[256]; // filepath of ns pid
|
||||
int ret = snprintf_s(nsPath, sizeof(nsPath), sizeof(nsPath) - 1, "/proc/%d/ns/pid", pid);
|
||||
if (ret < 0) {
|
||||
APPSPAWN_LOGE("SetPidNamespace failed, snprintf_s error:%{public}s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
int nsFd = open(nsPath, O_RDONLY);
|
||||
if (nsFd < 0) {
|
||||
APPSPAWN_LOGE("open ns pid:%{public}d failed, err:%{public}s", pid, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return nsFd;
|
||||
}
|
||||
|
||||
static int EnablePidNs(AppSpawnContent *content)
|
||||
{
|
||||
AppSpawnContentExt *appSpawnContent = (AppSpawnContentExt *)content;
|
||||
@ -616,16 +690,30 @@ static int EnablePidNs(AppSpawnContent *content)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = unshare(CLONE_NEWPID);
|
||||
APPSPAWN_CHECK(ret == 0, return -1, "unshare CLONE_NWEPID failed, errno=%{public}d", errno);
|
||||
// check if process pid_ns_init exists, this is the init process for pid namespace
|
||||
pid_t pid = GetPidByName("pid_ns_init");
|
||||
if (pid == -1) {
|
||||
APPSPAWN_LOGI("Start Create pid_ns_init");
|
||||
pid = clone(NsInitFunc, NULL, CLONE_NEWPID, NULL);
|
||||
if (pid < 0) {
|
||||
APPSPAWN_LOGE("clone pid ns init failed");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
APPSPAWN_LOGI("pid_ns_init exists, no need to create");
|
||||
}
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
setuid(PID_NS_INIT_UID);
|
||||
setgid(PID_NS_INIT_GID);
|
||||
setcon("u:r:pid_ns_init:s0");
|
||||
char* argv[] = {"/system/bin/pid_ns_init", NULL};
|
||||
execve("/system/bin/pid_ns_init", argv, NULL);
|
||||
content->nsSelfPidFd = GetNsPidFd(getpid());
|
||||
if (content->nsSelfPidFd < 0) {
|
||||
APPSPAWN_LOGE("open ns pid of appspawn fail");
|
||||
return -1;
|
||||
}
|
||||
|
||||
content->nsInitPidFd = GetNsPidFd(pid);
|
||||
if (content->nsInitPidFd < 0) {
|
||||
APPSPAWN_LOGE("open ns pid of pid_ns_init fail");
|
||||
close(content->nsSelfPidFd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
APPSPAWN_LOGI("Enable pid namespace success.");
|
||||
|
@ -702,6 +702,12 @@ static void AppSpawnRun(AppSpawnContent *content, int argc, char *const argv[])
|
||||
}
|
||||
LE_CloseSignalTask(LE_GetDefaultLoop(), appSpawnContent->sigHandler);
|
||||
// release resource
|
||||
if (content->nsInitPidFd > 0) {
|
||||
close(content->nsInitPidFd);
|
||||
}
|
||||
if (content->nsSelfPidFd > 0) {
|
||||
close(content->nsSelfPidFd);
|
||||
}
|
||||
OH_HashMapDestory(appSpawnContent->appMap, NULL);
|
||||
LE_CloseStreamTask(LE_GetDefaultLoop(), appSpawnContent->server);
|
||||
LE_CloseLoop(LE_GetDefaultLoop());
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include <stdbool.h>
|
||||
#include "interfaces/innerkits/include/appspawn_msg.h"
|
||||
#include "interfaces/innerkits_new/include/appspawn.h"
|
||||
#include "interfaces/innerkits_new/module_engine/include/appspawn_msg.h"
|
||||
#include "modules/module_engine/include/appspawn_msg.h"
|
||||
#include "appspawn_server.h"
|
||||
#include "init_hashmap.h"
|
||||
#include "loop_event.h"
|
||||
|
@ -29,6 +29,7 @@ ohos_executable("AppSpawnTest") {
|
||||
"${appspawn_path}/modules/ace_adapter",
|
||||
"${appspawn_path}/modules/common",
|
||||
"${appspawn_path}/modules/sandbox",
|
||||
"${appspawn_path}/modules//module_engine//include",
|
||||
"${appspawn_path}/test/moduletest/threadpool",
|
||||
"${appspawn_innerkits_path}/include",
|
||||
"${appspawn_innerkits_path}/client",
|
||||
@ -37,6 +38,7 @@ ohos_executable("AppSpawnTest") {
|
||||
"${appspawn_path}/test/mock",
|
||||
"${appspawn_path}/test/unittest",
|
||||
"${appspawn_path}/util/include",
|
||||
"${appspawn_path}/modules/module_engine/include",
|
||||
]
|
||||
|
||||
deps = [
|
||||
@ -82,6 +84,7 @@ ohos_moduletest("AppSpawnModuleTest") {
|
||||
"${appspawn_path}/test/mock",
|
||||
"${appspawn_path}/test/unittest",
|
||||
"${appspawn_path}/util/include",
|
||||
"${appspawn_path}/modules/module_engine/include",
|
||||
]
|
||||
|
||||
deps = [
|
||||
|
@ -34,6 +34,7 @@ ohos_unittest("AppSpawn_client_ut") {
|
||||
"waitpid=WaitpidStub",
|
||||
"HapContext=HapContextStub",
|
||||
"APPSPAWN_TEST",
|
||||
"APPSPAWN_CLIENT",
|
||||
"OHOS_DEBUG",
|
||||
"GRAPHIC_PERMISSION_CHECK",
|
||||
]
|
||||
@ -45,11 +46,13 @@ ohos_unittest("AppSpawn_client_ut") {
|
||||
"${appspawn_path}/adapter",
|
||||
"${appspawn_path}/adapter/sysevent",
|
||||
"${appspawn_path}/modules/sandbox",
|
||||
"${appspawn_path}/modules//module_engine//include",
|
||||
"${appspawn_path}/interfaces/innerkits_new/include",
|
||||
"${appspawn_path}/interfaces/innerkits_new/client",
|
||||
"${appspawn_path}/interfaces/innerkits_new/permission",
|
||||
"${appspawn_path}/util/include",
|
||||
"${appspawn_path}/interfaces/innerkits_new/module_engine/include",
|
||||
"${appspawn_path}/modules/module_engine/include",
|
||||
"//third_party/json/include",
|
||||
]
|
||||
sources = [
|
||||
|
Loading…
Reference in New Issue
Block a user