1
0
mirror of https://github.com/systemd/systemd synced 2025-10-06 00:13:24 +02:00

chase: invert CHASE_NO_AUTOFS and only set it where needed

Since c5de7b14ae
file searching implies a new mount api syscall by default,
to trigger automounts.

This is problematic in NSS plugins, as they are dlopen'ed inside
processes by glibc, for two reasons.

First of all, potentially searching on a networked filesystem
automount could lead to nasty surprises, such as the process
responsible for setting up the network filesystem trying to
search on that same filesystem.

More importantly, the new mount api syscall was never part of
the filesystem seccomp filter that we provide by default, and
given mounting/remounting/bind mounting is one of the possible
ways to bypass sandboxing it is very likely not allowed when
custom filters are used in sandboxed processes, if they don't
need to do these operations otherwise.
The filesystem seccomp mask we provide has been updated, however
this only takes effect on the next restart of a service. When
systemd is upgraded via a package upgrade, the new nss plugin is
installed and will be immediately dlopen'ed by glibc when needed,
without waiting for the process to restart, which means the existing
seccomp filter applies, causing the filter to trigger.
Given it's not really possible for any arbitrary program to
predict which NSS modules glibc will load, given programs do not
configure that and instead nsswitch is set up by the sysadmin,
it's impossible to handle at each process level. It's also not
possible to know when it will be triggered, given the plugin
is not linked in each binary tools like need-restart cannot
even pre-emptively restart services that may be affected.

This means in practice, upgrading from systemd << v258 to >= v258
requires a reboot to avoid either subtle or catastrophic system
failures.

By avoiding to trigger automounts in nss-systemd we can avoid
both issues.

userdb drop-ins are searched for in:

/etc/userdb/
/run/userdb/
/run/host/userdb/
/usr/local/lib/userdb/
/usr/lib/userdb/

none of which are supported as automounts anyway.

Note that this happens only when the userdbd service is not running,
as otherwise nss-systemd will go through the varlink IPC, rather than
doing the searches in-process.

So invert CHASE_NO_AUTOFS to CHASE_AUTOFS and set it in the places where
we do want to trigger automounts, like looking for the ESP.

Follow-up for c5de7b14ae
Fixes https://github.com/systemd/systemd/issues/38565
This commit is contained in:
Luca Boccassi
2025-08-14 17:22:30 +01:00
committed by Zbigniew Jędrzejewski-Szmek
parent b15ff659b4
commit 490aa05ca1
19 changed files with 75 additions and 59 deletions

View File

