From 0667ccb27829d58dd63110d6cb3460a958d28427 Mon Sep 17 00:00:00 2001 From: HumbleHunger <2495970924@qq.com> Date: Tue, 3 Aug 2021 17:30:00 +0800 Subject: [PATCH 1/2] iSulad: Add the function of isolating the user namespaces Signed-off-by: HumbleHunger <2495970924@qq.com> --- CI/test_cases/container_cases/userns_remap.sh | 256 ++++++++++++++++++ src/cmd/isula/base/create.c | 10 + src/cmd/isula/base/create.h | 7 + src/cmd/isulad/isulad_commands.h | 9 +- src/cmd/isulad/main.c | 71 +++++ src/daemon/config/isulad_config.c | 23 ++ src/daemon/config/isulad_config.h | 1 + .../executor/container_cb/execution_create.c | 8 + .../executor/container_cb/execution_network.c | 33 ++- .../graphdriver/overlay2/driver_overlay2.c | 81 +++++- .../graphdriver/overlay2/driver_overlay2.h | 2 +- .../modules/image/oci/storage/storage.c | 9 + src/daemon/modules/runtime/engines/engine.c | 33 ++- src/daemon/modules/spec/specs.c | 34 ++- src/daemon/modules/spec/specs_mount.c | 36 ++- src/daemon/modules/volume/local.c | 10 +- src/utils/cutils/utils_file.c | 25 ++ src/utils/cutils/utils_file.h | 1 + src/utils/tar/util_archive.c | 3 + src/utils/tar/util_archive.h | 2 + 20 files changed, 624 insertions(+), 30 deletions(-) create mode 100755 CI/test_cases/container_cases/userns_remap.sh diff --git a/CI/test_cases/container_cases/userns_remap.sh b/CI/test_cases/container_cases/userns_remap.sh new file mode 100755 index 00000000..21496941 --- /dev/null +++ b/CI/test_cases/container_cases/userns_remap.sh @@ -0,0 +1,256 @@ +#!/bin/bash + +####################################################################### +##- @Copyright (C) Huawei Technologies., Ltd. 2021. All rights reserved. +# - iSulad licensed under the Mulan PSL v2. +# - You can use this software according to the terms and conditions of the Mulan PSL v2. +# - You may obtain a copy of Mulan PSL v2 at: +# - http://license.coscl.org.cn/MulanPSL2 +# - THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +# - IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +# - PURPOSE. +# - See the Mulan PSL v2 for more details. +##- @Description:CI +##- @Author: liuyuji +##- @Create: 2021-08-20 +####################################################################### + +source ../helpers.sh + +ISULAD_ROOT_PATH="/var/lib/isulad/100000.100000" +LCR_ROOT_PATH="/var/lib/isulad/100000.100000/engines/lcr" +CONTAINER_PATH="/var/lib/isulad/100000.100000/storage/overlay" +IDMAP="100000:100000" +ROOT="0:0" + +function check_idmap_of_file() +{ + local ret=0 + + idmap=$(stat -c"%u:%g" ${1}) + [[ "${idmap}" != "${IDMAP}" ]] && msg_err "${2}" && ((ret++)) + + return ${ret} +} + +function check_idmap_of_file_in_container() +{ + local ret=0 + + idmap=$(isula exec -it ${1} stat -c"%u:%g" ${2}) + # delete \r of iamap + idmap=$(echo ${idmap} | sed -e 's/\r//g') + + [[ "${idmap}" != "${ROOT}" ]] && msg_err "${3}" && ((ret++)) + + return ${ret} +} + +function start_isulad_with_userns_remap() +{ + local test="start_isulad_with_userns_remap with userns-remap = 100000:100000:65535 => (${FUNCNAME[@]})" + + msg_info "${test} starting..." + + check_valgrind_log + [[ $? != 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - memory leak before current testcase, please check...." && return ${FAILURE} + + start_isulad_with_valgrind --userns-remap="100000:100000:65535" +} + +function check_the_management_directory_for_userns_remap() +{ + local ret=0 + local test="check_the_management_directory_for_userns_remap => (${FUNCNAME[@]})" + + msg_info "${test} starting..." + + check_idmap_of_file ${ISULAD_ROOT_PATH}/engines "${FUNCNAME[0]}:${LINENO} - The idmap of the storage directory is not correctly mapped" + [[ $? != 0 ]] && ((ret++)) + + check_idmap_of_file ${ISULAD_ROOT_PATH}/storage "${FUNCNAME[0]}:${LINENO} - The idmap of the storage directory is not correctly mapped" + [[ $? != 0 ]] && ((ret++)) + + check_idmap_of_file ${ISULAD_ROOT_PATH}/volumes "${FUNCNAME[0]}:${LINENO} - The idmap of the volumes directory is not correctly mapped" + [[ $? != 0 ]] && ((ret++)) + + mod=$(stat -c"%a" ${ISULAD_ROOT_PATH}/mnt) + [[ $mod != 751 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - The permissions of the mnt directory are not set correctly" && ((ret++)) + + mod=$(stat -c"%a" ${ISULAD_ROOT_PATH}/mnt/rootfs) + [[ $mod != 751 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - The permissions of the rootfs directory are not set correctly" && ((ret++)) + + msg_info "${test} finished with return ${ret}..." + return ${ret} +} + +function test_userns_remap_with_pull_image() +{ + local ret=0 + local image="busybox" + local test="test_userns_remap_with_pull_image => (${FUNCNAME[@]})" + + msg_info "${test} starting..." + + isula pull ${image} + [[ $? != 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - failed to pull image: ${image}" && return ${FAILURE} + + isula images | grep busybox + [[ $? != 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - missing list image: ${image}" && ((ret++)) + + layer_id=$(isula inspect -f '{{.image.top_layer}}' ${image}) + + check_idmap_of_file ${CONTAINER_PATH}/${layer_id}/diff "${FUNCNAME[0]}:${LINENO} - The idmap of the engines directory is not correctly mapped" + [[ $? != 0 ]] && ((ret++)) + + check_idmap_of_file ${ISULAD_ROOT_PATH}/storage "${FUNCNAME[0]}:${LINENO} - The idmap of the storage directory is not correctly mapped" + [[ $? != 0 ]] && ((ret++)) + + for file in ${CONTAINER_PATH}/${layer_id}/diff/* + do + check_idmap_of_file ${file} "${FUNCNAME[0]}:${LINENO} - The idmap of the image is not correctly mapped" + [[ $? != 0 ]] && ((ret++)) + done + + msg_info "${test} finished with return ${ret}..." + return ${ret} +} + +function test_userns_remap_with_create_container() +{ + local ret=0 + local image="busybox" + local test="test_userns_remap_with_create_container => (${FUNCNAME[@]})" + + msg_info "${test} starting..." + + CID=$(isula create -it busybox) + [[ $? != 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Failed to create container" && ((ret++)) + + check_idmap_of_file ${CONTAINER_PATH}/${CID}/diff "${FUNCNAME[0]}:${LINENO} - The idmap of the diff directory is not correctly mapped" + [[ $? != 0 ]] && ((ret++)) + + check_idmap_of_file ${CONTAINER_PATH}/${CID}/merged "${FUNCNAME[0]}:${LINENO} - The idmap of the merged directory is not correctly mapped" + [[ $? != 0 ]] && ((ret++)) + + check_idmap_of_file ${CONTAINER_PATH}/${CID}/work "${FUNCNAME[0]}:${LINENO} - The idmap of the work directory is not correctly mapped" + [[ $? != 0 ]] && ((ret++)) + + check_idmap_of_file ${LCR_ROOT_PATH}/${CID}/hostname "${FUNCNAME[0]}:${LINENO} - The idmap of the hostname is not correctly mapped" + [[ $? != 0 ]] && ((ret++)) + + check_idmap_of_file ${LCR_ROOT_PATH}/${CID}/hosts "${FUNCNAME[0]}:${LINENO} - The idmap of the hosts is not correctly mapped" + [[ $? != 0 ]] && ((ret++)) + + check_idmap_of_file ${LCR_ROOT_PATH}/${CID}/mounts "${FUNCNAME[0]}:${LINENO} - The idmap of the mounts is not correctly mapped" + [[ $? != 0 ]] && ((ret++)) + + check_idmap_of_file ${LCR_ROOT_PATH}/${CID}/resolv.conf "${FUNCNAME[0]}:${LINENO} - The idmap of the resolv.conf is not correctly mapped" + [[ $? != 0 ]] && ((ret++)) + + isula start ${CID} + [[ $? != 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Failed to start container" && ((ret++)) + testcontainer ${CID} running + + isula rm -f ${CID} + [[ $? != 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Failed to rm container" && ((ret++)) + + msg_info "${test} finished with return ${ret}..." + return ${ret} +} + +function check_lcr_config() +{ + local ret=0 + local image="busybox" + local test="check_lcr_config => (${FUNCNAME[@]})" + + msg_info "${test} starting..." + CID=`isula run -itd ${image}` + [[ $? != 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Failed to create container" && ((ret++)) + testcontainer ${CID} running + + cat "${LCR_ROOT_PATH}/${CID}/config" | grep "lxc.idmap = u 0 100000 65535" + [[ $? != 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Failed to find uidmap in lcr config" && ((ret++)) + + cat "${LCR_ROOT_PATH}/${CID}/config" | grep "lxc.idmap = g 0 100000 65535" + [[ $? != 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Failed to find gidmap in lcr config" && ((ret++)) + + isula rm -f ${CID} + [[ $? != 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Failed to rm container" && ((ret++)) + + return ${ret} +} + +function test_userns_remap_with_create_file_in_container() +{ + local ret=0 + local image="busybox" + local test="test_userns_remap_with_create_file_in_container => (${FUNCNAME[@]})" + local filename="test" + + msg_info "${test} starting..." + + CID=$(isula run -itd ${image}) + isula exec -it ${CID} touch ${filename} + [[ $? != 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Failed to create file in container" && ((ret++)) + + check_idmap_of_file_in_container ${CID} ${filename} "${FUNCNAME[0]}:${LINENO} - The idmap is not correctly mapped" + [[ $? != 0 ]] && ((ret++)) + + check_idmap_of_file ${CONTAINER_PATH}/${CID}/diff/${filename} "${FUNCNAME[0]}:${LINENO} - The idmap is not correctly mapped" + [[ $? != 0 ]] && ((ret++)) + + isula rm -f $CID + [[ $? != 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Failed to rm container" && ((ret++)) + + msg_info "${test} finished with return ${ret}..." + return ${ret} +} + +test_cancel_userns_remap() +{ + local ret=0 + local image="busybox" + local test="tess_cancel_userns_remap => (${FUNCNAME[@]})" + local filename="test" + + msg_info "${test} starting..." + + CID=$(isula run -itd --userns=host ${image}) + isula exec -it ${CID} touch ${filename} + [[ $? != 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Failed to create file in container" && ((ret++)) + + check_idmap_of_file_in_container ${CID} ${filename} "${FUNCNAME[0]}:${LINENO} - The idmap is not correctly mapped" + [[ $? != 0 ]] && ((ret++)) + + idmap=$(stat -c"%u:%g" ${CONTAINER_PATH}/${CID}/diff/${filename}) + [[ "${idmap}" != "${ROOT}" ]] && msg_err "${FUNCNAME[0]}:${LINENO} - The idmap is not correctly mapped" && ((ret++)) + + cat "${LCR_ROOT_PATH}/${CID}/config" | grep "lxc.idmap = u 0 100000 65535" + [[ $? == 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Uidmap should not exist in lcr config" && ((ret++)) + + cat "${LCR_ROOT_PATH}/${CID}/config" | grep "lxc.idmap = g 0 100000 65535" + [[ $? == 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Gidmap should not exist in lcr config" && ((ret++)) + + isula rm -f $CID + [[ $? != 0 ]] && msg_err "${FUNCNAME[0]}:${LINENO} - Failed to rm container" && ((ret++)) + + msg_info "${test} finished with return ${ret}..." + return ${ret} +} + +declare -i ans=0 + +start_isulad_with_userns_remap || ((ans++)) +check_the_management_directory_for_userns_remap || ((ans++)) +test_userns_remap_with_pull_image || ((ans++)) +test_userns_remap_with_create_container || ((ans++)) +check_lcr_config || ((ans++)) +test_userns_remap_with_create_file_in_container || ((ans++)) +test_cancel_userns_remap || ((ans++)) + +check_valgrind_log +start_isulad_without_valgrind + +show_result ${ans} "user namespaces remap" diff --git a/src/cmd/isula/base/create.c b/src/cmd/isula/base/create.c index 0b4a43a4..53fa7dc8 100644 --- a/src/cmd/isula/base/create.c +++ b/src/cmd/isula/base/create.c @@ -1974,6 +1974,7 @@ static int create_namespaces_checker(const struct client_arguments *args) { int ret = 0; const char *net_mode = args->custom_conf.share_ns[NAMESPACE_NET]; + const char *user_mode = args->custom_conf.share_ns[NAMESPACE_USER]; if (args->custom_conf.share_ns[NAMESPACE_NET]) { if (!namespace_is_host(net_mode) && !namespace_is_container(net_mode) && !namespace_is_none(net_mode)) { @@ -1982,6 +1983,15 @@ static int create_namespaces_checker(const struct client_arguments *args) goto out; } } + + if (args->custom_conf.share_ns[NAMESPACE_USER]) { + if (!namespace_is_host(user_mode) && !namespace_is_none(user_mode)) { + COMMAND_ERROR("Unsupported user mode %s", user_mode); + ret = -1; + goto out; + } + } + out: return ret; } diff --git a/src/cmd/isula/base/create.h b/src/cmd/isula/base/create.h index 610a289f..a638e1ca 100644 --- a/src/cmd/isula/base/create.h +++ b/src/cmd/isula/base/create.h @@ -484,6 +484,13 @@ extern "C" { 0, \ &(cmdargs).custom_conf.stop_signal, \ "Signal to stop a container (default \"SIGTERM\")", \ + NULL }, \ + { CMD_OPT_TYPE_STRING_DUP, \ + false, \ + "userns", \ + 0, \ + &(cmdargs).custom_conf.share_ns[NAMESPACE_USER], \ + "Set the usernamespace mode for the container when `userns-remap` option is enabled.", \ NULL }, #define CREATE_EXTEND_OPTIONS(cmdargs) \ diff --git a/src/cmd/isulad/isulad_commands.h b/src/cmd/isulad/isulad_commands.h index 02007f3c..23f87e0e 100644 --- a/src/cmd/isulad/isulad_commands.h +++ b/src/cmd/isulad/isulad_commands.h @@ -266,7 +266,14 @@ int command_default_ulimit_append(command_option_t *option, const char *arg); { CMD_OPT_TYPE_BOOL, \ false, "selinux-enabled", 0, &(cmdargs)->json_confs->selinux_enabled, \ "Enable selinux support", NULL \ - } + }, \ + { CMD_OPT_TYPE_STRING_DUP, \ + false, \ + "userns-remap", \ + 0, \ + &(cmdargs)->json_confs->userns_remap, \ + "User/Group setting for user namespaces", \ + NULL } #ifdef __cplusplus } diff --git a/src/cmd/isulad/main.c b/src/cmd/isulad/main.c index 4917a3d1..b6132e12 100644 --- a/src/cmd/isulad/main.c +++ b/src/cmd/isulad/main.c @@ -117,6 +117,7 @@ static int mount_rootfs_mnt_dir(const char *mountdir) char *rootfsdir = NULL; mountinfo_t **minfos = NULL; mountinfo_t *info = NULL; + char *userns_remap = conf_get_isulad_userns_remap(); if (mountdir == NULL) { ERROR("parent mount path is NULL"); @@ -131,6 +132,14 @@ static int mount_rootfs_mnt_dir(const char *mountdir) goto out; } + if (userns_remap != NULL) { + ret = chmod(rootfsdir, USER_REMAP_DIRECTORY_MODE); + if (ret != 0) { + ERROR("Failed to chmod mount dir '%s' for user remap", rootfsdir); + goto out; + } + } + // find parent directory p = strrchr(rootfsdir, '/'); if (p == NULL) { @@ -139,6 +148,14 @@ static int mount_rootfs_mnt_dir(const char *mountdir) } *p = '\0'; + if (userns_remap != NULL) { + ret = chmod(rootfsdir, USER_REMAP_DIRECTORY_MODE); + if (ret != 0) { + ERROR("Failed to chmod mount dir '%s' for user remap", rootfsdir); + goto out; + } + } + minfos = getmountsinfo(); if (minfos == NULL) { ERROR("Failed to get mounts info"); @@ -157,6 +174,7 @@ static int mount_rootfs_mnt_dir(const char *mountdir) out: free(rootfsdir); + free(userns_remap); free_mounts_info(minfos); return ret; } @@ -658,6 +676,38 @@ out: return ret; } +static int update_graph_for_userns_remap(struct service_arguments *args) +{ + int ret = 0; + int nret = 0; + char graph[PATH_MAX] = { 0 }; + uid_t host_uid = 0; + gid_t host_gid = 0; + unsigned int size = 0; + + if (args->json_confs->userns_remap == NULL) { + goto out; + } + + if (util_parse_user_remap(args->json_confs->userns_remap, &host_uid, &host_gid, &size)) { + ERROR("Failed to split string '%s'.", args->json_confs->userns_remap); + ret = -1; + goto out; + } + + nret = snprintf(graph, sizeof(graph), "%s/%d.%d", ISULAD_ROOT_PATH, host_uid, host_gid); + if (nret < 0 || (size_t)nret >= sizeof(graph)) { + ERROR("Path is too long"); + ret = -1; + goto out; + } + + free(args->json_confs->graph); + args->json_confs->graph = util_strdup_s(graph); + +out: + return ret; +} // update values for options after flag parsing is complete static int update_tls_options(struct service_arguments *args) { @@ -901,6 +951,11 @@ static int update_server_args(struct service_arguments *args) { int ret = 0; + if (update_graph_for_userns_remap(args) != 0) { + ret = -1; + goto out; + } + if (update_tls_options(args)) { ret = -1; goto out; @@ -1098,6 +1153,7 @@ static int isulad_server_pre_init(const struct service_arguments *args, const ch const char *fifo_full_path) { int ret = 0; + char* userns_remap = conf_get_isulad_userns_remap(); if (check_and_save_pid(args->json_confs->pidfile) != 0) { ERROR("Failed to save pid"); @@ -1122,6 +1178,20 @@ static int isulad_server_pre_init(const struct service_arguments *args, const ch goto out; } + if (userns_remap != NULL) { + if (chmod(ISULAD_ROOT_PATH, USER_REMAP_DIRECTORY_MODE) != 0) { + ERROR("Failed to chmod isulad root dir '%s' for user remap", ISULAD_ROOT_PATH); + ret = -1; + goto out; + } + + if (set_file_owner_for_userns_remap(args->json_confs->graph, userns_remap) != 0) { + ERROR("Unable to change root directory %s owner for user remap.", args->json_confs->graph); + ret = -1; + goto out; + } + } + if (mount_rootfs_mnt_dir(args->json_confs->rootfsmntdir)) { ERROR("Create and mount parent directory failed"); ret = -1; @@ -1135,6 +1205,7 @@ static int isulad_server_pre_init(const struct service_arguments *args, const ch } out: + free(userns_remap); return ret; } diff --git a/src/daemon/config/isulad_config.c b/src/daemon/config/isulad_config.c index f70b4575..539d30d2 100644 --- a/src/daemon/config/isulad_config.c +++ b/src/daemon/config/isulad_config.c @@ -1157,6 +1157,28 @@ out: return plugins; } +char *conf_get_isulad_userns_remap() +{ + struct service_arguments *conf = NULL; + char *userns_remap = NULL; + + if (isulad_server_conf_rdlock() != 0) { + ERROR("BUG conf_rdlock failed"); + return NULL; + } + + conf = conf_get_server_conf(); + if (conf == NULL || conf->json_confs == NULL || conf->json_confs->userns_remap == NULL) { + goto out; + } + + userns_remap = util_strdup_s(conf->json_confs->userns_remap); + +out: + (void)isulad_server_conf_unlock(); + return userns_remap; +} + /* conf get websocket server listening port */ int32_t conf_get_websocket_server_listening_port() { @@ -1510,6 +1532,7 @@ int merge_json_confs_into_global(struct service_arguments *args) override_string_value(&args->json_confs->engine, &tmp_json_confs->engine); override_string_value(&args->json_confs->hook_spec, &tmp_json_confs->hook_spec); override_string_value(&args->json_confs->enable_plugins, &tmp_json_confs->enable_plugins); + override_string_value(&args->json_confs->userns_remap, &tmp_json_confs->userns_remap); override_string_value(&args->json_confs->native_umask, &tmp_json_confs->native_umask); override_string_value(&args->json_confs->cgroup_parent, &tmp_json_confs->cgroup_parent); override_string_value(&args->json_confs->rootfsmntdir, &tmp_json_confs->rootfsmntdir); diff --git a/src/daemon/config/isulad_config.h b/src/daemon/config/isulad_config.h index 2b0ed349..5a9672a8 100644 --- a/src/daemon/config/isulad_config.h +++ b/src/daemon/config/isulad_config.h @@ -56,6 +56,7 @@ int conf_get_container_log_opts(isulad_daemon_configs_container_log **opts); char *conf_get_isulad_log_file(); char *conf_get_engine_log_file(); char *conf_get_enable_plugins(); +char *conf_get_isulad_userns_remap(); int32_t conf_get_websocket_server_listening_port(); int save_args_to_conf(struct service_arguments *args); diff --git a/src/daemon/executor/container_cb/execution_create.c b/src/daemon/executor/container_cb/execution_create.c index 114d2193..ac6b303a 100644 --- a/src/daemon/executor/container_cb/execution_create.c +++ b/src/daemon/executor/container_cb/execution_create.c @@ -880,6 +880,7 @@ static int create_container_root_dir(const char *id, const char *runtime_root) int nret; char container_root[PATH_MAX] = { 0x00 }; mode_t mask = umask(S_IWOTH); + char* userns_remap = conf_get_isulad_userns_remap(); nret = snprintf(container_root, sizeof(container_root), "%s/%s", runtime_root, id); if ((size_t)nret >= sizeof(container_root) || nret < 0) { @@ -894,8 +895,15 @@ static int create_container_root_dir(const char *id, const char *runtime_root) goto out; } + if (set_file_owner_for_userns_remap(container_root, userns_remap) != 0) { + ERROR("Unable to change directory %s owner for user remap.", container_root); + ret = -1; + goto out; + } + out: umask(mask); + free(userns_remap); return ret; } diff --git a/src/daemon/executor/container_cb/execution_network.c b/src/daemon/executor/container_cb/execution_network.c index 5532e3fc..d0a19c19 100644 --- a/src/daemon/executor/container_cb/execution_network.c +++ b/src/daemon/executor/container_cb/execution_network.c @@ -26,6 +26,7 @@ #include #include "isula_libutils/log.h" +#include "isulad_config.h" #include "utils.h" #include "container_api.h" #include "namespace.h" @@ -707,24 +708,48 @@ static int merge_network_for_universal_container(const host_config *host_spec, c int ret = 0; int nret = 0; char root_path[PATH_MAX] = { 0x00 }; + char *userns_remap = conf_get_isulad_userns_remap(); if (runtime_root == NULL || id == NULL) { ERROR("empty runtime root or id"); - return -1; + ret = -1; + goto out; } nret = snprintf(root_path, PATH_MAX, "%s/%s", runtime_root, id); if (nret < 0 || nret >= PATH_MAX) { ERROR("Failed to print string"); - return -1; + ret = -1; + goto out; + } + + ret = chown_network(userns_remap, root_path, "/hostname"); + if (ret) { + ret = -1; + goto out; + } + + ret = chown_network(userns_remap, root_path, "/hosts"); + if (ret) { + ret = -1; + goto out; } ret = merge_resolv(host_spec, root_path, "/resolv.conf"); if (ret) { - return -1; + ret = -1; + goto out; } - return 0; + ret = chown_network(userns_remap, root_path, "/resolv.conf"); + if (ret) { + ret = -1; + goto out; + } + +out: + free(userns_remap); + return ret; } static int merge_network_for_syscontainer(const host_config *host_spec, const char *rootfs, const char *hostname) diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.c b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.c index 659d9d52..32add2b4 100644 --- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.c +++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.c @@ -26,6 +26,7 @@ #include #include "isula_libutils/log.h" +#include "isulad_config.h" #include "path.h" #include "utils.h" #include "util_archive.h" @@ -268,13 +269,14 @@ out: return ret; } -int overlay2_init(struct graphdriver *driver, const char *drvier_home, const char **options, size_t len) +int overlay2_init(struct graphdriver *driver, const char *driver_home, const char **options, size_t len) { int ret = 0; char *link_dir = NULL; char *root_dir = NULL; + char *userns_remap = NULL; - if (driver == NULL || drvier_home == NULL) { + if (driver == NULL || driver_home == NULL) { ERROR("Invalid input arguments"); return -1; } @@ -291,9 +293,9 @@ int overlay2_init(struct graphdriver *driver, const char *drvier_home, const cha goto out; } - link_dir = util_path_join(drvier_home, OVERLAY_LINK_DIR); + link_dir = util_path_join(driver_home, OVERLAY_LINK_DIR); if (link_dir == NULL) { - ERROR("Unable to create driver link directory %s.", drvier_home); + ERROR("Unable to create driver link directory %s.", driver_home); ret = -1; goto out; } @@ -306,11 +308,26 @@ int overlay2_init(struct graphdriver *driver, const char *drvier_home, const cha rm_invalid_symlink(link_dir); - driver->home = util_strdup_s(drvier_home); + userns_remap = conf_get_isulad_userns_remap(); + if (userns_remap != NULL) { + if (set_file_owner_for_userns_remap(link_dir, userns_remap) != 0) { + ERROR("Unable to change directory %s owner for user remap.", link_dir); + ret = -1; + goto out; + } + + if (set_file_owner_for_userns_remap(driver_home, userns_remap) != 0) { + ERROR("Unable to change directory %s owner for user remap.", driver_home); + ret = -1; + goto out; + } + } - root_dir = util_path_dir(drvier_home); + driver->home = util_strdup_s(driver_home); + + root_dir = util_path_dir(driver_home); if (root_dir == NULL) { - ERROR("Unable to get driver root home directory %s.", drvier_home); + ERROR("Unable to get driver root home directory %s.", driver_home); ret = -1; goto out; } @@ -328,7 +345,7 @@ int overlay2_init(struct graphdriver *driver, const char *drvier_home, const cha goto out; } - if (!util_support_d_type(drvier_home)) { + if (!util_support_d_type(driver_home)) { ERROR("The backing %s filesystem is formatted without d_type support, which leads to incorrect behavior.", driver->backing_fs); ret = -1; @@ -337,7 +354,7 @@ int overlay2_init(struct graphdriver *driver, const char *drvier_home, const cha driver->support_dtype = true; if (!driver->overlay_opts->skip_mount_home) { - if (util_ensure_mounted_as(drvier_home, "private") != 0) { + if (util_ensure_mounted_as(driver_home, "private") != 0) { ret = -1; goto out; } @@ -351,6 +368,7 @@ int overlay2_init(struct graphdriver *driver, const char *drvier_home, const cha out: free(link_dir); free(root_dir); + free(userns_remap); return ret; } @@ -387,6 +405,7 @@ static int mk_diff_directory(const char *layer_dir) { int ret = 0; char *diff_dir = NULL; + char* userns_remap = conf_get_isulad_userns_remap(); diff_dir = util_path_join(layer_dir, OVERLAY_LAYER_DIFF); if (diff_dir == NULL) { @@ -401,8 +420,15 @@ static int mk_diff_directory(const char *layer_dir) goto out; } + if (set_file_owner_for_userns_remap(diff_dir, userns_remap) != 0) { + ERROR("Unable to change directory %s owner for user remap.", diff_dir); + ret = -1; + goto out; + } + out: free(diff_dir); + free(userns_remap); return ret; } @@ -488,6 +514,7 @@ static int mk_work_directory(const char *layer_dir) { int ret = 0; char *work_dir = NULL; + char* userns_remap = conf_get_isulad_userns_remap(); work_dir = util_path_join(layer_dir, OVERLAY_LAYER_WORK); if (work_dir == NULL) { @@ -502,8 +529,15 @@ static int mk_work_directory(const char *layer_dir) goto out; } + if (set_file_owner_for_userns_remap(work_dir, userns_remap) != 0) { + ERROR("Unable to change directory %s owner for user remap.", work_dir); + ret = -1; + goto out; + } + out: free(work_dir); + free(userns_remap); return ret; } @@ -511,6 +545,7 @@ static int mk_merged_directory(const char *layer_dir) { int ret = 0; char *merged_dir = NULL; + char* userns_remap = conf_get_isulad_userns_remap(); merged_dir = util_path_join(layer_dir, OVERLAY_LAYER_MERGED); if (merged_dir == NULL) { @@ -525,8 +560,15 @@ static int mk_merged_directory(const char *layer_dir) goto out; } + if (set_file_owner_for_userns_remap(merged_dir, userns_remap) != 0) { + ERROR("Unable to change directory %s owner for user remap.", merged_dir); + ret = -1; + goto out; + } + out: free(merged_dir); + free(userns_remap); return ret; } @@ -780,6 +822,7 @@ static int do_create(const char *id, const char *parent, const struct graphdrive { int ret = 0; char *layer_dir = NULL; + char* userns_remap = conf_get_isulad_userns_remap(); layer_dir = util_path_join(driver->home, id); if (layer_dir == NULL) { @@ -799,6 +842,12 @@ static int do_create(const char *id, const char *parent, const struct graphdrive goto out; } + if (set_file_owner_for_userns_remap(layer_dir, userns_remap) != 0) { + ERROR("Unable to change directory %s owner for user remap.", layer_dir); + ret = -1; + goto out; + } + if (create_opts->storage_opt != NULL && create_opts->storage_opt->len != 0) { if (set_layer_quota(layer_dir, create_opts->storage_opt, driver) != 0) { ERROR("Unable to set layer quota %s", layer_dir); @@ -821,6 +870,7 @@ err_out: out: free(layer_dir); + free(userns_remap); return ret; } @@ -1654,6 +1704,10 @@ out: int overlay2_apply_diff(const char *id, const struct graphdriver *driver, const struct io_read_wrapper *content) { int ret = 0; + + unsigned int size = 0; + char* userns_remap = conf_get_isulad_userns_remap(); + char *layer_dir = NULL; char *layer_diff = NULL; struct archive_options options = { 0 }; @@ -1681,6 +1735,14 @@ int overlay2_apply_diff(const char *id, const struct graphdriver *driver, const options.whiteout_format = OVERLAY_WHITEOUT_FORMATE; + if (userns_remap != NULL) { + if (util_parse_user_remap(userns_remap, &options.uid, &options.gid, &size)) { + ERROR("Failed to split string '%s'.", userns_remap); + ret = -1; + goto out; + } + } + ret = archive_unpack(content, layer_diff, &options, &err); if (ret != 0) { ERROR("Failed to unpack to %s: %s", layer_diff, err); @@ -1692,6 +1754,7 @@ out: free(err); free(layer_dir); free(layer_diff); + free(userns_remap); return ret; } diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.h b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.h index 5f3228f0..e14271b1 100644 --- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.h +++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.h @@ -33,7 +33,7 @@ struct io_read_wrapper; extern "C" { #endif -int overlay2_init(struct graphdriver *driver, const char *drvier_home, const char **options, size_t len); +int overlay2_init(struct graphdriver *driver, const char *driver_home, const char **options, size_t len); bool overlay2_is_quota_options(struct graphdriver *driver, const char *option); diff --git a/src/daemon/modules/image/oci/storage/storage.c b/src/daemon/modules/image/oci/storage/storage.c index 40fc15a8..87aad4de 100644 --- a/src/daemon/modules/image/oci/storage/storage.c +++ b/src/daemon/modules/image/oci/storage/storage.c @@ -29,6 +29,7 @@ #include "utils.h" #include "utils_images.h" #include "isula_libutils/log.h" +#include "isulad_config.h" #include "layer_store.h" #include "image_store.h" #include "rootfs_store.h" @@ -939,6 +940,7 @@ static int check_module_init_opt(struct storage_module_init_options *opts) static int make_storage_directory(struct storage_module_init_options *opts) { int ret = 0; + char* userns_remap = conf_get_isulad_userns_remap(); if (util_mkdir_p(opts->storage_root, IMAGE_STORE_PATH_MODE) != 0) { SYSERROR("Failed to make %s", opts->storage_root); @@ -946,6 +948,12 @@ static int make_storage_directory(struct storage_module_init_options *opts) goto out; } + if (set_file_owner_for_userns_remap(opts->storage_root, userns_remap) != 0) { + ERROR("Unable to change directory %s owner for user remap.", opts->storage_root); + ret = -1; + goto out; + } + if (util_mkdir_p(opts->storage_run_root, IMAGE_STORE_PATH_MODE) != 0) { SYSERROR("Failed to make %s", opts->storage_run_root); ret = -1; @@ -953,6 +961,7 @@ static int make_storage_directory(struct storage_module_init_options *opts) } out: + free(userns_remap); return ret; } diff --git a/src/daemon/modules/runtime/engines/engine.c b/src/daemon/modules/runtime/engines/engine.c index 0f27db12..ff010dff 100644 --- a/src/daemon/modules/runtime/engines/engine.c +++ b/src/daemon/modules/runtime/engines/engine.c @@ -121,6 +121,9 @@ void engine_operation_free(struct engine_operation *eop) static int create_engine_root_path(const char *path) { int ret = -1; + char *tmp_path = NULL; + char *p = NULL; + char *userns_remap = NULL; if (path == NULL) { return ret; @@ -130,12 +133,38 @@ static int create_engine_root_path(const char *path) ret = 0; goto out; } - ret = util_mkdir_p(path, CONFIG_DIRECTORY_MODE); - if (ret != 0) { + + if (util_mkdir_p(path, CONFIG_DIRECTORY_MODE) != 0) { ERROR("Unable to create engine root path: %s", path); + goto out; + } + + userns_remap = conf_get_isulad_userns_remap(); + if (userns_remap != NULL) { + if (set_file_owner_for_userns_remap(path, userns_remap) != 0) { + ERROR("Unable to change directory %s owner for user remap.", path); + goto out; + } + + // find parent directory + tmp_path = util_strdup_s(path); + p = strrchr(tmp_path, '/'); + if (p == NULL) { + ERROR("Failed to find parent directory for %s", tmp_path); + goto out; + } + *p = '\0'; + + if (set_file_owner_for_userns_remap(tmp_path, userns_remap) != 0) { + ERROR("Unable to change directory %s owner for user remap.", tmp_path); + goto out; + } } + ret = 0; out: + free(tmp_path); + free(userns_remap); return ret; } diff --git a/src/daemon/modules/spec/specs.c b/src/daemon/modules/spec/specs.c index fc53bd14..6cd00121 100644 --- a/src/daemon/modules/spec/specs.c +++ b/src/daemon/modules/spec/specs.c @@ -1483,6 +1483,14 @@ static int merge_share_network_namespace(oci_runtime_spec *oci_spec, const host_ return ret; } +static bool userns_remap_is_enabled(const oci_runtime_spec *oci_spec) +{ + if (oci_spec->linux->uid_mappings != NULL && oci_spec->linux->gid_mappings != NULL) { + return true; + } + return false; +} + int merge_share_namespace(oci_runtime_spec *oci_spec, const host_config *host_spec, const container_config_v2_common_config_network_settings *network_settings) { @@ -1497,13 +1505,7 @@ int merge_share_namespace(oci_runtime_spec *oci_spec, const host_config *host_sp } // user - if (merge_share_single_namespace(oci_spec, host_spec->userns_mode, TYPE_NAMESPACE_USER) != 0) { - ret = -1; - goto out; - } - - // user remap - if (host_spec->user_remap != NULL && merge_share_single_namespace(oci_spec, "user", TYPE_NAMESPACE_USER) != 0) { + if (userns_remap_is_enabled(oci_spec) && merge_share_single_namespace(oci_spec, "user", TYPE_NAMESPACE_USER) != 0) { ret = -1; goto out; } @@ -2076,6 +2078,7 @@ int merge_all_specs(host_config *host_spec, const char *real_rootfs, container_c oci_runtime_spec *oci_spec) { int ret = 0; + char *userns_remap = conf_get_isulad_userns_remap(); ret = merge_root(oci_spec, real_rootfs, host_spec); if (ret != 0) { @@ -2133,10 +2136,18 @@ int merge_all_specs(host_config *host_spec, const char *real_rootfs, container_c goto out; } - ret = make_userns_remap(oci_spec, host_spec->user_remap); - if (ret != 0) { - ERROR("Failed to make user remap for container"); - goto out; + if (!host_spec->system_container && !namespace_is_host(host_spec->userns_mode)) { + ret = make_userns_remap(oci_spec, userns_remap); + if (ret != 0) { + ERROR("Failed to make user remap for container"); + goto out; + } + } else { + ret = make_userns_remap(oci_spec, host_spec->user_remap); + if (ret != 0) { + ERROR("Failed to make user remap for container"); + goto out; + } } ret = merge_oci_cgroups_path(v2_spec->id, oci_spec, host_spec); @@ -2146,6 +2157,7 @@ int merge_all_specs(host_config *host_spec, const char *real_rootfs, container_c } out: + free(userns_remap); return ret; } diff --git a/src/daemon/modules/spec/specs_mount.c b/src/daemon/modules/spec/specs_mount.c index 6b6ac87d..f589bc3b 100644 --- a/src/daemon/modules/spec/specs_mount.c +++ b/src/daemon/modules/spec/specs_mount.c @@ -2588,7 +2588,9 @@ static int prepare_share_shm(host_config *host_spec, container_config_v2_common_ int nret = 0; bool has_mount = false; char *spath = NULL; - + char *tmp_path = NULL; + char *p = NULL; + char *userns_remap = NULL; // has mount for /dev/shm if (has_mount_shm(host_spec, v2_spec)) { return 0; @@ -2623,6 +2625,36 @@ static int prepare_share_shm(host_config *host_spec, container_config_v2_common_ } v2_spec->shm_path = spath; + userns_remap = conf_get_isulad_userns_remap(); + + if (host_spec->user_remap == NULL && userns_remap != NULL) { + // find parent directory + tmp_path = util_strdup_s(spath); + p = strrchr(tmp_path, '/'); + if (p == NULL) { + ERROR("Failed to find parent directory for %s", tmp_path); + goto out; + } + *p = '\0'; + + if (set_file_owner_for_userns_remap(tmp_path, userns_remap) != 0) { + ERROR("Unable to change directory %s owner for user remap.", tmp_path); + goto out; + } + + p = strrchr(tmp_path, '/'); + if (p == NULL) { + ERROR("Failed to find parent directory for %s", tmp_path); + goto out; + } + *p = '\0'; + + if (set_file_owner_for_userns_remap(tmp_path, userns_remap) != 0) { + ERROR("Unable to change directory %s owner for user remap.", tmp_path); + goto out; + } + } + spath = NULL; ret = 0; out: @@ -2630,6 +2662,8 @@ out: (void)umount(spath); } free(spath); + free(tmp_path); + free(userns_remap); return ret; } diff --git a/src/daemon/modules/volume/local.c b/src/daemon/modules/volume/local.c index a80a5eca..def2623d 100644 --- a/src/daemon/modules/volume/local.c +++ b/src/daemon/modules/volume/local.c @@ -23,6 +23,7 @@ #include #include "isula_libutils/log.h" +#include "isulad_config.h" #include "volume_api.h" #include "utils.h" #include "map.h" @@ -156,6 +157,7 @@ out: static int init_volume_root_dir(struct volumes_info *vols_info, char *root_dir) { int ret = 0; + char *userns_remap = conf_get_isulad_userns_remap(); ret = util_mkdir_p(root_dir, LOCAL_VOLUME_ROOT_DIR_MODE); if (ret != 0) { @@ -163,10 +165,16 @@ static int init_volume_root_dir(struct volumes_info *vols_info, char *root_dir) goto out; } + if (set_file_owner_for_userns_remap(root_dir, userns_remap) != 0) { + ERROR("Unable to change directory %s owner for user remap.", root_dir); + ret = -1; + goto out; + } + vols_info->root_dir = util_strdup_s(root_dir); out: - + free(userns_remap); return ret; } diff --git a/src/utils/cutils/utils_file.c b/src/utils/cutils/utils_file.c index dbdd70f2..e087d92f 100644 --- a/src/utils/cutils/utils_file.c +++ b/src/utils/cutils/utils_file.c @@ -2096,3 +2096,28 @@ out: return ret; } + +int set_file_owner_for_userns_remap(const char *filename, const char *userns_remap) +{ + int ret = 0; + uid_t host_uid = 0; + gid_t host_gid = 0; + unsigned int size = 0; + + if (filename == NULL || userns_remap == NULL) { + goto out; + } + + if (util_parse_user_remap(userns_remap, &host_uid, &host_gid, &size)) { + ERROR("Failed to split string '%s'.", userns_remap); + ret = -1; + goto out; + } + if (chown(filename, host_uid, host_gid) != 0) { + ERROR("Failed to chown host path '%s'.", filename); + ret = -1; + } + +out: + return ret; +} \ No newline at end of file diff --git a/src/utils/cutils/utils_file.h b/src/utils/cutils/utils_file.h index 1465ca7e..7b8c3ab4 100644 --- a/src/utils/cutils/utils_file.h +++ b/src/utils/cutils/utils_file.h @@ -120,6 +120,7 @@ int util_list_all_entries(const char *directory, char ***out); // 2. If fifo or socket exist in source, this function will return failure. int util_copy_dir_recursive(char *copy_dst, char *copy_src); +int set_file_owner_for_userns_remap(const char *filename, const char *userns_remap); #ifdef __cplusplus } #endif diff --git a/src/utils/tar/util_archive.c b/src/utils/tar/util_archive.c index 7d64e3aa..afb84a37 100644 --- a/src/utils/tar/util_archive.c +++ b/src/utils/tar/util_archive.c @@ -524,6 +524,9 @@ int archive_unpack_handler(const struct io_read_wrapper *content, const struct a try_to_replace_exited_dst(dst_path, entry); + archive_entry_set_uid(entry, options->uid); + archive_entry_set_gid(entry, options->gid); + ret = archive_write_header(ext, entry); if (ret != ARCHIVE_OK) { ERROR("Fail to handle tar header: %s", archive_error_string(ext)); diff --git a/src/utils/tar/util_archive.h b/src/utils/tar/util_archive.h index 55fd7683..09fad03a 100644 --- a/src/utils/tar/util_archive.h +++ b/src/utils/tar/util_archive.h @@ -41,6 +41,8 @@ typedef enum { struct archive_options { whiteout_format_type whiteout_format; + uid_t uid; + gid_t gid; // rename archive entry's name from src_base to dst_base const char *src_base; const char *dst_base; -- 2.25.1