From d231a8e5f8ea1c8a5584fdc8baa579b18d1b6a19 Mon Sep 17 00:00:00 2001 From: zhongtao Date: Wed, 29 Mar 2023 03:26:45 +0800 Subject: [PATCH 38/46] support to config selinux label in cri Signed-off-by: zhongtao --- .../cri/cri_container_manager_service_impl.cc | 47 +++++---- .../cri/cri_container_manager_service_impl.h | 1 + src/daemon/entry/cri/cri_helpers.cc | 95 ++++++++++++++++++- src/daemon/entry/cri/cri_helpers.h | 17 +++- .../cri_pod_sandbox_manager_service_impl.cc | 47 ++++----- 5 files changed, 149 insertions(+), 58 deletions(-) diff --git a/src/daemon/entry/cri/cri_container_manager_service_impl.cc b/src/daemon/entry/cri/cri_container_manager_service_impl.cc index a64d222c..6278512f 100644 --- a/src/daemon/entry/cri/cri_container_manager_service_impl.cc +++ b/src/daemon/entry/cri/cri_container_manager_service_impl.cc @@ -98,30 +98,21 @@ auto ContainerManagerServiceImpl::PackCreateContainerHostConfigSecurityContext( // security Opt Separator Change Version : k8s v1.23.0 (Corresponds to docker 1.11.x) // New version '=' , old version ':', iSulad cri is based on v18.09, so iSulad cri use new version separator const char securityOptSep { '=' }; - std::vector securityOpts = CRIHelpers::GetSecurityOpts( - containerConfig.linux().security_context().seccomp_profile_path(), securityOptSep, error); + const ::runtime::v1alpha2::LinuxContainerSecurityContext &context = containerConfig.linux().security_context(); + CRIHelpers::commonSecurityContext commonContext = { + .hasSELinuxOption = context.has_selinux_options(), + .selinuxOption = context.selinux_options(), + .seccompProfile = context.seccomp_profile_path(), + }; + std::vector securityOpts = CRIHelpers::GetSecurityOpts(commonContext, securityOptSep, error); if (error.NotEmpty()) { - error.Errorf("failed to generate security options for container %s", containerConfig.metadata().name().c_str()); + error.Errorf("Failed to generate security options for container %s", containerConfig.metadata().name().c_str()); return -1; } - if (!securityOpts.empty()) { - char **tmp_security_opt = nullptr; - if (securityOpts.size() > (SIZE_MAX / sizeof(char *)) - hostconfig->security_opt_len) { - error.Errorf("Out of memory"); - return -1; - } - size_t newSize = (hostconfig->security_opt_len + securityOpts.size()) * sizeof(char *); - size_t oldSize = hostconfig->security_opt_len * sizeof(char *); - int ret = util_mem_realloc((void **)(&tmp_security_opt), newSize, (void *)hostconfig->security_opt, oldSize); - if (ret != 0) { - error.Errorf("Out of memory"); - return -1; - } - hostconfig->security_opt = tmp_security_opt; - for (const auto &securityOpt : securityOpts) { - hostconfig->security_opt[hostconfig->security_opt_len] = util_strdup_s(securityOpt.c_str()); - hostconfig->security_opt_len++; - } + CRIHelpers::AddSecurityOptsToHostConfig(securityOpts, hostconfig, error); + if (error.NotEmpty()) { + error.Errorf("Failed to add securityOpts to hostconfig for container %s", containerConfig.metadata().name().c_str()); + return -1; } return 0; } @@ -148,7 +139,7 @@ auto ContainerManagerServiceImpl::DoUsePodLevelSELinuxConfig(const runtime::v1al } tmp_str = std::string(inspect->process_label); - selinuxLabelOpts = CRIHelpers::GetSELinuxLabelOpts(tmp_str, error); + selinuxLabelOpts = CRIHelpers::GetPodSELinuxLabelOpts(tmp_str, error); if (error.NotEmpty()) { ERROR("Failed to get SELinuxLabelOpts for container %s", containerConfig.metadata().name().c_str()); goto cleanup; @@ -181,7 +172,14 @@ cleanup: return ret; } - +auto ContainerManagerServiceImpl::IsSELinuxLabelEmpty(const ::runtime::v1alpha2::SELinuxOption &selinuxOption) -> bool +{ + if (selinuxOption.user().length() == 0 && selinuxOption.role().length() == 0 && selinuxOption.type().length() == 0 && + selinuxOption.level().length() == 0) { + return true; + } + return false; +} auto ContainerManagerServiceImpl::GenerateCreateContainerHostConfig( const runtime::v1alpha2::ContainerConfig &containerConfig, @@ -219,7 +217,8 @@ auto ContainerManagerServiceImpl::GenerateCreateContainerHostConfig( // If selinux label is not specified in container config, use pod level SELinux config if (!containerConfig.linux().has_security_context() || - !containerConfig.linux().security_context().has_selinux_options()) { + !containerConfig.linux().security_context().has_selinux_options() || + IsSELinuxLabelEmpty(containerConfig.linux().security_context().selinux_options())) { if (DoUsePodLevelSELinuxConfig(containerConfig, hostconfig, realPodSandboxID, error) != 0) { error.SetError("Failed to security context to host config"); goto cleanup; diff --git a/src/daemon/entry/cri/cri_container_manager_service_impl.h b/src/daemon/entry/cri/cri_container_manager_service_impl.h index dcb2cd44..ad53a65f 100644 --- a/src/daemon/entry/cri/cri_container_manager_service_impl.h +++ b/src/daemon/entry/cri/cri_container_manager_service_impl.h @@ -84,6 +84,7 @@ private: Errors &error) -> container_create_request *; auto GenerateCreateContainerHostConfig(const runtime::v1alpha2::ContainerConfig &containerConfig, const std::string &realPodSandboxID, Errors &error) -> host_config *; + auto IsSELinuxLabelEmpty(const ::runtime::v1alpha2::SELinuxOption &selinuxOption) -> bool; auto GenerateCreateContainerCustomConfig(const std::string &containerName, const std::string &realPodSandboxID, const runtime::v1alpha2::ContainerConfig &containerConfig, const runtime::v1alpha2::PodSandboxConfig &podSandboxConfig, diff --git a/src/daemon/entry/cri/cri_helpers.cc b/src/daemon/entry/cri/cri_helpers.cc index 2bc6bed7..ec14d0b2 100644 --- a/src/daemon/entry/cri/cri_helpers.cc +++ b/src/daemon/entry/cri/cri_helpers.cc @@ -68,6 +68,8 @@ const std::string Constants::CNI_MUTL_NET_EXTENSION_KEY { "extension.network.kub const std::string Constants::CNI_MUTL_NET_EXTENSION_ARGS_KEY { "CNI_MUTLINET_EXTENSION" }; const std::string Constants::CNI_ARGS_EXTENSION_PREFIX_KEY { "extension.network.kubernetes.io/cniargs/" }; const std::string Constants::IMAGE_NAME_ANNOTATION_KEY { "io.kubernetes.cri.image-name" }; +// Usually, the format of level is "s0:c60,c525" or "s0-s0:c40.c23" +const std::string Constants::SELINUX_LABEL_LEVEL_PATTERN { "^s[0-9](-s[0-9])?(:c[0-9]{1,4}(\\.c[0-9]{1,4})?(,c[0-9]{1,4}(\\.c[0-9]{1,4})?)*)?$" }; const char *InternalLabelKeys[] = { CRIHelpers::Constants::CONTAINER_TYPE_LABEL_KEY.c_str(), CRIHelpers::Constants::CONTAINER_LOGPATH_LABEL_KEY.c_str(), @@ -598,6 +600,34 @@ auto GetSeccompiSuladOpts(const std::string &seccompProfile, Errors &error) -> s return ret; } + +auto GetSelinuxiSuladOpts(const ::runtime::v1alpha2::SELinuxOption &selinux, Errors &error)-> std::vector +{ + std::vector selinuxOpts { }; + // LabeSep is consistent with the separator used when parsing labels + const char labeSep { ':' }; + + if (selinux.level().length() != 0 && + util_reg_match(CRIHelpers::Constants::SELINUX_LABEL_LEVEL_PATTERN.c_str(), selinux.level().c_str()) != 0) { + error.Errorf("The format of 'level' %s is not correct", selinux.level().c_str()); + return selinuxOpts; + } + + if (selinux.user().length() > 0) { + selinuxOpts.push_back({ "label", std::string("user") + std::string(1, labeSep) + selinux.user(), "" }); + } + if (selinux.role().length() > 0) { + selinuxOpts.push_back({ "label", std::string("role") + std::string(1, labeSep) + selinux.role(), "" }); + } + if (selinux.type().length() > 0) { + selinuxOpts.push_back({ "label", std::string("type") + std::string(1, labeSep) + selinux.type(), "" }); + } + if (selinux.level().length() > 0) { + selinuxOpts.push_back({ "label", std::string("level") + std::string(1, labeSep) + selinux.level(), "" }); + } + return selinuxOpts; +} + auto GetSeccompSecurityOpts(const std::string &seccompProfile, const char &separator, Errors &error) -> std::vector { @@ -609,17 +639,44 @@ auto GetSeccompSecurityOpts(const std::string &seccompProfile, const char &separ return fmtiSuladOpts(seccompOpts, separator); } -auto GetSecurityOpts(const std::string &seccompProfile, const char &separator, Errors &error) +auto GetSELinuxLabelOpts(const bool hasSELinuxOption, const ::runtime::v1alpha2::SELinuxOption &selinux, + const char &separator, Errors &error) -> std::vector { - std::vector seccompSecurityOpts = GetSeccompSecurityOpts(seccompProfile, separator, error); + if (!hasSELinuxOption) { + return std::vector(); + } + + std::vector selinuxOpts = GetSelinuxiSuladOpts(selinux, error); if (error.NotEmpty()) { - error.Errorf("failed to generate seccomp security options for container: %s", error.GetMessage().c_str()); + return std::vector(); } - return seccompSecurityOpts; + + return fmtiSuladOpts(selinuxOpts, separator); } -auto GetSELinuxLabelOpts(const std::string &selinuxLabel, Errors &error) +auto GetSecurityOpts(const commonSecurityContext &context, const char &separator, Errors &error) +-> std::vector +{ + std::vector securityOpts; + std::vector seccompSecurityOpts = GetSeccompSecurityOpts(context.seccompProfile, separator, error); + if (error.NotEmpty()) { + error.Errorf("Failed to generate seccomp security options for container: %s", error.GetMessage().c_str()); + return securityOpts; + } + + std::vector selinuxOpts = CRIHelpers::GetSELinuxLabelOpts(context.hasSELinuxOption, + context.selinuxOption, separator, error); + if (error.NotEmpty()) { + error.Errorf("Failed to generate SELinuxLabel options for container %s", error.GetMessage().c_str()); + return securityOpts; + } + securityOpts.insert(securityOpts.end(), seccompSecurityOpts.begin(), seccompSecurityOpts.end()); + securityOpts.insert(securityOpts.end(), selinuxOpts.begin(), selinuxOpts.end()); + return securityOpts; +} + +auto GetPodSELinuxLabelOpts(const std::string &selinuxLabel, Errors &error) -> std::vector { // security Opt Separator Change Version : k8s v1.23.0 (Corresponds to docker 1.11.x) @@ -650,6 +707,34 @@ auto GetSELinuxLabelOpts(const std::string &selinuxLabel, Errors &error) return fmtiSuladOpts(selinuxOpts, securityOptSep); } +void AddSecurityOptsToHostConfig(std::vector &securityOpts, host_config *hostconfig, Errors &error) +{ + if (securityOpts.empty()) { + return; + } + + char **tmp_security_opt = nullptr; + if (securityOpts.size() > (SIZE_MAX / sizeof(char *)) - hostconfig->security_opt_len) { + error.Errorf("Too many securityOpts"); + ERROR("Too many securityOpts"); + return; + } + size_t newSize = (hostconfig->security_opt_len + securityOpts.size()) * sizeof(char *); + size_t oldSize = hostconfig->security_opt_len * sizeof(char *); + int ret = util_mem_realloc((void **)(&tmp_security_opt), newSize, (void *)hostconfig->security_opt, oldSize); + if (ret != 0) { + error.Errorf("Out of memory"); + ERROR("Out of memory"); + return; + } + hostconfig->security_opt = tmp_security_opt; + for (const auto &securityOpt : securityOpts) { + hostconfig->security_opt[hostconfig->security_opt_len] = util_strdup_s(securityOpt.c_str()); + hostconfig->security_opt_len++; + } + +} + auto CreateCheckpoint(CRI::PodSandboxCheckpoint &checkpoint, Errors &error) -> std::string { cri_checkpoint *criCheckpoint { nullptr }; diff --git a/src/daemon/entry/cri/cri_helpers.h b/src/daemon/entry/cri/cri_helpers.h index 4ef227d7..a5d6cf61 100644 --- a/src/daemon/entry/cri/cri_helpers.h +++ b/src/daemon/entry/cri/cri_helpers.h @@ -67,10 +67,17 @@ public: static const std::string CNI_MUTL_NET_EXTENSION_KEY; static const std::string CNI_MUTL_NET_EXTENSION_ARGS_KEY; static const std::string CNI_ARGS_EXTENSION_PREFIX_KEY; + static const std::string SELINUX_LABEL_LEVEL_PATTERN; static const std::string IMAGE_NAME_ANNOTATION_KEY; }; +struct commonSecurityContext { + const bool hasSELinuxOption; + const ::runtime::v1alpha2::SELinuxOption selinuxOption; + const std::string seccompProfile; +}; + auto GetDefaultSandboxImage(Errors &err) -> std::string; auto MakeLabels(const google::protobuf::Map &mapLabels, Errors &error) @@ -124,12 +131,18 @@ auto ValidateCheckpointKey(const std::string &key, Errors &error) -> bool; auto ToIsuladContainerStatus(const runtime::v1alpha2::ContainerStateValue &state) -> std::string; -auto GetSecurityOpts(const std::string &seccompProfile, const char &separator, Errors &error) +auto GetSELinuxLabelOpts(const bool hasSELinuxOption, const ::runtime::v1alpha2::SELinuxOption &selinux, + const char &separator, Errors &error) -> std::vector; -auto GetSELinuxLabelOpts(const std::string &selinuxLabel, Errors &error) +auto GetSecurityOpts(const commonSecurityContext &context, const char &separator, Errors &error) -> std::vector; +auto GetPodSELinuxLabelOpts(const std::string &selinuxLabel, Errors &error) +-> std::vector; + +void AddSecurityOptsToHostConfig(std::vector &securityOpts, host_config *hostconfig, Errors &error); + auto CreateCheckpoint(CRI::PodSandboxCheckpoint &checkpoint, Errors &error) -> std::string; void GetCheckpoint(const std::string &jsonCheckPoint, CRI::PodSandboxCheckpoint &checkpoint, Errors &error); diff --git a/src/daemon/entry/cri/cri_pod_sandbox_manager_service_impl.cc b/src/daemon/entry/cri/cri_pod_sandbox_manager_service_impl.cc index 7ff545db..1cb3254d 100644 --- a/src/daemon/entry/cri/cri_pod_sandbox_manager_service_impl.cc +++ b/src/daemon/entry/cri/cri_pod_sandbox_manager_service_impl.cc @@ -197,34 +197,27 @@ void PodSandboxManagerServiceImpl::MakeSandboxIsuladConfig(const runtime::v1alph const char securityOptSep = '='; // Security Opts - if (c.linux().has_security_context()) { - std::vector securityOpts = - CRIHelpers::GetSecurityOpts(c.linux().security_context().seccomp_profile_path(), securityOptSep, error); - if (error.NotEmpty()) { - error.Errorf("failed to generate security options for sandbox %s: %s", - c.metadata().name().c_str(), error.GetMessage().c_str()); - return; - } - if (!securityOpts.empty()) { - char **tmp_security_opt = nullptr; + if (!c.linux().has_security_context()) { + return; + } - if (securityOpts.size() > (SIZE_MAX / sizeof(char *)) - hc->security_opt_len) { - error.Errorf("Out of memory"); - return; - } - size_t newSize = (hc->security_opt_len + securityOpts.size()) * sizeof(char *); - size_t oldSize = hc->security_opt_len * sizeof(char *); - int ret = util_mem_realloc((void **)(&tmp_security_opt), newSize, (void *)hc->security_opt, oldSize); - if (ret != 0) { - error.Errorf("Out of memory"); - return; - } - hc->security_opt = tmp_security_opt; - for (const auto &securityOpt : securityOpts) { - hc->security_opt[hc->security_opt_len] = util_strdup_s(securityOpt.c_str()); - hc->security_opt_len++; - } - } + CRIHelpers::commonSecurityContext commonContext = { + .hasSELinuxOption = c.linux().security_context().has_selinux_options(), + .selinuxOption = c.linux().security_context().selinux_options(), + .seccompProfile = c.linux().security_context().seccomp_profile_path(), + }; + + std::vector securityOpts = CRIHelpers::GetSecurityOpts(commonContext, securityOptSep, error); + if (error.NotEmpty()) { + error.Errorf("Failed to generate security options for sandbox %s: %s", + c.metadata().name().c_str(), error.GetMessage().c_str()); + return; + } + CRIHelpers::AddSecurityOptsToHostConfig(securityOpts, hc, error); + if (error.NotEmpty()) { + error.Errorf("Failed to add securityOpts to hostconfig for sandbox %s: %s", c.metadata().name().c_str(), + error.GetMessage().c_str()); + return; } } -- 2.25.1