diff options
author | Lennart Poettering <lennart@poettering.net> | 2025-01-06 22:47:34 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2025-01-06 23:37:45 +0100 |
commit | c0381ba6e84a12d400d218c0979e7a348518743b (patch) | |
tree | 18b69930e8e177d39a16151b9e85d347813cebe9 /src/machine | |
parent | fs-util: add XO_REGULAR flag for xopenat() (diff) | |
download | systemd-c0381ba6e84a12d400d218c0979e7a348518743b.tar.xz systemd-c0381ba6e84a12d400d218c0979e7a348518743b.zip |
machine: transition back to host mount ns before copying files from/to container
When copying files from or to a container we so far opened the host side
fd first, then entered the container (specifically, joined it's mount
namespace) in a forked off child process, and opened the other side
there, followed by the (potentially slow) copying from inside the
container mount namespace.
This commit changes this so that we rejoin the host mount namespace
before doing the copying routine. This is relevant, so that we can rely
on /proc/self/fd/… to work, which is not the case otherwise, as we'll
see /proc/ from a pidns that is not our own, in wich case
/proc/self/fd/… is refused. By moving back to the host mount namespace
our own pidns and the pidns the /proc/ mount belongs to will be in sync
again, and all is good.
This is in particular preparation for the next commit, that makes the
copy routine strictly depending on /proc/ being accessible and working.
Diffstat (limited to 'src/machine')
-rw-r--r-- | src/machine/machine.c | 26 |
1 files changed, 16 insertions, 10 deletions
diff --git a/src/machine/machine.c b/src/machine/machine.c index 1e6a5e0606..7abf5437c4 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -988,7 +988,7 @@ int machine_copy_from_to( CopyFlags copy_flags, Operation **ret) { - _cleanup_close_ int host_fd = -EBADF, mntns_fd = -EBADF; + _cleanup_close_ int host_fd = -EBADF, target_mntns_fd = -EBADF, source_mntns_fd = -EBADF; _cleanup_close_pair_ int errno_pipe_fd[2] = EBADF_PAIR; _cleanup_free_ char *host_basename = NULL, *container_basename = NULL; uid_t uid_shift; @@ -1018,14 +1018,13 @@ int machine_copy_from_to( if (r < 0) return log_debug_errno(r, "Failed to get UID shift of machine '%s': %m", machine->name); - r = pidref_namespace_open(&machine->leader, - /* ret_pidns_fd = */ NULL, - &mntns_fd, - /* ret_netns_fd = */ NULL, - /* ret_userns_fd = */ NULL, - /* ret_root_fd = */ NULL); - if (r < 0) - return log_debug_errno(r, "Failed to open mount namespace of machine '%s': %m", machine->name); + target_mntns_fd = pidref_namespace_open_by_type(&machine->leader, NAMESPACE_MOUNT); + if (target_mntns_fd < 0) + return log_debug_errno(target_mntns_fd, "Failed to open mount namespace of machine '%s': %m", machine->name); + + source_mntns_fd = namespace_open_by_type(NAMESPACE_MOUNT); + if (source_mntns_fd < 0) + return log_debug_errno(source_mntns_fd, "Failed to open our own mount namespace: %m"); if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0) return log_debug_errno(errno, "Failed to create pipe: %m"); @@ -1036,7 +1035,7 @@ int machine_copy_from_to( /* n_except_fds = */ 0, FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL, /* pidns_fd = */ -EBADF, - mntns_fd, + target_mntns_fd, /* netns_fd = */ -EBADF, /* userns_fd = */ -EBADF, /* root_fd = */ -EBADF, @@ -1053,6 +1052,13 @@ int machine_copy_from_to( report_errno_and_exit(errno_pipe_fd[1], container_fd); } + /* Rejoin the host namespace, so that /proc/self/fd/… works, which copy_tree_at() relies on + * in some cases (by means of fd_reopen()) */ + if (setns(source_mntns_fd, CLONE_NEWNS) < 0) { + r = log_debug_errno(errno, "Failed to rejoin namespace of host: %m"); + report_errno_and_exit(errno_pipe_fd[1], r); + } + /* Run the actual copy operation. Note that when a UID shift is set we'll either clamp the UID/GID to * 0 or to the actual UID shift depending on the direction we copy. If no UID shift is set we'll copy * the UID/GIDs as they are. */ |