diff options
Diffstat (limited to '0009-2243-Refactor-capbilities-specs.patch')
-rw-r--r-- | 0009-2243-Refactor-capbilities-specs.patch | 1056 |
1 files changed, 1056 insertions, 0 deletions
diff --git a/0009-2243-Refactor-capbilities-specs.patch b/0009-2243-Refactor-capbilities-specs.patch new file mode 100644 index 0000000..116a30f --- /dev/null +++ b/0009-2243-Refactor-capbilities-specs.patch @@ -0,0 +1,1056 @@ +From e84112fd7128e05a1a4a380d8242c672d1f539f9 Mon Sep 17 00:00:00 2001 +From: xuxuepeng <xuxuepeng1@huawei.com> +Date: Mon, 13 Nov 2023 08:44:15 +0000 +Subject: [PATCH 09/14] !2243 Refactor capbilities specs * Refactor capbilities + specs + +--- + src/cmd/isula/isula_host_spec.c | 1 + + src/daemon/modules/spec/specs.c | 12 +- + src/daemon/modules/spec/specs_security.c | 140 ++++---- + src/utils/cutils/utils_cap.c | 119 +++++++ + src/utils/cutils/utils_cap.h | 39 +++ + src/utils/cutils/utils_verify.c | 81 ----- + src/utils/cutils/utils_verify.h | 6 - + test/cutils/utils_verify/utils_verify_ut.cc | 14 - + .../image/oci/oci_config_merge/CMakeLists.txt | 1 + + test/image/oci/storage/images/CMakeLists.txt | 1 + + test/specs/specs/CMakeLists.txt | 1 + + test/specs/specs/oci_runtime_spec.json | 32 ++ + test/specs/specs/specs_ut.cc | 315 ++++++++++++++++++ + test/specs/specs_extend/CMakeLists.txt | 1 + + 14 files changed, 573 insertions(+), 190 deletions(-) + create mode 100644 src/utils/cutils/utils_cap.c + create mode 100644 src/utils/cutils/utils_cap.h + +diff --git a/src/cmd/isula/isula_host_spec.c b/src/cmd/isula/isula_host_spec.c +index 6f39588d..09dea271 100644 +--- a/src/cmd/isula/isula_host_spec.c ++++ b/src/cmd/isula/isula_host_spec.c +@@ -36,6 +36,7 @@ + #include "utils_file.h" + #include "utils_string.h" + #include "utils_verify.h" ++#include "utils_cap.h" + #include "opt_ulimit.h" + + static bool parse_restart_policy(const char *policy, host_config_restart_policy **rp) +diff --git a/src/daemon/modules/spec/specs.c b/src/daemon/modules/spec/specs.c +index 95346603..cc49d85f 100644 +--- a/src/daemon/modules/spec/specs.c ++++ b/src/daemon/modules/spec/specs.c +@@ -49,6 +49,7 @@ + #include "utils_file.h" + #include "utils_string.h" + #include "utils_verify.h" ++#include "utils_cap.h" + + #ifndef CLONE_NEWUTS + #define CLONE_NEWUTS 0x04000000 +@@ -814,15 +815,16 @@ static int adapt_settings_for_privileged(oci_runtime_spec *oci_spec, bool privil + { + int ret = 0; + size_t all_caps_len = 0; ++ const char **all_caps = NULL; + + if (!privileged) { + return 0; + } + +- all_caps_len = util_get_all_caps_len(); +- if (oci_spec == NULL) { +- ret = -1; +- goto out; ++ all_caps = util_get_all_caps(&all_caps_len); ++ if (all_caps == NULL) { ++ ERROR("Failed to get all capabilities"); ++ return -1; + } + + clean_correlated_items(oci_spec); +@@ -838,7 +840,7 @@ static int adapt_settings_for_privileged(oci_runtime_spec *oci_spec, bool privil + goto out; + } + +- ret = refill_oci_process_capabilities(&oci_spec->process->capabilities, g_all_caps, all_caps_len); ++ ret = refill_oci_process_capabilities(&oci_spec->process->capabilities, all_caps, all_caps_len); + if (ret != 0) { + ERROR("Failed to copy all capabilities"); + ret = -1; +diff --git a/src/daemon/modules/spec/specs_security.c b/src/daemon/modules/spec/specs_security.c +index e78cc744..b34aec7c 100644 +--- a/src/daemon/modules/spec/specs_security.c ++++ b/src/daemon/modules/spec/specs_security.c +@@ -37,6 +37,7 @@ + #include "utils_array.h" + #include "utils_string.h" + #include "utils_verify.h" ++#include "utils_cap.h" + + #define MAX_CAP_LEN 32 + +@@ -104,41 +105,31 @@ static int tweak_drops_capabilities(char ***new_caps, size_t *new_caps_len, char + size_t i = 0; + int ret = 0; + +- if (util_strings_in_slice((const char **)drops, drops_len, "all")) { +- goto out; ++ if (basic_caps == NULL || basic_caps_len == 0) { ++ *new_caps = NULL; ++ *new_caps_len = 0; ++ return 0; + } + +- for (i = 0; (basic_caps != NULL && i < basic_caps_len); i++) { +- // skip `all` already handled above +- if (!basic_caps[i] || !strcasecmp(basic_caps[i], "all")) { +- continue; +- } +- +- // if we don't drop `all`, add back all the non-dropped caps ++ for (i = 0; i < basic_caps_len; i++) { + if (!util_strings_in_slice((const char **)drops, drops_len, basic_caps[i] + strlen("CAP_"))) { + ret = append_capability(new_caps, new_caps_len, basic_caps[i]); + if (ret != 0) { + ERROR("Failed to append capabilities"); +- ret = -1; +- goto out; ++ return -1; + } + } + } + +-out: +- return ret; ++ return 0; + } + + static int tweak_adds_capabilities(char ***new_caps, size_t *new_caps_len, const char **adds, size_t adds_len) + { + size_t i = 0; +- int ret = 0; + int nret = 0; +- size_t all_caps_len = 0; + char tmpcap[MAX_CAP_LEN] = { 0 }; + +- all_caps_len = util_get_all_caps_len(); +- + for (i = 0; i < adds_len; i++) { + // skip `all` already handled above + if (strcasecmp(adds[i], "all") == 0) { +@@ -148,111 +139,92 @@ static int tweak_adds_capabilities(char ***new_caps, size_t *new_caps_len, const + nret = snprintf(tmpcap, sizeof(tmpcap), "CAP_%s", adds[i]); + if (nret < 0 || (size_t)nret >= sizeof(tmpcap)) { + ERROR("Failed to print string"); +- ret = -1; +- goto out; +- } +- if (!util_strings_in_slice(g_all_caps, all_caps_len, tmpcap)) { +- ERROR("Unknown capability to add: '%s'", tmpcap); +- ret = -1; +- goto out; ++ return -1; + } + + // add cap if not already in the list + if (!util_strings_in_slice((const char **)*new_caps, *new_caps_len, tmpcap)) { +- ret = append_capability(new_caps, new_caps_len, tmpcap); +- if (ret != 0) { ++ nret = append_capability(new_caps, new_caps_len, tmpcap); ++ if (nret != 0) { + ERROR("Failed to append capabilities"); +- ret = -1; +- goto out; ++ return -1; + } + } + } + +-out: +- return ret; +-} +- +-static bool valid_drops_cap(const char **drops, size_t drops_len) +-{ +- int nret = 0; +- size_t i; +- size_t all_caps_len = 0; +- char tmpcap[MAX_CAP_LEN] = { 0 }; +- +- all_caps_len = util_get_all_caps_len(); +- // look for invalid cap in the drop list +- for (i = 0; i < drops_len; i++) { +- if (strcasecmp(drops[i], "all") == 0) { +- continue; +- } +- +- nret = snprintf(tmpcap, sizeof(tmpcap), "CAP_%s", drops[i]); +- if (nret < 0 || (size_t)nret >= sizeof(tmpcap)) { +- ERROR("Failed to print string"); +- return false; +- } +- if (!util_strings_in_slice(g_all_caps, all_caps_len, tmpcap)) { +- ERROR("Unknown capability to drop: '%s'", drops[i]); +- return false; +- } +- } +- +- return true; ++ return 0; + } + + // tweak_capabilities can tweak capabilities by adding or dropping capabilities +-// based on the basic capabilities. ++// based on the basic capabilities. The following are the priorities of the tweaks: ++// 1. if adds contains "all", then the basic capabilities will be ignored, and all capabilities will be added. ++// 2. if drops contains "all", all capabilities will be dropped. ++// 3. add individual capabilities in adds ++// 4. drop individual capabilities in drops. ++// The reason why we handle "all" first is that we can avoid the case that the individual capabilities are ++// not included by "all". + static int tweak_capabilities(char ***caps, size_t *caps_len, const char **adds, size_t adds_len, const char **drops, + size_t drops_len) + { +- size_t i; +- size_t all_caps_len = 0; + int ret = 0; + char **new_caps = NULL; + char **basic_caps = NULL; ++ const char **all_caps = NULL; + size_t new_caps_len = 0; + size_t basic_caps_len = 0; ++ size_t all_caps_len = 0; ++ bool add_all = false; ++ bool drop_all = false; + +- all_caps_len = util_get_all_caps_len(); +- if (!valid_drops_cap(drops, drops_len)) { ++ all_caps = util_get_all_caps(&all_caps_len); ++ if (all_caps == NULL) { ++ ERROR("Failed to get all capabilities"); + return -1; + } + +- if (util_strings_in_slice((const char **)adds, adds_len, "all")) { +- ret = copy_capabilities(&basic_caps, &basic_caps_len, g_all_caps, all_caps_len); +- } else { ++ add_all = util_strings_in_slice((const char **)adds, adds_len, "all"); ++ drop_all = util_strings_in_slice((const char **)drops, drops_len, "all"); ++ ++ ++ if (!add_all && !drop_all) { ++ // if neither add_all nor drop_all, we start with the default capabilities + ret = copy_capabilities(&basic_caps, &basic_caps_len, (const char **)*caps, *caps_len); +- } +- if (ret != 0) { +- ERROR("Failed to copy capabilities"); +- ret = -1; +- goto free_out; ++ if (ret != 0) { ++ ERROR("Failed to copy capabilities"); ++ ret = -1; ++ goto free_out; ++ } ++ } else if (drop_all) { ++ // if drop_all, we start with an empty set ++ basic_caps = NULL; ++ basic_caps_len = 0; ++ } else { ++ // if not drop_all but add_all, we start with all capabilities ++ ret = copy_capabilities(&basic_caps, &basic_caps_len, all_caps, all_caps_len); ++ if (ret != 0) { ++ ERROR("Failed to copy all capabilities"); ++ ret = -1; ++ goto free_out; ++ } + } + +- ret = tweak_drops_capabilities(&new_caps, &new_caps_len, basic_caps, basic_caps_len, drops, drops_len); ++ // Add capabilities to the basic capabilities ++ ret = tweak_adds_capabilities(&basic_caps, &basic_caps_len, adds, adds_len); + if (ret != 0) { + ret = -1; + goto free_out; + } + +- ret = tweak_adds_capabilities(&new_caps, &new_caps_len, adds, adds_len); ++ // Drop capabilities from the basic capabilities ++ ret = tweak_drops_capabilities(&new_caps, &new_caps_len, basic_caps, basic_caps_len, drops, drops_len); + if (ret != 0) { + ret = -1; + goto free_out; + } + + free_out: +- for (i = 0; i < basic_caps_len; i++) { +- free(basic_caps[i]); +- } +- free(basic_caps); +- +- // free old caps +- for (i = 0; i < *caps_len; i++) { +- free((*caps)[i]); +- (*caps)[i] = NULL; +- } +- free(*caps); ++ util_free_array_by_len(basic_caps, basic_caps_len); ++ util_free_array_by_len(*caps, *caps_len); + + // set new caps + *caps = new_caps; +diff --git a/src/utils/cutils/utils_cap.c b/src/utils/cutils/utils_cap.c +new file mode 100644 +index 00000000..6473df45 +--- /dev/null ++++ b/src/utils/cutils/utils_cap.c +@@ -0,0 +1,119 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2018-2022. 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. ++ * Author: xuxuepeng ++ * Create: 2023-11-08 ++ * Description: provide capbilities utils functions ++ *******************************************************************************/ ++ ++#define _GNU_SOURCE ++ ++#include "utils_cap.h" ++ ++#include <stdint.h> ++#include <stdio.h> ++#include <isula_libutils/log.h> ++ ++#include "utils_string.h" ++ ++const char *g_all_caps[] = { ++ "CAP_CHOWN", ++ "CAP_DAC_OVERRIDE", ++ "CAP_DAC_READ_SEARCH", ++ "CAP_FOWNER", ++ "CAP_FSETID", ++ "CAP_KILL", ++ "CAP_SETGID", ++ "CAP_SETUID", ++ "CAP_SETPCAP", ++ "CAP_LINUX_IMMUTABLE", ++ "CAP_NET_BIND_SERVICE", ++ "CAP_NET_BROADCAST", ++ "CAP_NET_ADMIN", ++ "CAP_NET_RAW", ++ "CAP_IPC_LOCK", ++ "CAP_IPC_OWNER", ++ "CAP_SYS_MODULE", ++ "CAP_SYS_RAWIO", ++ "CAP_SYS_CHROOT", ++ "CAP_SYS_PTRACE", ++ "CAP_SYS_PACCT", ++ "CAP_SYS_ADMIN", ++ "CAP_SYS_BOOT", ++ "CAP_SYS_NICE", ++ "CAP_SYS_RESOURCE", ++ "CAP_SYS_TIME", ++ "CAP_SYS_TTY_CONFIG", ++ "CAP_MKNOD", ++ "CAP_LEASE", ++#ifdef CAP_AUDIT_WRITE ++ "CAP_AUDIT_WRITE", ++#endif ++#ifdef CAP_AUDIT_CONTROL ++ "CAP_AUDIT_CONTROL", ++#endif ++ "CAP_SETFCAP", ++ "CAP_MAC_OVERRIDE", ++ "CAP_MAC_ADMIN", ++#ifdef CAP_SYSLOG ++ "CAP_SYSLOG", ++#endif ++#ifdef CAP_WAKE_ALARM ++ "CAP_WAKE_ALARM", ++#endif ++#ifdef CAP_BLOCK_SUSPEND ++ "CAP_BLOCK_SUSPEND", ++#endif ++#ifdef CAP_AUDIT_READ ++ "CAP_AUDIT_READ", ++#endif ++#ifdef CAP_PERFMON ++ "CAP_PERFMON", ++#endif ++#ifdef CAP_BPF ++ "CAP_BPF", ++#endif ++#ifdef CAP_CHECKPOINT_RESTORE ++ "CAP_CHECKPOINT_RESTORE", ++#endif ++}; ++ ++static inline size_t util_get_all_caps_len() ++{ ++ return sizeof(g_all_caps) / sizeof(char *); ++} ++ ++bool util_valid_cap(const char *cap) ++{ ++ int nret = 0; ++ char tmpcap[32] = { 0 }; ++ size_t all_caps_len = util_get_all_caps_len(); ++ ++ if (cap == NULL) { ++ return false; ++ } ++ ++ nret = snprintf(tmpcap, sizeof(tmpcap), "CAP_%s", cap); ++ if (nret < 0 || (size_t)nret >= sizeof(tmpcap)) { ++ ERROR("Failed to print string"); ++ return false; ++ } ++ if (!util_strings_in_slice(g_all_caps, all_caps_len, tmpcap)) { ++ return false; ++ } ++ ++ return true; ++} ++ ++const char **util_get_all_caps(size_t *cap_len) ++{ ++ *cap_len = util_get_all_caps_len(); ++ return g_all_caps; ++} +diff --git a/src/utils/cutils/utils_cap.h b/src/utils/cutils/utils_cap.h +new file mode 100644 +index 00000000..de63d070 +--- /dev/null ++++ b/src/utils/cutils/utils_cap.h +@@ -0,0 +1,39 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2018-2022. 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. ++ * Author: xuxuepeng ++ * Create: 2023-11-08 ++ * Description: provide capbilities utils functions ++ *******************************************************************************/ ++ ++#ifndef UTILS_CUTILS_UTILS_CAP_H ++#define UTILS_CUTILS_UTILS_CAP_H ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#include <stdbool.h> ++#include <stddef.h> ++#include <linux/capability.h> ++ ++bool util_valid_cap(const char *cap); ++ ++/** ++ * Get all supported capabilities for linux, ++ * note that the returned strings are unmutable ++ */ ++const char **util_get_all_caps(size_t *cap_len); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif // UTILS_CUTILS_UTILS_CAP_H +diff --git a/src/utils/cutils/utils_verify.c b/src/utils/cutils/utils_verify.c +index 2f10f278..f4ce3199 100644 +--- a/src/utils/cutils/utils_verify.c ++++ b/src/utils/cutils/utils_verify.c +@@ -22,7 +22,6 @@ + #include <sys/stat.h> + #include <errno.h> + #include <fcntl.h> +-#include <linux/capability.h> + #include <stdio.h> + #include <strings.h> + +@@ -32,59 +31,6 @@ + #include "utils_array.h" + #include "utils_string.h" + +-const char *g_all_caps[] = { +- "CAP_CHOWN", +- "CAP_DAC_OVERRIDE", +- "CAP_DAC_READ_SEARCH", +- "CAP_FOWNER", +- "CAP_FSETID", +- "CAP_KILL", +- "CAP_SETGID", +- "CAP_SETUID", +- "CAP_SETPCAP", +- "CAP_LINUX_IMMUTABLE", +- "CAP_NET_BIND_SERVICE", +- "CAP_NET_BROADCAST", +- "CAP_NET_ADMIN", +- "CAP_NET_RAW", +- "CAP_IPC_LOCK", +- "CAP_IPC_OWNER", +- "CAP_SYS_MODULE", +- "CAP_SYS_RAWIO", +- "CAP_SYS_CHROOT", +- "CAP_SYS_PTRACE", +- "CAP_SYS_PACCT", +- "CAP_SYS_ADMIN", +- "CAP_SYS_BOOT", +- "CAP_SYS_NICE", +- "CAP_SYS_RESOURCE", +- "CAP_SYS_TIME", +- "CAP_SYS_TTY_CONFIG", +- "CAP_MKNOD", +- "CAP_LEASE", +-#ifdef CAP_AUDIT_WRITE +- "CAP_AUDIT_WRITE", +-#endif +-#ifdef CAP_AUDIT_CONTROL +- "CAP_AUDIT_CONTROL", +-#endif +- "CAP_SETFCAP", +- "CAP_MAC_OVERRIDE", +- "CAP_MAC_ADMIN", +-#ifdef CAP_SYSLOG +- "CAP_SYSLOG", +-#endif +-#ifdef CAP_WAKE_ALARM +- "CAP_WAKE_ALARM", +-#endif +-#ifdef CAP_BLOCK_SUSPEND +- "CAP_BLOCK_SUSPEND", +-#endif +-#ifdef CAP_AUDIT_READ +- "CAP_AUDIT_READ", +-#endif +-}; +- + bool util_valid_cmd_arg(const char *arg) + { + return (arg != NULL) && (strchr(arg, '|') == NULL) && (strchr(arg, '`') == NULL) && (strchr(arg, '&')) == NULL && +@@ -215,33 +161,6 @@ bool util_valid_str(const char *str) + return (str != NULL && str[0] != '\0') ? true : false; + } + +-size_t util_get_all_caps_len() +-{ +- return sizeof(g_all_caps) / sizeof(char *); +-} +- +-bool util_valid_cap(const char *cap) +-{ +- int nret = 0; +- char tmpcap[32] = { 0 }; +- size_t all_caps_len = util_get_all_caps_len(); +- +- if (cap == NULL) { +- return false; +- } +- +- nret = snprintf(tmpcap, sizeof(tmpcap), "CAP_%s", cap); +- if (nret < 0 || (size_t)nret >= sizeof(tmpcap)) { +- ERROR("Failed to print string"); +- return false; +- } +- if (!util_strings_in_slice(g_all_caps, all_caps_len, tmpcap)) { +- return false; +- } +- +- return true; +-} +- + bool util_valid_container_id(const char *id) + { + char *patten = "^[a-f0-9]{1,64}$"; +diff --git a/src/utils/cutils/utils_verify.h b/src/utils/cutils/utils_verify.h +index ad4466ef..54d1ce71 100644 +--- a/src/utils/cutils/utils_verify.h ++++ b/src/utils/cutils/utils_verify.h +@@ -38,8 +38,6 @@ extern "C" { + + #define VALID_VOLUME_NAME "[a-zA-Z0-9][a-zA-Z0-9_.-]{1,63}" + +-extern const char *g_all_caps[]; +- + bool util_valid_cmd_arg(const char *arg); + + bool util_valid_signal(int sig); +@@ -54,10 +52,6 @@ bool util_valid_device_mode(const char *mode); + + bool util_valid_str(const char *str); + +-size_t util_get_all_caps_len(); +- +-bool util_valid_cap(const char *cap); +- + bool util_valid_time_tz(const char *time); + + bool util_valid_embedded_image_name(const char *name); +diff --git a/test/cutils/utils_verify/utils_verify_ut.cc b/test/cutils/utils_verify/utils_verify_ut.cc +index 99775d09..79670ec1 100644 +--- a/test/cutils/utils_verify/utils_verify_ut.cc ++++ b/test/cutils/utils_verify/utils_verify_ut.cc +@@ -98,20 +98,6 @@ TEST(utils_verify, test_util_valid_str) + ASSERT_EQ(util_valid_str(nullptr), false); + } + +-TEST(utils_verify, test_util_get_all_caps_len) +-{ +- ASSERT_NE(util_get_all_caps_len(), 0); +-} +- +-TEST(utils_verify, test_util_valid_cap) +-{ +- ASSERT_EQ(util_valid_cap("DAC_READ_SEARCH"), true); +- +- ASSERT_EQ(util_valid_cap(nullptr), false); +- ASSERT_EQ(util_valid_cap(""), false); +- ASSERT_EQ(util_valid_cap("DA_READ_SEARCH"), false); +-} +- + TEST(utils_verify, test_util_valid_time_tz) + { + ASSERT_EQ(util_valid_time_tz("2022-10-04T18:22:45.289257759Z"), true); +diff --git a/test/image/oci/oci_config_merge/CMakeLists.txt b/test/image/oci/oci_config_merge/CMakeLists.txt +index ce4df5ba..90809080 100644 +--- a/test/image/oci/oci_config_merge/CMakeLists.txt ++++ b/test/image/oci/oci_config_merge/CMakeLists.txt +@@ -14,6 +14,7 @@ add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/utils_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/utils_timestamp.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/utils_fs.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/utils_cap.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/map/map.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/map/rb_tree.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/util_atomic.c +diff --git a/test/image/oci/storage/images/CMakeLists.txt b/test/image/oci/storage/images/CMakeLists.txt +index 8446ebba..28e0b505 100644 +--- a/test/image/oci/storage/images/CMakeLists.txt ++++ b/test/image/oci/storage/images/CMakeLists.txt +@@ -11,6 +11,7 @@ add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/utils_convert.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/utils_file.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/utils_base64.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/utils_cap.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/util_atomic.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/sha256/sha256.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/cutils/path.c +diff --git a/test/specs/specs/CMakeLists.txt b/test/specs/specs/CMakeLists.txt +index 1d627e37..a9dbc52c 100644 +--- a/test/specs/specs/CMakeLists.txt ++++ b/test/specs/specs/CMakeLists.txt +@@ -14,6 +14,7 @@ add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/util_atomic.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_mount_spec.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_fs.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_cap.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/sha256/sha256.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/path.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/map/map.c +diff --git a/test/specs/specs/oci_runtime_spec.json b/test/specs/specs/oci_runtime_spec.json +index 0223fd6f..efd5da35 100644 +--- a/test/specs/specs/oci_runtime_spec.json ++++ b/test/specs/specs/oci_runtime_spec.json +@@ -154,6 +154,38 @@ + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE" ++ ], ++ "effective": [ ++ "CAP_CHOWN", ++ "CAP_DAC_OVERRIDE", ++ "CAP_FSETID", ++ "CAP_FOWNER", ++ "CAP_MKNOD", ++ "CAP_NET_RAW", ++ "CAP_SETGID", ++ "CAP_SETUID", ++ "CAP_SETFCAP", ++ "CAP_SETPCAP", ++ "CAP_NET_BIND_SERVICE", ++ "CAP_SYS_CHROOT", ++ "CAP_KILL", ++ "CAP_AUDIT_WRITE" ++ ], ++ "permitted": [ ++ "CAP_CHOWN", ++ "CAP_DAC_OVERRIDE", ++ "CAP_FSETID", ++ "CAP_FOWNER", ++ "CAP_MKNOD", ++ "CAP_NET_RAW", ++ "CAP_SETGID", ++ "CAP_SETUID", ++ "CAP_SETFCAP", ++ "CAP_SETPCAP", ++ "CAP_NET_BIND_SERVICE", ++ "CAP_SYS_CHROOT", ++ "CAP_KILL", ++ "CAP_AUDIT_WRITE" + ] + } + }, +diff --git a/test/specs/specs/specs_ut.cc b/test/specs/specs/specs_ut.cc +index 96aa1c63..ad903a3f 100644 +--- a/test/specs/specs/specs_ut.cc ++++ b/test/specs/specs/specs_ut.cc +@@ -20,6 +20,7 @@ + #include "isula_libutils/oci_runtime_spec.h" + #include "specs_api.h" + #include "specs_namespace.h" ++#include "specs_security.h" + #include "isula_libutils/host_config.h" + #include "isula_libutils/container_config.h" + #include "oci_ut_common.h" +@@ -27,6 +28,7 @@ + #include <gmock/gmock.h> + #include "isulad_config_mock.h" + #include "utils.h" ++#include "utils_cap.h" + + using ::testing::Args; + using ::testing::ByRef; +@@ -344,3 +346,316 @@ TEST_F(SpecsUnitTest, test_merge_container_cgroups_path_5) + + testing::Mock::VerifyAndClearExpectations(&m_isulad_conf); + } ++ ++/********************************* UT for merge caps *******************************************/ ++struct capabilities_lens { ++ size_t bounding_len; ++ size_t effective_len; ++ size_t inheritable_len; ++ size_t permitted_len; ++ size_t ambient_len; ++}; ++ ++void check_capabilities_len(defs_process_capabilities *cap, struct capabilities_lens *lens) ++{ ++ lens->bounding_len = cap->bounding_len; ++ lens->effective_len = cap->effective_len; ++ lens->inheritable_len = cap->inheritable_len; ++ lens->permitted_len = cap->permitted_len; ++ lens->ambient_len = cap->ambient_len; ++} ++ ++void validate_capabilities_len(defs_process_capabilities *cap, struct capabilities_lens *lens, ssize_t len_diff) ++{ ++ ASSERT_EQ((ssize_t)cap->bounding_len, (ssize_t)lens->bounding_len + len_diff); ++ ASSERT_EQ((ssize_t)cap->effective_len, (ssize_t)lens->effective_len + len_diff); ++ ASSERT_EQ((ssize_t)cap->permitted_len, (ssize_t)lens->permitted_len + len_diff); ++ // Currently we don't support inheritable and ambient capabilities ++} ++ ++TEST(merge_capability_ut, test_merge_caps_without_adds_drops) ++{ ++ oci_runtime_spec *oci_spec = nullptr; ++ int ret = 0; ++ char *err = nullptr; ++ struct capabilities_lens old_lens = { 0 }; ++ char *oci_config_file = nullptr; ++ ++ oci_config_file = json_path(OCI_RUNTIME_SPEC_FILE); ++ ASSERT_TRUE(oci_config_file != nullptr); ++ ++ ++ oci_spec = oci_runtime_spec_parse_file(oci_config_file, nullptr, &err); ++ ASSERT_TRUE(oci_spec != nullptr); ++ free(err); ++ ++ check_capabilities_len(oci_spec->process->capabilities, &old_lens); ++ ++ ret = merge_caps(oci_spec, nullptr, 0, nullptr, 0); ++ ASSERT_EQ(ret, 0); ++ ++ validate_capabilities_len(oci_spec->process->capabilities, &old_lens, 0); ++ ++ free_oci_runtime_spec(oci_spec); ++} ++ ++TEST(merge_capability_ut, test_merge_caps_adds_without_drops) ++{ ++ oci_runtime_spec *oci_spec = nullptr; ++ int ret = 0; ++ char *err = nullptr; ++ struct capabilities_lens old_lens = { 0 }; ++ char *oci_config_file = nullptr; ++ /* All of below capabilities are not in oci_config_file */ ++ const char *adds[] = { "NET_ADMIN", "SYS_ADMIN", "SYS_TTY_CONFIG", "SYS_PTRACE" }; ++ const char *drops[] = {}; ++ size_t adds_len = sizeof(adds) / sizeof(adds[0]); ++ size_t drops_len = sizeof(drops) / sizeof(drops[0]); ++ ++ oci_config_file = json_path(OCI_RUNTIME_SPEC_FILE); ++ ASSERT_TRUE(oci_config_file != nullptr); ++ ++ ++ oci_spec = oci_runtime_spec_parse_file(oci_config_file, nullptr, &err); ++ ASSERT_TRUE(oci_spec != nullptr); ++ free(err); ++ ++ check_capabilities_len(oci_spec->process->capabilities, &old_lens); ++ ++ ret = merge_caps(oci_spec, adds, adds_len, drops, drops_len); ++ ASSERT_EQ(ret, 0); ++ ++ /* All of capabilities in adds are added */ ++ validate_capabilities_len(oci_spec->process->capabilities, &old_lens, adds_len); ++ ++ free_oci_runtime_spec(oci_spec); ++} ++ ++TEST(merge_capability_ut, test_merge_caps_adds_existing_without_drops) ++{ ++ oci_runtime_spec *oci_spec = nullptr; ++ int ret = 0; ++ char *err = nullptr; ++ struct capabilities_lens old_lens = { 0 }; ++ char *oci_config_file = nullptr; ++ /* CHOWN already exits in oci_config_file */ ++ const char *adds[] = { "CHOWN", "SYS_ADMIN", "SYS_TTY_CONFIG", "SYS_PTRACE" }; ++ const char *drops[] = {}; ++ size_t adds_len = sizeof(adds) / sizeof(adds[0]); ++ size_t drops_len = sizeof(drops) / sizeof(drops[0]); ++ ++ oci_config_file = json_path(OCI_RUNTIME_SPEC_FILE); ++ ASSERT_TRUE(oci_config_file != nullptr); ++ ++ ++ oci_spec = oci_runtime_spec_parse_file(oci_config_file, nullptr, &err); ++ ASSERT_TRUE(oci_spec != nullptr); ++ free(err); ++ ++ check_capabilities_len(oci_spec->process->capabilities, &old_lens); ++ ++ ret = merge_caps(oci_spec, adds, adds_len, drops, drops_len); ++ ASSERT_EQ(ret, 0); ++ ++ /* CHOWN is not added, since it already exits in the default list */ ++ validate_capabilities_len(oci_spec->process->capabilities, &old_lens, adds_len - 1); ++ ++ free_oci_runtime_spec(oci_spec); ++} ++ ++TEST(merge_capability_ut, test_merge_caps_drops_without_adds) ++{ ++ oci_runtime_spec *oci_spec = nullptr; ++ int ret = 0; ++ char *err = nullptr; ++ struct capabilities_lens old_lens = { 0 }; ++ char *oci_config_file = nullptr; ++ const char *adds[] = {}; ++ /* Below capabilities are not in the oci_config_file */ ++ const char *drops[] = { "SYS_TTY_CONFIG", "SYS_PTRACE" }; ++ size_t adds_len = sizeof(adds) / sizeof(adds[0]); ++ size_t drops_len = sizeof(drops) / sizeof(drops[0]); ++ ++ oci_config_file = json_path(OCI_RUNTIME_SPEC_FILE); ++ ASSERT_TRUE(oci_config_file != nullptr); ++ ++ ++ oci_spec = oci_runtime_spec_parse_file(oci_config_file, nullptr, &err); ++ ASSERT_TRUE(oci_spec != nullptr); ++ free(err); ++ ++ check_capabilities_len(oci_spec->process->capabilities, &old_lens); ++ ++ ret = merge_caps(oci_spec, adds, adds_len, drops, drops_len); ++ ASSERT_EQ(ret, 0); ++ ++ /* Nothing dropped */ ++ validate_capabilities_len(oci_spec->process->capabilities, &old_lens, 0); ++ ++ free_oci_runtime_spec(oci_spec); ++} ++ ++TEST(merge_capability_ut, test_merge_caps_drops_existing_without_adds) ++{ ++ oci_runtime_spec *oci_spec = nullptr; ++ int ret = 0; ++ char *err = nullptr; ++ struct capabilities_lens old_lens = { 0 }; ++ char *oci_config_file = nullptr; ++ const char *adds[] = {}; ++ /* Below capabilities are in the oci_config_file */ ++ const char *drops[] = { "CHOWN", "MKNOD" }; ++ size_t adds_len = sizeof(adds) / sizeof(adds[0]); ++ size_t drops_len = sizeof(drops) / sizeof(drops[0]); ++ ++ oci_config_file = json_path(OCI_RUNTIME_SPEC_FILE); ++ ASSERT_TRUE(oci_config_file != nullptr); ++ ++ ++ oci_spec = oci_runtime_spec_parse_file(oci_config_file, nullptr, &err); ++ ASSERT_TRUE(oci_spec != nullptr); ++ free(err); ++ ++ check_capabilities_len(oci_spec->process->capabilities, &old_lens); ++ ++ ret = merge_caps(oci_spec, adds, adds_len, drops, drops_len); ++ ASSERT_EQ(ret, 0); ++ ++ /* All dropped */ ++ validate_capabilities_len(oci_spec->process->capabilities, &old_lens, adds_len - drops_len); ++ ++ free_oci_runtime_spec(oci_spec); ++} ++ ++TEST(merge_capability_ut, test_merge_caps_adds_drops) ++{ ++ oci_runtime_spec *oci_spec = nullptr; ++ int ret = 0; ++ char *err = nullptr; ++ struct capabilities_lens old_lens = { 0 }; ++ char *oci_config_file = nullptr; ++ /* All of below capabilities are not in oci_config_file */ ++ const char *adds[] = { "NET_ADMIN", "SYS_ADMIN", "SYS_TTY_CONFIG", "SYS_PTRACE" }; ++ const char *drops[] = { "SYS_TTY_CONFIG", "SYS_PTRACE" }; ++ size_t adds_len = sizeof(adds) / sizeof(adds[0]); ++ size_t drops_len = sizeof(drops) / sizeof(drops[0]); ++ ++ oci_config_file = json_path(OCI_RUNTIME_SPEC_FILE); ++ ASSERT_TRUE(oci_config_file != nullptr); ++ ++ ++ oci_spec = oci_runtime_spec_parse_file(oci_config_file, nullptr, &err); ++ ASSERT_TRUE(oci_spec != nullptr); ++ free(err); ++ ++ check_capabilities_len(oci_spec->process->capabilities, &old_lens); ++ ++ ret = merge_caps(oci_spec, adds, adds_len, drops, drops_len); ++ ASSERT_EQ(ret, 0); ++ ++ validate_capabilities_len(oci_spec->process->capabilities, &old_lens, adds_len - drops_len); ++ ++ free_oci_runtime_spec(oci_spec); ++} ++ ++TEST(merge_capability_ut, test_merge_caps_adds_all_without_drops) ++{ ++ oci_runtime_spec *oci_spec = nullptr; ++ int ret = 0; ++ char *err = nullptr; ++ struct capabilities_lens old_lens = { 0 }; ++ char *oci_config_file = nullptr; ++ /* NET_ADMIN is in all */ ++ const char *adds[] = { "ALL", "NET_ADMIN" }; ++ const char *drops[] = {}; ++ size_t adds_len = sizeof(adds) / sizeof(adds[0]); ++ size_t drops_len = sizeof(drops) / sizeof(drops[0]); ++ size_t all_caps_len = 0; ++ util_get_all_caps(&all_caps_len); ++ ++ oci_config_file = json_path(OCI_RUNTIME_SPEC_FILE); ++ ASSERT_TRUE(oci_config_file != nullptr); ++ ++ oci_spec = oci_runtime_spec_parse_file(oci_config_file, nullptr, &err); ++ ASSERT_TRUE(oci_spec != nullptr); ++ free(err); ++ ++ check_capabilities_len(oci_spec->process->capabilities, &old_lens); ++ ++ ret = merge_caps(oci_spec, adds, adds_len, drops, drops_len); ++ ASSERT_EQ(ret, 0); ++ ++ ASSERT_EQ(oci_spec->process->capabilities->bounding_len, all_caps_len); ++ ASSERT_EQ(oci_spec->process->capabilities->effective_len, all_caps_len); ++ ASSERT_EQ(oci_spec->process->capabilities->permitted_len, all_caps_len); ++ ++ free_oci_runtime_spec(oci_spec); ++} ++ ++TEST(merge_capability_ut, test_merge_caps_adds_all_and_extra_without_drops) ++{ ++ oci_runtime_spec *oci_spec = nullptr; ++ int ret = 0; ++ char *err = nullptr; ++ struct capabilities_lens old_lens = { 0 }; ++ char *oci_config_file = nullptr; ++ /* ABC is not in all */ ++ const char *adds[] = { "ALL", "ABC" }; ++ const char *drops[] = {}; ++ size_t adds_len = sizeof(adds) / sizeof(adds[0]); ++ size_t drops_len = sizeof(drops) / sizeof(drops[0]); ++ size_t all_caps_len = 0; ++ util_get_all_caps(&all_caps_len); ++ ++ oci_config_file = json_path(OCI_RUNTIME_SPEC_FILE); ++ ASSERT_TRUE(oci_config_file != nullptr); ++ ++ oci_spec = oci_runtime_spec_parse_file(oci_config_file, nullptr, &err); ++ ASSERT_TRUE(oci_spec != nullptr); ++ free(err); ++ ++ check_capabilities_len(oci_spec->process->capabilities, &old_lens); ++ ++ ret = merge_caps(oci_spec, adds, adds_len, drops, drops_len); ++ ASSERT_EQ(ret, 0); ++ ++ ASSERT_EQ(oci_spec->process->capabilities->bounding_len, all_caps_len + 1); ++ ASSERT_EQ(oci_spec->process->capabilities->effective_len, all_caps_len + 1); ++ ASSERT_EQ(oci_spec->process->capabilities->permitted_len, all_caps_len + 1); ++ ++ free_oci_runtime_spec(oci_spec); ++} ++ ++TEST(merge_capability_ut, test_merge_caps_adds_all_drops_all) ++{ ++ oci_runtime_spec *oci_spec = nullptr; ++ int ret = 0; ++ char *err = nullptr; ++ struct capabilities_lens old_lens = { 0 }; ++ char *oci_config_file = nullptr; ++ /* ABC, EFG is not in all */ ++ const char *adds[] = { "ALL", "ABC", "EFG"}; ++ const char *drops[] = { "ALL", "ABC" }; ++ size_t adds_len = sizeof(adds) / sizeof(adds[0]); ++ size_t drops_len = sizeof(drops) / sizeof(drops[0]); ++ size_t all_caps_len = 0; ++ util_get_all_caps(&all_caps_len); ++ ++ oci_config_file = json_path(OCI_RUNTIME_SPEC_FILE); ++ ASSERT_TRUE(oci_config_file != nullptr); ++ ++ oci_spec = oci_runtime_spec_parse_file(oci_config_file, nullptr, &err); ++ ASSERT_TRUE(oci_spec != nullptr); ++ free(err); ++ ++ check_capabilities_len(oci_spec->process->capabilities, &old_lens); ++ ++ ret = merge_caps(oci_spec, adds, adds_len, drops, drops_len); ++ ASSERT_EQ(ret, 0); ++ ++ ASSERT_EQ(oci_spec->process->capabilities->bounding_len, 1); ++ ASSERT_EQ(oci_spec->process->capabilities->effective_len, 1); ++ ASSERT_EQ(oci_spec->process->capabilities->permitted_len, 1); ++ ++ free_oci_runtime_spec(oci_spec); ++} +diff --git a/test/specs/specs_extend/CMakeLists.txt b/test/specs/specs_extend/CMakeLists.txt +index 294690e8..bf4b378e 100644 +--- a/test/specs/specs_extend/CMakeLists.txt ++++ b/test/specs/specs_extend/CMakeLists.txt +@@ -14,6 +14,7 @@ add_executable(${EXE} + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/util_atomic.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_mount_spec.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_fs.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/utils_cap.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/sha256/sha256.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/path.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/utils/cutils/map/map.c +-- +2.42.0 + |