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
This commit is contained in:
Lennart Poettering
2025-07-03 11:49:44 +02:00
committed by Luca Boccassi
parent 0754db571b
commit c5de7b14ae

View 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;