From 32c9572a5be943d46ae20f12a19ed50d21ec1806 Mon Sep 17 00:00:00 2001 From: lifeng68 Date: Fri, 10 Jul 2020 15:44:45 +0800 Subject: [PATCH] selinux: support selinux mount label in image Signed-off-by: lifeng68 --- CI/test_cases/image_cases/registry.bash | 4 - .../{modules/spec => common}/selinux_label.c | 91 +++++++++++++++++++ .../{modules/spec => common}/selinux_label.h | 1 + src/daemon/modules/api/image_api.h | 1 + src/daemon/modules/image/CMakeLists.txt | 2 + src/daemon/modules/image/image.c | 3 + src/daemon/modules/image/oci/oci_image.c | 3 +- .../graphdriver/devmapper/deviceset.c | 19 ++++ .../graphdriver/overlay2/driver_overlay2.c | 46 ++++++++++ .../modules/image/oci/storage/storage.c | 26 +++--- .../modules/image/oci/storage/storage.h | 3 +- test/image/oci/storage/layers/CMakeLists.txt | 5 +- .../oci/storage/layers/storage_driver_ut.cpp | 1 - test/services/execution/spec/CMakeLists.txt | 4 +- 14 files changed, 187 insertions(+), 22 deletions(-) rename src/daemon/{modules/spec => common}/selinux_label.c (92%) rename src/daemon/{modules/spec => common}/selinux_label.h (95%) diff --git a/CI/test_cases/image_cases/registry.bash b/CI/test_cases/image_cases/registry.bash index fba76b5..0ea34b8 100755 --- a/CI/test_cases/image_cases/registry.bash +++ b/CI/test_cases/image_cases/registry.bash @@ -34,10 +34,6 @@ function isula_pull() isula rm -f `isula ps -a -q` isula rmi centos - isula pull centos & - isula pull centos - fn_check_eq "$?" "0" "isula pull centos" - isula pull hub-mirror.c.163.com/library/busybox fn_check_eq "$?" "0" "isula pull hub-mirror.c.163.com/library/busybox" diff --git a/src/daemon/modules/spec/selinux_label.c b/src/daemon/common/selinux_label.c similarity index 92% rename from src/daemon/modules/spec/selinux_label.c rename to src/daemon/common/selinux_label.c index a420069..572ea22 100644 --- a/src/daemon/modules/spec/selinux_label.c +++ b/src/daemon/common/selinux_label.c @@ -1071,3 +1071,94 @@ int get_disable_security_opt(char ***labels, size_t *labels_len) return 0; } + +#define MOUNT_CONTEXT "context=" + +static char *fill_selinux_label_with_src(const char *src, const char *mount_label) +{ + int nret = 0; + char *result = NULL; + size_t data_size = 0; + + if (strlen(mount_label) >= (INT_MAX - strlen(src) - strlen(MOUNT_CONTEXT) - 4)) { + ERROR("mount_label string too large"); + goto err_out; + } + + data_size = strlen(src) + 1 + strlen(MOUNT_CONTEXT) + 2 + strlen(mount_label) + 1; + + result = util_common_calloc_s(data_size); + if (result == NULL) { + ERROR("Memory out"); + goto err_out; + } + + nret = snprintf(result, data_size, "%s,%s\"%s\"", src, MOUNT_CONTEXT, mount_label); + if (nret < 0 || (size_t)nret >= data_size) { + ERROR("failed to snprintf selinux label"); + goto err_out; + } + + goto out; + +err_out: + free(result); + result = NULL; + +out: + return result; +} + +static char *fill_selinux_label_without_src(const char *mount_label) +{ + int nret = 0; + char *result = NULL; + size_t data_size = 0; + + if (strlen(mount_label) >= (INT_MAX - strlen(MOUNT_CONTEXT) - 3)) { + ERROR("mount_label string too large"); + goto err_out; + } + + data_size = strlen(MOUNT_CONTEXT) + strlen(mount_label) + 3; + + result = util_common_calloc_s(data_size); + if (result == NULL) { + ERROR("Memory out"); + goto err_out; + } + + nret = snprintf(result, data_size, "%s\"%s\"", MOUNT_CONTEXT, mount_label); + if (nret < 0 || (size_t)nret >= data_size) { + ERROR("failed to snprintf selinux label"); + goto err_out; + } + + goto out; + +err_out: + free(result); + result = NULL; + +out: + return result; +} + +char *selinux_format_mountlabel(const char *src, const char *mount_label) +{ + char *result = NULL; + + if (src == NULL && mount_label == NULL) { + return NULL; + } + + if (src != NULL && mount_label != NULL) { + result = fill_selinux_label_with_src(src, mount_label); + } else if (src == NULL) { + result = fill_selinux_label_without_src(mount_label); + } else { + result = util_strdup_s(src); + } + + return result; +} \ No newline at end of file diff --git a/src/daemon/modules/spec/selinux_label.h b/src/daemon/common/selinux_label.h similarity index 95% rename from src/daemon/modules/spec/selinux_label.h rename to src/daemon/common/selinux_label.h index 65c64aa..62c6276 100644 --- a/src/daemon/modules/spec/selinux_label.h +++ b/src/daemon/common/selinux_label.h @@ -30,6 +30,7 @@ int init_label(const char **label_opts, size_t label_opts_len, char **process_la int relabel(const char *path, const char *file_label, bool shared); int get_disable_security_opt(char ***labels, size_t *labels_len); int dup_security_opt(const char *src, char ***dst, size_t *len); +char *selinux_format_mountlabel(const char *src, const char *mount_label); #ifdef __cplusplus } diff --git a/src/daemon/modules/api/image_api.h b/src/daemon/modules/api/image_api.h index b8d7776..c6e9f1f 100644 --- a/src/daemon/modules/api/image_api.h +++ b/src/daemon/modules/api/image_api.h @@ -189,6 +189,7 @@ typedef struct { char *image_name; char *container_id; char *rootfs; // only used for external image type + char *mount_label; // mount label for selinux json_map_string_string *storage_opt; } im_prepare_request; diff --git a/src/daemon/modules/image/CMakeLists.txt b/src/daemon/modules/image/CMakeLists.txt index c0c05de..5199601 100644 --- a/src/daemon/modules/image/CMakeLists.txt +++ b/src/daemon/modules/image/CMakeLists.txt @@ -65,6 +65,7 @@ add_library(${LIB_ISULAD_IMG} ${LIBTYPE} ${CMAKE_SOURCE_DIR}/src/utils/cutils/map/rb_tree.c ${CMAKE_SOURCE_DIR}/src/utils/sha256/sha256.c ${CMAKE_SOURCE_DIR}/src/daemon/common/err_msg.c + ${CMAKE_SOURCE_DIR}/src/daemon/common/selinux_label.c ${CMAKE_SOURCE_DIR}/src/daemon/config/isulad_config.c ${CMAKE_SOURCE_DIR}/src/daemon/config/daemon_arguments.c ${CMAKE_SOURCE_DIR}/src/daemon/common/sysinfo.c @@ -93,6 +94,7 @@ target_link_libraries(${LIB_ISULAD_IMG} ${ISULA_LIBUTILS_LIBRARY} ${DEVMAPPER_LIBRARY} ${LIBTAR_LIBRARY} + ${SELINUX_LIBRARY} -lpthread -lcrypto -larchive -lz libhttpclient) install(TARGETS ${LIB_ISULAD_IMG} diff --git a/src/daemon/modules/image/image.c b/src/daemon/modules/image/image.c index 1fbdb38..5f837a0 100644 --- a/src/daemon/modules/image/image.c +++ b/src/daemon/modules/image/image.c @@ -453,6 +453,9 @@ void free_im_prepare_request(im_prepare_request *request) free(request->image_type); request->image_type = NULL; + free(request->mount_label); + request->mount_label = NULL; + free_json_map_string_string(request->storage_opt); request->storage_opt = NULL; diff --git a/src/daemon/modules/image/oci/oci_image.c b/src/daemon/modules/image/oci/oci_image.c index ca003f8..ff792d5 100644 --- a/src/daemon/modules/image/oci/oci_image.c +++ b/src/daemon/modules/image/oci/oci_image.c @@ -161,7 +161,8 @@ int oci_prepare_rf(const im_prepare_request *request, char **real_rootfs) return -1; } - if (storage_rootfs_create(request->container_id, request->image_name, request->storage_opt, real_rootfs) != 0) { + if (storage_rootfs_create(request->container_id, request->image_name, request->mount_label, request->storage_opt, + real_rootfs) != 0) { ERROR("Failed to create container rootfs:%s", request->container_id); isulad_set_error_message("Failed to create container rootfs:%s", request->container_id); ret = -1; diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.c b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.c index 2fa44b0..2bf8641 100644 --- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.c +++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.c @@ -46,6 +46,7 @@ #include "utils_fs.h" #include "utils_string.h" #include "utils_verify.h" +#include "selinux_label.h" #define DM_LOG_FATAL 2 #define DM_LOG_DEBUG 7 @@ -2810,6 +2811,7 @@ static char *generate_mount_options(const struct driver_mount_opts *moptions, co char *res_str = NULL; char *options = NULL; bool add_nouuid = false; + char *tmp = NULL; options = util_strdup_s(dev_options); if (moptions != NULL && moptions->options_len > 0) { @@ -2823,6 +2825,23 @@ static char *generate_mount_options(const struct driver_mount_opts *moptions, co append_mount_options(&res_str, options); + if (moptions != NULL && moptions->mount_label != NULL) { + tmp = selinux_format_mountlabel(res_str, moptions->mount_label); + if (tmp == NULL) { + goto error_out; + } + free(res_str); + res_str = tmp; + tmp = NULL; + } + + goto out; + +error_out: + free(res_str); + res_str = NULL; + +out: free(options); return res_str; } diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.c b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.c index 41f1ee5..5ab22a2 100644 --- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.c +++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/overlay2/driver_overlay2.c @@ -39,6 +39,7 @@ #include "utils_fs.h" #include "utils_string.h" #include "utils_timestamp.h" +#include "selinux_label.h" struct io_read_wrapper; @@ -622,6 +623,11 @@ static char *get_lower(const char *parent, const char *driver_home) } lower = util_common_calloc_s(lower_len); + if (lower == NULL) { + ERROR("Memory out"); + goto err_out; + } + if (parent_lowers != NULL) { nret = snprintf(lower, lower_len, "%s/%s:%s", OVERLAY_LINK_DIR, parent_link, parent_lowers); } else { @@ -1118,6 +1124,10 @@ static char *get_mount_opt_data_with_custom_option(size_t cur_size, const char * data_size = cur_size + strlen(custom_opts) + 1; mount_data = util_common_calloc_s(data_size); + if (mount_data == NULL) { + ERROR("Memory out"); + goto error_out; + } nret = snprintf(mount_data, data_size, "%s,%s", custom_opts, cur_opts); if (nret < 0 || (size_t)nret >= data_size) { @@ -1149,6 +1159,10 @@ static char *get_mount_opt_data_with_driver_option(size_t cur_size, const char * data_size = cur_size + strlen(mount_opts) + 1; mount_data = util_common_calloc_s(data_size); + if (mount_data == NULL) { + ERROR("Memory out"); + goto error_out; + } nret = snprintf(mount_data, data_size, "%s,%s", mount_opts, cur_opts); if (nret < 0 || (size_t)nret >= data_size) { @@ -1197,6 +1211,10 @@ static char *get_abs_mount_opt_data(const char *layer_dir, const char *abs_lower strlen(",workdir=") + strlen(work_dir) + 1; mount_data = util_common_calloc_s(data_size); + if (mount_data == NULL) { + ERROR("Memory out"); + goto error_out; + } nret = snprintf(mount_data, data_size, "lowerdir=%s,upperdir=%s,workdir=%s", abs_lower_dir, upper_dir, work_dir); if (nret < 0 || (size_t)nret >= data_size) { @@ -1211,6 +1229,7 @@ static char *get_abs_mount_opt_data(const char *layer_dir, const char *abs_lower } free(mount_data); mount_data = tmp; + tmp = NULL; } else if (driver->overlay_opts->mount_options != NULL) { tmp = get_mount_opt_data_with_driver_option(data_size, mount_data, driver->overlay_opts->mount_options); if (tmp == NULL) { @@ -1218,6 +1237,17 @@ static char *get_abs_mount_opt_data(const char *layer_dir, const char *abs_lower } free(mount_data); mount_data = tmp; + tmp = NULL; + } + + if (mount_opts != NULL && mount_opts->mount_label != NULL) { + tmp = selinux_format_mountlabel(mount_data, mount_opts->mount_label); + if (tmp == NULL) { + goto error_out; + } + free(mount_data); + mount_data = tmp; + tmp = NULL; } goto out; @@ -1263,6 +1293,10 @@ static char *get_rel_mount_opt_data(const char *id, const char *rel_lower_dir, c strlen(",workdir=") + strlen(work_dir) + 1; mount_data = util_common_calloc_s(data_size); + if (mount_data == NULL) { + ERROR("Memory out"); + goto error_out; + } nret = snprintf(mount_data, data_size, "lowerdir=%s,upperdir=%s,workdir=%s", rel_lower_dir, upper_dir, work_dir); if (nret < 0 || (size_t)nret >= data_size) { @@ -1277,6 +1311,7 @@ static char *get_rel_mount_opt_data(const char *id, const char *rel_lower_dir, c } free(mount_data); mount_data = tmp; + tmp = NULL; } else if (driver->overlay_opts->mount_options != NULL) { tmp = get_mount_opt_data_with_driver_option(data_size, mount_data, driver->overlay_opts->mount_options); if (tmp == NULL) { @@ -1284,6 +1319,17 @@ static char *get_rel_mount_opt_data(const char *id, const char *rel_lower_dir, c } free(mount_data); mount_data = tmp; + tmp = NULL; + } + + if (mount_opts != NULL && mount_opts->mount_label != NULL) { + tmp = selinux_format_mountlabel(mount_data, mount_opts->mount_label); + if (tmp == NULL) { + goto error_out; + } + free(mount_data); + mount_data = tmp; + tmp = NULL; } goto out; diff --git a/src/daemon/modules/image/oci/storage/storage.c b/src/daemon/modules/image/oci/storage/storage.c index 7f71f05..bc8d2c2 100644 --- a/src/daemon/modules/image/oci/storage/storage.c +++ b/src/daemon/modules/image/oci/storage/storage.c @@ -129,7 +129,7 @@ out: return ret; } -static struct layer_opts *fill_create_layer_opts(storage_layer_create_opts_t *copts) +static struct layer_opts *fill_create_layer_opts(storage_layer_create_opts_t *copts, const char *mount_label) { struct layer_opts *opts = NULL; @@ -144,12 +144,15 @@ static struct layer_opts *fill_create_layer_opts(storage_layer_create_opts_t *co opts->compressed_digest = util_strdup_s(copts->compressed_digest); opts->writable = copts->writable; + opts->opts = util_common_calloc_s(sizeof(struct layer_store_mount_opts)); + if (opts->opts == NULL) { + ERROR("Memory out"); + goto err_out; + } + + opts->opts->mount_label = util_strdup_s(mount_label); + if (copts->storage_opts != NULL) { - opts->opts = util_common_calloc_s(sizeof(struct layer_store_mount_opts)); - if (opts->opts == NULL) { - ERROR("Memory out"); - goto err_out; - } opts->opts->mount_opts = util_common_calloc_s(sizeof(json_map_string_string)); if (opts->opts->mount_opts == NULL) { ERROR("Memory out"); @@ -194,7 +197,7 @@ int storage_layer_create(const char *layer_id, storage_layer_create_opts_t *copt goto out; } - opts = fill_create_layer_opts(copts); + opts = fill_create_layer_opts(copts, NULL); if (opts == NULL) { ERROR("Failed to fill create ro layer options"); ret = -1; @@ -984,7 +987,7 @@ void free_layer_list(struct layer_list *ptr) free(ptr); } -static int do_create_container_rw_layer(const char *container_id, const char *image_top_layer, +static int do_create_container_rw_layer(const char *container_id, const char *image_top_layer, const char *mount_label, json_map_string_string *storage_opts) { int ret = 0; @@ -996,7 +999,7 @@ static int do_create_container_rw_layer(const char *container_id, const char *im .storage_opts = storage_opts, }; - opts = fill_create_layer_opts(&copts); + opts = fill_create_layer_opts(&copts, mount_label); if (opts == NULL) { ERROR("Failed to fill create opts"); ret = -1; @@ -1014,7 +1017,8 @@ out: return ret; } -int storage_rootfs_create(const char *container_id, const char *image, json_map_string_string *storage_opts, +int storage_rootfs_create(const char *container_id, const char *image, const char *mount_label, + json_map_string_string *storage_opts, char **mountpoint) { int ret = 0; @@ -1042,7 +1046,7 @@ int storage_rootfs_create(const char *container_id, const char *image, json_map_ } // note: we use container id as the layer id of the container - if (do_create_container_rw_layer(container_id, image_info->top_layer, storage_opts) != 0) { + if (do_create_container_rw_layer(container_id, image_info->top_layer, mount_label, storage_opts) != 0) { ERROR("Failed to do create rootfs layer"); ret = -1; goto unlock_out; diff --git a/src/daemon/modules/image/oci/storage/storage.h b/src/daemon/modules/image/oci/storage/storage.h index 6e2a569..1ebcdca 100644 --- a/src/daemon/modules/image/oci/storage/storage.h +++ b/src/daemon/modules/image/oci/storage/storage.h @@ -161,7 +161,8 @@ void free_layer(struct layer *l); void free_layer_list(struct layer_list *ptr); /* container rootfs operations */ -int storage_rootfs_create(const char *container_id, const char *image, json_map_string_string *storage_opts, +int storage_rootfs_create(const char *container_id, const char *image, const char *mount_label, + json_map_string_string *storage_opts, char **mountpoint); int storage_rootfs_delete(const char *container_id); diff --git a/test/image/oci/storage/layers/CMakeLists.txt b/test/image/oci/storage/layers/CMakeLists.txt index 046153a..06996a8 100644 --- a/test/image/oci/storage/layers/CMakeLists.txt +++ b/test/image/oci/storage/layers/CMakeLists.txt @@ -20,6 +20,7 @@ add_executable(${DRIVER_EXE} ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/tar/util_archive.c ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/utils/sha256/sha256.c ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/common/err_msg.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/common/selinux_label.c ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.c ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/deviceset.c ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.c @@ -58,7 +59,7 @@ target_link_libraries(${DRIVER_EXE} ${CMAKE_THREAD_LIBS_INIT} ${ISULA_LIBUTILS_LIBRARY} ${LIBTAR_LIBRARY} - -lwebsockets -lcrypto -lyajl -larchive -ldevmapper -lz) + -lwebsockets -lcrypto -lyajl -larchive ${SELINUX_LIBRARY} -ldevmapper -lz) add_test(NAME ${DRIVER_EXE} COMMAND ${DRIVER_EXE}) @@ -132,5 +133,5 @@ target_link_libraries(${EXE} ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} - -lwebsockets -lcrypto -lyajl -larchive -ldevmapper -lz) + -lwebsockets -lcrypto -lyajl -larchive ${SELINUX_LIBRARY} -ldevmapper -lz) ]] diff --git a/test/image/oci/storage/layers/storage_driver_ut.cpp b/test/image/oci/storage/layers/storage_driver_ut.cpp index c5928f3..966c243 100644 --- a/test/image/oci/storage/layers/storage_driver_ut.cpp +++ b/test/image/oci/storage/layers/storage_driver_ut.cpp @@ -202,7 +202,6 @@ TEST_F(StorageDriverUnitTest, test_graphdriver_mount_layer) mount_opts = (struct driver_mount_opts *)malloc(sizeof(struct driver_mount_opts)); ASSERT_NE(mount_opts, nullptr); - mount_opts->mount_label = strdup("mount_label"); mount_opts->options = (char **)malloc(1 * sizeof(char *)); mount_opts->options[0] = strdup("ro"); mount_opts->options_len = 1; diff --git a/test/services/execution/spec/CMakeLists.txt b/test/services/execution/spec/CMakeLists.txt index 46c21fb..af2da46 100644 --- a/test/services/execution/spec/CMakeLists.txt +++ b/test/services/execution/spec/CMakeLists.txt @@ -17,7 +17,7 @@ add_executable(${EXE} ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/utils/cutils/map/rb_tree.c ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/common/err_msg.c ${CMAKE_CURRENT_SOURCE_DIR}/../../../mocks/namespace_mock.cc - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/spec//selinux_label.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/common/selinux_label.c selinux_label_ut.cpp) add_executable(${MOCK_EXE} @@ -36,7 +36,7 @@ add_executable(${MOCK_EXE} ${CMAKE_CURRENT_SOURCE_DIR}/../../../mocks/namespace_mock.cc ${CMAKE_CURRENT_SOURCE_DIR}/../../../mocks/syscall_mock.cc ${CMAKE_CURRENT_SOURCE_DIR}/../../../mocks/selinux_mock.cc - ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/modules/spec//selinux_label.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/common/selinux_label.c selinux_label_mock_ut.cpp) target_include_directories(${EXE} PUBLIC -- GitLab