From c1eb46b00ea65fc5601f0d843bc485d087f687e0 Mon Sep 17 00:00:00 2001
From: jikai <jikai11@huawei.com>
Date: Mon, 6 Nov 2023 17:31:58 +0800
Subject: [PATCH 03/14] Add Readonly/Masked Path and RunAsGroup support for cri

Signed-off-by: jikai<jikai11@huawei.com>
---
 .../common/cri/v1/v1_cri_security_context.cc  | 111 ++++++++++++++++--
 .../v1/v1_cri_container_manager_service.cc    |  16 ++-
 .../entry/cri/v1alpha/cri_security_context.cc | 110 +++++++++++++++--
 src/daemon/modules/spec/specs.c               |  74 +++++++++++-
 src/daemon/modules/spec/specs_extend.c        |  17 ++-
 src/daemon/modules/spec/specs_security.c      |  19 +--
 6 files changed, 294 insertions(+), 53 deletions(-)

diff --git a/src/daemon/common/cri/v1/v1_cri_security_context.cc b/src/daemon/common/cri/v1/v1_cri_security_context.cc
index f6441f42..930710e0 100644
--- a/src/daemon/common/cri/v1/v1_cri_security_context.cc
+++ b/src/daemon/common/cri/v1/v1_cri_security_context.cc
@@ -19,15 +19,28 @@
 #include <memory>
 
 namespace CRISecurityV1 {
-static void ModifyContainerConfig(const runtime::v1::LinuxContainerSecurityContext &sc, container_config *config)
+static void ModifyContainerConfig(const runtime::v1::LinuxContainerSecurityContext &sc, container_config *config, Errors &error)
 {
+    // none -> ""; username -> username; username, uid -> username; username, uid, gid -> username:gid;
+    // username, gid -> username:gid; uid -> uid; uid, gid -> uid:gid; gid -> error
+    std::string user;
     if (sc.has_run_as_user()) {
-        free(config->user);
-        config->user = util_strdup_s(std::to_string(sc.run_as_user().value()).c_str());
+        user = std::to_string(sc.run_as_user().value());
     }
     if (!sc.run_as_username().empty()) {
+        user = sc.run_as_username();
+    }
+    if (sc.has_run_as_group()) {
+        if (user.empty()) {
+            ERROR("Invalid security context: runAsGroup without runAsUser or runAsUsername");
+            error.SetError("Invalid security context: runAsGroup without runAsUser or runAsUsername");
+            return;
+        }
+        user += ":" + std::to_string(sc.run_as_group().value());
+    }
+    if (!user.empty()) {
         free(config->user);
-        config->user = util_strdup_s(sc.run_as_username().c_str());
+        config->user = util_strdup_s(user.c_str());
     }
 }
 
@@ -42,6 +55,7 @@ static void ModifyHostConfigCapabilities(const runtime::v1::LinuxContainerSecuri
     if (!capAdd.empty()) {
         hostConfig->cap_add = (char **)util_smart_calloc_s(sizeof(char *), capAdd.size());
         if (hostConfig->cap_add == nullptr) {
+            ERROR("Out of memory");
             error.SetError("Out of memory");
             return;
         }
@@ -54,6 +68,7 @@ static void ModifyHostConfigCapabilities(const runtime::v1::LinuxContainerSecuri
     if (!capDrop.empty()) {
         hostConfig->cap_drop = (char **)util_smart_calloc_s(sizeof(char *), capDrop.size());
         if (hostConfig->cap_drop == nullptr) {
+            ERROR("Out of memory");
             error.SetError("Out of memory");
             return;
         }
@@ -74,7 +89,8 @@ static void ModifyHostConfigNoNewPrivs(const runtime::v1::LinuxContainerSecurity
     }
 
     if (hostConfig->security_opt_len > (SIZE_MAX / sizeof(char *)) - 1) {
-        error.Errorf("Out of memory");
+        ERROR("The size of security opts exceeds the limit");
+        error.Errorf("The size of security opts exceeds the limit");
         return;
     }
 
@@ -82,6 +98,7 @@ static void ModifyHostConfigNoNewPrivs(const runtime::v1::LinuxContainerSecurity
     size_t newSize = oldSize + sizeof(char *);
     int ret = util_mem_realloc((void **)(&tmp_security_opt), newSize, (void *)hostConfig->security_opt, oldSize);
     if (ret != 0) {
+        ERROR("Out of memory");
         error.Errorf("Out of memory");
         return;
     }
@@ -98,12 +115,9 @@ static void ModifyHostConfigscSupplementalGroups(const runtime::v1::LinuxContain
 
     const google::protobuf::RepeatedField<google::protobuf::int64> &groups = sc.supplemental_groups();
     if (!groups.empty()) {
-        if (static_cast<size_t>(groups.size()) > SIZE_MAX / sizeof(char *)) {
-            error.SetError("Invalid group size");
-            return;
-        }
-        hostConfig->group_add = (char **)util_common_calloc_s(sizeof(char *) * groups.size());
+        hostConfig->group_add = (char **)util_smart_calloc_s(sizeof(char *), groups.size());
         if (hostConfig->group_add == nullptr) {
+            ERROR("Out of memory");
             error.SetError("Out of memory");
             return;
         }
@@ -114,6 +128,64 @@ static void ModifyHostConfigscSupplementalGroups(const runtime::v1::LinuxContain
     }
 }
 
+static void ApplyMaskedPathsToHostConfig(const runtime::v1::LinuxContainerSecurityContext &sc, host_config *hostConfig,
+                                         Errors &error)
+{
+    if (sc.masked_paths_size() <= 0) {
+        return;
+    }
+
+    if (hostConfig->masked_paths_len > ((SIZE_MAX / sizeof(char *)) - sc.masked_paths_size())) {
+        ERROR("The size of masked paths exceeds the limit");
+        error.Errorf("The size of masked paths exceeds the limit");
+        return;
+    }
+
+    char **tmp_masked_paths {nullptr};
+    size_t oldSize = hostConfig->masked_paths_len * sizeof(char *);
+    size_t newSize = oldSize + sc.masked_paths_size() * sizeof(char *);
+    int ret = util_mem_realloc((void **)&tmp_masked_paths, newSize, (void *)hostConfig->masked_paths, oldSize);
+    if (ret != 0) {
+        ERROR("Out of memory");
+        error.Errorf("Out of memory");
+        return;
+    }
+
+    hostConfig->masked_paths = tmp_masked_paths;
+    for (int i = 0; i < sc.masked_paths_size(); ++i) {
+        hostConfig->masked_paths[hostConfig->masked_paths_len++] = util_strdup_s(sc.masked_paths(i).c_str());
+    }
+}
+
+static void ApplyReadonlyPathsToHostConfig(const runtime::v1::LinuxContainerSecurityContext &sc, host_config *hostConfig,
+                                           Errors &error)
+{
+    if (sc.readonly_paths_size() <= 0) {
+        return;
+    }
+
+    if (hostConfig->readonly_paths_len > ((SIZE_MAX / sizeof(char *)) - sc.readonly_paths_size())) {
+        ERROR("The size of readonly paths exceeds the limit");
+        error.Errorf("The size of readonly paths exceeds the limit");
+        return;
+    }
+
+    char **tmp_readonly_paths {nullptr};
+    size_t oldSize = hostConfig->readonly_paths_len * sizeof(char *);
+    size_t newSize = oldSize + sc.readonly_paths_size() * sizeof(char *);
+    int ret = util_mem_realloc((void **)&tmp_readonly_paths, newSize, (void *)hostConfig->readonly_paths, oldSize);
+    if (ret != 0) {
+        ERROR("Out of memory");
+        error.Errorf("Out of memory");
+        return;
+    }
+
+    hostConfig->readonly_paths = tmp_readonly_paths;
+    for (int i = 0; i < sc.readonly_paths_size(); ++i) {
+        hostConfig->readonly_paths[hostConfig->readonly_paths_len++] = util_strdup_s(sc.readonly_paths(i).c_str());
+    }
+}
+
 static void ModifyHostConfig(const runtime::v1::LinuxContainerSecurityContext &sc, host_config *hostConfig,
                              Errors &error)
 {
@@ -123,6 +195,8 @@ static void ModifyHostConfig(const runtime::v1::LinuxContainerSecurityContext &s
     ModifyHostConfigCapabilities(sc, hostConfig, error);
     ModifyHostConfigNoNewPrivs(sc, hostConfig, error);
     ModifyHostConfigscSupplementalGroups(sc, hostConfig, error);
+    ApplyMaskedPathsToHostConfig(sc, hostConfig, error);
+    ApplyReadonlyPathsToHostConfig(sc, hostConfig, error);
 }
 
 static void ModifyContainerNamespaceOptions(const runtime::v1::NamespaceOption &nsOpts,
@@ -196,11 +270,18 @@ void ApplySandboxSecurityContext(const runtime::v1::LinuxPodSandboxConfig &lc, c
         *sc->mutable_supplemental_groups() = old.supplemental_groups();
         sc->set_readonly_rootfs(old.readonly_rootfs());
     }
-    ModifyContainerConfig(*sc, config);
+    ModifyContainerConfig(*sc, config, error);
+    if (error.NotEmpty()) {
+        ERROR("Failed to modify container config for sandbox");
+        return;
+    }
+
     ModifyHostConfig(*sc, hc, error);
     if (error.NotEmpty()) {
+        ERROR("Failed to modify host config for sandbox");
         return;
     }
+
     ModifySandboxNamespaceOptions(sc->namespace_options(), hc);
 }
 
@@ -209,9 +290,15 @@ void ApplyContainerSecurityContext(const runtime::v1::LinuxContainerConfig &lc,
 {
     if (lc.has_security_context()) {
         const runtime::v1::LinuxContainerSecurityContext &sc = lc.security_context();
-        ModifyContainerConfig(sc, config);
+        ModifyContainerConfig(sc, config, error);
+        if (error.NotEmpty()) {
+            ERROR("Failed to modify container config for container");
+            return;
+        }
+
         ModifyHostConfig(sc, hc, error);
         if (error.NotEmpty()) {
+            ERROR("Failed to modify host config for container");
             return;
         }
     }
diff --git a/src/daemon/entry/cri/v1/v1_cri_container_manager_service.cc b/src/daemon/entry/cri/v1/v1_cri_container_manager_service.cc
index 70629591..1f20d2d2 100644
--- a/src/daemon/entry/cri/v1/v1_cri_container_manager_service.cc
+++ b/src/daemon/entry/cri/v1/v1_cri_container_manager_service.cc
@@ -128,8 +128,22 @@ void ContainerManagerService::DoUsePodLevelSELinuxConfig(const runtime::v1::Cont
         return;
     }
 
+    const char securityOptSep = '=';
+
     const runtime::v1::LinuxSandboxSecurityContext &context = config.linux().security_context();
-    CRIHelpersV1::ApplySandboxSecurityContextToHostConfig(context, hostconfig, error);
+    std::vector<std::string> selinuxOpts = CRIHelpersV1::GetSELinuxLabelOpts(context.has_selinux_options(),
+                                                                             context.selinux_options(), securityOptSep, error);
+    if (error.NotEmpty()) {
+        ERROR("Failed to generate SELinuxLabel options for container %s", error.GetMessage().c_str());
+        error.Errorf("Failed to generate SELinuxLabel options for container %s", error.GetMessage().c_str());
+        return;
+    }
+    CRIHelpersV1::AddSecurityOptsToHostConfig(selinuxOpts, hostconfig, error);
+    if (error.NotEmpty()) {
+        ERROR("Failed to add securityOpts to hostconfig: %s", error.GetMessage().c_str());
+        error.Errorf("Failed to add securityOpts to hostconfig: %s", error.GetMessage().c_str());
+        return;
+    }
 }
 
 auto ContainerManagerService::IsSELinuxLabelEmpty(const ::runtime::v1::SELinuxOption &selinuxOption) -> bool
diff --git a/src/daemon/entry/cri/v1alpha/cri_security_context.cc b/src/daemon/entry/cri/v1alpha/cri_security_context.cc
index 0535b438..57ec3a63 100644
--- a/src/daemon/entry/cri/v1alpha/cri_security_context.cc
+++ b/src/daemon/entry/cri/v1alpha/cri_security_context.cc
@@ -20,15 +20,29 @@
 #include <memory>
 
 namespace CRISecurity {
-static void ModifyContainerConfig(const runtime::v1alpha2::LinuxContainerSecurityContext &sc, container_config *config)
+static void ModifyContainerConfig(const runtime::v1alpha2::LinuxContainerSecurityContext &sc, container_config *config,
+                                  Errors &error)
 {
+    // none -> ""; username -> username; username, uid -> username; username, uid, gid -> username:gid;
+    // username, gid -> username:gid; uid -> uid; uid, gid -> uid:gid; gid -> error
+    std::string user;
     if (sc.has_run_as_user()) {
-        free(config->user);
-        config->user = util_strdup_s(std::to_string(sc.run_as_user().value()).c_str());
+        user = std::to_string(sc.run_as_user().value());
     }
     if (!sc.run_as_username().empty()) {
+        user = sc.run_as_username();
+    }
+    if (sc.has_run_as_group()) {
+        if (user.empty()) {
+            ERROR("Invalid security context: runAsGroup without runAsUser or runAsUsername");
+            error.SetError("Invalid security context: runAsGroup without runAsUser or runAsUsername");
+            return;
+        }
+        user += ":" + std::to_string(sc.run_as_group().value());
+    }
+    if (!user.empty()) {
         free(config->user);
-        config->user = util_strdup_s(sc.run_as_username().c_str());
+        config->user = util_strdup_s(user.c_str());
     }
 }
 
@@ -43,6 +57,7 @@ static void ModifyHostConfigCapabilities(const runtime::v1alpha2::LinuxContainer
     if (!capAdd.empty()) {
         hostConfig->cap_add = (char **)util_smart_calloc_s(sizeof(char *), capAdd.size());
         if (hostConfig->cap_add == nullptr) {
+            ERROR("Out of memory");
             error.SetError("Out of memory");
             return;
         }
@@ -55,6 +70,7 @@ static void ModifyHostConfigCapabilities(const runtime::v1alpha2::LinuxContainer
     if (!capDrop.empty()) {
         hostConfig->cap_drop = (char **)util_smart_calloc_s(sizeof(char *), capDrop.size());
         if (hostConfig->cap_drop == nullptr) {
+            ERROR("Out of memory");
             error.SetError("Out of memory");
             return;
         }
@@ -75,7 +91,8 @@ static void ModifyHostConfigNoNewPrivs(const runtime::v1alpha2::LinuxContainerSe
     }
 
     if (hostConfig->security_opt_len > (SIZE_MAX / sizeof(char *)) - 1) {
-        error.Errorf("Out of memory");
+        ERROR("The size of security opts exceeds the limit");
+        error.Errorf("The size of security opts exceeds the limit");
         return;
     }
 
@@ -83,6 +100,7 @@ static void ModifyHostConfigNoNewPrivs(const runtime::v1alpha2::LinuxContainerSe
     size_t newSize = oldSize + sizeof(char *);
     int ret = util_mem_realloc((void **)(&tmp_security_opt), newSize, (void *)hostConfig->security_opt, oldSize);
     if (ret != 0) {
+        ERROR("Out of memory");
         error.Errorf("Out of memory");
         return;
     }
@@ -99,12 +117,9 @@ static void ModifyHostConfigscSupplementalGroups(const runtime::v1alpha2::LinuxC
 
     const google::protobuf::RepeatedField<google::protobuf::int64> &groups = sc.supplemental_groups();
     if (!groups.empty()) {
-        if (static_cast<size_t>(groups.size()) > SIZE_MAX / sizeof(char *)) {
-            error.SetError("Invalid group size");
-            return;
-        }
-        hostConfig->group_add = (char **)util_common_calloc_s(sizeof(char *) * groups.size());
+        hostConfig->group_add = (char **)util_smart_calloc_s(sizeof(char *), groups.size());
         if (hostConfig->group_add == nullptr) {
+            ERROR("Out of memory");
             error.SetError("Out of memory");
             return;
         }
@@ -115,6 +130,64 @@ static void ModifyHostConfigscSupplementalGroups(const runtime::v1alpha2::LinuxC
     }
 }
 
+static void ApplyMaskedPathsToHostConfig(const runtime::v1alpha2::LinuxContainerSecurityContext &sc, host_config *hostConfig,
+                                         Errors &error)
+{
+    if (sc.masked_paths_size() <= 0) {
+        return;
+    }
+
+    if (hostConfig->masked_paths_len > ((SIZE_MAX / sizeof(char *)) - sc.masked_paths_size())) {
+        ERROR("The size of masked paths exceeds the limit");
+        error.Errorf("The size of masked paths exceeds the limit");
+        return;
+    }
+
+    char **tmp_masked_paths {nullptr};
+    size_t oldSize = hostConfig->masked_paths_len * sizeof(char *);
+    size_t newSize = oldSize + sc.masked_paths_size() * sizeof(char *);
+    int ret = util_mem_realloc((void **)&tmp_masked_paths, newSize, (void *)hostConfig->masked_paths, oldSize);
+    if (ret != 0) {
+        ERROR("Out of memory");
+        error.Errorf("Out of memory");
+        return;
+    }
+
+    hostConfig->masked_paths = tmp_masked_paths;
+    for (int i = 0; i < sc.masked_paths_size(); ++i) {
+        hostConfig->masked_paths[hostConfig->masked_paths_len++] = util_strdup_s(sc.masked_paths(i).c_str());
+    }
+}
+
+static void ApplyReadonlyPathsToHostConfig(const runtime::v1alpha2::LinuxContainerSecurityContext &sc, host_config *hostConfig,
+                                           Errors &error)
+{
+    if (sc.readonly_paths_size() <= 0) {
+        return;
+    }
+
+    if (hostConfig->readonly_paths_len > ((SIZE_MAX / sizeof(char *)) - sc.readonly_paths_size())) {
+        ERROR("The size of readonly paths exceeds the limit");
+        error.Errorf("The size of readonly paths exceeds the limit");
+        return;
+    }
+
+    char **tmp_readonly_paths {nullptr};
+    size_t oldSize = hostConfig->readonly_paths_len * sizeof(char *);
+    size_t newSize = oldSize + sc.readonly_paths_size() * sizeof(char *);
+    int ret = util_mem_realloc((void **)&tmp_readonly_paths, newSize, (void *)hostConfig->readonly_paths, oldSize);
+    if (ret != 0) {
+        ERROR("Out of memory");
+        error.Errorf("Out of memory");
+        return;
+    }
+
+    hostConfig->readonly_paths = tmp_readonly_paths;
+    for (int i = 0; i < sc.readonly_paths_size(); ++i) {
+        hostConfig->readonly_paths[hostConfig->readonly_paths_len++] = util_strdup_s(sc.readonly_paths(i).c_str());
+    }
+}
+
 static void ModifyHostConfig(const runtime::v1alpha2::LinuxContainerSecurityContext &sc, host_config *hostConfig,
                              Errors &error)
 {
@@ -124,6 +197,8 @@ static void ModifyHostConfig(const runtime::v1alpha2::LinuxContainerSecurityCont
     ModifyHostConfigCapabilities(sc, hostConfig, error);
     ModifyHostConfigNoNewPrivs(sc, hostConfig, error);
     ModifyHostConfigscSupplementalGroups(sc, hostConfig, error);
+    ApplyMaskedPathsToHostConfig(sc, hostConfig, error);
+    ApplyReadonlyPathsToHostConfig(sc, hostConfig, error);
 }
 
 static void ModifyContainerNamespaceOptions(const runtime::v1alpha2::NamespaceOption &nsOpts,
@@ -179,6 +254,7 @@ void ApplySandboxSecurityContext(const runtime::v1alpha2::LinuxPodSandboxConfig
     std::unique_ptr<runtime::v1alpha2::LinuxContainerSecurityContext> sc(
         new (std::nothrow) runtime::v1alpha2::LinuxContainerSecurityContext);
     if (sc == nullptr) {
+        ERROR("Out of memory");
         error.SetError("Out of memory");
         return;
     }
@@ -197,9 +273,14 @@ void ApplySandboxSecurityContext(const runtime::v1alpha2::LinuxPodSandboxConfig
         *sc->mutable_supplemental_groups() = old.supplemental_groups();
         sc->set_readonly_rootfs(old.readonly_rootfs());
     }
-    ModifyContainerConfig(*sc, config);
+    ModifyContainerConfig(*sc, config, error);
+    if (error.NotEmpty()) {
+        ERROR("Failed to modify container config for sandbox");
+        return;
+    }
     ModifyHostConfig(*sc, hc, error);
     if (error.NotEmpty()) {
+        ERROR("Failed to modify host config for sandbox");
         return;
     }
     ModifySandboxNamespaceOptions(sc->namespace_options(), hc);
@@ -210,9 +291,14 @@ void ApplyContainerSecurityContext(const runtime::v1alpha2::LinuxContainerConfig
 {
     if (lc.has_security_context()) {
         const runtime::v1alpha2::LinuxContainerSecurityContext &sc = lc.security_context();
-        ModifyContainerConfig(sc, config);
+        ModifyContainerConfig(sc, config, error);
+        if (error.NotEmpty()) {
+            ERROR("Failed to modify container config for container");
+            return;
+        }
         ModifyHostConfig(sc, hc, error);
         if (error.NotEmpty()) {
+            ERROR("Failed to modify host config for container");
             return;
         }
     }
diff --git a/src/daemon/modules/spec/specs.c b/src/daemon/modules/spec/specs.c
index a7751d1b..95346603 100644
--- a/src/daemon/modules/spec/specs.c
+++ b/src/daemon/modules/spec/specs.c
@@ -2133,6 +2133,58 @@ static int generate_security_opt(host_config *hc)
 }
 #endif
 
+static int merge_paths(char ***dest_paths, size_t *dest_paths_len, char **src_paths, size_t src_paths_len)
+{
+    if (dest_paths == NULL || dest_paths_len == NULL) {
+        ERROR("Invalid args");
+        return -1;
+    }
+
+    if (src_paths_len > SIZE_MAX / sizeof(char *) ||
+        *dest_paths_len > ((SIZE_MAX / sizeof(char *)) - src_paths_len)) {
+        ERROR("Out of memory");
+        return -1;
+    }
+
+    size_t i;
+    char **tmp_paths = NULL;
+    size_t old_size = *dest_paths_len * sizeof(char *);
+    size_t new_size = old_size + src_paths_len * sizeof(char *);
+    int ret = util_mem_realloc((void **)&tmp_paths, new_size,
+                               (void *)*dest_paths, old_size);
+    if (ret != 0) {
+        ERROR("Out of memory");
+        return -1;
+    }
+
+    *dest_paths = tmp_paths;
+    for (i = 0; i < src_paths_len; i++) {
+        (*dest_paths)[(*dest_paths_len)++] = util_strdup_s(src_paths[i]);
+    }
+
+    return 0;
+}
+
+static int merge_masked_paths(oci_runtime_spec *oci_spec, char **masked_paths, size_t masked_paths_len)
+{
+    if (masked_paths == NULL || masked_paths_len == 0) {
+        return 0;
+    }
+
+    return merge_paths(&oci_spec->linux->masked_paths, &oci_spec->linux->masked_paths_len,
+                       masked_paths, masked_paths_len);
+}
+
+static int merge_readonly_paths(oci_runtime_spec *oci_spec, char **readonly_paths, size_t readonly_paths_len)
+{
+    if (readonly_paths == NULL || readonly_paths_len == 0) {
+        return 0;
+    }
+
+    return merge_paths(&oci_spec->linux->readonly_paths, &oci_spec->linux->readonly_paths_len,
+                       readonly_paths, readonly_paths_len);
+}
+
 static int merge_security_conf(oci_runtime_spec *oci_spec, host_config *host_spec,
                                container_config_v2_common_config *v2_spec)
 {
@@ -2180,6 +2232,18 @@ static int merge_security_conf(oci_runtime_spec *oci_spec, host_config *host_spe
     }
 #endif
 
+    ret = merge_masked_paths(oci_spec, host_spec->masked_paths, host_spec->masked_paths_len);
+    if (ret != 0) {
+        ERROR("Failed to merge masked paths");
+        goto out;
+    }
+
+    ret = merge_readonly_paths(oci_spec, host_spec->readonly_paths, host_spec->readonly_paths_len);
+    if (ret != 0) {
+        ERROR("Failed to merge readonly paths");
+        goto out;
+    }
+
 out:
     return ret;
 }
@@ -2205,11 +2269,6 @@ static int merge_oci_cgroups_path(const char *id, oci_runtime_spec *oci_spec, co
         return -1;
     }
 
-    if (make_sure_oci_spec_linux(oci_spec) != 0) {
-        ERROR("Failed to make oci spec linux");
-        return -1;
-    }
-
     free(oci_spec->linux->cgroups_path);
     oci_spec->linux->cgroups_path = merge_container_cgroups_path(id, host_spec);
 
@@ -2228,6 +2287,11 @@ int merge_all_specs(host_config *host_spec, const char *real_rootfs, container_c
     char *userns_remap = conf_get_isulad_userns_remap();
 #endif
 
+    if (make_sure_oci_spec_linux(oci_spec) != 0) {
+        ERROR("Failed to make oci spec linux");
+        return -1;
+    }
+
     ret = merge_root(oci_spec, real_rootfs, host_spec);
     if (ret != 0) {
         ERROR("Failed to merge root");
diff --git a/src/daemon/modules/spec/specs_extend.c b/src/daemon/modules/spec/specs_extend.c
index 5ede7936..199cba54 100644
--- a/src/daemon/modules/spec/specs_extend.c
+++ b/src/daemon/modules/spec/specs_extend.c
@@ -136,28 +136,21 @@ static int make_linux_uid_gid_mappings(oci_runtime_spec *container, unsigned int
                                        unsigned int size)
 {
     int ret = 0;
-
-    ret = make_sure_oci_spec_linux(container);
-    if (ret < 0) {
-        goto out;
-    }
-
     if (container->linux->uid_mappings == NULL) {
         ret = make_one_id_mapping(&(container->linux->uid_mappings), host_uid, size);
         if (ret < 0) {
-            goto out;
+            return ret;
         }
         container->linux->uid_mappings_len++;
     }
     if (container->linux->gid_mappings == NULL) {
         ret = make_one_id_mapping(&(container->linux->gid_mappings), host_gid, size);
         if (ret < 0) {
-            goto out;
+            return ret;
         }
         container->linux->gid_mappings_len++;
     }
 
-out:
     return ret;
 }
 
@@ -180,6 +173,12 @@ int make_userns_remap(oci_runtime_spec *container, const char *user_remap)
     if (host_uid == 0 && host_gid == 0) {
         return 0;
     }
+
+    if (make_sure_oci_spec_linux(container) != 0) {
+        ERROR("Failed to make oci spce linux");
+        return -1;
+    }
+
     ret = make_linux_uid_gid_mappings(container, host_uid, host_gid, size);
     if (ret) {
         ERROR("Make linux uid and gid mappings failed");
diff --git a/src/daemon/modules/spec/specs_security.c b/src/daemon/modules/spec/specs_security.c
index 08db8d0d..e78cc744 100644
--- a/src/daemon/modules/spec/specs_security.c
+++ b/src/daemon/modules/spec/specs_security.c
@@ -879,13 +879,6 @@ int merge_caps(oci_runtime_spec *oci_spec, const char **adds, size_t adds_len, c
 
 static int make_sure_oci_spec_linux_sysctl(oci_runtime_spec *oci_spec)
 {
-    int ret = 0;
-
-    ret = make_sure_oci_spec_linux(oci_spec);
-    if (ret < 0) {
-        return -1;
-    }
-
     if (oci_spec->linux->sysctl == NULL) {
         oci_spec->linux->sysctl = util_common_calloc_s(sizeof(json_map_string_string));
         if (oci_spec->linux->sysctl == NULL) {
@@ -904,6 +897,11 @@ int merge_sysctls(oci_runtime_spec *oci_spec, const json_map_string_string *sysc
         return 0;
     }
 
+    ret = make_sure_oci_spec_linux(oci_spec);
+    if (ret < 0) {
+        return -1;
+    }
+
     ret = make_sure_oci_spec_linux_sysctl(oci_spec);
     if (ret < 0) {
         goto out;
@@ -1004,13 +1002,6 @@ static void free_adds_cap_for_system_container(char **adds, size_t adds_len)
 
 static int make_sure_oci_spec_linux_seccomp(oci_runtime_spec *oci_spec)
 {
-    int ret = 0;
-
-    ret = make_sure_oci_spec_linux(oci_spec);
-    if (ret < 0) {
-        return -1;
-    }
-
     if (oci_spec->linux->seccomp == NULL) {
         oci_spec->linux->seccomp = util_common_calloc_s(sizeof(oci_runtime_config_linux_seccomp));
         if (oci_spec->linux->seccomp == NULL) {
-- 
2.42.0

