/****************************************************************************** * Copyright (c) Huawei Technologies Co., Ltd. 2017-2019. All rights reserved. * iSulad licensed under the Mulan PSL v1. * You can use this software according to the terms and conditions of the Mulan PSL v1. * You may obtain a copy of Mulan PSL v1 at: * http://license.coscl.org.cn/MulanPSL * 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 v1 for more details. * Author: tanyifeng * Create: 2017-11-22 * Description: provide cri security context functions *********************************************************************************/ #include "cri_security_context.h" #include #include "cri_runtime_service.h" #include "utils.h" #include "log.h" namespace CRISecurity { static void ModifyContainerConfig(const runtime::v1alpha2::LinuxContainerSecurityContext &sc, container_config *config) { if (sc.has_run_as_user()) { free(config->user); config->user = util_strdup_s(std::to_string(sc.run_as_user().value()).c_str()); } if (!sc.run_as_username().empty()) { free(config->user); config->user = util_strdup_s(sc.run_as_username().c_str()); } } static void ModifyHostConfigCapabilities(const runtime::v1alpha2::LinuxContainerSecurityContext &sc, host_config *hostConfig, Errors &error) { if (!sc.has_capabilities()) { return; } const google::protobuf::RepeatedPtrField &capAdd = sc.capabilities().add_capabilities(); if (capAdd.size() > 0) { if (static_cast(capAdd.size()) > SIZE_MAX / sizeof(char *)) { error.SetError("Invalid capability add size"); return; } hostConfig->cap_add = (char **)util_common_calloc_s(sizeof(char *) * capAdd.size()); if (hostConfig->cap_add == nullptr) { error.SetError("Out of memory"); return; } for (int i {}; i < capAdd.size(); i++) { hostConfig->cap_add[i] = util_strdup_s(capAdd[i].c_str()); hostConfig->cap_add_len++; } } const google::protobuf::RepeatedPtrField &capDrop = sc.capabilities().drop_capabilities(); if (capDrop.size() > 0) { if (static_cast(capDrop.size()) > SIZE_MAX / sizeof(char *)) { error.SetError("Invalid capability drop size"); return; } hostConfig->cap_drop = (char **)util_common_calloc_s(sizeof(char *) * capDrop.size()); if (hostConfig->cap_drop == nullptr) { error.SetError("Out of memory"); return; } for (int i = 0; i < capDrop.size(); i++) { hostConfig->cap_drop[i] = util_strdup_s(capDrop[i].c_str()); hostConfig->cap_drop_len++; } } } static void ModifyHostConfigNoNewPrivs(const runtime::v1alpha2::LinuxContainerSecurityContext &sc, host_config *hostConfig, Errors &error) { char **tmp_security_opt { nullptr }; if (!sc.no_new_privs()) { return; } if (hostConfig->security_opt_len > (SIZE_MAX / sizeof(char *)) - 1) { error.Errorf("Out of memory"); return; } size_t oldSize = hostConfig->security_opt_len * sizeof(char *); size_t newSize = oldSize + sizeof(char *); int ret = mem_realloc((void **)(&tmp_security_opt), newSize, (void *)hostConfig->security_opt, oldSize); if (ret != 0) { error.Errorf("Out of memory"); return; } hostConfig->security_opt = tmp_security_opt; hostConfig->security_opt[hostConfig->security_opt_len++] = util_strdup_s("no-new-privileges"); } static void ModifyHostConfigscSupplementalGroups(const runtime::v1alpha2::LinuxContainerSecurityContext &sc, host_config *hostConfig, Errors &error) { if (sc.supplemental_groups().size() == 0) { return; } const google::protobuf::RepeatedField &groups = sc.supplemental_groups(); if (groups.size() > 0) { if (static_cast(groups.size()) > SIZE_MAX / sizeof(char *)) { error.SetError("Invalid group size"); return; } hostConfig->group_add = (char **)util_common_calloc_s(sizeof(char *) * groups.size()); if (hostConfig->group_add == nullptr) { error.SetError("Out of memory"); return; } for (int i = 0; i < groups.size(); i++) { hostConfig->group_add[i] = util_strdup_s(std::to_string(groups[i]).c_str()); hostConfig->group_add_len++; } } } static void ModifyHostConfig(const runtime::v1alpha2::LinuxContainerSecurityContext &sc, host_config *hostConfig, Errors &error) { hostConfig->privileged = sc.privileged(); hostConfig->readonly_rootfs = sc.readonly_rootfs(); // note: Apply apparmor options, selinux options, noNewPrivilege ModifyHostConfigCapabilities(sc, hostConfig, error); ModifyHostConfigNoNewPrivs(sc, hostConfig, error); ModifyHostConfigscSupplementalGroups(sc, hostConfig, error); } static void ModifyCommonNamespaceOptions(const runtime::v1alpha2::NamespaceOption &nsOpts, host_config *hostConfig) { if (nsOpts.pid() == runtime::v1alpha2::NamespaceMode::NODE) { free(hostConfig->pid_mode); hostConfig->pid_mode = util_strdup_s(CRIRuntimeService::Constants::namespaceModeHost.c_str()); } } static void ModifyHostNetworkOptionForContainer(const runtime::v1alpha2::NamespaceMode &hostNetwork, const std::string &podSandboxID, host_config *hostConfig) { std::string sandboxNSMode = "container:" + podSandboxID; free(hostConfig->network_mode); hostConfig->network_mode = util_strdup_s(sandboxNSMode.c_str()); free(hostConfig->ipc_mode); hostConfig->ipc_mode = util_strdup_s(sandboxNSMode.c_str()); if (hostNetwork == runtime::v1alpha2::NamespaceMode::NODE) { free(hostConfig->uts_mode); hostConfig->uts_mode = util_strdup_s(CRIRuntimeService::Constants::namespaceModeHost.c_str()); } } static void ModifyHostNetworkOptionForSandbox(const runtime::v1alpha2::NamespaceOption &nsOpts, host_config *hostConfig) { if (nsOpts.ipc() == runtime::v1alpha2::NamespaceMode::NODE) { free(hostConfig->ipc_mode); hostConfig->ipc_mode = util_strdup_s(CRIRuntimeService::Constants::namespaceModeHost.c_str()); } if (nsOpts.network() == runtime::v1alpha2::NamespaceMode::NODE) { free(hostConfig->network_mode); hostConfig->network_mode = util_strdup_s(CRIRuntimeService::Constants::namespaceModeHost.c_str()); } // Note: default networkMode is not supported } static void ModifyContainerNamespaceOptions(const runtime::v1alpha2::NamespaceOption &nsOpts, const std::string &podSandboxID, host_config *hostConfig, Errors &error) { std::string sandboxNSMode = "container:" + podSandboxID; if (nsOpts.pid() == runtime::v1alpha2::NamespaceMode::POD) { free(hostConfig->pid_mode); hostConfig->pid_mode = util_strdup_s(sandboxNSMode.c_str()); } /* set common Namespace options */ ModifyCommonNamespaceOptions(nsOpts, hostConfig); /* modify host network option for container */ ModifyHostNetworkOptionForContainer(nsOpts.network(), podSandboxID, hostConfig); } static void ModifySandboxNamespaceOptions(const runtime::v1alpha2::NamespaceOption &nsOpts, host_config *hostConfig, Errors &error) { /* set common Namespace options */ ModifyCommonNamespaceOptions(nsOpts, hostConfig); /* modify host network option for container */ ModifyHostNetworkOptionForSandbox(nsOpts, hostConfig); } void ApplySandboxSecurityContext(const runtime::v1alpha2::LinuxPodSandboxConfig &lc, container_config *config, host_config *hc, Errors &error) { std::unique_ptr sc( new (std::nothrow) runtime::v1alpha2::LinuxContainerSecurityContext); if (sc == nullptr) { error.SetError("Out of memory"); return; } if (lc.has_security_context()) { const runtime::v1alpha2::LinuxSandboxSecurityContext &old = lc.security_context(); if (old.has_run_as_user()) { *sc->mutable_run_as_user() = old.run_as_user(); } if (old.has_namespace_options()) { *sc->mutable_namespace_options() = old.namespace_options(); } if (old.has_selinux_options()) { *sc->mutable_selinux_options() = old.selinux_options(); } *sc->mutable_supplemental_groups() = old.supplemental_groups(); sc->set_readonly_rootfs(old.readonly_rootfs()); } ModifyContainerConfig(*sc, config); ModifyHostConfig(*sc, hc, error); if (error.NotEmpty()) { return; } ModifySandboxNamespaceOptions(sc->namespace_options(), hc, error); } void ApplyContainerSecurityContext(const runtime::v1alpha2::LinuxContainerConfig &lc, const std::string &podSandboxID, container_config *config, host_config *hc, Errors &error) { if (lc.has_security_context()) { const runtime::v1alpha2::LinuxContainerSecurityContext &sc = lc.security_context(); ModifyContainerConfig(sc, config); ModifyHostConfig(sc, hc, error); if (error.NotEmpty()) { return; } } ModifyContainerNamespaceOptions(lc.security_context().namespace_options(), podSandboxID, hc, error); if (error.NotEmpty()) { ERROR("Modify namespace options failed: %s", error.GetCMessage()); return; } } } // namespace CRISecurity