From: Lennart Poettering Date: Thu, 3 Jul 2025 09:49:44 +0000 (+0200) Subject: chase: when chasing paths, trigger automounts X-Git-Tag: v258-rc1~187 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c5de7b14ae2e08d267d8d75bc88934ac6aa7dcd6;p=thirdparty%2Fsystemd.git chase: when chasing paths, trigger automounts 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 --- diff --git a/src/basic/chase.c b/src/basic/chase.c index 8fd7e67559e..dba3a616876 100644 --- a/src/basic/chase.c +++ b/src/basic/chase.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include +#include #include #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;