]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
chase: when chasing paths, trigger automounts
authorLennart Poettering <lennart@poettering.net>
Thu, 3 Jul 2025 09:49:44 +0000 (11:49 +0200)
committerLuca Boccassi <luca.boccassi@gmail.com>
Thu, 3 Jul 2025 21:18:56 +0000 (22:18 +0100)
As it turns out open() with O_PATH does *not* trigger autofs, you get a
reference to the autofs inode, if not triggered.

But there's a way out: open_tree() (when specified without
OPEN_TREE_CLONE) is actually fully equivalent to open() with O_PATH –
with the exception of one thing: it *does* trigger automounts.

Thanks for Christian Brauner for pointing me to this and saving my day.

Fixes: #33155
src/basic/chase.c

index 8fd7e67559e100f2ef42c6cc6fad7f7724d52bdf..dba3a616876fc4b9e75fc02d213d91b3700085be 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <linux/magic.h>
+#include <sys/mount.h>
 #include <unistd.h>
 
 #include "alloc-util.h"
@@ -370,8 +371,22 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
                         continue;
                 }
 
-                /* Otherwise let's see what this is. */
-                child = r = RET_NERRNO(openat(fd, first, O_CLOEXEC|O_NOFOLLOW|O_PATH));
+                /* Otherwise let's pin it by file descriptor, via O_PATH. 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 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.
+                 *
+                 * As it turns out some sandboxes prohibit open_tree(), and return EPERM or ENOSYS if we call
+                 * it. But since autofs does not work inside of mount namespace anyway, let's simply handle
+                 * this as gracefully as we can, and fall back to classic openat() if we see EPERM/ENOSYS. */
+                if (FLAGS_SET(flags, CHASE_NO_AUTOFS))
+                        r = -EPERM;
+                else
+                        child = r = RET_NERRNO(open_tree(fd, first, AT_SYMLINK_NOFOLLOW|OPEN_TREE_CLOEXEC));
+                if (r == -EPERM || ERRNO_IS_NEG_NOT_SUPPORTED(r))
+                        child = r = RET_NERRNO(openat(fd, first, O_CLOEXEC|O_NOFOLLOW|O_PATH));
                 if (r < 0) {
                         if (r != -ENOENT)
                                 return r;