mirror of
https://gitee.com/openharmony/startup_init
synced 2024-11-27 10:20:46 +00:00
eaed55b921
Feature or Bugfix:Bugfix Binary Source: No Signed-off-by: cat <chenjinxiang3@huawei.com>
704 lines
24 KiB
C
Executable File
704 lines
24 KiB
C
Executable File
/*
|
|
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "sandbox.h"
|
|
|
|
#include <limits.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <sched.h>
|
|
#include <sys/mount.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/syscall.h>
|
|
#include <errno.h>
|
|
#include "beget_ext.h"
|
|
#include "config_policy_utils.h"
|
|
#include "init_utils.h"
|
|
#include "cJSON.h"
|
|
#include "list.h"
|
|
#include "sandbox_namespace.h"
|
|
#include "securec.h"
|
|
|
|
#define SANDBOX_ROOT_TAG "sandbox-root"
|
|
#define SANDBOX_MOUNT_PATH_TAG "mount-bind-paths"
|
|
#define SANDBOX_MOUNT_FILE_TAG "mount-bind-files"
|
|
#define SANDBOX_SOURCE "src-path"
|
|
#define SANDBOX_TARGET "sandbox-path"
|
|
#define SANDBOX_FLAGS "sandbox-flags"
|
|
#define SANDBOX_IGNORE_ERRORS "ignore"
|
|
#define SANDBOX_SYMLINK_TAG "symbol-links"
|
|
#define SANDBOX_SYMLINK_TARGET "target-name"
|
|
#define SANDBOX_SYMLINK_NAME "link-name"
|
|
|
|
#define SANDBOX_SYSTEM_CONFIG_FILE "etc/sandbox/system-sandbox.json"
|
|
#define SANDBOX_CHIPSET_CONFIG_FILE "etc/sandbox/chipset-sandbox.json"
|
|
|
|
#ifdef STARTUP_INIT_TEST
|
|
#define SANDBOX_TEST_CONFIG_FILE "/data/init_ut/test-sandbox.json"
|
|
#endif
|
|
|
|
#define SANDBOX_MOUNT_FLAGS_MS_BIND "bind"
|
|
#define SANDBOX_MOUNT_FLAGS_MS_PRIVATE "private"
|
|
#define SANDBOX_MOUNT_FLAGS_MS_REC "rec"
|
|
#define SANDBOX_MOUNT_FLAGS_MS_MOVE "move"
|
|
|
|
struct SandboxMountFlags {
|
|
const char *flag;
|
|
unsigned long value;
|
|
};
|
|
|
|
static const struct SandboxMountFlags FLAGS[] = {
|
|
{
|
|
.flag = "bind",
|
|
.value = MS_BIND,
|
|
},
|
|
{
|
|
.flag = "private",
|
|
.value = MS_PRIVATE,
|
|
},
|
|
{
|
|
.flag = "rec",
|
|
.value = MS_REC,
|
|
},
|
|
{
|
|
.flag = "move",
|
|
.value = MS_MOVE,
|
|
}
|
|
};
|
|
|
|
static sandbox_t g_systemSandbox = {};
|
|
static sandbox_t g_chipsetSandbox = {};
|
|
#ifdef STARTUP_INIT_TEST
|
|
static sandbox_t g_testSandbox = {};
|
|
#endif
|
|
|
|
struct SandboxMap {
|
|
const char *name;
|
|
sandbox_t *sandbox;
|
|
const char *configfile;
|
|
};
|
|
|
|
static const struct SandboxMap MAP[] = {
|
|
{
|
|
.name = "system",
|
|
.sandbox = &g_systemSandbox,
|
|
.configfile = SANDBOX_SYSTEM_CONFIG_FILE,
|
|
},
|
|
{
|
|
.name = "chipset",
|
|
.sandbox = &g_chipsetSandbox,
|
|
.configfile = SANDBOX_CHIPSET_CONFIG_FILE,
|
|
},
|
|
#ifdef STARTUP_INIT_TEST
|
|
{
|
|
.name = "test",
|
|
.sandbox = &g_testSandbox,
|
|
.configfile = SANDBOX_TEST_CONFIG_FILE,
|
|
}
|
|
#endif
|
|
};
|
|
|
|
static unsigned long GetSandboxMountFlags(cJSON *item)
|
|
{
|
|
BEGET_ERROR_CHECK(item != NULL, return 0, "Invalid parameter.");
|
|
char *str = cJSON_GetStringValue(item);
|
|
BEGET_CHECK(str != NULL, return 0);
|
|
for (size_t i = 0; i < ARRAY_LENGTH(FLAGS); i++) {
|
|
if (strcmp(str, FLAGS[i].flag) == 0) {
|
|
return FLAGS[i].value;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void FreeSandboxMountInfo(ListNode *list)
|
|
{
|
|
if (list == NULL) {
|
|
return;
|
|
}
|
|
mountlist_t *info = ListEntry(list, mountlist_t, node);
|
|
if (info == NULL) {
|
|
return;
|
|
}
|
|
if (info->source != NULL) {
|
|
free(info->source);
|
|
info->source = NULL;
|
|
}
|
|
if (info->target != NULL) {
|
|
free(info->target);
|
|
info->target = NULL;
|
|
}
|
|
free(info);
|
|
info = NULL;
|
|
return;
|
|
}
|
|
|
|
static void FreeSandboxLinkInfo(ListNode *list)
|
|
{
|
|
if (list == NULL) {
|
|
return;
|
|
}
|
|
linklist_t *info = ListEntry(list, linklist_t, node);
|
|
if (info == NULL) {
|
|
return;
|
|
}
|
|
if (info->target != NULL) {
|
|
free(info->target);
|
|
info->target = NULL;
|
|
}
|
|
if (info->linkName != NULL) {
|
|
free(info->linkName);
|
|
info->linkName = NULL;
|
|
}
|
|
free(info);
|
|
info = NULL;
|
|
return;
|
|
}
|
|
|
|
static int CompareSandboxListForMountTarget(ListNode *list, void *data)
|
|
{
|
|
if ((list == NULL) || (data == NULL)) {
|
|
return -1;
|
|
}
|
|
mountlist_t *info = ListEntry(list, mountlist_t, node);
|
|
if (info == NULL) {
|
|
return -1;
|
|
}
|
|
const char *mountTarget = (const char *)data;
|
|
return strcmp(info->target, mountTarget);
|
|
}
|
|
|
|
static void RemoveOldSandboxMountListNode(ListNode *head, const char *targetMount)
|
|
{
|
|
if ((head == NULL) || (targetMount == NULL)) {
|
|
return;
|
|
}
|
|
ListNode *node = OH_ListFind(head, (void *)targetMount, CompareSandboxListForMountTarget);
|
|
if (node == NULL) {
|
|
return;
|
|
}
|
|
OH_ListRemove(node);
|
|
FreeSandboxMountInfo(node);
|
|
}
|
|
|
|
static int CompareSandboxListForLinkName(ListNode *list, void *data)
|
|
{
|
|
if ((list == NULL) || (data == NULL)) {
|
|
return -1;
|
|
}
|
|
linklist_t *info = ListEntry(list, linklist_t, node);
|
|
if (info == NULL) {
|
|
return -1;
|
|
}
|
|
const char *linkName = (const char *)data;
|
|
return strcmp(info->linkName, linkName);
|
|
}
|
|
|
|
static void RemoveOldSandboxLinkListNode(ListNode *head, const char *linkName)
|
|
{
|
|
if ((head == NULL) || (linkName == NULL)) {
|
|
return;
|
|
}
|
|
ListNode *node = OH_ListFind(head, (void *)linkName, CompareSandboxListForLinkName);
|
|
if (node == NULL) {
|
|
return;
|
|
}
|
|
OH_ListRemove(node);
|
|
FreeSandboxLinkInfo(node);
|
|
}
|
|
|
|
typedef int (*AddInfoToSandboxCallback)(sandbox_t *sandbox, cJSON *item, const char *type);
|
|
|
|
static int AddMountInfoToSandbox(sandbox_t *sandbox, cJSON *item, const char *type)
|
|
{
|
|
BEGET_CHECK(sandbox != NULL && item != NULL && type != NULL, return -1);
|
|
char *srcPath = cJSON_GetStringValue(cJSON_GetObjectItem(item, SANDBOX_SOURCE));
|
|
BEGET_INFO_CHECK(srcPath != NULL, return 0, "Get src-path is null");
|
|
char *dstPath = cJSON_GetStringValue(cJSON_GetObjectItem(item, SANDBOX_TARGET));
|
|
BEGET_INFO_CHECK(dstPath != NULL, return 0, "Get sandbox-path is null");
|
|
cJSON *obj = cJSON_GetObjectItem(item, SANDBOX_FLAGS);
|
|
BEGET_INFO_CHECK(obj != NULL, return 0, "Get sandbox-flags is null");
|
|
int ret = cJSON_IsArray(obj);
|
|
BEGET_INFO_CHECK(ret, return 0, "Sandbox-flags is not array");
|
|
int count = cJSON_GetArraySize(obj);
|
|
BEGET_INFO_CHECK(count > 0, return 0, "Get sandbox-flags array size is zero");
|
|
mountlist_t *tmpMount = (mountlist_t *)calloc(1, sizeof(mountlist_t));
|
|
BEGET_ERROR_CHECK(tmpMount != NULL, return -1, "Failed calloc err=%d", errno);
|
|
tmpMount->source = strdup(srcPath);
|
|
BEGET_ERROR_CHECK(tmpMount->source != NULL, free(tmpMount); return -1, "Failed to dup source");
|
|
tmpMount->target = strdup(dstPath);
|
|
BEGET_ERROR_CHECK(tmpMount->target != NULL, free(tmpMount); return -1, "Failed to dup target");
|
|
for (int i = 0; i < count; i++) {
|
|
cJSON *item = cJSON_GetArrayItem(obj, i);
|
|
tmpMount->flags |= GetSandboxMountFlags(item);
|
|
}
|
|
tmpMount->ignoreErrors = false;
|
|
obj = cJSON_GetObjectItem(item, SANDBOX_IGNORE_ERRORS);
|
|
if (obj != NULL) {
|
|
if (cJSON_GetNumberValue(obj) == 1) {
|
|
tmpMount->ignoreErrors = true;
|
|
}
|
|
}
|
|
OH_ListInit(&tmpMount->node);
|
|
if (strcmp(type, SANDBOX_MOUNT_PATH_TAG) == 0) {
|
|
tmpMount->tag = SANDBOX_TAG_MOUNT_PATH;
|
|
RemoveOldSandboxMountListNode(&sandbox->pathMountsHead, dstPath);
|
|
OH_ListAddTail(&sandbox->pathMountsHead, &tmpMount->node);
|
|
} else if (strcmp(type, SANDBOX_MOUNT_FILE_TAG) == 0) {
|
|
tmpMount->tag = SANDBOX_TAG_MOUNT_FILE;
|
|
RemoveOldSandboxMountListNode(&sandbox->fileMountsHead, dstPath);
|
|
OH_ListAddTail(&sandbox->fileMountsHead, &tmpMount->node);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int AddSymbolLinksToSandbox(sandbox_t *sandbox, cJSON *item, const char *type)
|
|
{
|
|
BEGET_CHECK(!(sandbox == NULL || item == NULL || type == NULL), return -1);
|
|
BEGET_ERROR_CHECK(strcmp(type, SANDBOX_SYMLINK_TAG) == 0, return -1, "Type is not sandbox symbolLink.");
|
|
char *target = cJSON_GetStringValue(cJSON_GetObjectItem(item, SANDBOX_SYMLINK_TARGET));
|
|
BEGET_ERROR_CHECK(target != NULL, return 0, "Get target-name is null");
|
|
char *name = cJSON_GetStringValue(cJSON_GetObjectItem(item, SANDBOX_SYMLINK_NAME));
|
|
BEGET_ERROR_CHECK(name != NULL, return 0, "Get link-name is null");
|
|
linklist_t *tmpLink = (linklist_t *)calloc(1, sizeof(linklist_t));
|
|
BEGET_ERROR_CHECK(tmpLink != NULL, return -1, "Failed calloc err=%d", errno);
|
|
tmpLink->target = strdup(target);
|
|
BEGET_ERROR_CHECK(tmpLink->target != NULL, free(tmpLink); return -1, "Failed to dup target");
|
|
tmpLink->linkName = strdup(name);
|
|
BEGET_ERROR_CHECK(tmpLink->linkName != NULL, free(tmpLink); return -1, "Failed to dup linkName");
|
|
OH_ListInit(&tmpLink->node);
|
|
RemoveOldSandboxLinkListNode(&sandbox->linksHead, tmpLink->linkName);
|
|
OH_ListAddTail(&sandbox->linksHead, &tmpLink->node);
|
|
return 0;
|
|
}
|
|
|
|
static int GetSandboxInfo(sandbox_t *sandbox, cJSON *root, const char *itemName)
|
|
{
|
|
BEGET_ERROR_CHECK(!(sandbox == NULL || root == NULL || itemName == NULL), return -1,
|
|
"Get sandbox mount info with invalid argument");
|
|
cJSON *obj = cJSON_GetObjectItem(root, itemName);
|
|
BEGET_ERROR_CHECK(obj != NULL, return 0, "Cannot find item \' %s \' in sandbox config", itemName);
|
|
BEGET_ERROR_CHECK(cJSON_IsArray(obj), return 0, "ItemName %s with invalid type, should be array", itemName);
|
|
|
|
int counts = cJSON_GetArraySize(obj);
|
|
BEGET_ERROR_CHECK(counts > 0, return 0, "Item %s array size is zero.", itemName);
|
|
AddInfoToSandboxCallback func = NULL;
|
|
if (strcmp(itemName, SANDBOX_MOUNT_PATH_TAG) == 0) {
|
|
func = AddMountInfoToSandbox;
|
|
} else if (strcmp(itemName, SANDBOX_MOUNT_FILE_TAG) == 0) {
|
|
func = AddMountInfoToSandbox;
|
|
} else if (strcmp(itemName, SANDBOX_SYMLINK_TAG) == 0) {
|
|
func = AddSymbolLinksToSandbox;
|
|
} else {
|
|
BEGET_LOGE("Item %s is not support.", itemName);
|
|
return -1;
|
|
}
|
|
for (int i = 0; i < counts; i++) {
|
|
cJSON *item = cJSON_GetArrayItem(obj, i);
|
|
BEGET_ERROR_CHECK(item != NULL, return -1, "Failed get json array item %d", i);
|
|
BEGET_ERROR_CHECK(func(sandbox, item, itemName) == 0, return -1, "Failed add info to sandbox.");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int ParseSandboxConfig(cJSON *root, sandbox_t *sandbox)
|
|
{
|
|
BEGET_ERROR_CHECK(!(root == NULL || sandbox == NULL), return -1, "Invalid parameter.");
|
|
// sandbox rootpath must initialize according to the system configuration, and it can only be initialized once.
|
|
if (sandbox->rootPath == NULL) {
|
|
cJSON *sandboxRoot = cJSON_GetObjectItem(root, SANDBOX_ROOT_TAG);
|
|
BEGET_ERROR_CHECK(sandboxRoot != NULL, return -1,
|
|
"Cannot find item \' %s \' in sandbox config", SANDBOX_ROOT_TAG);
|
|
|
|
char *rootdir = cJSON_GetStringValue(sandboxRoot);
|
|
if (rootdir != NULL) {
|
|
sandbox->rootPath = strdup(rootdir);
|
|
BEGET_ERROR_CHECK(sandbox->rootPath != NULL, return -1,
|
|
"Get sandbox root path out of memory");
|
|
}
|
|
}
|
|
BEGET_ERROR_CHECK(GetSandboxInfo(sandbox, root, SANDBOX_MOUNT_PATH_TAG) == 0, return -1,
|
|
"config info %s error", SANDBOX_MOUNT_PATH_TAG);
|
|
BEGET_ERROR_CHECK(GetSandboxInfo(sandbox, root, SANDBOX_MOUNT_FILE_TAG) == 0, return -1,
|
|
"config info %s error", SANDBOX_MOUNT_FILE_TAG);
|
|
BEGET_ERROR_CHECK(GetSandboxInfo(sandbox, root, SANDBOX_SYMLINK_TAG) == 0, return -1,
|
|
"config info %s error", SANDBOX_SYMLINK_TAG);
|
|
return 0;
|
|
}
|
|
|
|
static const struct SandboxMap *GetSandboxMapByName(const char *name)
|
|
{
|
|
BEGET_ERROR_CHECK(name != NULL, return NULL, "Sandbox map name is NULL.");
|
|
int len = ARRAY_LENGTH(MAP);
|
|
for (int i = 0; i < len; i++) {
|
|
if (strcmp(MAP[i].name, name) == 0) {
|
|
return &MAP[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static int ParseInitSandboxConfigFile(sandbox_t *sandbox, const char *sandboxConfigFile, const char *name)
|
|
{
|
|
char *contents = ReadFileToBuf(sandboxConfigFile);
|
|
if (contents == NULL) {
|
|
return 0;
|
|
}
|
|
cJSON *root = cJSON_Parse(contents);
|
|
free(contents);
|
|
BEGET_ERROR_CHECK(root != NULL, return -1, "Parse sandbox config \' %s \' failed", sandboxConfigFile);
|
|
int ret = ParseSandboxConfig(root, sandbox);
|
|
cJSON_Delete(root);
|
|
if (ret < 0) {
|
|
DestroySandbox(name);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void ParseInitSandboxConfigPath(sandbox_t *sandbox, const char *sandboxConfig, const char *name)
|
|
{
|
|
CfgFiles *files = GetCfgFiles(sandboxConfig);
|
|
for (int i = 0; files && i < MAX_CFG_POLICY_DIRS_CNT; i++) {
|
|
if (files->paths[i]) {
|
|
BEGET_LOGI("Parse sandbox cfg file is %s", files->paths[i]);
|
|
if (ParseInitSandboxConfigFile(sandbox, files->paths[i], name) < 0) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
FreeCfgFiles(files);
|
|
}
|
|
|
|
static void InitSandbox(sandbox_t *sandbox, const char *sandboxConfig, const char *name)
|
|
{
|
|
BEGET_ERROR_CHECK(!(sandbox == NULL || sandboxConfig == NULL || name == NULL), return,
|
|
"Init sandbox with invalid arguments");
|
|
if (sandbox->isCreated) {
|
|
BEGET_LOGE("Sandbox %s has created.", name);
|
|
return;
|
|
}
|
|
if (UnshareNamespace(CLONE_NEWNS) < 0) {
|
|
return;
|
|
}
|
|
sandbox->ns = GetNamespaceFd("/proc/self/ns/mnt");
|
|
BEGET_ERROR_CHECK(!(sandbox->ns < 0), return, "Get sandbox namespace fd is failed");
|
|
|
|
BEGET_ERROR_CHECK(strcpy_s(sandbox->name, MAX_BUFFER_LEN - 1, name) == 0, return, "Failed to copy sandbox name");
|
|
OH_ListInit(&sandbox->pathMountsHead);
|
|
OH_ListInit(&sandbox->fileMountsHead);
|
|
OH_ListInit(&sandbox->linksHead);
|
|
// parse json config
|
|
#ifdef STARTUP_INIT_TEST
|
|
(void)ParseInitSandboxConfigFile(sandbox, sandboxConfig, name);
|
|
#else
|
|
ParseInitSandboxConfigPath(sandbox, sandboxConfig, name);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
static int CheckAndMakeDir(const char *dir, mode_t mode)
|
|
{
|
|
struct stat sb;
|
|
|
|
if ((stat(dir, &sb) == 0) && S_ISDIR(sb.st_mode)) {
|
|
BEGET_LOGI("Mount point \' %s \' already exist, no need to mkdir", dir);
|
|
return 0;
|
|
} else {
|
|
if (errno == ENOENT) {
|
|
BEGET_ERROR_CHECK(MakeDirRecursive(dir, mode) == 0, return -1,
|
|
"Failed MakeDirRecursive %s, err=%d", dir, errno);
|
|
} else {
|
|
BEGET_LOGW("Failed to access mount point \' %s \', err = %d", dir, errno);
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int BindMount(const char *source, const char *target, unsigned long flags, SandboxTag tag)
|
|
{
|
|
if (source == NULL || target == NULL) {
|
|
BEGET_LOGE("Mount with invalid arguments");
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
unsigned long tmpflags = flags;
|
|
mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
|
|
if (tag == SANDBOX_TAG_MOUNT_PATH) {
|
|
BEGET_ERROR_CHECK(CheckAndMakeDir(target, mode) == 0, return -1, "Failed make %s dir.", target);
|
|
} else if (tag == SANDBOX_TAG_MOUNT_FILE) {
|
|
BEGET_ERROR_CHECK(CheckAndCreatFile(target, mode) == 0, return -1, "Failed make %s file.", target);
|
|
} else {
|
|
BEGET_LOGE("Tag is error.");
|
|
return -1;
|
|
}
|
|
|
|
BEGET_WARNING_CHECK((tmpflags & MS_BIND) != 0, tmpflags |= MS_BIND,
|
|
"Not configure mount bind, must configure mount bind flag.");
|
|
BEGET_WARNING_CHECK((tmpflags & MS_REC) != 0, tmpflags |= MS_REC,
|
|
"Not configure mount rec, must configure mount rec flag.");
|
|
|
|
// do mount
|
|
if (mount(source, target, NULL, tmpflags, NULL) != 0) {
|
|
BEGET_LOGE("Failed to bind mount \' %s \' to \' %s \', err = %d", source, target, errno);
|
|
if (errno != ENOTDIR) { // mount errno is 'Not a directory' can ignore
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static bool IsValidSandbox(sandbox_t *sandbox)
|
|
{
|
|
BEGET_ERROR_CHECK(sandbox != NULL, return false, "preparing sandbox with invalid argument");
|
|
|
|
if (sandbox->rootPath == NULL) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static int MountSandboxNode(ListNode *list, void *data)
|
|
{
|
|
if ((list == NULL) || (data == NULL)) {
|
|
return 0;
|
|
}
|
|
const char *rootPath = (const char *)data;
|
|
mountlist_t *info = ListEntry(list, mountlist_t, node);
|
|
char target[PATH_MAX] = {};
|
|
BEGET_ERROR_CHECK(snprintf_s(target, PATH_MAX, PATH_MAX - 1, "%s%s", rootPath, info->target) > 0,
|
|
return -1, "Failed snprintf_s err=%d", errno);
|
|
int rc = BindMount(info->source, target, info->flags, info->tag);
|
|
if (rc != 0) {
|
|
BEGET_LOGW("Failed bind mount %s to %s.", info->source, target);
|
|
if (info->ignoreErrors == false) {
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int MountSandboxInfo(struct ListNode *head, const char *rootPath, SandboxTag tag)
|
|
{
|
|
if ((head == NULL) || (rootPath == NULL)) {
|
|
return 0;
|
|
}
|
|
int ret = OH_ListTraversal(head, (void *)rootPath, MountSandboxNode, 1);
|
|
return ret;
|
|
}
|
|
|
|
static int LinkSandboxNode(ListNode *list, void *data)
|
|
{
|
|
if ((list == NULL) || (data == NULL)) {
|
|
return 0;
|
|
}
|
|
const char *rootPath = (const char *)data;
|
|
linklist_t *info = ListEntry(list, linklist_t, node);
|
|
char linkName[PATH_MAX] = {0};
|
|
BEGET_ERROR_CHECK(!(snprintf_s(linkName, PATH_MAX, PATH_MAX - 1, "%s%s", rootPath, info->linkName) < 0),
|
|
return -1, "snprintf_s failed, err=%d", errno);
|
|
int rc = symlink(info->target, linkName);
|
|
if (rc != 0) {
|
|
if (errno == EEXIST) {
|
|
BEGET_LOGW("symbol link name \' %s \' already exist", linkName);
|
|
} else {
|
|
BEGET_LOGE("Failed to link \' %s \' to \' %s \', err = %d", info->target, linkName, errno);
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int LinkSandboxInfo(struct ListNode *head, const char *rootPath)
|
|
{
|
|
if ((head == NULL) || (rootPath == NULL)) {
|
|
return 0;
|
|
}
|
|
int ret = OH_ListTraversal(head, (void *)rootPath, LinkSandboxNode, 1);
|
|
return ret;
|
|
}
|
|
|
|
int PrepareSandbox(const char *name)
|
|
{
|
|
BEGET_ERROR_CHECK(name != NULL, return -1, "Prepare sandbox name is NULL.");
|
|
BEGET_ERROR_CHECK(getuid() == 0, return -1, "Current process uid is not root, exit.");
|
|
const struct SandboxMap *map = GetSandboxMapByName(name);
|
|
BEGET_ERROR_CHECK(map != NULL, return -1, "Cannot get sandbox map by name %s.", name);
|
|
sandbox_t *sandbox = map->sandbox;
|
|
BEGET_CHECK(IsValidSandbox(sandbox) == true, return -1);
|
|
BEGET_INFO_CHECK(sandbox->isCreated == false, return 0, "Sandbox %s already created", sandbox->name);
|
|
BEGET_CHECK(sandbox->rootPath != NULL, return -1);
|
|
mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
|
|
BEGET_ERROR_CHECK(CheckAndMakeDir(sandbox->rootPath, mode) == 0, return -1, "Failed root %s.", sandbox->rootPath);
|
|
int rc = mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL);
|
|
BEGET_ERROR_CHECK(rc == 0, return -1, "Failed set mount slave err = %d", errno);
|
|
rc = BindMount(sandbox->rootPath, sandbox->rootPath, MS_BIND | MS_REC, SANDBOX_TAG_MOUNT_PATH);
|
|
BEGET_ERROR_CHECK(rc == 0, return -1, "Failed to mount rootpath bind err = %d", errno);
|
|
|
|
// 1) walk through all mounts and do bind mount
|
|
rc = MountSandboxInfo(&sandbox->pathMountsHead, sandbox->rootPath, SANDBOX_TAG_MOUNT_PATH);
|
|
BEGET_CHECK(rc == 0, return -1);
|
|
|
|
rc = MountSandboxInfo(&sandbox->fileMountsHead, sandbox->rootPath, SANDBOX_TAG_MOUNT_FILE);
|
|
BEGET_CHECK(rc == 0, return -1);
|
|
|
|
// 2) walk through all links and do symbol link
|
|
rc = LinkSandboxInfo(&sandbox->linksHead, sandbox->rootPath);
|
|
BEGET_CHECK(rc == 0, return -1);
|
|
|
|
BEGET_ERROR_CHECK(chdir(sandbox->rootPath) == 0, return -1, "Change to %s, err = %d", sandbox->rootPath, errno);
|
|
BEGET_ERROR_CHECK(syscall(SYS_pivot_root, sandbox->rootPath, sandbox->rootPath) == 0, return -1,
|
|
"Failed system call pivot root, err=%d", errno);
|
|
BEGET_ERROR_CHECK(umount2(".", MNT_DETACH) == 0, return -1, "Failed umount2 MNT_DETACH, err=%d", errno);
|
|
sandbox->isCreated = true;
|
|
return 0;
|
|
}
|
|
|
|
bool InitSandboxWithName(const char *name)
|
|
{
|
|
bool isFound = false;
|
|
if (name == NULL) {
|
|
BEGET_LOGE("Init sandbox name is NULL.");
|
|
return isFound;
|
|
}
|
|
const struct SandboxMap *map = GetSandboxMapByName(name);
|
|
if (map != NULL) {
|
|
InitSandbox(map->sandbox, map->configfile, name);
|
|
isFound = true;
|
|
}
|
|
|
|
if (!isFound) {
|
|
BEGET_LOGE("Cannot find sandbox with name %s.", name);
|
|
}
|
|
return isFound;
|
|
}
|
|
|
|
void DestroySandbox(const char *name)
|
|
{
|
|
if (name == NULL) {
|
|
BEGET_LOGE("Destroy sandbox name is NULL.");
|
|
return;
|
|
}
|
|
const struct SandboxMap *map = GetSandboxMapByName(name);
|
|
if (map == NULL) {
|
|
BEGET_LOGE("Cannot get sandbox map by name %s.", name);
|
|
return;
|
|
}
|
|
sandbox_t *sandbox = map->sandbox;
|
|
|
|
BEGET_CHECK(sandbox != NULL, return);
|
|
|
|
if (sandbox->rootPath != NULL) {
|
|
free(sandbox->rootPath);
|
|
sandbox->rootPath = NULL;
|
|
}
|
|
OH_ListRemoveAll(&sandbox->linksHead, FreeSandboxLinkInfo);
|
|
OH_ListRemoveAll(&sandbox->fileMountsHead, FreeSandboxMountInfo);
|
|
OH_ListRemoveAll(&sandbox->pathMountsHead, FreeSandboxMountInfo);
|
|
|
|
if (sandbox->ns > 0) {
|
|
(void)close(sandbox->ns);
|
|
}
|
|
sandbox->isCreated = false;
|
|
return;
|
|
}
|
|
|
|
int EnterSandbox(const char *name)
|
|
{
|
|
if (name == NULL) {
|
|
BEGET_LOGE("Sandbox name is NULL.");
|
|
return -1;
|
|
}
|
|
const struct SandboxMap *map = GetSandboxMapByName(name);
|
|
if (map == NULL) {
|
|
BEGET_LOGE("Cannot get sandbox map by name %s.", name);
|
|
return -1;
|
|
}
|
|
sandbox_t *sandbox = map->sandbox;
|
|
|
|
BEGET_CHECK(sandbox != NULL, return -1);
|
|
if (sandbox->isCreated == false) {
|
|
BEGET_LOGE("Sandbox %s has not been created.", name);
|
|
return -1;
|
|
}
|
|
if (sandbox->ns > 0) {
|
|
BEGET_ERROR_CHECK(!(SetNamespace(sandbox->ns, CLONE_NEWNS) < 0), return -1,
|
|
"Cannot enter mount namespace for sandbox \' %s \', err=%d.", name, errno);
|
|
} else {
|
|
BEGET_LOGE("Sandbox \' %s \' namespace fd is invalid.", name);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int DumpSandboxMountInfo(ListNode *list, void *data)
|
|
{
|
|
if (list == NULL) {
|
|
return -1;
|
|
}
|
|
mountlist_t *info = ListEntry(list, mountlist_t, node);
|
|
if (info != NULL) {
|
|
if (info->source != NULL) {
|
|
printf("Sandbox mounts list source: %s \n", info->source);
|
|
}
|
|
if (info->target != NULL) {
|
|
printf("Sandbox mounts list target: %s \n", info->target);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int DumpSandboxLinkInfo(ListNode *list, void *data)
|
|
{
|
|
if (list == NULL) {
|
|
return -1;
|
|
}
|
|
linklist_t *info = ListEntry(list, linklist_t, node);
|
|
if (info != NULL) {
|
|
if (info->linkName != NULL) {
|
|
printf("Sandbox link list name: %s \n", info->linkName);
|
|
}
|
|
if (info->target != NULL) {
|
|
printf("Sandbox link list target: %s \n", info->target);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void DumpSandboxByName(const char *name)
|
|
{
|
|
if (name == NULL) {
|
|
BEGET_LOGE("Init sandbox name is NULL.");
|
|
return;
|
|
}
|
|
const struct SandboxMap *map = GetSandboxMapByName(name);
|
|
if (map == NULL) {
|
|
return;
|
|
}
|
|
printf("Sandbox Map name: %s \n", map->name);
|
|
printf("Sandbox Map config file: %s. \n", map->configfile);
|
|
printf("Sandbox name: %s. \n", map->sandbox->name);
|
|
printf("Sandbox root path is %s. \n", map->sandbox->rootPath);
|
|
printf("Sandbox mounts info: \n");
|
|
OH_ListTraversal(&map->sandbox->pathMountsHead, NULL, DumpSandboxMountInfo, 0);
|
|
OH_ListTraversal(&map->sandbox->fileMountsHead, NULL, DumpSandboxMountInfo, 0);
|
|
printf("Sandbox links info: \n");
|
|
OH_ListTraversal(&map->sandbox->linksHead, NULL, DumpSandboxLinkInfo, 0);
|
|
return;
|
|
}
|