From 040cb2e7064420caa61649998e0214e5e218a46b Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 20 May 2025 16:54:55 +0200 Subject: [PATCH 1/8] linux: include errno check in UNLIKELY macro Signed-off-by: Giuseppe Scrivano --- src/libcrun/linux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcrun/linux.c b/src/libcrun/linux.c index 79a1421dfc..956cb09a65 100644 --- a/src/libcrun/linux.c +++ b/src/libcrun/linux.c @@ -4303,7 +4303,7 @@ prepare_and_send_dev_mounts (libcrun_container_t *container, int sync_socket_hos return ret; ret = mkdir (devs_path, 0700); - if (UNLIKELY (ret < 0) && errno != EEXIST) + if (UNLIKELY (ret < 0 && errno != EEXIST)) return crun_make_error (err, errno, "mkdir `%s`", devs_path); current_mountns = open ("/proc/self/ns/mnt", O_RDONLY | O_CLOEXEC); From 9ddddfb05a74ff533da50e7db8e5e6ba060ac307 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 20 May 2025 16:53:56 +0200 Subject: [PATCH 2/8] test: fix mount to test Signed-off-by: Giuseppe Scrivano --- tests/test_mounts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_mounts.py b/tests/test_mounts.py index ad0cd5c755..0232e04963 100755 --- a/tests/test_mounts.py +++ b/tests/test_mounts.py @@ -109,7 +109,7 @@ def prepare_rootfs(rootfs): conf = base_config() conf['process']['args'] = ['/init', 'mode', '/tmp'] add_all_namespaces(conf) - mount_opt = {"destination": "/tmp", "type": "tmpfs", "source": "tmpfs", "options": ["bind", "ro"]} + conf['mounts'].append({"destination": "/tmp", "type": "tmpfs", "source": "tmpfs", "options": ["bind", "ro"]}) out, _ = run_and_get_output(conf, hide_stderr=True, callback_prepare_rootfs=prepare_rootfs) if "712" in out: return 0 From 372446d747377c58f8f830d1072934f0b95252df Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 20 May 2025 16:03:51 +0200 Subject: [PATCH 3/8] tests: fix unused variable Signed-off-by: Giuseppe Scrivano --- tests/tests_libcrun_intelrdt.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/tests_libcrun_intelrdt.c b/tests/tests_libcrun_intelrdt.c index 21c84d17f1..e1a972166f 100644 --- a/tests/tests_libcrun_intelrdt.c +++ b/tests/tests_libcrun_intelrdt.c @@ -84,6 +84,8 @@ test_get_rdt_value () { \ char *result = NULL; \ int r = get_rdt_value (&result, L3, MB, SCHEMATA); \ + if (strlen (result) != r) \ + return 1; \ int cmp = strcmp (result, EXPECTED); \ free (result); \ if (cmp != 0) \ From 953a8c49d63098cf5ea489f15ade73ff81d6a562 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 20 May 2025 15:40:53 +0200 Subject: [PATCH 4/8] utils: crun_safe_ensure_at opens empty paths if `do_open` is used with an empty path, the reopen the `dirpath`. Signed-off-by: Giuseppe Scrivano --- src/libcrun/utils.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/libcrun/utils.c b/src/libcrun/utils.c index 694d352c0c..340d9c7d9f 100644 --- a/src/libcrun/utils.c +++ b/src/libcrun/utils.c @@ -449,7 +449,11 @@ crun_safe_ensure_at (bool do_open, bool dir, int dirfd, const char *dirpath, /* Empty path, nothing to do. */ if (*path == '\0') - return 0; + { + if (do_open) + return open (dirpath, O_CLOEXEC | O_PATH, 0); + return 0; + } npath = xstrdup (path); @@ -577,12 +581,12 @@ crun_safe_ensure_at (bool do_open, bool dir, int dirfd, const char *dirpath, int crun_safe_create_and_open_ref_at (bool dir, int dirfd, const char *dirpath, const char *path, int mode, libcrun_error_t *err) { - int fd; + int ret; /* If the file/dir already exists, just open it. */ - fd = safe_openat (dirfd, dirpath, path, O_PATH | O_CLOEXEC, 0, err); - if (LIKELY (fd >= 0)) - return fd; + ret = safe_openat (dirfd, dirpath, path, O_PATH | O_CLOEXEC, 0, err); + if (LIKELY (ret >= 0)) + return ret; crun_error_release (err); return crun_safe_ensure_at (true, dir, dirfd, dirpath, path, mode, MAX_READLINKS, err); From e9d159f727867e33ed264b9296b5e86e0bf6097a Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 20 May 2025 17:26:37 +0200 Subject: [PATCH 5/8] linux: store rootfsfd under private data only Signed-off-by: Giuseppe Scrivano --- src/libcrun/linux.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/libcrun/linux.c b/src/libcrun/linux.c index 956cb09a65..6e1167d284 100644 --- a/src/libcrun/linux.c +++ b/src/libcrun/linux.c @@ -167,6 +167,9 @@ cleanup_private_data (void *private_data) if (p->dev_fds) cleanup_close_mapp (&(p->dev_fds)); + if (p->rootfsfd >= 0) + close (p->rootfsfd); + free (p->unified_cgroup_path); free (p->host_notify_socket_path); free (p->container_notify_socket_path); @@ -2045,13 +2048,14 @@ get_force_cgroup_v1_annotation (libcrun_container_t *container) } static int -do_mounts (libcrun_container_t *container, int rootfsfd, const char *rootfs, libcrun_error_t *err) +do_mounts (libcrun_container_t *container, const char *rootfs, libcrun_error_t *err) { size_t i; int ret; runtime_spec_schema_config_schema *def = container->container_def; const char *systemd_cgroup_v1 = get_force_cgroup_v1_annotation (container); cleanup_close_map struct libcrun_fd_map *mount_fds = NULL; + int rootfsfd = get_private_data (container)->rootfsfd; mount_fds = get_private_data (container)->mount_fds; get_private_data (container)->mount_fds = NULL; @@ -2576,9 +2580,7 @@ int libcrun_set_mounts (struct container_entrypoint_s *entrypoint_args, libcrun_container_t *container, const char *rootfs, set_mounts_cb_t cb, void *cb_data, libcrun_error_t *err) { runtime_spec_schema_config_schema *def = container->container_def; - cleanup_close int rootfsfd_cleanup = -1; unsigned long rootfs_propagation = 0; - int rootfsfd = -1; int cgroup_mode; int is_user_ns = 0; int ret = 0; @@ -2609,12 +2611,12 @@ libcrun_set_mounts (struct container_entrypoint_s *entrypoint_args, libcrun_cont return ret; } - rootfsfd = rootfsfd_cleanup = open (rootfs, O_PATH | O_CLOEXEC); - if (UNLIKELY (rootfsfd < 0)) + ret = open (rootfs, O_PATH | O_CLOEXEC); + if (UNLIKELY (ret < 0)) return crun_make_error (err, errno, "open `%s`", rootfs); + get_private_data (container)->rootfsfd = ret; get_private_data (container)->rootfs = rootfs; - get_private_data (container)->rootfsfd = rootfsfd; // configure handler mounts ret = libcrun_container_notify_handler (entrypoint_args, HANDLER_CONFIGURE_MOUNTS, container, rootfs, err); @@ -2627,7 +2629,7 @@ libcrun_set_mounts (struct container_entrypoint_s *entrypoint_args, libcrun_cont unsigned long remount_flags = MS_REMOUNT | MS_BIND | MS_RDONLY; int fd; - fd = dup (rootfsfd); + fd = dup (get_private_data (container)->rootfsfd); if (UNLIKELY (fd < 0)) return crun_make_error (err, errno, "dup fd for `%s`", rootfs); @@ -2655,7 +2657,7 @@ libcrun_set_mounts (struct container_entrypoint_s *entrypoint_args, libcrun_cont if (UNLIKELY (ret < 0)) return ret; - ret = do_mounts (container, rootfsfd, rootfs, err); + ret = do_mounts (container, rootfs, err); if (UNLIKELY (ret < 0)) return ret; @@ -2691,7 +2693,7 @@ libcrun_set_mounts (struct container_entrypoint_s *entrypoint_args, libcrun_cont libcrun_error_t tmp_err = NULL; const char *rel_cwd = consume_slashes (def->process->cwd); /* Ignore errors here and let it fail later. */ - (void) crun_safe_ensure_directory_at (rootfsfd, rootfs, rel_cwd, 0755, &tmp_err); + (void) crun_safe_ensure_directory_at (get_private_data (container)->rootfsfd, rootfs, rel_cwd, 0755, &tmp_err); crun_error_release (&tmp_err); } @@ -2708,7 +2710,7 @@ libcrun_set_mounts (struct container_entrypoint_s *entrypoint_args, libcrun_cont if (UNLIKELY (ret < 0)) return crun_make_error (err, errno, "failed configuring mounts for handler at phase: HANDLER_CONFIGURE_AFTER_MOUNTS"); - get_private_data (container)->rootfsfd = -1; + close_and_reset (&(get_private_data (container)->rootfsfd)); return 0; } From 2e210bdce68aafcd078d996b9f954b9e0447d0cd Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 20 May 2025 19:01:37 +0200 Subject: [PATCH 6/8] linux: use rootfsfd directly from container data This change ensures that the file descriptor for the rootfs is always sourced directly from the container's private data. This avoids potential stale file descriptor issues that could happen if a local variable were used and the descriptor in the private data was updated elsewhere. Should not introduce any behavior change. Signed-off-by: Giuseppe Scrivano --- src/libcrun/linux.c | 44 +++++++++++++++++++------------------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/src/libcrun/linux.c b/src/libcrun/linux.c index 6e1167d284..2c550f9627 100644 --- a/src/libcrun/linux.c +++ b/src/libcrun/linux.c @@ -1030,7 +1030,6 @@ do_masked_or_readonly_path (libcrun_container_t *container, const char *rel_path { unsigned long mount_flags = 0; const char *rootfs = get_private_data (container)->rootfs; - int rootfsfd = get_private_data (container)->rootfsfd; cleanup_close int pathfd = -1; struct statfs sfs; int ret; @@ -1039,7 +1038,7 @@ do_masked_or_readonly_path (libcrun_container_t *container, const char *rel_path if (rel_path[0] == '/') rel_path++; - pathfd = safe_openat (rootfsfd, rootfs, rel_path, O_PATH | O_CLOEXEC, 0, err); + pathfd = safe_openat (get_private_data (container)->rootfsfd, rootfs, rel_path, O_PATH | O_CLOEXEC, 0, err); if (UNLIKELY (pathfd < 0)) { if (errno != ENOENT && errno != EACCES) @@ -1588,7 +1587,6 @@ libcrun_create_dev (libcrun_container_t *container, int devfd, int srcfd, mode_t type = (device->type[0] == 'b') ? S_IFBLK : ((device->type[0] == 'p') ? S_IFIFO : S_IFCHR); const char *fullname = device->path; cleanup_close int fd = -1; - int rootfsfd = get_private_data (container)->rootfsfd; const char *rootfs = get_private_data (container)->rootfs; if (is_empty_string (fullname)) return crun_make_error (err, EINVAL, "device path is empty"); @@ -1619,7 +1617,7 @@ libcrun_create_dev (libcrun_container_t *container, int devfd, int srcfd, { const char *rel_path = consume_slashes (normalized_path); - fd = crun_safe_create_and_open_ref_at (false, rootfsfd, rootfs, rel_path, 0755, err); + fd = crun_safe_create_and_open_ref_at (false, get_private_data (container)->rootfsfd, rootfs, rel_path, 0755, err); if (UNLIKELY (fd < 0)) return fd; } @@ -1684,18 +1682,18 @@ libcrun_create_dev (libcrun_container_t *container, int devfd, int srcfd, if (dirname[0] == '\0') { - dirfd = dup (rootfsfd); + dirfd = dup (get_private_data (container)->rootfsfd); if (UNLIKELY (dirfd < 0)) return crun_make_error (err, errno, "dup fd for `%s`", rootfs); } else { - dirfd = safe_openat (rootfsfd, rootfs, dirname, O_DIRECTORY | O_PATH | O_CLOEXEC, 0, err); + dirfd = safe_openat (get_private_data (container)->rootfsfd, rootfs, dirname, O_DIRECTORY | O_PATH | O_CLOEXEC, 0, err); if (dirfd < 0 && ensure_parent_dir) { crun_error_release (err); - dirfd = crun_safe_create_and_open_ref_at (true, rootfsfd, rootfs, dirname, 0755, err); + dirfd = crun_safe_create_and_open_ref_at (true, get_private_data (container)->rootfsfd, rootfs, dirname, 0755, err); } if (UNLIKELY (dirfd < 0)) return dirfd; @@ -1751,13 +1749,12 @@ create_missing_devs (libcrun_container_t *container, bool binds, libcrun_error_t cleanup_close int devfd = -1; runtime_spec_schema_config_schema *def = container->container_def; const char *rootfs = get_private_data (container)->rootfs; - int rootfsfd = get_private_data (container)->rootfsfd; cleanup_close_map struct libcrun_fd_map *dev_fds = NULL; dev_fds = get_private_data (container)->dev_fds; get_private_data (container)->dev_fds = NULL; - devfd = openat (rootfsfd, "dev", O_CLOEXEC | O_PATH | O_DIRECTORY); + devfd = openat (get_private_data (container)->rootfsfd, "dev", O_CLOEXEC | O_PATH | O_DIRECTORY); if (UNLIKELY (devfd < 0)) return crun_make_error (err, errno, "open `/dev` directory in `%s`", rootfs); @@ -1912,7 +1909,6 @@ static int append_tmpfs_mode_if_missing (libcrun_container_t *container, runtime_spec_schema_defs_mount *mount, char **data, libcrun_error_t *err) { const char *rootfs = get_private_data (container)->rootfs; - int rootfsfd = get_private_data (container)->rootfsfd; bool empty_data = is_empty_string (*data); cleanup_close int fd = -1; struct stat st; @@ -1921,7 +1917,7 @@ append_tmpfs_mode_if_missing (libcrun_container_t *container, runtime_spec_schem if (*data != NULL && strstr (*data, "mode=")) return 0; - fd = safe_openat (rootfsfd, rootfs, mount->destination, O_CLOEXEC | O_RDONLY, 0, err); + fd = safe_openat (get_private_data (container)->rootfsfd, rootfs, mount->destination, O_CLOEXEC | O_RDONLY, 0, err); if (fd < 0) { if (crun_error_get_errno (err) != ENOENT) @@ -2050,12 +2046,11 @@ get_force_cgroup_v1_annotation (libcrun_container_t *container) static int do_mounts (libcrun_container_t *container, const char *rootfs, libcrun_error_t *err) { - size_t i; - int ret; runtime_spec_schema_config_schema *def = container->container_def; const char *systemd_cgroup_v1 = get_force_cgroup_v1_annotation (container); cleanup_close_map struct libcrun_fd_map *mount_fds = NULL; - int rootfsfd = get_private_data (container)->rootfsfd; + size_t i; + int ret; mount_fds = get_private_data (container)->mount_fds; get_private_data (container)->mount_fds = NULL; @@ -2137,7 +2132,7 @@ do_mounts (libcrun_container_t *container, const char *rootfs, libcrun_error_t * if (UNLIKELY (len < 0)) return len; - ret = safe_create_symlink (rootfsfd, rootfs, target, def->mounts[i]->destination, err); + ret = safe_create_symlink (get_private_data (container)->rootfsfd, rootfs, target, def->mounts[i]->destination, err); if (UNLIKELY (ret < 0)) return ret; @@ -2146,7 +2141,7 @@ do_mounts (libcrun_container_t *container, const char *rootfs, libcrun_error_t * else if (is_sysfs_or_proc) { /* Enforce sysfs and proc to be mounted on a regular directory. */ - ret = openat (rootfsfd, target, O_CLOEXEC | O_NOFOLLOW | O_DIRECTORY); + ret = openat (get_private_data (container)->rootfsfd, target, O_CLOEXEC | O_NOFOLLOW | O_DIRECTORY); if (UNLIKELY (ret < 0)) { if (errno == ENOENT) @@ -2154,12 +2149,12 @@ do_mounts (libcrun_container_t *container, const char *rootfs, libcrun_error_t * if (strchr (target, '/')) return crun_make_error (err, 0, "invalid target `%s`: it must be mounted at the root", target); - ret = mkdirat (rootfsfd, target, 0755); + ret = mkdirat (get_private_data (container)->rootfsfd, target, 0755); if (UNLIKELY (ret < 0)) return crun_make_error (err, errno, "mkdirat `%s`", target); /* Try opening it again. */ - ret = openat (rootfsfd, target, O_CLOEXEC | O_NOFOLLOW | O_DIRECTORY); + ret = openat (get_private_data (container)->rootfsfd, target, O_CLOEXEC | O_NOFOLLOW | O_DIRECTORY); } else if (errno == ENOTDIR) return crun_make_error (err, errno, "the target `/%s` is invalid", target); @@ -2175,7 +2170,7 @@ do_mounts (libcrun_container_t *container, const char *rootfs, libcrun_error_t * bool is_dir = S_ISDIR (src_mode); /* Make sure any other directory/file is created and take a O_PATH reference to it. */ - ret = crun_safe_create_and_open_ref_at (is_dir, rootfsfd, rootfs, target, is_dir ? 01755 : 0755, err); + ret = crun_safe_create_and_open_ref_at (is_dir, get_private_data (container)->rootfsfd, rootfs, target, is_dir ? 01755 : 0755, err); if (UNLIKELY (ret < 0)) return ret; @@ -2248,7 +2243,7 @@ do_mounts (libcrun_container_t *container, const char *rootfs, libcrun_error_t * { int destfd, tmpfd; - destfd = safe_openat (rootfsfd, rootfs, target, O_CLOEXEC | O_DIRECTORY, 0, err); + destfd = safe_openat (get_private_data (container)->rootfsfd, rootfs, target, O_CLOEXEC | O_DIRECTORY, 0, err); if (UNLIKELY (destfd < 0)) return crun_error_wrap (err, "open `%s` to write for tmpcopyup", target); @@ -2265,7 +2260,7 @@ do_mounts (libcrun_container_t *container, const char *rootfs, libcrun_error_t * const bool is_dir = S_ISDIR (src_mode); cleanup_close int dfd = -1; - dfd = safe_openat (rootfsfd, rootfs, target, O_RDONLY | O_PATH | O_CLOEXEC | (is_dir ? O_DIRECTORY : 0), 0, err); + dfd = safe_openat (get_private_data (container)->rootfsfd, rootfs, target, O_RDONLY | O_PATH | O_CLOEXEC | (is_dir ? O_DIRECTORY : 0), 0, err); if (UNLIKELY (dfd < 0)) return crun_make_error (err, errno, "open mount target `/%s`", target); @@ -2286,7 +2281,6 @@ do_mounts (libcrun_container_t *container, const char *rootfs, libcrun_error_t * int libcrun_container_do_bind_mount (libcrun_container_t *container, char *mount_source, char *mount_destination, char **mount_options, size_t mount_options_len, libcrun_error_t *err) { - int ret, rootfsfd; const char *target = consume_slashes (mount_destination); cleanup_free char *data = NULL; unsigned long flags = 0; @@ -2296,9 +2290,9 @@ libcrun_container_do_bind_mount (libcrun_container_t *container, char *mount_sou uint64_t rec_clear = 0; uint64_t rec_set = 0; const char *rootfs = get_private_data (container)->rootfs; - rootfsfd = get_private_data (container)->rootfsfd; + int ret; - if ((rootfsfd < 0) || (rootfs == NULL)) + if ((get_private_data (container)->rootfsfd < 0) || (rootfs == NULL)) return crun_make_error (err, 0, "invalid rootfs state while performing bind mount from external plugin or handler"); if (mount_options == NULL) @@ -2324,7 +2318,7 @@ libcrun_container_do_bind_mount (libcrun_container_t *container, char *mount_sou } /* Make sure any other directory/file is created and take a O_PATH reference to it. */ - ret = crun_safe_create_and_open_ref_at (is_dir, rootfsfd, rootfs, target, is_dir ? 01755 : 0755, err); + ret = crun_safe_create_and_open_ref_at (is_dir, get_private_data (container)->rootfsfd, rootfs, target, is_dir ? 01755 : 0755, err); if (UNLIKELY (ret < 0)) return ret; From 7de03e622f19deac25ba3fe24f3863af6c520ac4 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 20 May 2025 15:36:27 +0200 Subject: [PATCH 7/8] linux: safe_openat reopens root If an empty path is used, reopens directly the rootfs so that it can grab a reference to the topmost mount, not the previously open file descriptor. Signed-off-by: Giuseppe Scrivano --- src/libcrun/utils.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/libcrun/utils.c b/src/libcrun/utils.c index 340d9c7d9f..4f20d7291c 100644 --- a/src/libcrun/utils.c +++ b/src/libcrun/utils.c @@ -298,6 +298,25 @@ crun_ensure_directory_at (int dirfd, const char *path, int mode, bool nofollow, return 0; } +static int +check_fd_is_path (const char *path, int fd, const char *fdname, libcrun_error_t *err) +{ + proc_fd_path_t fdpath; + size_t path_len = strlen (path); + char link[PATH_MAX]; + int ret; + + get_proc_self_fd_path (fdpath, fd); + ret = TEMP_FAILURE_RETRY (readlink (fdpath, link, sizeof (link))); + if (UNLIKELY (ret < 0)) + return crun_make_error (err, errno, "readlink `%s`", fdname); + + if (((size_t) ret) != path_len || memcmp (link, path, path_len)) + return crun_make_error (err, 0, "target `%s` does not point to the directory `%s`", fdname, path); + + return 0; +} + static int check_fd_under_path (const char *rootfs, size_t rootfslen, int fd, const char *fdname, libcrun_error_t *err) { @@ -377,6 +396,23 @@ safe_openat (int dirfd, const char *rootfs, const char *path, int flags, int mod static bool openat2_supported = true; int ret; + if (is_empty_string (path)) + { + cleanup_close int fd = -1; + + fd = open (rootfs, flags, mode); + if (UNLIKELY (fd < 0)) + return crun_make_error (err, errno, "open `%s`", rootfs); + + ret = check_fd_is_path (rootfs, fd, path, err); + if (UNLIKELY (ret < 0)) + return ret; + + ret = fd; + fd = -1; + return ret; + } + if (openat2_supported) { repeat: From 64a2e0e1c6439b298e48b75d50dc8e179e1b190a Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Tue, 20 May 2025 18:49:39 +0200 Subject: [PATCH 8/8] linux: Update rootfsfd when rootfs is replaced When a mount operation replaces the container's root filesystem ("/"), the existing `rootfsfd` becomes stale. This file descriptor would still point to the old, now overmounted root, potentially causing subsequent filesystem operations within the container setup to fail or target the incorrect filesystem. Closes: https://github.com/containers/crun/issues/1752 Signed-off-by: Giuseppe Scrivano --- src/libcrun/linux.c | 11 +++++++++++ tests/test_mounts.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/libcrun/linux.c b/src/libcrun/linux.c index 2c550f9627..118e0bc5a4 100644 --- a/src/libcrun/linux.c +++ b/src/libcrun/linux.c @@ -1227,6 +1227,17 @@ do_mount (libcrun_container_t *container, const char *source, int targetfd, if (UNLIKELY (fd < 0)) return fd; + /* We are replacing the rootfs, reopen it. */ + if (is_empty_string (target)) + { + int tmp = dup (fd); + if (UNLIKELY (tmp < 0)) + return crun_make_error (err, errno, "dup"); + + TEMP_FAILURE_RETRY (close (get_private_data (container)->rootfsfd)); + get_private_data (container)->rootfsfd = tmp; + } + #ifdef HAVE_FGETXATTR if (label_how == LABEL_XATTR) { diff --git a/tests/test_mounts.py b/tests/test_mounts.py index 0232e04963..20808b8ffc 100755 --- a/tests/test_mounts.py +++ b/tests/test_mounts.py @@ -115,6 +115,33 @@ def prepare_rootfs(rootfs): return 0 return -1 +def test_mount_bind_to_rootfs(): + conf = base_config() + conf['process']['args'] = ['/init', 'true'] + add_all_namespaces(conf) + tmpdir = tempfile.mkdtemp() + shutil.copy(get_init_path(), tmpdir) + + mounts = [ + {"destination": "/", "type": "bind", "source": tmpdir, "options": ["bind"]}, + ] + conf['mounts'] = mounts + conf['mounts'] + _, _ = run_and_get_output(conf, hide_stderr=True) + return 0 + +def test_mount_tmpfs_to_rootfs(): + conf = base_config() + conf['process']['args'] = ['/init', 'true'] + add_all_namespaces(conf) + tmpdir = tempfile.mkdtemp() + + mounts = [ + {"destination": "/", "type": "tmpfs", "source": "tmpfs", "options": ["tmpcopyup"]}, + ] + conf['mounts'] = mounts + conf['mounts'] + _, _ = run_and_get_output(conf, hide_stderr=True) + return 0 + def test_ro_cgroup(): for cgroupns in [True, False]: for netns in [True, False]: @@ -693,6 +720,8 @@ def test_mount_help(): "mount-unix-socket" : test_mount_unix_socket, "mount-symlink-not-existing" : test_mount_symlink_not_existing, "mount-dev" : test_mount_dev, + "mount-bind-to-rootfs": test_mount_bind_to_rootfs, + "mount-tmpfs-to-rootfs": test_mount_tmpfs_to_rootfs, "mount-nodev" : test_mount_nodev, "mount-path-with-multiple-slashes" : test_mount_path_with_multiple_slashes, "mount-userns-bind-mount" : test_userns_bind_mount,