From dc2d6667f3a340c9147acc72002d2980a18ceefa Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Mon, 15 Nov 2021 13:00:33 +0100 Subject: [PATCH] linux: add function to send mounts from the host preparation patch to enable the creation of mounts before joining or creating a user namespace. This is needed for creating idmapped mounts that are usable from the container user namespace. Signed-off-by: Giuseppe Scrivano --- src/libcrun/linux.c | 102 ++++++++++++++++++++++++++++++++++++++++++-- src/libcrun/utils.c | 14 +++++- src/libcrun/utils.h | 2 + 3 files changed, 114 insertions(+), 4 deletions(-) diff --git a/src/libcrun/linux.c b/src/libcrun/linux.c index 5265f25006..1e9fdd24f3 100644 --- a/src/libcrun/linux.c +++ b/src/libcrun/linux.c @@ -3243,6 +3243,94 @@ root_mapped_in_container_p (runtime_spec_schema_defs_id_mapping **mappings, size return false; } +static struct libcrun_fd_map * +get_fd_map (libcrun_container_t *container) +{ + struct libcrun_fd_map *mount_fds = get_private_data (container)->mount_fds; + + if (mount_fds == NULL) + { + runtime_spec_schema_config_schema *def = container->container_def; + mount_fds = make_libcrun_fd_map (def->mounts_len); + get_private_data (container)->mount_fds = mount_fds; + } + return mount_fds; +} + +static int +prepare_and_send_mounts (libcrun_container_t *container, struct init_status_s *init_status, + pid_t pid, int sync_socket_host, libcrun_error_t *err) +{ + runtime_spec_schema_config_schema *def = container->container_def; + cleanup_close_map struct libcrun_fd_map *mount_fds = NULL; + size_t how_many = 0; + size_t i; + int ret; + + if (def->mounts_len == 0) + return 0; + + mount_fds = make_libcrun_fd_map (def->mounts_len); + + for (i = 0; i < def->mounts_len; i++) + { + if (mount_fds->fds[i] >= 0) + how_many++; + } + + ret = TEMP_FAILURE_RETRY (write (sync_socket_host, &how_many, sizeof (how_many))); + if (UNLIKELY (ret < 0)) + return crun_make_error (err, errno, "write to sync socket"); + + for (i = 0; i < def->mounts_len; i++) + { + if (mount_fds->fds[i] >= 0) + { + ret = send_fd_to_socket_with_payload (sync_socket_host, mount_fds->fds[i], (char *) &i, sizeof (i), err); + if (UNLIKELY (ret < 0)) + return ret; + } + } + + return 0; +} + +static int +receive_mounts (libcrun_container_t *container, int sync_socket_container, libcrun_error_t *err) +{ + runtime_spec_schema_config_schema *def = container->container_def; + size_t i, how_many = 0; + struct libcrun_fd_map *mount_fds = NULL; + int ret; + + if (def->mounts_len == 0) + return 0; + + mount_fds = get_fd_map (container); + + ret = TEMP_FAILURE_RETRY (read (sync_socket_container, &how_many, sizeof (how_many))); + if (UNLIKELY (ret < 0)) + return crun_make_error (err, errno, "read from sync socket"); + + for (i = 0; i < how_many; i++) + { + size_t index; + + ret = receive_fd_from_socket_with_payload (sync_socket_container, (char *) &index, sizeof (index), err); + if (UNLIKELY (ret < 0)) + return ret; + if (index >= def->mounts_len) + return crun_make_error (err, 0, "invalid mount data received"); + + if (mount_fds->fds[index] >= 0) + TEMP_FAILURE_RETRY (close (mount_fds->fds[index])); + + mount_fds->fds[index] = ret; + } + + return 0; +} + static int set_id_init (libcrun_container_t *container, libcrun_error_t *err) { @@ -3290,7 +3378,7 @@ init_container (libcrun_container_t *container, int sync_socket_container, struc libcrun_error_t *err) { runtime_spec_schema_config_schema *def = container->container_def; - cleanup_close_map struct libcrun_fd_map *mount_fds = NULL; + struct libcrun_fd_map *mount_fds = get_fd_map (container); pid_t pid_container = 0; size_t i; int ret; @@ -3353,8 +3441,6 @@ init_container (libcrun_container_t *container, int sync_socket_container, struc return ret; } - mount_fds = make_libcrun_fd_map (def->mounts_len); - /* If the container needs to join an existing PID namespace, take a reference to it before creating a new user namespace, as we could lose the access to the existing namespace. @@ -3470,6 +3556,11 @@ init_container (libcrun_container_t *container, int sync_socket_container, struc return ret; } + /* Receive the mounts sent by `prepare_and_send_mounts`. */ + ret = receive_mounts (container, sync_socket_container, err); + if (UNLIKELY (ret < 0)) + return ret; + ret = libcrun_container_setgroups (container, container->container_def->process, err); if (UNLIKELY (ret < 0)) return ret; @@ -3679,6 +3770,11 @@ libcrun_run_linux_container (libcrun_container_t *container, container_entrypoin pid_to_clean = pid = grandchild; } + /* They are received by `receive_mounts`. */ + ret = prepare_and_send_mounts (container, &init_status, pid, sync_socket_host, err); + if (UNLIKELY (ret < 0)) + return ret; + ret = expect_success_from_sync_socket (sync_socket_host, err); if (UNLIKELY (ret < 0)) return ret; diff --git a/src/libcrun/utils.c b/src/libcrun/utils.c index 06f00ee522..28222c9853 100644 --- a/src/libcrun/utils.c +++ b/src/libcrun/utils.c @@ -1010,7 +1010,7 @@ send_fd_to_socket_with_payload (int server, int fd, const char *payload, size_t } int -receive_fd_from_socket (int from, libcrun_error_t *err) +receive_fd_from_socket_with_payload (int from, char *payload, size_t payload_len, libcrun_error_t *err) { cleanup_close int fd = -1; int ret; @@ -1024,6 +1024,12 @@ receive_fd_from_socket (int from, libcrun_error_t *err) iov[0].iov_base = data; iov[0].iov_len = sizeof (data); + if (payload_len > 0) + { + iov[0].iov_base = (void *) payload; + iov[0].iov_len = payload_len; + } + msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = iov; @@ -1047,6 +1053,12 @@ receive_fd_from_socket (int from, libcrun_error_t *err) return ret; } +int +receive_fd_from_socket (int from, libcrun_error_t *err) +{ + return receive_fd_from_socket_with_payload (from, NULL, 0, err); +} + int create_socket_pair (int *pair, libcrun_error_t *err) { diff --git a/src/libcrun/utils.h b/src/libcrun/utils.h index 2af0917cf9..6b4a99f228 100644 --- a/src/libcrun/utils.h +++ b/src/libcrun/utils.h @@ -265,6 +265,8 @@ int create_socket_pair (int *pair, libcrun_error_t *err); int receive_fd_from_socket (int from, libcrun_error_t *err); +int receive_fd_from_socket_with_payload (int from, char *payload, size_t payload_len, libcrun_error_t *err); + int create_signalfd (sigset_t *mask, libcrun_error_t *err); int epoll_helper (int *fds, int *levelfds, libcrun_error_t *err);