diff --git a/0107-add-bind-mount-file-lock.patch b/0107-add-bind-mount-file-lock.patch new file mode 100644 index 0000000000000000000000000000000000000000..1561a6b7bfc28b0f0854c38045230c545e6f3c93 --- /dev/null +++ b/0107-add-bind-mount-file-lock.patch @@ -0,0 +1,996 @@ +From f067baa54b112e67f7ee3a0dfc89f8a3feb9fe7d Mon Sep 17 00:00:00 2001 +From: zhongtao +Date: Tue, 19 Sep 2023 16:20:41 +0800 +Subject: [PATCH] add bind mount file lock + +Signed-off-by: zhangxiaoyu +--- + src/cmd/isula/stream/cp.c | 66 ++++++- + src/cmd/isulad/main.c | 50 ++++++ + src/common/constants.h | 4 + + .../executor/container_cb/execution_stream.c | 23 ++- + src/daemon/modules/image/oci/oci_export.c | 13 +- + src/daemon/modules/image/oci/oci_load.c | 13 +- + .../graphdriver/devmapper/driver_devmapper.c | 12 +- + .../graphdriver/overlay2/driver_overlay2.c | 12 +- + src/utils/cutils/utils_file.c | 27 +++ + src/utils/cutils/utils_file.h | 2 + + src/utils/tar/isulad_tar.c | 20 ++- + src/utils/tar/isulad_tar.h | 4 +- + src/utils/tar/util_archive.c | 163 +++++++++++++++--- + src/utils/tar/util_archive.h | 8 +- + test/image/oci/storage/layers/CMakeLists.txt | 4 + + 15 files changed, 371 insertions(+), 50 deletions(-) + +diff --git a/src/cmd/isula/stream/cp.c b/src/cmd/isula/stream/cp.c +index b869741..5de271a 100644 +--- a/src/cmd/isula/stream/cp.c ++++ b/src/cmd/isula/stream/cp.c +@@ -73,6 +73,44 @@ static void print_copy_from_container_error(const char *ops_err, const char *arc + } + } + ++static int client_get_root_dir(const isula_connect_ops *ops, const client_connect_config_t *config, char **root_dir) ++{ ++ int ret = 0; ++ struct isula_info_request request = { 0 }; ++ struct isula_info_response *response = NULL; ++ ++ response = util_common_calloc_s(sizeof(struct isula_info_response)); ++ if (response == NULL) { ++ COMMAND_ERROR("Info: Out of memory"); ++ return -1; ++ } ++ ++ if (!ops->container.info) { ++ COMMAND_ERROR("Unimplemented info op"); ++ ret = -1; ++ goto out; ++ } ++ ++ ret = ops->container.info(&request, response, (void *)config); ++ if (ret != 0) { ++ client_print_error(response->cc, response->server_errono, response->errmsg); ++ ret = -1; ++ goto out; ++ } ++ ++ if (response->isulad_root_dir == NULL) { ++ COMMAND_ERROR("None root dir"); ++ ret = -1; ++ goto out; ++ } ++ ++ *root_dir = util_strdup_s(response->isulad_root_dir); ++ ++out: ++ isula_info_response_free(response); ++ return ret; ++} ++ + static int client_copy_from_container(const struct client_arguments *args, const char *id, const char *srcpath, + const char *destpath) + { +@@ -84,6 +122,7 @@ static int client_copy_from_container(const struct client_arguments *args, const + char *archive_err = NULL; + char *ops_err = NULL; + char *resolved = NULL; ++ char *root_dir = NULL; + struct archive_copy_info *srcinfo = NULL; + client_connect_config_t config; + +@@ -92,18 +131,24 @@ static int client_copy_from_container(const struct client_arguments *args, const + COMMAND_ERROR("Unimplemented copy from container operation"); + return -1; + } ++ config = get_connect_config(args); ++ ++ ret = client_get_root_dir(ops, &config, &root_dir); ++ if (ret != 0) { ++ return -1; ++ } + + response = util_common_calloc_s(sizeof(struct isula_copy_from_container_response)); + if (response == NULL) { + ERROR("Event: Out of memory"); +- return -1; ++ ret = -1; ++ goto out; + } + + request.id = (char *)id; + request.runtime = args->runtime; + request.srcpath = (char *)srcpath; + +- config = get_connect_config(args); + ret = ops->container.copy_from_container(&request, response, &config); + if (ret) { + ops_err = (response->errmsg != NULL) ? util_strdup_s(response->errmsg) : NULL; +@@ -125,7 +170,7 @@ static int client_copy_from_container(const struct client_arguments *args, const + srcinfo->path = util_strdup_s(srcpath); + srcinfo->isdir = S_ISDIR(response->stat->mode); + +- nret = archive_copy_to(&response->reader, srcinfo, resolved, &archive_err); ++ nret = archive_copy_to(&response->reader, srcinfo, resolved, root_dir, &archive_err); + if (nret != 0) { + ret = nret; + } +@@ -137,6 +182,7 @@ static int client_copy_from_container(const struct client_arguments *args, const + + out: + print_copy_from_container_error(ops_err, archive_err, ret, args); ++ free(root_dir); + free(resolved); + free(archive_err); + free(ops_err); +@@ -167,6 +213,7 @@ static int client_copy_to_container(const struct client_arguments *args, const c + int nret = 0; + char *archive_err = NULL; + char *resolved = NULL; ++ char *root_dir = NULL; + struct archive_copy_info *srcinfo = NULL; + struct io_read_wrapper archive_reader = { 0 }; + client_connect_config_t config = { 0 }; +@@ -176,11 +223,18 @@ static int client_copy_to_container(const struct client_arguments *args, const c + COMMAND_ERROR("Unimplemented copy to container operation"); + return -1; + } ++ config = get_connect_config(args); ++ ++ ret = client_get_root_dir(ops, &config, &root_dir); ++ if (ret != 0) { ++ return -1; ++ } + + response = util_common_calloc_s(sizeof(struct isula_copy_to_container_response)); + if (response == NULL) { + ERROR("Event: Out of memory"); +- return -1; ++ ret = -1; ++ goto out; + } + + request.id = (char *)id; +@@ -199,7 +253,7 @@ static int client_copy_to_container(const struct client_arguments *args, const c + goto out; + } + +- nret = tar_resource(srcinfo, &archive_reader, &archive_err); ++ nret = tar_resource(srcinfo, root_dir, &archive_reader, &archive_err); + if (nret != 0) { + ret = -1; + goto out; +@@ -212,7 +266,6 @@ static int client_copy_to_container(const struct client_arguments *args, const c + request.reader.read = archive_reader.read; + request.reader.close = archive_reader.close; + +- config = get_connect_config(args); + ret = ops->container.copy_to_container(&request, response, &config); + if (ret) { + goto out; +@@ -225,6 +278,7 @@ static int client_copy_to_container(const struct client_arguments *args, const c + + out: + print_copy_to_container_error(response, archive_err, ret, args); ++ free(root_dir); + free(resolved); + free(archive_err); + free_archive_copy_info(srcinfo); +diff --git a/src/cmd/isulad/main.c b/src/cmd/isulad/main.c +index 633de61..8d46a1b 100644 +--- a/src/cmd/isulad/main.c ++++ b/src/cmd/isulad/main.c +@@ -1360,6 +1360,50 @@ out: + return ret; + } + ++static int create_mount_flock_file(const struct service_arguments *args) ++{ ++ int nret = 0; ++ int fd = -1; ++ char path[PATH_MAX] = { 0 }; ++ char cleanpath[PATH_MAX] = { 0 }; ++ ++ nret = snprintf(path, PATH_MAX, "%s/%s", args->json_confs->graph, MOUNT_FLOCK_FILE_PATH); ++ if (nret < 0 || (size_t)nret >= PATH_MAX) { ++ ERROR("Failed to snprintf"); ++ return -1; ++ } ++ ++ if (util_clean_path(path, cleanpath, sizeof(cleanpath)) == NULL) { ++ ERROR("clean path for %s failed", path); ++ return -1; ++ } ++ ++ if (util_fileself_exists(cleanpath)) { ++ int err = 0; ++ // recreate mount flock file ++ // and make file uid/gid and permission correct ++ if (!util_force_remove_file(cleanpath, &err)) { ++ ERROR("Failed to delete %s, error: %s. Please delete %s manually.", path, strerror(err), path); ++ return -1; ++ } ++ } ++ ++ fd = util_open(cleanpath, O_RDWR | O_CREAT, MOUNT_FLOCK_FILE_MODE); ++ if (fd < 0) { ++ ERROR("Failed to create file %s", cleanpath); ++ return -1; ++ } ++ close(fd); ++ ++ nret = util_set_file_group(cleanpath, args->json_confs->group); ++ if (nret < 0) { ++ ERROR("set group of the path %s failed", cleanpath); ++ return -1; ++ } ++ ++ return 0; ++} ++ + static int isulad_server_init_service() + { + int ret = -1; +@@ -1390,6 +1434,12 @@ static int isulad_server_init_service() + goto unlock_out; + } + ++ ret = create_mount_flock_file(args); ++ if (ret != 0) { ++ ERROR("Failed to create mount flock file"); ++ goto unlock_out; ++ } ++ + unlock_out: + if (isulad_server_conf_unlock()) { + ret = -1; +diff --git a/src/common/constants.h b/src/common/constants.h +index dd2f3e5..f59761c 100644 +--- a/src/common/constants.h ++++ b/src/common/constants.h +@@ -64,6 +64,8 @@ extern "C" { + + #define DEFAULT_HIGHEST_DIRECTORY_MODE 0755 + ++#define MOUNT_FLOCK_FILE_MODE 0660 ++ + #define ISULAD_CONFIG "/etc/isulad" + + #define ISULAD_DAEMON_JSON_CONF_FILE ISULAD_CONFIG "/daemon.json" +@@ -110,6 +112,8 @@ extern "C" { + #define OCI_VERSION "1.0.1" + #endif + ++#define MOUNT_FLOCK_FILE_PATH "isulad-chroot-mount.flock" ++ + #define OCI_IMAGE_GRAPH_ROOTPATH_NAME "storage" + + #define DEFAULT_TCP_HOST "tcp://localhost:2375" +diff --git a/src/daemon/executor/container_cb/execution_stream.c b/src/daemon/executor/container_cb/execution_stream.c +index 7d165fb..fcb31f4 100644 +--- a/src/daemon/executor/container_cb/execution_stream.c ++++ b/src/daemon/executor/container_cb/execution_stream.c +@@ -61,6 +61,7 @@ + #include "utils.h" + #include "utils_file.h" + #include "utils_verify.h" ++#include "isulad_config.h" + + struct container_log_config { + char *driver; +@@ -407,6 +408,7 @@ static int archive_and_send_copy_data(const stream_func_wrapper *stream, + char *absbase = NULL; + char *err = NULL; + char *buf = NULL; ++ char *root_dir = NULL; + char cleaned[PATH_MAX + 2] = { 0 }; + struct io_read_wrapper reader = { 0 }; + char *tar_path = NULL; +@@ -439,9 +441,15 @@ static int archive_and_send_copy_data(const stream_func_wrapper *stream, + goto cleanup; + } + ++ root_dir = conf_get_isulad_rootdir(); ++ if (root_dir == NULL) { ++ ERROR("Failed to get isulad rootdir"); ++ goto cleanup; ++ } ++ + DEBUG("archive chroot tar stream container_fs(%s) srcdir(%s) relative(%s) srcbase(%s) absbase(%s)", + container_fs, srcdir, tar_path, srcbase, absbase); +- nret = archive_chroot_tar_stream(container_fs, tar_path, srcbase, absbase, &reader); ++ nret = archive_chroot_tar_stream(container_fs, tar_path, srcbase, absbase, root_dir, &reader); + if (nret != 0) { + ERROR("Archive %s failed", resolvedpath); + goto cleanup; +@@ -469,6 +477,7 @@ cleanup: + free(srcdir); + free(srcbase); + free(absbase); ++ free(root_dir); + if (reader.close != NULL) { + int cret = reader.close(reader.context, &err); + if (err != NULL) { +@@ -737,15 +746,25 @@ static int read_and_extract_archive(stream_func_wrapper *stream, const char *con + { + int ret = -1; + char *err = NULL; ++ char *root_dir = NULL; + struct io_read_wrapper content = { 0 }; + content.context = stream; + content.read = extract_stream_to_io_read; +- ret = archive_chroot_untar_stream(&content, container_fs, dstdir_in_container, src_rebase, dst_rebase, &err); ++ ++ root_dir = conf_get_isulad_rootdir(); ++ if (root_dir == NULL) { ++ ERROR("Failed to get isulad rootdir"); ++ isulad_set_error_message("Failed to get isulad rootdir"); ++ return -1; ++ } ++ ++ ret = archive_chroot_untar_stream(&content, container_fs, dstdir_in_container, src_rebase, dst_rebase, root_dir, &err); + if (ret != 0) { + ERROR("Can not untar to container: %s", (err != NULL) ? err : "unknown"); + isulad_set_error_message("Can not untar to container: %s", (err != NULL) ? err : "unknown"); + } + free(err); ++ free(root_dir); + return ret; + } + +diff --git a/src/daemon/modules/image/oci/oci_export.c b/src/daemon/modules/image/oci/oci_export.c +index 4b9d518..e994200 100644 +--- a/src/daemon/modules/image/oci/oci_export.c ++++ b/src/daemon/modules/image/oci/oci_export.c +@@ -20,6 +20,7 @@ + #include "isula_libutils/log.h" + #include "err_msg.h" + #include "util_archive.h" ++#include "isulad_config.h" + + int oci_do_export(char *id, char *file) + { +@@ -27,6 +28,7 @@ int oci_do_export(char *id, char *file) + int ret2 = 0; + char *mount_point = NULL; + char *errmsg = NULL; ++ char *root_dir = NULL; + + if (id == NULL || file == NULL) { + ERROR("Invalid NULL param"); +@@ -40,7 +42,15 @@ int oci_do_export(char *id, char *file) + return -1; + } + +- ret = archive_chroot_tar(mount_point, file, &errmsg); ++ root_dir = conf_get_isulad_rootdir(); ++ if (root_dir == NULL) { ++ ERROR("Failed to get isulad rootdir"); ++ isulad_set_error_message("Failed to get isulad rootdir"); ++ ret = -1; ++ goto out; ++ } ++ ++ ret = archive_chroot_tar(mount_point, file, root_dir, &errmsg); + if (ret != 0) { + ERROR("failed to export container %s to file %s: %s", id, file, errmsg); + isulad_set_error_message("Failed to export rootfs with error: %s", errmsg); +@@ -52,6 +62,7 @@ out: + mount_point = NULL; + free(errmsg); + errmsg = NULL; ++ free(root_dir); + + ret2 = storage_rootfs_umount(id, false); + if (ret2 != 0) { +diff --git a/src/daemon/modules/image/oci/oci_load.c b/src/daemon/modules/image/oci/oci_load.c +index a8eecfe..37a14b3 100644 +--- a/src/daemon/modules/image/oci/oci_load.c ++++ b/src/daemon/modules/image/oci/oci_load.c +@@ -42,6 +42,7 @@ + #include "utils_file.h" + #include "utils_verify.h" + #include "oci_image.h" ++#include "isulad_config.h" + + #define MANIFEST_BIG_DATA_KEY "manifest" + #define OCI_SCHEMA_VERSION 2 +@@ -1062,6 +1063,7 @@ int oci_do_load(const im_load_request *request) + char *digest = NULL; + char *dstdir = NULL; + char *err = NULL; ++ char *root_dir = NULL; + + if (request == NULL || request->file == NULL) { + ERROR("Invalid input arguments, cannot load image"); +@@ -1082,8 +1084,16 @@ int oci_do_load(const im_load_request *request) + goto out; + } + ++ root_dir = conf_get_isulad_rootdir(); ++ if (root_dir == NULL) { ++ ERROR("Failed to get isulad rootdir"); ++ isulad_try_set_error_message("Failed to get isulad rootdir"); ++ ret = -1; ++ goto out; ++ } ++ + options.whiteout_format = NONE_WHITEOUT_FORMATE; +- if (archive_unpack(&reader, dstdir, &options, &err) != 0) { ++ if (archive_unpack(&reader, dstdir, &options, root_dir, &err) != 0) { + ERROR("Failed to unpack to %s: %s", dstdir, err); + isulad_try_set_error_message("Failed to unpack to %s: %s", dstdir, err); + ret = -1; +@@ -1169,5 +1179,6 @@ out: + } + free(dstdir); + free(err); ++ free(root_dir); + return ret; + } +diff --git a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.c b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.c +index e91ffe0..43d3939 100644 +--- a/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.c ++++ b/src/daemon/modules/image/oci/storage/layer_store/graphdriver/devmapper/driver_devmapper.c +@@ -33,6 +33,7 @@ + #include "utils_file.h" + #include "utils_fs.h" + #include "utils_string.h" ++#include "isulad_config.h" + + struct io_read_wrapper; + +@@ -320,6 +321,7 @@ int devmapper_apply_diff(const char *id, const struct graphdriver *driver, const + int ret = 0; + struct archive_options options = { 0 }; + char *err = NULL; ++ char *root_dir = NULL; + + if (!util_valid_str(id) || driver == NULL || content == NULL) { + ERROR("invalid argument to apply diff with id(%s)", id); +@@ -340,8 +342,15 @@ int devmapper_apply_diff(const char *id, const struct graphdriver *driver, const + goto out; + } + ++ root_dir = conf_get_isulad_rootdir(); ++ if (root_dir == NULL) { ++ ERROR("Failed to get isulad rootdir"); ++ ret = -1; ++ goto out; ++ } ++ + options.whiteout_format = REMOVE_WHITEOUT_FORMATE; +- if (archive_unpack(content, layer_fs, &options, &err) != 0) { ++ if (archive_unpack(content, layer_fs, &options, root_dir, &err) != 0) { + ERROR("devmapper: failed to unpack to %s: %s", layer_fs, err); + ret = -1; + goto out; +@@ -357,6 +366,7 @@ out: + free_driver_mount_opts(mount_opts); + free(layer_fs); + free(err); ++ free(root_dir); + return ret; + } + +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 659d9d5..8940162 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 +@@ -41,6 +41,7 @@ + #include "utils_timestamp.h" + #include "selinux_label.h" + #include "err_msg.h" ++#include "isulad_config.h" + + struct io_read_wrapper; + +@@ -1658,6 +1659,7 @@ int overlay2_apply_diff(const char *id, const struct graphdriver *driver, const + char *layer_diff = NULL; + struct archive_options options = { 0 }; + char *err = NULL; ++ char *root_dir = NULL; + + if (id == NULL || driver == NULL || content == NULL) { + ERROR("invalid argument"); +@@ -1681,7 +1683,14 @@ int overlay2_apply_diff(const char *id, const struct graphdriver *driver, const + + options.whiteout_format = OVERLAY_WHITEOUT_FORMATE; + +- ret = archive_unpack(content, layer_diff, &options, &err); ++ root_dir = conf_get_isulad_rootdir(); ++ if (root_dir == NULL) { ++ ERROR("Failed to get isulad rootdir"); ++ ret = -1; ++ goto out; ++ } ++ ++ ret = archive_unpack(content, layer_diff, &options, root_dir ,&err); + if (ret != 0) { + ERROR("Failed to unpack to %s: %s", layer_diff, err); + ret = -1; +@@ -1690,6 +1699,7 @@ int overlay2_apply_diff(const char *id, const struct graphdriver *driver, const + + out: + free(err); ++ free(root_dir); + free(layer_dir); + free(layer_diff); + return ret; +diff --git a/src/utils/cutils/utils_file.c b/src/utils/cutils/utils_file.c +index 302e4e3..f440b62 100644 +--- a/src/utils/cutils/utils_file.c ++++ b/src/utils/cutils/utils_file.c +@@ -275,6 +275,33 @@ out: + return ret; + } + ++bool util_force_remove_file(const char *fname, int *saved_errno) ++{ ++ if (fname == NULL) { ++ return true; ++ } ++ ++ if (unlink(fname) == 0) { ++ return true; ++ } ++ ++ if (saved_errno != NULL && *saved_errno == 0) { ++ *saved_errno = errno; ++ } ++ SYSWARN("Failed to delete %s", fname); ++ ++ if (mark_file_mutable(fname) != 0) { ++ WARN("Failed to mark file mutable"); ++ } ++ ++ if (unlink(fname) != 0) { ++ SYSERROR("Failed to delete \"%s\"", fname); ++ return false; ++ } ++ ++ return true; ++} ++ + static int recursive_rmdir_next_depth(struct stat fstat, const char *fname, int recursive_depth, int *saved_errno, + int failure) + { +diff --git a/src/utils/cutils/utils_file.h b/src/utils/cutils/utils_file.h +index 125f43a..a7fbbb6 100644 +--- a/src/utils/cutils/utils_file.h ++++ b/src/utils/cutils/utils_file.h +@@ -36,6 +36,8 @@ bool util_file_exists(const char *f); + + int util_path_remove(const char *path); + ++bool util_force_remove_file(const char *fname, int *saved_errno); ++ + ssize_t util_write_nointr(int fd, const void *buf, size_t count); + + ssize_t util_write_nointr_in_total(int fd, const char *buf, size_t count); +diff --git a/src/utils/tar/isulad_tar.c b/src/utils/tar/isulad_tar.c +index 0327737..5f26ff5 100644 +--- a/src/utils/tar/isulad_tar.c ++++ b/src/utils/tar/isulad_tar.c +@@ -451,7 +451,7 @@ cleanup: + } + + int archive_copy_to(const struct io_read_wrapper *content, const struct archive_copy_info *srcinfo, +- const char *dstpath, char **err) ++ const char *dstpath, const char *root_dir, char **err) + { + int ret = -1; + struct archive_copy_info *dstinfo = NULL; +@@ -459,6 +459,10 @@ int archive_copy_to(const struct io_read_wrapper *content, const struct archive_ + char *src_base = NULL; + char *dst_base = NULL; + ++ if (err == NULL || dstpath == NULL || srcinfo == NULL || content == NULL || root_dir == NULL) { ++ return -1; ++ } ++ + dstinfo = copy_info_destination_path(dstpath, err); + if (dstinfo == NULL) { + ERROR("Can not get destination info: %s", dstpath); +@@ -471,7 +475,7 @@ int archive_copy_to(const struct io_read_wrapper *content, const struct archive_ + goto cleanup; + } + +- ret = archive_chroot_untar_stream(content, dstdir, ".", src_base, dst_base, err); ++ ret = archive_chroot_untar_stream(content, dstdir, ".", src_base, dst_base, root_dir, err); + + cleanup: + free_archive_copy_info(dstinfo); +@@ -481,7 +485,7 @@ cleanup: + return ret; + } + +-static int tar_resource_rebase(const char *path, const char *rebase, struct io_read_wrapper *archive_reader, char **err) ++static int tar_resource_rebase(const char *path, const char *rebase, const char *root_dir, struct io_read_wrapper *archive_reader, char **err) + { + int ret = -1; + int nret; +@@ -500,7 +504,7 @@ static int tar_resource_rebase(const char *path, const char *rebase, struct io_r + } + + DEBUG("chroot tar stream srcdir(%s) srcbase(%s) rebase(%s)", srcdir, srcbase, rebase); +- nret = archive_chroot_tar_stream(srcdir, srcbase, srcbase, rebase, archive_reader); ++ nret = archive_chroot_tar_stream(srcdir, srcbase, srcbase, rebase, root_dir, archive_reader); + if (nret < 0) { + ERROR("Can not archive path: %s", path); + goto cleanup; +@@ -512,7 +516,11 @@ cleanup: + return ret; + } + +-int tar_resource(const struct archive_copy_info *info, struct io_read_wrapper *archive_reader, char **err) ++int tar_resource(const struct archive_copy_info *info, const char *root_dir, struct io_read_wrapper *archive_reader, char **err) + { +- return tar_resource_rebase(info->path, info->rebase_name, archive_reader, err); ++ if (info == NULL || root_dir == NULL || archive_reader == NULL || err == NULL) { ++ return -1; ++ } ++ ++ return tar_resource_rebase(info->path, info->rebase_name, root_dir, archive_reader, err); + } +diff --git a/src/utils/tar/isulad_tar.h b/src/utils/tar/isulad_tar.h +index c773fe9..e0d4dab 100644 +--- a/src/utils/tar/isulad_tar.h ++++ b/src/utils/tar/isulad_tar.h +@@ -59,10 +59,10 @@ struct archive_copy_info *copy_info_source_path(const char *path, bool follow_li + char *prepare_archive_copy(const struct archive_copy_info *srcinfo, const struct archive_copy_info *dstinfo, + char **src_base, char **dst_base, char **err); + +-int tar_resource(const struct archive_copy_info *info, struct io_read_wrapper *archive_reader, char **err); ++int tar_resource(const struct archive_copy_info *info, const char *root_dir, struct io_read_wrapper *archive_reader, char **err); + + int archive_copy_to(const struct io_read_wrapper *content, const struct archive_copy_info *srcinfo, +- const char *dstpath, char **err); ++ const char *dstpath, const char *root_dir, char **err); + + #ifdef __cplusplus + } +diff --git a/src/utils/tar/util_archive.c b/src/utils/tar/util_archive.c +index c48472d..80e1587 100644 +--- a/src/utils/tar/util_archive.c ++++ b/src/utils/tar/util_archive.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + + #include "stdbool.h" + #include "utils.h" +@@ -77,6 +78,31 @@ ssize_t read_content(struct archive *a, void *client_data, const void **buff) + return mydata->content->read(mydata->content->context, mydata->buff, sizeof(mydata->buff)); + } + ++static char *generate_flock_path(const char *root_dir) ++{ ++ int nret = 0; ++ char path[PATH_MAX] = { 0 }; ++ char cleanpath[PATH_MAX] = { 0 }; ++ ++ nret = snprintf(path, PATH_MAX, "%s/%s", root_dir, MOUNT_FLOCK_FILE_PATH); ++ if (nret < 0 || (size_t)nret >= PATH_MAX) { ++ ERROR("Failed to snprintf"); ++ return NULL; ++ } ++ ++ if (util_clean_path(path, cleanpath, sizeof(cleanpath)) == NULL) { ++ ERROR("clean path for %s failed", path); ++ return NULL; ++ } ++ ++ if (!util_file_exists(cleanpath)) { ++ ERROR("flock file %s doesn't exist", cleanpath); ++ return NULL; ++ } ++ ++ return util_strdup_s(cleanpath); ++} ++ + static void do_disable_unneccessary_caps() + { + cap_t caps; +@@ -98,7 +124,61 @@ static void do_disable_unneccessary_caps() + cap_free(caps); + } + +-static int make_safedir_is_noexec(const char *dstdir, char **safe_dir) ++// Add flock when bind mount and make it private. ++// Because bind mount usually makes safedir shared mount point, ++// and sometimes it will cause "mount point explosion". ++// E.g. concurrently execute isula cp /tmp/ : ++static int bind_mount_with_flock(const char *flock_path, const char *dstdir, const char *tmp_dir) ++{ ++ int fd = -1; ++ int ret = -1; ++ ++ fd = open(flock_path, O_RDWR | O_CLOEXEC); ++ if (fd < 0) { ++ SYSERROR("Failed to open file %s", flock_path); ++ return -1; ++ } ++ ++ if (flock(fd, LOCK_EX) != 0) { ++ SYSERROR("Failed to lock file %s", flock_path); ++ goto out; ++ } ++ ++ if (mount(dstdir, tmp_dir, "none", MS_BIND, NULL) != 0) { ++ SYSERROR("Mount safe dir failed"); ++ goto unlock_out; ++ } ++ ++ if (mount(tmp_dir, tmp_dir, "none", MS_BIND | MS_REMOUNT | MS_NOEXEC, NULL) != 0) { ++ SYSERROR("Mount safe dir failed"); ++ if (umount(tmp_dir) != 0) { ++ SYSERROR("Failed to umount target %s", tmp_dir); ++ } ++ goto unlock_out; ++ } ++ ++ // Change the propagation type. ++ if (mount("", tmp_dir, "", MS_PRIVATE, "") != 0) { ++ SYSERROR("Failed to change the propagation type"); ++ if (umount(tmp_dir) != 0) { ++ SYSERROR("Failed to umount target %s", tmp_dir); ++ } ++ goto unlock_out; ++ } ++ ++ ret = 0; ++ ++unlock_out: ++ if (flock(fd, LOCK_UN) != 0) { ++ SYSERROR("Failed to unlock file %s", flock_path); ++ } ++ ++out: ++ close(fd); ++ return ret; ++} ++ ++static int make_safedir_is_noexec(const char *flock_path, const char *dstdir, char **safe_dir) + { + struct stat buf; + char *isulad_tmpdir_env = NULL; +@@ -150,19 +230,8 @@ static int make_safedir_is_noexec(const char *dstdir, char **safe_dir) + return -1; + } + +- if (mount(dstdir, tmp_dir, "none", MS_BIND, NULL) != 0) { +- SYSERROR("Mount safe dir failed"); +- if (util_path_remove(tmp_dir) != 0) { +- ERROR("Failed to remove path %s", tmp_dir); +- } +- return -1; +- } +- +- if (mount(tmp_dir, tmp_dir, "none", MS_BIND | MS_REMOUNT | MS_NOEXEC, NULL) != 0) { +- SYSERROR("Mount safe dir failed"); +- if (umount(tmp_dir) != 0) { +- ERROR("Failed to umount target %s", tmp_dir); +- } ++ if (bind_mount_with_flock(flock_path, dstdir, tmp_dir) != 0) { ++ ERROR("Failed to bind mount from %s to %s with flock", dstdir, tmp_dir); + if (util_path_remove(tmp_dir) != 0) { + ERROR("Failed to remove path %s", tmp_dir); + } +@@ -704,7 +773,7 @@ static void close_archive_pipes_fd(int *pipes, size_t pipe_size) + } + + int archive_unpack(const struct io_read_wrapper *content, const char *dstdir, const struct archive_options *options, +- char **errmsg) ++ const char *root_dir, char **errmsg) + { + int ret = 0; + pid_t pid = -1; +@@ -712,12 +781,24 @@ int archive_unpack(const struct io_read_wrapper *content, const char *dstdir, co + int pipe_stderr[2] = { -1, -1 }; + char errbuf[BUFSIZ] = { 0 }; + char *safe_dir = NULL; ++ char *flock_path = NULL; + +- if (make_safedir_is_noexec(dstdir, &safe_dir) != 0) { +- ERROR("Prepare safe dir failed"); ++ if (content == NULL || dstdir == NULL || options == NULL || root_dir == NULL) { + return -1; + } + ++ flock_path = generate_flock_path(root_dir); ++ if (flock_path == NULL) { ++ ERROR("Failed to generate flock path"); ++ return -1; ++ } ++ ++ if (make_safedir_is_noexec(flock_path, dstdir, &safe_dir) != 0) { ++ ERROR("Prepare safe dir failed"); ++ ret = -1; ++ goto cleanup; ++ } ++ + if (pipe2(pipe_stderr, O_CLOEXEC) != 0) { + ERROR("Failed to create pipe"); + ret = -1; +@@ -796,6 +877,7 @@ cleanup: + ERROR("Failed to remove path %s", safe_dir); + } + free(safe_dir); ++ free(flock_path); + return ret; + } + +@@ -1087,7 +1169,7 @@ static ssize_t fd_write(void *context, const void *data, size_t len) + return util_write_nointr(*(int *)context, data, len); + } + +-int archive_chroot_tar(char *path, char *file, char **errmsg) ++int archive_chroot_tar(const char *path, const char *file, const char *root_dir, char **errmsg) + { + struct io_write_wrapper pipe_context = { 0 }; + int ret = 0; +@@ -1097,12 +1179,24 @@ int archive_chroot_tar(char *path, char *file, char **errmsg) + char errbuf[BUFSIZ] = { 0 }; + int fd = 0; + char *safe_dir = NULL; ++ char *flock_path = NULL; + +- if (make_safedir_is_noexec(path, &safe_dir) != 0) { +- ERROR("Prepare safe dir failed"); ++ if (path == NULL || file == NULL || root_dir == NULL) { + return -1; + } + ++ flock_path = generate_flock_path(root_dir); ++ if (flock_path == NULL) { ++ ERROR("Failed to generate flock path"); ++ return -1; ++ } ++ ++ if (make_safedir_is_noexec(flock_path, path, &safe_dir) != 0) { ++ ERROR("Prepare safe dir failed"); ++ ret = -1; ++ goto cleanup; ++ } ++ + if (pipe2(pipe_for_read, O_CLOEXEC) != 0) { + ERROR("Failed to create pipe"); + ret = -1; +@@ -1191,6 +1285,7 @@ cleanup: + ERROR("Failed to remove path %s", safe_dir); + } + free(safe_dir); ++ free(flock_path); + return ret; + } + +@@ -1311,7 +1406,7 @@ static int archive_context_close(void *context, char **err) + } + + int archive_chroot_untar_stream(const struct io_read_wrapper *context, const char *chroot_dir, const char *untar_dir, +- const char *src_base, const char *dst_base, char **errmsg) ++ const char *src_base, const char *dst_base, const char *root_dir, char **errmsg) + { + struct io_read_wrapper pipe_context = { 0 }; + int pipe_stream[2] = { -1, -1 }; +@@ -1329,12 +1424,19 @@ int archive_chroot_untar_stream(const struct io_read_wrapper *context, const cha + .dst_base = dst_base + }; + char *safe_dir = NULL; ++ char *flock_path = NULL; + +- if (make_safedir_is_noexec(chroot_dir, &safe_dir) != 0) { +- ERROR("Prepare safe dir failed"); ++ flock_path = generate_flock_path(root_dir); ++ if (flock_path == NULL) { ++ ERROR("Failed to generate flock path"); + return -1; + } + ++ if (make_safedir_is_noexec(flock_path, chroot_dir, &safe_dir) != 0) { ++ ERROR("Prepare safe dir failed"); ++ goto cleanup; ++ } ++ + if (pipe(pipe_stderr) != 0) { + ERROR("Failed to create pipe: %s", strerror(errno)); + goto cleanup; +@@ -1441,12 +1543,13 @@ cleanup: + ERROR("Failed to remove path %s", safe_dir); + } + free(safe_dir); ++ free(flock_path); + + return ret; + } + + int archive_chroot_tar_stream(const char *chroot_dir, const char *tar_path, const char *src_base, const char *dst_base, +- struct io_read_wrapper *reader) ++ const char *root_dir, struct io_read_wrapper *reader) + { + struct io_write_wrapper pipe_context = { 0 }; + int keepfds[] = { -1, -1, -1 }; +@@ -1456,12 +1559,19 @@ int archive_chroot_tar_stream(const char *chroot_dir, const char *tar_path, cons + pid_t pid; + struct archive_context *ctx = NULL; + char *safe_dir = NULL; ++ char *flock_path = NULL; + +- if (make_safedir_is_noexec(chroot_dir, &safe_dir) != 0) { +- ERROR("Prepare safe dir failed"); ++ flock_path = generate_flock_path(root_dir); ++ if (flock_path == NULL) { ++ ERROR("Failed to generate flock path"); + return -1; + } + ++ if (make_safedir_is_noexec(flock_path, chroot_dir, &safe_dir) != 0) { ++ ERROR("Prepare safe dir failed"); ++ goto free_out; ++ } ++ + if (pipe(pipe_stderr) != 0) { + ERROR("Failed to create pipe: %s", strerror(errno)); + goto free_out; +@@ -1563,6 +1673,7 @@ free_out: + close_archive_pipes_fd(pipe_stderr, 2); + close_archive_pipes_fd(pipe_stream, 2); + free(ctx); ++ free(flock_path); + if (safe_dir != NULL) { + if (umount(safe_dir) != 0) { + ERROR("Failed to umount target %s", safe_dir); +diff --git a/src/utils/tar/util_archive.h b/src/utils/tar/util_archive.h +index 55fd768..8e4cf57 100644 +--- a/src/utils/tar/util_archive.h ++++ b/src/utils/tar/util_archive.h +@@ -47,17 +47,17 @@ struct archive_options { + }; + + int archive_unpack(const struct io_read_wrapper *content, const char *dstdir, const struct archive_options *options, +- char **errmsg); ++ const char *root_dir, char **errmsg); + + bool valid_archive_format(const char *file); + +-int archive_chroot_tar(char *path, char *file, char **errmsg); ++int archive_chroot_tar(const char *path, const char *file, const char *root_dir, char **errmsg); + + int archive_chroot_tar_stream(const char *chroot_dir, const char *tar_path, const char *src_base, +- const char *dst_base, struct io_read_wrapper *content); ++ const char *dst_base, const char *root_dir, struct io_read_wrapper *content); + int archive_chroot_untar_stream(const struct io_read_wrapper *content, const char *chroot_dir, + const char *untar_dir, const char *src_base, const char *dst_base, +- char **errmsg); ++ const char *root_dir, char **errmsg); + + #ifdef __cplusplus + } +diff --git a/test/image/oci/storage/layers/CMakeLists.txt b/test/image/oci/storage/layers/CMakeLists.txt +index e9374cd..d57fba3 100644 +--- a/test/image/oci/storage/layers/CMakeLists.txt ++++ b/test/image/oci/storage/layers/CMakeLists.txt +@@ -22,6 +22,8 @@ add_executable(${DRIVER_EXE} + ${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/config/daemon_arguments.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/config/isulad_config.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 +@@ -91,6 +93,8 @@ add_executable(${LAYER_EXE} + ${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/config/daemon_arguments.c ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/config/isulad_config.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/modules/image/oci/storage/layer_store/layer.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/modules/image/oci/storage/layer_store/layer_store.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../src/daemon/modules/image/oci/storage/layer_store/graphdriver/driver.c +-- +2.40.1 + diff --git a/iSulad.spec b/iSulad.spec index 274548d1a3c92d811ed21a7422da941958040e27..7c696a90c0848f2d3d40335600266e997ae96d14 100644 --- a/iSulad.spec +++ b/iSulad.spec @@ -1,5 +1,5 @@ %global _version 2.0.8 -%global _release 20230216.115407.git40ea936a +%global _release 20230216.115408.git40ea936a %global is_systemd 1 Name: iSulad @@ -118,6 +118,7 @@ Patch103: 0103-optimize-token-generation.patch Patch104: 0104-fix-string-array-initialization-failure.patch Patch105: 0105-suppress-proxy-connect-headers-message.patch Patch106: 0106-fix-loading-of-nsswitch-based-config-inside-chroot-u.patch +Patch107: 0107-add-bind-mount-file-lock.patch %ifarch x86_64 aarch64 Provides: libhttpclient.so()(64bit) @@ -334,6 +335,12 @@ fi %endif %changelog +* Tue Sep 19 2023 zhongtao - 2.0.8-20230216.115408.git40ea936a +- Type: bugfix +- ID: NA +- SUG: NA +- DESC: add bind mount file lock + * Thu Feb 16 2023 zhangxiaoyu - 2.0.8-20230216.115407.git40ea936a - Type: bugfix - ID: NA