From 02167555e702316fe14cc963f9e978e9f66f59ba Mon Sep 17 00:00:00 2001
From: chengzrz <czrzrichard@gmail.com>
Date: Fri, 24 Dec 2021 10:47:31 +0800
Subject: [PATCH 05/30] Seccomp optimization

Signed-off-by: chengzrz <czrzrichard@gmail.com>
---
 src/common/constants.h                   |   2 +
 src/daemon/modules/spec/specs_security.c | 112 +++++++++++++++++++----
 src/utils/cutils/utils.c                 |  54 ++++++-----
 3 files changed, 128 insertions(+), 40 deletions(-)

diff --git a/src/common/constants.h b/src/common/constants.h
index 60fb9abe..294f4b78 100644
--- a/src/common/constants.h
+++ b/src/common/constants.h
@@ -142,6 +142,8 @@ extern "C" {
 
 /* RUNPATH is defined by -DRUNPATH=$value when execute cmake, default is "/var/run" */
 #define CLIENT_RUNDIR RUNPATH"/isula"
+#define SCMP_ARCH_X86_64 "SCMP_ARCH_X86_64"
+#define SCMP_ARCH_AARCH64 "SCMP_ARCH_AARCH64"
 
 typedef enum {
     CONTAINER_STATUS_UNKNOWN = 0,
diff --git a/src/daemon/modules/spec/specs_security.c b/src/daemon/modules/spec/specs_security.c
index 658c2e1f..8a8b2d86 100644
--- a/src/daemon/modules/spec/specs_security.c
+++ b/src/daemon/modules/spec/specs_security.c
@@ -457,45 +457,123 @@ static bool meet_filtering_rules(const docker_seccomp *seccomp, const docker_sec
     return meet_include_arch && meet_include_cap && meet_exclude_arch && meet_exclude_cap;
 }
 
-static size_t docker_seccomp_arches_count(const docker_seccomp *docker_seccomp_spec)
+static size_t docker_seccomp_arches_count(const char* seccomp_architecture, const docker_seccomp *docker_seccomp_spec)
 {
     size_t count = 0;
     size_t i = 0;
-    for (i = 0; i < docker_seccomp_spec->arch_map_len; i++) {
-        count += docker_seccomp_spec->arch_map[i]->sub_architectures_len + 1;
+
+    if (seccomp_architecture == NULL) {
+        ERROR("Invalid input seccomp architecture");
+        return -1;
+    }
+
+    for (i = 0; i < docker_seccomp_spec->arch_map_len; ++i) {
+        if (docker_seccomp_spec->arch_map[i] == NULL ||  docker_seccomp_spec->arch_map[i]->architecture == NULL) {
+            continue;
+        }
+        if (strcmp(seccomp_architecture, docker_seccomp_spec->arch_map[i]->architecture) == 0) {
+            count = docker_seccomp_spec->arch_map[i]->sub_architectures_len + 1;
+            break;
+        }
+    }
+
+    if (count == 0) {
+        ERROR("seccomp architecture not found");
+        count = -1;
     }
+
     return count;
 }
 
-static int dup_architectures_to_oci_spec(const docker_seccomp *docker_seccomp_spec,
+static int dup_architectures_to_oci_spec(const char* seccomp_architecture, const docker_seccomp *docker_seccomp_spec,
                                          oci_runtime_config_linux_seccomp *oci_seccomp_spec)
 {
+    size_t i = 0;
+    size_t j = 0;
     size_t arch_size = 0;
 
-    arch_size = docker_seccomp_arches_count(docker_seccomp_spec);
-    if (arch_size != 0) {
-        size_t i;
-        size_t j;
-        if (arch_size > (SIZE_MAX / sizeof(char *))) {
-            return -1;
-        }
-        oci_seccomp_spec->architectures = util_common_calloc_s(arch_size * sizeof(char *));
-        if (oci_seccomp_spec->architectures == NULL) {
-            return -1;
+    if (seccomp_architecture == NULL) {
+        oci_seccomp_spec->architectures_len = 0;
+        return 0;
+    }
+
+    arch_size = docker_seccomp_arches_count(seccomp_architecture, docker_seccomp_spec);
+    if (arch_size < 0) {
+        ERROR("Failed to get arches count from docker seccomp spec");
+        return -1;
+    }
+
+    oci_seccomp_spec->architectures = util_common_calloc_s(arch_size * sizeof(char *));
+    if (oci_seccomp_spec->architectures == NULL) {
+        ERROR("Failed to calloc memory for architectures in seccomp spec");
+        return -1;
+    }
+
+    for (i = 0; i < docker_seccomp_spec->arch_map_len; ++i) {
+        if (docker_seccomp_spec->arch_map[i] == NULL || docker_seccomp_spec->arch_map[i]->architecture == NULL) {
+            continue;
         }
-        for (i = 0; i < docker_seccomp_spec->arch_map_len; i++) {
+        if (strcmp(seccomp_architecture, docker_seccomp_spec->arch_map[i]->architecture) == 0) {
             oci_seccomp_spec->architectures[oci_seccomp_spec->architectures_len++] =
                 util_strdup_s(docker_seccomp_spec->arch_map[i]->architecture);
-            for (j = 0; j < docker_seccomp_spec->arch_map[i]->sub_architectures_len; j++) {
+
+            for (j = 0; j < docker_seccomp_spec->arch_map[i]->sub_architectures_len; ++j) {
                 oci_seccomp_spec->architectures[oci_seccomp_spec->architectures_len++] =
                     util_strdup_s(docker_seccomp_spec->arch_map[i]->sub_architectures[j]);
             }
+            break;
         }
     }
 
     return 0;
 }
 
+// return 0 when normalized_arch has been properly set into seccomp spec
+static int normalized_arch_to_seccomp_arch(const char *host_arch, const docker_seccomp *docker_seccomp_spec,
+                                           oci_runtime_config_linux_seccomp *oci_seccomp_spec)
+{
+    INFO("host architecture is %s", host_arch);
+    // x86 archs
+    if (strcasecmp(host_arch, "386") == 0 || strcasecmp(host_arch, "amd64") == 0) {
+        return dup_architectures_to_oci_spec(SCMP_ARCH_X86_64, docker_seccomp_spec, oci_seccomp_spec);
+    }
+    // arm archs
+    if (strcasecmp(host_arch, "arm64") == 0 || strcasecmp(host_arch, "arm") == 0) {
+        return dup_architectures_to_oci_spec(SCMP_ARCH_AARCH64, docker_seccomp_spec, oci_seccomp_spec);
+    }
+    //other archs
+    return dup_architectures_to_oci_spec(NULL, docker_seccomp_spec, oci_seccomp_spec);
+}
+
+static int load_architectures_into_oci_spec(const docker_seccomp *docker_seccomp_spec,
+                                            oci_runtime_config_linux_seccomp *oci_seccomp_spec)
+{
+    int ret = 0;
+    char *host_os = NULL;
+    char *host_arch = NULL;
+    char *host_variant = NULL;
+
+    ret = util_normalized_host_os_arch(&host_os, &host_arch, &host_variant);
+    if (ret != 0) {
+        ERROR("get host os and arch for import failed");
+        isulad_try_set_error_message("get host os and arch for import failed");
+        goto out;
+    }
+
+    ret = normalized_arch_to_seccomp_arch(host_arch, docker_seccomp_spec, oci_seccomp_spec);
+    if (ret != 0) {
+        ERROR("transfer normalized arch to seccomp arch failed");
+        isulad_try_set_error_message("transfer normalized arch to seccomp arch failed");
+        goto out;
+    }
+
+out:
+    free(host_os);
+    free(host_arch);
+    free(host_variant);
+    return ret;
+}
+
 static int dup_syscall_args_to_oci_spec(const docker_seccomp_syscalls_element *docker_syscall,
                                         defs_syscall *oci_syscall)
 {
@@ -606,7 +684,7 @@ static oci_runtime_config_linux_seccomp *trans_docker_seccomp_to_oci_format(cons
     oci_seccomp_spec->default_action = util_strdup_s(docker_seccomp_spec->default_action);
 
     // architectures
-    if (dup_architectures_to_oci_spec(docker_seccomp_spec, oci_seccomp_spec)) {
+    if (load_architectures_into_oci_spec(docker_seccomp_spec, oci_seccomp_spec)) {
         goto out;
     }
 
diff --git a/src/utils/cutils/utils.c b/src/utils/cutils/utils.c
index a647f7bc..278a72c5 100644
--- a/src/utils/cutils/utils.c
+++ b/src/utils/cutils/utils.c
@@ -1353,6 +1353,7 @@ static char *get_cpu_variant()
 int util_normalized_host_os_arch(char **host_os, char **host_arch, char **host_variant)
 {
     int ret = 0;
+    int i = 0;
     struct utsname uts;
     char *tmp_variant = NULL;
 
@@ -1367,20 +1368,31 @@ int util_normalized_host_os_arch(char **host_os, char **host_arch, char **host_v
         goto out;
     }
 
+    const char *arch_map[][2] = { { "i386", "386" },
+        { "x86_64", "amd64" },
+        { "x86-64", "amd64" },
+        { "aarch64", "arm64" },
+        { "armhf", "arm" },
+        { "armel", "arm" },
+        { "mips64le", "mips64le" },
+        { "mips64el", "mips64le" }
+    };
+
+    const char *variant_map[][2] = { { "5", "v5" },
+        { "6", "v6" },
+        { "7", "v7" },
+        { "8", "v8" }
+    };
+
     *host_os = util_strings_to_lower(uts.sysname);
+    *host_arch = util_strdup_s(uts.machine);
 
-    if (strcasecmp("i386", uts.machine) == 0) {
-        *host_arch = util_strdup_s("386");
-    } else if ((strcasecmp("x86_64", uts.machine) == 0) || (strcasecmp("x86-64", uts.machine) == 0)) {
-        *host_arch = util_strdup_s("amd64");
-    } else if (strcasecmp("aarch64", uts.machine) == 0) {
-        *host_arch = util_strdup_s("arm64");
-    } else if ((strcasecmp("armhf", uts.machine) == 0) || (strcasecmp("armel", uts.machine) == 0)) {
-        *host_arch = util_strdup_s("arm");
-    } else if ((strcasecmp("mips64le", uts.machine) == 0) || (strcasecmp("mips64el", uts.machine) == 0)) {
-        *host_arch = util_strdup_s("mips64le");
-    } else {
-        *host_arch = util_strdup_s(uts.machine);
+    for (i = 0; i < sizeof(arch_map) / sizeof(arch_map[0]); ++i) {
+        if (strcasecmp(uts.machine, arch_map[i][0]) == 0) {
+            free(*host_arch);
+            *host_arch = util_strdup_s(arch_map[i][1]);
+            break;
+        }
     }
 
     if (!strcmp(*host_arch, "arm") || !strcmp(*host_arch, "arm64")) {
@@ -1394,17 +1406,13 @@ int util_normalized_host_os_arch(char **host_os, char **host_arch, char **host_v
             *host_variant = util_strdup_s("v7");
         } else if (!strcmp(*host_arch, "arm") && *host_variant != NULL) {
             tmp_variant = *host_variant;
-            *host_variant = NULL;
-            if (!strcmp(tmp_variant, "5")) {
-                *host_variant = util_strdup_s("v5");
-            } else if (!strcmp(tmp_variant, "6")) {
-                *host_variant = util_strdup_s("v6");
-            } else if (!strcmp(tmp_variant, "7")) {
-                *host_variant = util_strdup_s("v7");
-            } else if (!strcmp(tmp_variant, "8")) {
-                *host_variant = util_strdup_s("v8");
-            } else {
-                *host_variant = util_strdup_s(tmp_variant);
+            *host_variant = util_strdup_s(tmp_variant);
+            for (i = 0; i < sizeof(variant_map) / sizeof(variant_map[0]); ++i) {
+                if (!strcmp(tmp_variant, variant_map[i][0])) {
+                    free(*host_variant);
+                    *host_variant = util_strdup_s(variant_map[i][1]);
+                    break;
+                }
             }
             free(tmp_variant);
             tmp_variant = NULL;
-- 
2.32.1 (Apple Git-133)

