iSulad/0009-2243-Refactor-capbilities-specs.patch
zhongtao 8c5a1e32f7 !632 Upgrade to v2.1.4
* Upgrade to v2.1.4
2023-11-15 03:46:42 +00:00

1057 lines
34 KiB
Diff

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