]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
tar-util: make sure we can unpack hardlinked symlinks 39619/head
authorLennart Poettering <lennart@poettering.net>
Thu, 6 Nov 2025 09:47:26 +0000 (10:47 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 7 Nov 2025 13:04:36 +0000 (14:04 +0100)
This is something ostree does. Yuck. But let's make t work.

src/shared/tar-util.c
test/units/TEST-13-NSPAWN.unpriv.sh

index 05dd4cd9fc9de873962d3f0e6273d222563fedec..d66bba1d60d638dba926586479673f56dcdecbc6 100644 (file)
@@ -827,7 +827,7 @@ int tar_x(int input_fd, int tree_fd, TarFlags flags) {
                                                                 "Invalid hardlink path name '%s' in entry, refusing.", target);
 
                                         _cleanup_close_ int target_fd = -EBADF;
-                                        r = chaseat(tree_fd, target, CHASE_PROHIBIT_SYMLINKS|CHASE_AT_RESOLVE_IN_ROOT, /* ret_path= */ NULL, &target_fd);
+                                        r = chaseat(tree_fd, target, CHASE_PROHIBIT_SYMLINKS|CHASE_AT_RESOLVE_IN_ROOT|CHASE_NOFOLLOW, /* ret_path= */ NULL, &target_fd);
                                         if (r < 0)
                                                 return log_error_errno(
                                                                 r,
@@ -856,7 +856,7 @@ int tar_x(int input_fd, int tree_fd, TarFlags flags) {
 
                                                 _cleanup_close_ int target_parent_fd = -EBADF;
                                                 _cleanup_free_ char *target_filename = NULL;
-                                                r = chaseat(tree_fd, target, CHASE_PROHIBIT_SYMLINKS|CHASE_AT_RESOLVE_IN_ROOT|CHASE_PARENT|CHASE_EXTRACT_FILENAME, &target_filename, &target_parent_fd);
+                                                r = chaseat(tree_fd, target, CHASE_PROHIBIT_SYMLINKS|CHASE_AT_RESOLVE_IN_ROOT|CHASE_PARENT|CHASE_EXTRACT_FILENAME|CHASE_NOFOLLOW, &target_filename, &target_parent_fd);
                                                 if (r < 0)
                                                         return log_error_errno(
                                                                         r,
index 02faeb1796a20987fe6de389550e2e5938202aa8..7ae2c74efa31c7a23013785e334a3d4df2564603 100755 (executable)
@@ -175,9 +175,15 @@ chattr +A /home/testuser/.local/state/machines/inodetest/testfile
 chown foreign-0:foreign-0 /home/testuser/.local/state/machines/inodetest/testfile.hard /home/testuser/.local/state/machines/inodetest
 ls -al /home/testuser/.local/state/machines/inodetest
 
+# Verify UID squashing
 echo gaga > /home/testuser/.local/state/machines/inodetest/squashtest
 chown 1000:1000 /home/testuser/.local/state/machines/inodetest/squashtest
 
+# Ensure hardlinked symlinks work
+ln -s sometarget /home/testuser/.local/state/machines/inodetest/testfile.sym
+ln /home/testuser/.local/state/machines/inodetest/testfile.sym /home/testuser/.local/state/machines/inodetest/testfile.symhard
+chown -h foreign-0:foreign-0 /home/testuser/.local/state/machines/inodetest/testfile.symhard
+
 run0 --pipe -u testuser importctl -m --user export-tar inodetest |
     run0 --pipe -u testuser importctl -m --user import-tar - inodetest2
 
@@ -199,7 +205,11 @@ cmp <(lsattr /home/testuser/.local/state/machines/inodetest/testfile | cut -d "
 # verify that squashing outside of 64K works
 test "$(stat -c'%U:%G' /home/testuser/.local/state/machines/inodetest2/squashtest)" = "foreign-65534:foreign-65534"
 
-# chown to foreing UID range, so that removal works
+# Verify that the hardlinked symlink is restored as such
+cmp <(stat -c"%i" /home/testuser/.local/state/machines/inodetest2/testfile.sym) <(stat -c"%i" /home/testuser/.local/state/machines/inodetest2/testfile.symhard)
+test "$(readlink /home/testuser/.local/state/machines/inodetest2/testfile.symhard)" = "sometarget"
+
+# chown to foreign UID range, so that removal works
 chown foreign-4711:foreign-4711 /home/testuser/.local/state/machines/inodetest/squashtest
 
 run0 -u testuser machinectl --user remove inodetest