@@ -62,6 +62,7 @@ wrap=(
findmnt
getent
getfacl
groups
id
integritysetup
iscsid

View File

@@ -83,7 +83,7 @@ static int openat_opath_with_automount(int dir_fd, const char *path, bool automo
/* Pin an inode via O_PATH semantics. Sounds pretty obvious to do this, right? You just do open()
* with O_PATH, and there you go. But uh, it's not that easy. open() via O_PATH does not trigger
* automounts, but we usually want that (except if CHASE_NO_AUTOFS is used). But thankfully there's
* automounts, but we usually want that (when CHASE_AUTOFS is used). But thankfully there's
* a way out: the newer open_tree() call, when specified without OPEN_TREE_CLONE actually is fully
* equivalent to open() with O_PATH except for one thing: it triggers automounts.
*
@@ -202,7 +202,7 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
* -ENOLINK. If CHASE_WARN is also set, a warning describing the unsafe transition is emitted.
* CHASE_WARN cannot be used in PID 1.
*
* 5. With CHASE_NO_AUTOFS: in this case if an autofs mount point is encountered, path normalization
* 5. Without CHASE_AUTOFS: in this case if an autofs mount point is encountered, path normalization
* is aborted and -EREMOTE is returned. If CHASE_WARN is also set, a warning showing the path of
* the mount point is emitted. CHASE_WARN cannot be used in PID 1.
*/
@@ -219,7 +219,7 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
}
if (!(flags &
(CHASE_AT_RESOLVE_IN_ROOT|CHASE_NONEXISTENT|CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_STEP|
(CHASE_AT_RESOLVE_IN_ROOT|CHASE_NONEXISTENT|CHASE_AUTOFS|CHASE_SAFE|CHASE_STEP|
CHASE_PROHIBIT_SYMLINKS|CHASE_MKDIR_0755|CHASE_PARENT)) &&
!ret_path && ret_fd) {
@@ -396,7 +396,7 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
}
/* Otherwise let's pin it by file descriptor, via O_PATH. */
child = r = openat_opath_with_automount(fd, first, /* automount = */ !FLAGS_SET(flags, CHASE_NO_AUTOFS));
child = r = openat_opath_with_automount(fd, first, /* automount = */ FLAGS_SET(flags, CHASE_AUTOFS));
if (r < 0) {
if (r != -ENOENT)
return r;
@@ -435,7 +435,7 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
unsafe_transition(&st, &st_child))
return log_unsafe_transition(fd, child, path, flags);
if (FLAGS_SET(flags, CHASE_NO_AUTOFS) &&
if (!FLAGS_SET(flags, CHASE_AUTOFS) &&
fd_is_fs_type(child, AUTOFS_SUPER_MAGIC) > 0)
return log_autofs_mount_point(child, path, flags);
@@ -783,7 +783,7 @@ int chase_and_open(
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
if (empty_or_root(root) && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
(chase_flags & (CHASE_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
/* Shortcut this call if none of the special features of this call are requested */
return xopenat_full(AT_FDCWD, path,
open_flags | (FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? O_NOFOLLOW : 0),
@@ -822,7 +822,7 @@ int chase_and_opendir(const char *path, const char *root, ChaseFlags chase_flags
assert(ret_dir);
if (empty_or_root(root) && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0) {
(chase_flags & (CHASE_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0) {
/* Shortcut this call if none of the special features of this call are requested */
d = opendir(path);
if (!d)
@@ -858,7 +858,7 @@ int chase_and_stat(const char *path, const char *root, ChaseFlags chase_flags, c
assert(ret_stat);
if (empty_or_root(root) && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
(chase_flags & (CHASE_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
/* Shortcut this call if none of the special features of this call are requested */
return RET_NERRNO(fstatat(AT_FDCWD, path, ret_stat,
FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0));
@@ -886,7 +886,7 @@ int chase_and_access(const char *path, const char *root, ChaseFlags chase_flags,
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
if (empty_or_root(root) && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
(chase_flags & (CHASE_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
/* Shortcut this call if none of the special features of this call are requested */
return RET_NERRNO(faccessat(AT_FDCWD, path, access_mode,
FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0));
@@ -992,7 +992,7 @@ int chase_and_openat(
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
if (dir_fd == AT_FDCWD && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
(chase_flags & (CHASE_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
/* Shortcut this call if none of the special features of this call are requested */
return xopenat_full(dir_fd, path,
open_flags | (FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? O_NOFOLLOW : 0),
@@ -1029,7 +1029,7 @@ int chase_and_opendirat(int dir_fd, const char *path, ChaseFlags chase_flags, ch
assert(ret_dir);
if (dir_fd == AT_FDCWD && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0) {
(chase_flags & (CHASE_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0) {
/* Shortcut this call if none of the special features of this call are requested */
d = opendir(path);
if (!d)
@@ -1065,7 +1065,7 @@ int chase_and_statat(int dir_fd, const char *path, ChaseFlags chase_flags, char
assert(ret_stat);
if (dir_fd == AT_FDCWD && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
(chase_flags & (CHASE_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
/* Shortcut this call if none of the special features of this call are requested */
return RET_NERRNO(fstatat(AT_FDCWD, path, ret_stat,
FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0));
@@ -1093,7 +1093,7 @@ int chase_and_accessat(int dir_fd, const char *path, ChaseFlags chase_flags, int
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
if (dir_fd == AT_FDCWD && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
(chase_flags & (CHASE_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
/* Shortcut this call if none of the special features of this call are requested */
return RET_NERRNO(faccessat(AT_FDCWD, path, access_mode,
FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0));

View File

@@ -6,7 +6,7 @@
typedef enum ChaseFlags {
CHASE_PREFIX_ROOT = 1 << 0, /* The specified path will be prefixed by the specified root before beginning the iteration */
CHASE_NONEXISTENT = 1 << 1, /* It's OK if the path doesn't actually exist. */
CHASE_NO_AUTOFS = 1 << 2, /* Return -EREMOTE if autofs mount point found */
CHASE_AUTOFS = 1 << 2, /* Trigger automount if autofs mount point found instead of returning -EREMOTE */
CHASE_SAFE = 1 << 3, /* Return -EPERM if we ever traverse from unprivileged to privileged files or directories */
CHASE_TRAIL_SLASH = 1 << 4, /* Any trailing slash will be preserved */
CHASE_STEP = 1 << 5, /* Just execute a single step of the normalization */

View File

@@ -343,7 +343,7 @@ static int update_efi_boot_binaries(const char *esp_path, const char *source_pat
assert(esp_path);
assert(source_path);
r = chase_and_opendir("/EFI/BOOT", esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &p, &d);
r = chase_and_opendir("/EFI/BOOT", esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, &p, &d);
if (r == -ENOENT)
return 0;
if (r < 0)
@@ -396,10 +396,10 @@ static int copy_one_file(const char *esp_path, const char *name, bool force) {
if (!p)
return log_oom();
r = chase(p, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &source_path, NULL);
r = chase(p, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, &source_path, NULL);
/* If we had a root directory to try, we didn't find it and we are in auto mode, retry on the host */
if (r == -ENOENT && root && arg_install_source == ARG_INSTALL_SOURCE_AUTO)
r = chase(p, NULL, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &source_path, NULL);
r = chase(p, NULL, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, &source_path, NULL);
if (r < 0)
return log_error_errno(r,
"Failed to resolve path %s%s%s: %m",
@@ -411,7 +411,7 @@ static int copy_one_file(const char *esp_path, const char *name, bool force) {
if (!q)
return log_oom();
r = chase(q, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_NONEXISTENT, &dest_path, NULL);
r = chase(q, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_NONEXISTENT|CHASE_AUTOFS, &dest_path, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve path %s under directory %s: %m", q, esp_path);
@@ -428,7 +428,7 @@ static int copy_one_file(const char *esp_path, const char *name, bool force) {
v = strjoina("/EFI/BOOT/BOOT", e);
ascii_strupper(strrchr(v, '/') + 1);
r = chase(v, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_NONEXISTENT, &default_dest_path, NULL);
r = chase(v, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_NONEXISTENT|CHASE_AUTOFS, &default_dest_path, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve path %s under directory %s: %m", v, esp_path);
@@ -449,10 +449,10 @@ static int install_binaries(const char *esp_path, const char *arch, bool force)
_cleanup_free_ char *path = NULL;
int r;
r = chase_and_opendir(BOOTLIBDIR, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &path, &d);
r = chase_and_opendir(BOOTLIBDIR, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, &path, &d);
/* If we had a root directory to try, we didn't find it and we are in auto mode, retry on the host */
if (r == -ENOENT && root && arg_install_source == ARG_INSTALL_SOURCE_AUTO)
r = chase_and_opendir(BOOTLIBDIR, NULL, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &path, &d);
r = chase_and_opendir(BOOTLIBDIR, NULL, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, &path, &d);
if (r == -ENOENT && arg_graceful) {
log_debug("Source directory does not exist, ignoring.");
return 0;
@@ -634,7 +634,7 @@ static int install_secure_boot_auto_enroll(const char *esp, X509 *certificate, E
if (r < 0)
return r;
_cleanup_close_ int keys_fd = chase_and_open("loader/keys/auto", esp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, O_DIRECTORY, NULL);
_cleanup_close_ int keys_fd = chase_and_open("loader/keys/auto", esp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, O_DIRECTORY, NULL);
if (keys_fd < 0)
return log_error_errno(keys_fd, "Failed to chase loader/keys/auto in the ESP: %m");
@@ -881,7 +881,7 @@ static int install_variables(
uint16_t slot;
int r;
r = chase_and_access(path, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, F_OK, NULL);
r = chase_and_access(path, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, F_OK, NULL);
if (r == -ENOENT)
return 0;
if (r < 0)
@@ -1097,7 +1097,7 @@ static int remove_boot_efi(const char *esp_path) {
_cleanup_free_ char *p = NULL;
int r, c = 0;
r = chase_and_opendir("/EFI/BOOT", esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &p, &d);
r = chase_and_opendir("/EFI/BOOT", esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, &p, &d);
if (r == -ENOENT)
return 0;
if (r < 0)

View File

@@ -222,7 +222,7 @@ static int enumerate_binaries(
assert(previous);
assert(is_first);
r = chase_and_opendir(path, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &p, &d);
r = chase_and_opendir(path, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, &p, &d);
if (r == -ENOENT)
return 0;
if (r < 0)
@@ -693,7 +693,7 @@ static void deref_unlink_file(Hashmap **known_files, const char *fn, const char
return;
if (arg_dry_run) {
r = chase_and_access(fn, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, F_OK, &path);
r = chase_and_access(fn, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, F_OK, &path);
if (r < 0)
log_info_errno(r, "Unable to determine whether \"%s\" exists, ignoring: %m", fn);
else
@@ -701,7 +701,7 @@ static void deref_unlink_file(Hashmap **known_files, const char *fn, const char
return;
}
r = chase_and_unlink(fn, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, 0, &path);
r = chase_and_unlink(fn, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, 0, &path);
if (r >= 0)
log_info("Removed \"%s\"", path);
else if (r != -ENOENT)
@@ -709,7 +709,7 @@ static void deref_unlink_file(Hashmap **known_files, const char *fn, const char
_cleanup_free_ char *d = NULL;
if (path_extract_directory(fn, &d) >= 0 && !path_equal(d, "/")) {
r = chase_and_unlink(d, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, AT_REMOVEDIR, NULL);
r = chase_and_unlink(d, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, AT_REMOVEDIR, NULL);
if (r < 0 && !IN_SET(r, -ENOTEMPTY, -ENOENT))
log_warning_errno(r, "Failed to remove directory \"%s\", ignoring: %m", d);
}
@@ -801,7 +801,7 @@ static int unlink_entry(const BootConfig *config, const char *root, const char *
if (arg_dry_run)
log_info("Would remove \"%s\"", e->path);
else {
r = chase_and_unlink(e->path, root, CHASE_PROHIBIT_SYMLINKS, 0, NULL);
r = chase_and_unlink(e->path, root, CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, 0, NULL);
if (r < 0)
return log_error_errno(r, "Failed to remove \"%s\": %m", e->path);
@@ -862,7 +862,7 @@ static int cleanup_orphaned_files(
if (r < 0)
return log_error_errno(r, "Failed to count files in %s: %m", root);
dir_fd = chase_and_open(arg_entry_token, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS,
dir_fd = chase_and_open(arg_entry_token, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS,
O_DIRECTORY|O_CLOEXEC, &full);
if (dir_fd == -ENOENT)
return 0;

View File

@@ -3079,7 +3079,7 @@ static int setup_exec_directory(
* since they all support the private/ symlink logic at least in some
* configurations, see above. */
r = chase(target, NULL, 0, &target_resolved, NULL);
r = chase(target, NULL, CHASE_AUTOFS, &target_resolved, NULL);
if (r < 0)
goto fail;
@@ -3090,7 +3090,7 @@ static int setup_exec_directory(
}
/* /var/lib or friends may be symlinks. So, let's chase them also. */
r = chase(q, NULL, CHASE_NONEXISTENT, &q_resolved, NULL);
r = chase(q, NULL, CHASE_NONEXISTENT|CHASE_AUTOFS, &q_resolved, NULL);
if (r < 0)
goto fail;
@@ -3985,7 +3985,7 @@ static int apply_working_directory(
r = chase(wd,
runtime->ephemeral_copy ?: context->root_directory,
CHASE_PREFIX_ROOT|CHASE_AT_RESOLVE_IN_ROOT,
CHASE_PREFIX_ROOT|CHASE_AT_RESOLVE_IN_ROOT|CHASE_AUTOFS,
/* ret_path= */ NULL,
&dfd);
if (r >= 0)

View File

@@ -1196,7 +1196,7 @@ static void mount_enter_mounting(Mount *m) {
/* Validate that the path we are overmounting does not contain any symlinks, because if it does, we
* couldn't support that reasonably: the mounts in /proc/self/mountinfo would not be recognizable to
* us anymore. */
fd = chase_and_open_parent(m->where, /* root= */ NULL, CHASE_PROHIBIT_SYMLINKS|CHASE_MKDIR_0755, &fn);
fd = chase_and_open_parent(m->where, /* root= */ NULL, CHASE_PROHIBIT_SYMLINKS|CHASE_MKDIR_0755|CHASE_AUTOFS, &fn);
if (fd == -EREMCHG) {
r = unit_log_noncanonical_mount_path(UNIT(m), m->where);
goto fail;

View File

@@ -1793,7 +1793,7 @@ static int follow_symlink(
* a time by specifying CHASE_STEP. This function returns 0 if we resolved one step, and > 0 if we reached the
* end and already have a fully normalized name. */
r = chase(mount_entry_path(m), root_directory, CHASE_STEP|CHASE_NONEXISTENT, &target, NULL);
r = chase(mount_entry_path(m), root_directory, CHASE_STEP|CHASE_NONEXISTENT|CHASE_AUTOFS, &target, NULL);
if (r < 0)
return log_debug_errno(r, "Failed to chase symlinks '%s': %m", mount_entry_path(m));
if (r > 0) /* Reached the end, nothing more to resolve */
@@ -1991,7 +1991,7 @@ static int apply_one_mount(
return log_error_errno(r, "Failed to set label of the source directory %s: %m", mount_entry_source(m));
}
r = chase(mount_entry_source(m), NULL, CHASE_TRAIL_SLASH, &chased, NULL);
r = chase(mount_entry_source(m), NULL, CHASE_TRAIL_SLASH|CHASE_AUTOFS, &chased, NULL);
if (r == -ENOENT && m->ignore) {
log_debug_errno(r, "Path %s does not exist, ignoring.", mount_entry_source(m));
return 0;
@@ -3434,7 +3434,7 @@ static int is_extension_overlay(const char *path, int fd) {
assert(path);
if (fd < 0) {
r = chase(path, /* root= */ NULL, CHASE_TRAIL_SLASH|CHASE_MUST_BE_DIRECTORY, /* ret_path= */ NULL, &dfd);
r = chase(path, /* root= */ NULL, CHASE_TRAIL_SLASH|CHASE_MUST_BE_DIRECTORY|CHASE_AUTOFS, /* ret_path= */ NULL, &dfd);
if (r < 0)
return r;
fd = dfd;

View File

@@ -5622,7 +5622,7 @@ int service_determine_exec_selinux_label(Service *s, char **ret) {
return -ENODATA;
_cleanup_free_ char *path = NULL;
r = chase(c->path, s->exec_context.root_directory, CHASE_PREFIX_ROOT, &path, NULL);
r = chase(c->path, s->exec_context.root_directory, CHASE_PREFIX_ROOT|CHASE_AUTOFS, &path, NULL);
if (r < 0) {
log_unit_debug_errno(UNIT(s), r, "Failed to resolve service binary '%s', ignoring.", c->path);
return -ENODATA;

View File

@@ -2476,7 +2476,7 @@ int device_chase(sd_device *device, const char *path, ChaseFlags flags, char **r
_cleanup_free_ char *resolved = NULL;
_cleanup_close_ int fd = -EBADF;
r = chase(path, /* root = */ NULL, CHASE_NO_AUTOFS | flags, &resolved, ret_fd ? &fd : NULL);
r = chase(path, /* root = */ NULL, flags, &resolved, ret_fd ? &fd : NULL);
if (r < 0)
return r;

View File

@@ -91,7 +91,7 @@ static int parse_where(const char *input, char **ret_where) {
assert(ret_where);
if (arg_transport == BUS_TRANSPORT_LOCAL && arg_canonicalize) {
r = chase(input, /* root= */ NULL, CHASE_NONEXISTENT, ret_where, /* ret_fd= */ NULL);
r = chase(input, /* root= */ NULL, CHASE_NONEXISTENT|CHASE_AUTOFS, ret_where, /* ret_fd= */ NULL);
if (r < 0)
return log_error_errno(r, "Failed to make path %s absolute: %m", input);
} else {
@@ -476,7 +476,7 @@ static int parse_argv(int argc, char *argv[]) {
}
if (arg_transport == BUS_TRANSPORT_LOCAL && arg_canonicalize) {
r = chase(p, /* root= */ NULL, /* flags= */ 0, &arg_mount_what, /* ret_fd= */ NULL);
r = chase(p, /* root= */ NULL, CHASE_AUTOFS, &arg_mount_what, /* ret_fd= */ NULL);
if (r < 0)
return log_error_errno(r, "Failed to chase path '%s': %m", p);
} else {
@@ -1103,7 +1103,7 @@ static int action_umount(sd_bus *bus, int argc, char **argv) {
return log_oom();
_cleanup_close_ int fd = -EBADF;
r = chase(u, /* root= */ NULL, 0, &p, &fd);
r = chase(u, /* root= */ NULL, CHASE_AUTOFS, &p, &fd);
if (r < 0) {
RET_GATHER(ret, log_error_errno(r, "Failed to chase path '%s': %m", u));
continue;

View File

@@ -176,7 +176,7 @@ static int verify_trusted_image_fd_by_path(int fd) {
struct stat stb;
const char *e;
r = chase(s, NULL, CHASE_SAFE, &q, &dir_fd);
r = chase(s, NULL, CHASE_SAFE|CHASE_AUTOFS, &q, &dir_fd);
if (r == -ENOENT)
continue;
if (r < 0) {
@@ -194,7 +194,7 @@ static int verify_trusted_image_fd_by_path(int fd) {
if (!filename_is_valid(e))
continue;
r = chaseat(dir_fd, e, CHASE_SAFE, NULL, &inode_fd);
r = chaseat(dir_fd, e, CHASE_SAFE|CHASE_AUTOFS, NULL, &inode_fd);
if (r < 0)
return log_error_errno(r, "Couldn't verify that specified image '%s' is in search path '%s': %m", p, s);

View File

@@ -371,7 +371,7 @@ static int verify_esp(
/* Non-root user can only check the status, so if an error occurred in the following, it does not cause any
* issues. Let's also, silence the error messages. */
r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT|CHASE_PARENT, &p, &pfd);
r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT|CHASE_PARENT|CHASE_AUTOFS, &p, &pfd);
if (r < 0)
return log_full_errno((searching && r == -ENOENT) ||
(unprivileged_mode && ERRNO_IS_PRIVILEGE(r)) ? LOG_DEBUG : LOG_ERR,
@@ -492,7 +492,7 @@ int find_esp_and_warn_at(
"$SYSTEMD_ESP_PATH does not refer to an absolute path, refusing to use it: %s",
path);
r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT, &p, &fd);
r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT|CHASE_AUTOFS, &p, &fd);
if (r < 0)
return log_error_errno(r, "Failed to resolve path %s: %m", path);
@@ -766,7 +766,7 @@ static int verify_xbootldr(
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(path);
r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT|CHASE_PARENT, &p, &pfd);
r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT|CHASE_PARENT|CHASE_AUTOFS, &p, &pfd);
if (r < 0)
return log_full_errno((searching && r == -ENOENT) ||
(unprivileged_mode && ERRNO_IS_PRIVILEGE(r)) ? LOG_DEBUG : LOG_ERR,
@@ -844,7 +844,7 @@ int find_xbootldr_and_warn_at(
"$SYSTEMD_XBOOTLDR_PATH does not refer to an absolute path, refusing to use it: %s",
path);
r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT, &p, &fd);
r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT|CHASE_AUTOFS, &p, &fd);
if (r < 0)
return log_error_errno(r, "Failed to resolve path %s: %m", p);

View File

@@ -660,7 +660,7 @@ int resource_resolve_path(
_cleanup_free_ char *resolved = NULL;
struct stat st;
r = chase(rr->path, root, CHASE_PREFIX_ROOT, &resolved, &fd);
r = chase(rr->path, root, CHASE_PREFIX_ROOT|CHASE_AUTOFS, &resolved, &fd);
if (r < 0)
return log_error_errno(r, "Failed to resolve '%s': %m", rr->path);
@@ -697,7 +697,7 @@ int resource_resolve_path(
} else if (RESOURCE_IS_FILESYSTEM(rr->type)) {
_cleanup_free_ char *resolved = NULL, *relative_to = NULL;
ChaseFlags chase_flags = CHASE_NONEXISTENT | CHASE_PREFIX_ROOT;
ChaseFlags chase_flags = CHASE_NONEXISTENT | CHASE_PREFIX_ROOT | CHASE_AUTOFS;
if (rr->path_relative_to == PATH_RELATIVE_TO_EXPLICIT) {
assert(relative_to_directory);

View File

@@ -1498,7 +1498,7 @@ int transfer_install_instance(
assert_not_reached();
if (resolve_link_path && root) {
r = chase(link_path, root, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &resolved, NULL);
r = chase(link_path, root, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT|CHASE_AUTOFS, &resolved, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve current symlink path '%s': %m", link_path);

View File

@@ -1557,7 +1557,7 @@ static int verb_components(int argc, char **argv, void *userdata) {
_cleanup_closedir_ DIR *d = NULL;
_cleanup_free_ char *p = NULL;
r = chase_and_opendir(*i, arg_root, CHASE_PREFIX_ROOT, &p, &d);
r = chase_and_opendir(*i, arg_root, CHASE_PREFIX_ROOT|CHASE_AUTOFS, &p, &d);
if (r == -ENOENT)
continue;
if (r < 0)

View File

@@ -24,7 +24,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "prefix-root", no_argument, NULL, CHASE_PREFIX_ROOT },
{ "nonexistent", no_argument, NULL, CHASE_NONEXISTENT },
{ "no_autofs", no_argument, NULL, CHASE_NO_AUTOFS },
{ "autofs", no_argument, NULL, CHASE_AUTOFS },
{ "safe", no_argument, NULL, CHASE_SAFE },
{ "trail-slash", no_argument, NULL, CHASE_TRAIL_SLASH },
{ "step", no_argument, NULL, CHASE_STEP },
@@ -60,7 +60,7 @@ static int parse_argv(int argc, char *argv[]) {
case CHASE_PREFIX_ROOT:
case CHASE_NONEXISTENT:
case CHASE_NO_AUTOFS:
case CHASE_AUTOFS:
case CHASE_SAFE:
case CHASE_TRAIL_SLASH:
case CHASE_STEP:

View File

@@ -1082,7 +1082,7 @@ static int path_open_parent_safe(const char *path, bool allow_failure) {
path,
allow_failure ? ", ignoring" : "");
r = chase(dn, arg_root, allow_failure ? CHASE_SAFE : CHASE_SAFE|CHASE_WARN, NULL, &fd);
r = chase(dn, arg_root, allow_failure ? CHASE_SAFE|CHASE_AUTOFS : CHASE_SAFE|CHASE_WARN|CHASE_AUTOFS, NULL, &fd);
if (r == -ENOLINK) /* Unsafe symlink: already covered by CHASE_WARN */
return r;
if (r < 0)
@@ -1107,7 +1107,7 @@ static int path_open_safe(const char *path) {
if (!path_is_normalized(path))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to open invalid path '%s'.", path);
r = chase(path, arg_root, CHASE_SAFE|CHASE_WARN|CHASE_NOFOLLOW, NULL, &fd);
r = chase(path, arg_root, CHASE_SAFE|CHASE_WARN|CHASE_NOFOLLOW|CHASE_AUTOFS, NULL, &fd);
if (r == -ENOLINK)
return r; /* Unsafe symlink: already covered by CHASE_WARN */
if (r < 0)
@@ -2162,7 +2162,7 @@ static int empty_directory(
assert(i);
assert(i->type == EMPTY_DIRECTORY);
r = chase(path, arg_root, CHASE_SAFE|CHASE_WARN, NULL, &fd);
r = chase(path, arg_root, CHASE_SAFE|CHASE_WARN|CHASE_AUTOFS, NULL, &fd);
if (r == -ENOLINK) /* Unsafe symlink: already covered by CHASE_WARN */
return r;
if (r == -ENOENT) {
@@ -2406,7 +2406,7 @@ 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);
r = chase(i->argument, arg_root, CHASE_SAFE|CHASE_PREFIX_ROOT|CHASE_NOFOLLOW|CHASE_AUTOFS, /* ret_path = */ NULL, /* ret_fd = */ NULL);
if (r == -ENOENT) {
/* Silently skip over lines where the source file is missing. */
log_info("Symlink source path '%s/%s' does not exist, skipping line.",
@@ -3232,7 +3232,7 @@ static int process_item(
path = _path;
}
r = chase(path, arg_root, CHASE_NO_AUTOFS|CHASE_NONEXISTENT|CHASE_WARN, NULL, NULL);
r = chase(path, arg_root, CHASE_NONEXISTENT|CHASE_WARN|CHASE_AUTOFS, NULL, NULL);
if (r == -EREMOTE) {
log_notice_errno(r, "Skipping %s", i->path); /* We log the configured path, to not confuse the user. */
return 0;

View File

@@ -46,3 +46,18 @@ userdbctl user 65534 -j | userdbctl -F- user | cmp - <(userdbctl user 65534)
userdbctl group root -j | userdbctl -F- group | cmp - <(userdbctl group root)
userdbctl group systemd-network -j | userdbctl -F- group | cmp - <(userdbctl group systemd-network)
userdbctl group 65534 -j | userdbctl -F- group | cmp - <(userdbctl group 65534)
# Ensure NSS doesn't try to automount via open_tree
if [[ ! -v ASAN_OPTIONS ]]; then
systemctl stop systemd-userdbd.socket systemd-userdbd.service
set +o pipefail
systemd-run -q -t --property SystemCallFilter=~open_tree id definitelynotarealuser | grep -q "no such user"
systemd-run -q -t --property SystemCallFilter=~open_tree id --groups definitelynotarealuser | grep -q "no such user"
systemd-run -q -t --property SystemCallFilter=~open_tree groups definitelynotarealuser | grep -q "no such user"
set -o pipefail
# getent shows no output when the entry is not found, but exists with 2, while sd-run crashing will exit
# with 1
assert_rc 2 systemd-run -q -t --property SystemCallFilter=~open_tree getent passwd definitelynotarealuser
assert_rc 2 systemd-run -q -t --property SystemCallFilter=~open_tree getent group definitelynotarealgroup
systemctl start systemd-userdbd.socket systemd-userdbd.service
fi