From c1c5159675073450fe13906771cec6f666053380 Mon Sep 17 00:00:00 2001 From: zhangxiaoyu Date: Thu, 31 Aug 2023 13:14:02 +0000 Subject: [PATCH 05/33] !2163 add bind mount file lock * add bind mount file lock --- src/cmd/isula/stream/cp.c | 66 ++++++- src/cmd/isulad/main.c | 51 ++++++ 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/tar/isulad_tar.c | 16 +- src/utils/tar/isulad_tar.h | 4 +- src/utils/tar/util_archive.c | 163 +++++++++++++++--- src/utils/tar/util_archive.h | 8 +- 12 files changed, 332 insertions(+), 53 deletions(-) diff --git a/src/cmd/isula/stream/cp.c b/src/cmd/isula/stream/cp.c index f0cd99c9..b1e3bbd6 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); // archive reader close if copy to container failed @@ -223,6 +276,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 681dcf03..b32b6626 100644 --- a/src/cmd/isulad/main.c +++ b/src/cmd/isulad/main.c @@ -72,6 +72,7 @@ #include "utils_file.h" #include "utils_string.h" #include "utils_verify.h" +#include "path.h" #include "volume_api.h" #ifndef DISABLE_CLEANUP #include "leftover_cleanup_api.h" @@ -1383,6 +1384,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; @@ -1413,6 +1458,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 409a83a1..d93bb464 100644 --- a/src/common/constants.h +++ b/src/common/constants.h @@ -68,6 +68,8 @@ extern "C" { #define DEFAULT_HIGHEST_DIRECTORY_MODE 0755 +#define MOUNT_FLOCK_FILE_MODE 0660 + #define ISULAD_CONFIG SYSCONFDIR_PREFIX"/etc/isulad" #define ISULAD_DAEMON_CONTAINER_CONTEXTS ISULAD_CONFIG "/container_contexts" @@ -119,6 +121,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" #ifdef ENABLE_GRPC_REMOTE_CONNECT diff --git a/src/daemon/executor/container_cb/execution_stream.c b/src/daemon/executor/container_cb/execution_stream.c index 32721e68..244ec6a0 100644 --- a/src/daemon/executor/container_cb/execution_stream.c +++ b/src/daemon/executor/container_cb/execution_stream.c @@ -62,6 +62,7 @@ #include "utils.h" #include "utils_file.h" #include "utils_verify.h" +#include "isulad_config.h" #if defined (__ANDROID__) || defined(__MUSL__) #define SIG_CANCEL_SIGNAL SIGUSR1 @@ -442,6 +443,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; @@ -474,9 +476,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; @@ -504,6 +512,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) { @@ -776,15 +785,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 e27ed6d8..6bfcf4d5 100644 --- a/src/daemon/modules/image/oci/oci_export.c +++ b/src/daemon/modules/image/oci/oci_export.c @@ -23,6 +23,7 @@ #include "util_archive.h" #include "path.h" #include "utils_file.h" +#include "isulad_config.h" int oci_do_export(char *id, char *file) { @@ -30,6 +31,7 @@ int oci_do_export(char *id, char *file) int ret2 = 0; char *mount_point = NULL; char *errmsg = NULL; + char *root_dir = NULL; char cleanpath[PATH_MAX] = { 0 }; if (id == NULL || file == NULL) { @@ -56,7 +58,15 @@ int oci_do_export(char *id, char *file) return -1; } - ret = archive_chroot_tar(mount_point, cleanpath, &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, cleanpath, root_dir, &errmsg); if (ret != 0) { ERROR("failed to export container %s to file %s: %s", id, cleanpath, errmsg); isulad_set_error_message("Failed to export rootfs with error: %s", errmsg); @@ -68,6 +78,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 04a9f947..4385e55e 100644 --- a/src/daemon/modules/image/oci/oci_load.c +++ b/src/daemon/modules/image/oci/oci_load.c @@ -41,6 +41,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 @@ -1068,6 +1069,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"); @@ -1088,8 +1090,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; @@ -1175,5 +1185,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 998ea8c2..ecb62f79 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 @@ -32,6 +32,7 @@ #include "utils_file.h" #include "utils_fs.h" #include "utils_string.h" +#include "isulad_config.h" struct io_read_wrapper; @@ -346,6 +347,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); @@ -366,8 +368,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 umount_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 umount_out; @@ -384,6 +393,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 c5864c90..b177f594 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 @@ -45,6 +45,7 @@ #include "utils_timestamp.h" #include "selinux_label.h" #include "err_msg.h" +#include "isulad_config.h" #ifdef ENABLE_REMOTE_LAYER_STORE #include "ro_symlink_maintain.h" #endif @@ -1886,6 +1887,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"); @@ -1919,7 +1921,14 @@ int overlay2_apply_diff(const char *id, const struct graphdriver *driver, const } #endif - 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; @@ -1928,6 +1937,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); #ifdef ENABLE_USERNS_REMAP diff --git a/src/utils/tar/isulad_tar.c b/src/utils/tar/isulad_tar.c index 74176b12..24269c70 100644 --- a/src/utils/tar/isulad_tar.c +++ b/src/utils/tar/isulad_tar.c @@ -385,7 +385,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; @@ -393,7 +393,7 @@ 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) { + if (err == NULL || dstpath == NULL || srcinfo == NULL || content == NULL || root_dir == NULL) { return -1; } @@ -409,7 +409,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); @@ -419,7 +419,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; @@ -438,7 +438,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; @@ -450,11 +450,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) { - if (info == NULL || archive_reader == NULL || err == NULL) { + if (info == NULL || root_dir == NULL || archive_reader == NULL || err == NULL) { return -1; } - return tar_resource_rebase(info->path, info->rebase_name, archive_reader, err); + 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 cdd9858a..414bb024 100644 --- a/src/utils/tar/isulad_tar.h +++ b/src/utils/tar/isulad_tar.h @@ -43,10 +43,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 0fb7769b..d2fc5488 100644 --- a/src/utils/tar/util_archive.c +++ b/src/utils/tar/util_archive.c @@ -33,10 +33,12 @@ #include #include #include +#include #include #include #include +#include #include "error.h" #include "map.h" @@ -83,6 +85,31 @@ static ssize_t read_content(struct archive *a, void *client_data, const void **b 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; @@ -104,7 +131,58 @@ 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) +{ + __isula_auto_close 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); + return -1; + } + + 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); + } + 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; @@ -156,19 +234,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); } @@ -723,7 +790,7 @@ static void set_child_process_pdeathsig(void) } 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; @@ -731,12 +798,24 @@ int archive_unpack(const struct io_read_wrapper *content, const char *dstdir, co int pipe_stderr[2] = { -1, -1 }; char errbuf[BUFSIZ + 1] = { 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; @@ -816,6 +895,7 @@ cleanup: ERROR("Failed to remove path %s", safe_dir); } free(safe_dir); + free(flock_path); return ret; } @@ -1126,7 +1206,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; @@ -1136,12 +1216,24 @@ int archive_chroot_tar(char *path, char *file, char **errmsg) char errbuf[BUFSIZ + 1] = { 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; @@ -1232,6 +1324,7 @@ cleanup: ERROR("Failed to remove path %s", safe_dir); } free(safe_dir); + free(flock_path); return ret; } @@ -1352,7 +1445,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 }; @@ -1370,12 +1463,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; @@ -1483,12 +1583,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 }; @@ -1498,12 +1599,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; @@ -1607,6 +1715,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); @@ -1848,4 +1957,4 @@ int archive_copy_oci_tar_split_and_ret_size(int src_fd, const char *dist_file, i } return foreach_archive_entry(archive_entry_parse, src_fd, dist_file, ret_size); -} \ No newline at end of file +} diff --git a/src/utils/tar/util_archive.h b/src/utils/tar/util_archive.h index 5cc2c5ec..8f0ab2a4 100644 --- a/src/utils/tar/util_archive.h +++ b/src/utils/tar/util_archive.h @@ -45,17 +45,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); int archive_copy_oci_tar_split_and_ret_size(int src_fd, const char *dist_file, int64_t *ret_size); -- 2.40.1