tmpfiles: fix root handling and target resolution (#43031)
This commit is contained in:
+35
-20
@@ -322,16 +322,7 @@ static int specifier_directory(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (arg_root) {
|
||||
_cleanup_free_ char *j = NULL;
|
||||
|
||||
j = path_join(arg_root, p);
|
||||
if (!j)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = TAKE_PTR(j);
|
||||
} else
|
||||
*ret = TAKE_PTR(p);
|
||||
*ret = TAKE_PTR(p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -817,9 +808,14 @@ static int dir_cleanup(
|
||||
|
||||
log_action("Would remove", "Removing", "%s directory \"%s\"", sub_path);
|
||||
if (!arg_dry_run &&
|
||||
unlinkat(dirfd(d), de->d_name, AT_REMOVEDIR) < 0 &&
|
||||
!IN_SET(errno, ENOENT, ENOTEMPTY))
|
||||
r = log_warning_errno(errno, "Failed to remove directory \"%s\", ignoring: %m", sub_path);
|
||||
unlinkat(dirfd(d), de->d_name, AT_REMOVEDIR) < 0) {
|
||||
if (errno == ENOTEMPTY)
|
||||
continue;
|
||||
if (errno != ENOENT)
|
||||
r = log_warning_errno(errno, "Failed to remove directory \"%s\", ignoring: %m", sub_path);
|
||||
}
|
||||
|
||||
deleted = true;
|
||||
|
||||
} else {
|
||||
_cleanup_close_ int fd = -EBADF; /* This file descriptor is defined here so that the
|
||||
@@ -2247,11 +2243,14 @@ static int copy_files(Context *c, Item *i) {
|
||||
return log_error_errno(errno, "Failed to openat(%s): %m", i->path);
|
||||
}
|
||||
|
||||
if (r < 0 && !IN_SET(r, -EEXIST, -EROFS))
|
||||
return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
|
||||
|
||||
if (fstat(fd, &st) < 0)
|
||||
return log_error_errno(errno, "Failed to fstat(%s): %m", i->path);
|
||||
|
||||
if (stat(i->argument, &a) < 0)
|
||||
return log_error_errno(errno, "Failed to stat(%s): %m", i->argument);
|
||||
if (lstat(i->argument, &a) < 0)
|
||||
return log_error_errno(errno, "Failed to lstat(%s): %m", i->argument);
|
||||
|
||||
if (((st.st_mode ^ a.st_mode) & S_IFMT) != 0) {
|
||||
log_debug("Can't copy to %s, file exists already and is of different type", i->path);
|
||||
@@ -2689,16 +2688,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);
|
||||
@@ -4707,6 +4720,8 @@ static int read_config_file(
|
||||
if (candidate_item && candidate_item->age_set) {
|
||||
i->age = candidate_item->age;
|
||||
i->age_set = true;
|
||||
i->age_by_file = candidate_item->age_by_file;
|
||||
i->age_by_dir = candidate_item->age_by_dir;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
set -eux
|
||||
set -o pipefail
|
||||
|
||||
# shellcheck source=test/units/util.sh
|
||||
. "$(dirname "$0")"/util.sh
|
||||
|
||||
rm -fr /tmp/{f,F,w}
|
||||
mkdir /tmp/{f,F,w}
|
||||
touch /tmp/file-owned-by-root
|
||||
@@ -190,6 +193,31 @@ F /tmp/F/daemon/unsafe-symlink/exploit 0644 daemon daemon - -
|
||||
EOF
|
||||
test ! -e /tmp/F/daemon/unsafe-symlink/exploit
|
||||
|
||||
#
|
||||
# 'C'
|
||||
#
|
||||
rm -rf /tmp/C-copy-failure-src /tmp/C-copy-failure-dst
|
||||
mkdir /tmp/C-copy-failure-src /tmp/C-copy-failure-dst
|
||||
printf payload >/tmp/C-copy-failure-src/file
|
||||
chmod 555 /tmp/C-copy-failure-dst
|
||||
|
||||
(! runas nobody systemd-tmpfiles --create - <<EOF
|
||||
C /tmp/C-copy-failure-dst - - - - /tmp/C-copy-failure-src
|
||||
EOF
|
||||
)
|
||||
test ! -e /tmp/C-copy-failure-dst/file
|
||||
chmod 755 /tmp/C-copy-failure-dst
|
||||
rm -rf /tmp/C-copy-failure-src /tmp/C-copy-failure-dst
|
||||
|
||||
rm -f /tmp/C-copy-link-src /tmp/C-copy-link-dst
|
||||
ln -s missing-target /tmp/C-copy-link-src
|
||||
systemd-tmpfiles --create - <<EOF
|
||||
C /tmp/C-copy-link-dst - - - - /tmp/C-copy-link-src
|
||||
EOF
|
||||
test -L /tmp/C-copy-link-dst
|
||||
test "$(readlink /tmp/C-copy-link-dst)" = "missing-target"
|
||||
rm -f /tmp/C-copy-link-src /tmp/C-copy-link-dst
|
||||
|
||||
#
|
||||
# 'w'
|
||||
#
|
||||
|
||||
@@ -204,3 +204,34 @@ test ! -d /tmp/ageby/d3
|
||||
|
||||
# Cleanup the test directory (fail if not empty).
|
||||
rmdir /tmp/ageby
|
||||
|
||||
# Removing an old child directory should restore the parent directory mtime.
|
||||
rm -rf /tmp/ageby-mtime
|
||||
mkdir -p /tmp/ageby-mtime/old-child
|
||||
touch --date "2020-01-01 00:00:00" /tmp/ageby-mtime/old-child /tmp/ageby-mtime
|
||||
before="$(stat -c %Y /tmp/ageby-mtime)"
|
||||
|
||||
systemd-tmpfiles --clean - <<-EOF
|
||||
d /tmp/ageby-mtime - - - M:1s
|
||||
EOF
|
||||
|
||||
after="$(stat -c %Y /tmp/ageby-mtime)"
|
||||
test "$before" = "$after"
|
||||
test ! -e /tmp/ageby-mtime/old-child
|
||||
rmdir /tmp/ageby-mtime
|
||||
|
||||
# X entries inherit the parent cleanup age and its age-by fields.
|
||||
rm -rf /tmp/ageby-x-inherit
|
||||
mkdir -p /tmp/ageby-x-inherit/parent/child /tmp/ageby-x-inherit/parent/other
|
||||
printf old >/tmp/ageby-x-inherit/parent/child/file
|
||||
printf old >/tmp/ageby-x-inherit/parent/other/file
|
||||
touch --date "3 days ago" /tmp/ageby-x-inherit/parent/child/file /tmp/ageby-x-inherit/parent/other/file
|
||||
|
||||
systemd-tmpfiles --clean - <<-EOF
|
||||
d /tmp/ageby-x-inherit/parent - - - m:1d
|
||||
X /tmp/ageby-x-inherit/parent/child - - - -
|
||||
EOF
|
||||
|
||||
test ! -e /tmp/ageby-x-inherit/parent/child/file
|
||||
test ! -e /tmp/ageby-x-inherit/parent/other/file
|
||||
rm -rf /tmp/ageby-x-inherit
|
||||
|
||||
@@ -42,3 +42,48 @@ systemd-tmpfiles --create --root="$root" - <<EOF
|
||||
L %h - - - -
|
||||
EOF
|
||||
test "$(readlink "$dst")" = "$src"
|
||||
|
||||
# Check that directory specifiers are not prefixed with --root twice.
|
||||
root='/tmp/L/3'
|
||||
rm -rf "$root"
|
||||
mkdir -p "$root"
|
||||
|
||||
output="$(systemd-tmpfiles --create --dry-run --root="$root" - 2>&1 <<EOF
|
||||
d %t/test - - - -
|
||||
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 - <<EOF
|
||||
L? $root/link - - - - target
|
||||
EOF
|
||||
test "$(readlink "$root/link")" = "target"
|
||||
|
||||
rm -f "$root/link" "$root/target"
|
||||
systemd-tmpfiles --create - <<EOF
|
||||
L? $root/link - - - - target
|
||||
EOF
|
||||
test ! -e "$root/link"
|
||||
|
||||
# Check the same relative target lookup with --root=.
|
||||
rm -rf "$root"
|
||||
mkdir -p "$root/dir"
|
||||
touch "$root/dir/target"
|
||||
|
||||
systemd-tmpfiles --create --root="$root" - <<EOF
|
||||
L? /dir/link - - - - target
|
||||
EOF
|
||||
test "$(readlink "$root/dir/link")" = "target"
|
||||
|
||||
rm -f "$root/dir/link" "$root/dir/target"
|
||||
systemd-tmpfiles --create --root="$root" - <<EOF
|
||||
L? /dir/link - - - - target
|
||||
EOF
|
||||
test ! -e "$root/dir/link"
|
||||
|
||||
Reference in New Issue
Block a user