]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
dissect: do not follow copy-to directory symlinks
authordongshengyuan <545258830@qq.com>
Tue, 7 Jul 2026 11:11:06 +0000 (19:11 +0800)
committerLennart Poettering <lennart@poettering.net>
Thu, 9 Jul 2026 09:01:29 +0000 (11:01 +0200)
When copying a directory into an image, open an existing destination
with O_NOFOLLOW before passing it to copy_tree_at(). This rejects a
symlink used as the final destination component without a separate
stat-before-use check.

Previously the pre-opened destination followed that symlink. That
allowed --copy-to to be redirected outside the image root when the
image was a directory tree.

If the destination does not exist yet, keep delegating creation to
copy_tree_at(). Real existing directories still use COPY_MERGE through
the opened directory fd.

Signed-off-by: dongshengyuan <dongshengyuan@uniontech.com>
src/dissect/dissect.c

index e70263a9fd4f5a6959e8d6f40f3d8cd0a80c3f3b..7a82d905da2d75200e48f66cf4b896b1e81d3089 100644 (file)
@@ -1490,8 +1490,12 @@ static int action_list_or_mtree_or_copy_or_make_archive(DissectedImage *m, LoopD
 
                         /* We are looking at a directory. */
 
-                        target_fd = openat(dfd, bn, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
+                        target_fd = openat(dfd, bn, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
                         if (target_fd < 0) {
+                                if (errno == ELOOP)
+                                        return log_error_errno(SYNTHETIC_ERRNO(ELOOP),
+                                                        "Refusing to copy directory to symlink destination '%s'.", arg_target);
+
                                 if (errno != ENOENT)
                                         return log_error_errno(errno, "Failed to open destination '%s': %m", arg_target);