]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
fs: support FD_FAILFS_ROOT in fchdir()
authorChristian Brauner <brauner@kernel.org>
Fri, 24 Jul 2026 13:41:18 +0000 (15:41 +0200)
committerChristian Brauner <brauner@kernel.org>
Mon, 27 Jul 2026 15:17:59 +0000 (17:17 +0200)
Add a new file descriptor sentinel FD_FAILFS_ROOT following
FD_PIDFS_ROOT and FD_NSFS_ROOT and teach fchdir() to accept it. A
process calling fchdir(FD_FAILFS_ROOT) moves its working directory
into failfs. Every AT_FDCWD-relative lookup afterwards fails with
EOPNOTSUPP including "." and ".." and getcwd() reports the working
directory as unreachable from the process root by returning a path
prefixed with "(unreachable)". Lookups relative to explicit directory
file descriptors are unaffected.

The sentinel is the only way in. No privilege or gating is required.
Setting the working directory to a directory in which every operation
fails grants nothing and loses nothing that closing file descriptors
couldn't lose. An unlinked working directory behaves the same way today
modulo errno. The working directory also plays no role in confining ".."
resolution so no boundary is weakened.

Link: https://patch.msgid.link/20260724-work-failfs-v2-2-485dabbae185@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
fs/failfs.c
fs/internal.h
fs/open.c
include/uapi/linux/fcntl.h

index d0ca1fc6c45910ebff4a64a221ba1448963da7ef..66a36da3d236d6d2964781a100cdb4a3b4f22b98 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/fs.h>
 #include <linux/fs/super_types.h>
 #include <linux/fs_context.h>
+#include <linux/fs_struct.h>
 #include <linux/magic.h>
 #include <linux/mount.h>
 
@@ -135,6 +136,16 @@ static int failfs_init_fs_context(struct fs_context *fc)
        return 0;
 }
 
+int failfs_current_chdir(void)
+{
+       struct path path;
+
+       failfs_get_root(&path);
+       set_fs_pwd(current->fs, &path);
+       path_put(&path);
+       return 0;
+}
+
 static struct file_system_type failfs_fs_type = {
        .name                   = "failfs",
        .init_fs_context        = failfs_init_fs_context,
index ce7f12c5a65b3ad184e02b13e49396ab5e96f533..67aa0444351b1acb22365920312d1e9983606a90 100644 (file)
@@ -365,3 +365,4 @@ void nsfs_get_root(struct path *path);
 void failfs_get_root(struct path *path);
 void __init failfs_init(void);
 bool failfs_mnt(const struct vfsmount *mnt);
+int failfs_current_chdir(void);
index 408925d7bd0b7702895fff07b5a94ba754d2c877..56b6032d4d813c8c44c8fa17b0b40a41397c0b22 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -570,9 +570,12 @@ retry:
 
 SYSCALL_DEFINE1(fchdir, unsigned int, fd)
 {
-       CLASS(fd_raw, f)(fd);
        int error;
 
+       if ((int)fd == FD_FAILFS_ROOT)
+               return failfs_current_chdir();
+
+       CLASS(fd_raw, f)(fd);
        if (fd_empty(f))
                return -EBADF;
 
index aadfbf6e0cb3a004e4a67a6f0607b2e0ff6dd06f..e43e3de3e9ee44a209448ebe1f907394a7c07ad6 100644 (file)
@@ -124,6 +124,7 @@ struct delegation {
 
 #define FD_PIDFS_ROOT                  -10002 /* Root of the pidfs filesystem */
 #define FD_NSFS_ROOT                   -10003 /* Root of the nsfs filesystem */
+#define FD_FAILFS_ROOT                 -10004 /* Root of the failfs filesystem */
 #define FD_INVALID                     -10009 /* Invalid file descriptor: -10000 - EBADF = -10009 */
 
 /* Generic flags for the *at(2) family of syscalls. */