From: Lennart Poettering Date: Thu, 6 Nov 2025 09:47:26 +0000 (+0100) Subject: tar-util: make sure we can unpack hardlinked symlinks X-Git-Tag: v259-rc1~137^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F39619%2Fhead;p=thirdparty%2Fsystemd.git tar-util: make sure we can unpack hardlinked symlinks This is something ostree does. Yuck. But let's make t work. --- diff --git a/src/shared/tar-util.c b/src/shared/tar-util.c index 05dd4cd9fc9..d66bba1d60d 100644 --- a/src/shared/tar-util.c +++ b/src/shared/tar-util.c @@ -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, diff --git a/test/units/TEST-13-NSPAWN.unpriv.sh b/test/units/TEST-13-NSPAWN.unpriv.sh index 02faeb1796a..7ae2c74efa3 100755 --- a/test/units/TEST-13-NSPAWN.unpriv.sh +++ b/test/units/TEST-13-NSPAWN.unpriv.sh @@ -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