From: dongshengyuan <545258830@qq.com> Date: Wed, 15 Jul 2026 05:23:23 +0000 (+0800) Subject: tmpfiles: check relative L? targets beside the link X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=35e9ca257d2fbb545b17fd3dcd89800ba03a0e7d;p=thirdparty%2Fsystemd.git tmpfiles: check relative L? targets beside the link Relative symlink targets are resolved from the directory containing the link. Make the L? existence check use the same rule. Reproducer: tmp=$(mktemp -d /tmp/tmpfiles-link.XXXXXX) conf=$(mktemp /tmp/tmpfiles-conf.XXXXXX) printf data >"$tmp/target" printf 'L? %s/link - - - - target\n' "$tmp" >"$conf" systemd-tmpfiles --create --dry-run "$conf" Before: The target was checked root-relative, not beside the link. Follow-up for b5dc805583bbb019c6bf4c73bf0814a396dc0f12. --- diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 0e3244fcebe..42512da6041 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -2680,16 +2680,30 @@ static int create_symlink(Context *c, Item *i) { assert(i); if (i->ignore_if_target_missing) { - r = chase(i->argument, arg_root, CHASE_SAFE|CHASE_PREFIX_ROOT|CHASE_NOFOLLOW, /* ret_path= */ NULL, /* ret_fd= */ NULL); + _cleanup_free_ char *target = NULL; + ChaseFlags chase_flags = CHASE_SAFE|CHASE_NOFOLLOW; + + if (!path_is_absolute(i->argument)) { + _cleanup_free_ char *dn = NULL; + + r = path_extract_directory(i->path, &dn); + if (r < 0) + return log_error_errno(r, "Failed to extract directory from path '%s': %m", i->path); + + target = path_join(dn, i->argument); + if (!target) + return log_oom(); + } else + chase_flags |= CHASE_PREFIX_ROOT; + + r = chase(target ?: i->argument, arg_root, chase_flags, /* ret_path= */ NULL, /* ret_fd= */ NULL); if (r == -ENOENT) { /* Silently skip over lines where the source file is missing. */ - log_debug_errno(r, "Symlink source path '%s/%s' does not exist, skipping line.", - strempty(arg_root), skip_leading_slash(i->argument)); + log_debug_errno(r, "Symlink source path '%s' does not exist, skipping line.", i->argument); return 0; } if (r < 0) - return log_error_errno(r, "Failed to check if symlink source path '%s/%s' exists: %m", - strempty(arg_root), skip_leading_slash(i->argument)); + return log_error_errno(r, "Failed to check if symlink source path '%s' exists: %m", i->argument); } r = path_extract_filename(i->path, &bn); diff --git a/test/units/TEST-22-TMPFILES.15.sh b/test/units/TEST-22-TMPFILES.15.sh index 68c6c301bd6..78be11357df 100755 --- a/test/units/TEST-22-TMPFILES.15.sh +++ b/test/units/TEST-22-TMPFILES.15.sh @@ -54,3 +54,36 @@ EOF )" [[ "$output" == *"Would create directory $root/run/test"* ]] [[ "$output" != *"$root$root"* ]] + +# Check that L? resolves relative targets from the symlink's parent directory. +root='/tmp/L/4' +rm -rf "$root" +mkdir -p "$root" +touch "$root/target" + +systemd-tmpfiles --create - <