/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <linux/magic.h>
+#include <sys/mount.h>
#include <unistd.h>
#include "alloc-util.h"
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;