Linux EFI development
 help / color / mirror / Atom feed
* [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage
@ 2026-11-14 13:01 Christian Brauner
  2026-11-14 13:01 ` [PATCH RFC v2 01/42] loop: refuse backing files that aren't open for reading Christian Brauner
                   ` (41 more replies)
  0 siblings, 42 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:01 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable), stable,
	Alexander Mikhalitsyn, Breno Leitao, Casey Schaufler, Chuck Lever,
	Sashiko

Loop happily takes any regular file with ->read_iter() as a backing
file and any file that also has ->write_iter() as a writable one. A few
examples:

* /proc/kcore attaches read-only as a loop device the size of the
  kernel's virtual address space (64 PiB with 5-level paging)
* sysfs attributes attach read-write as 4096 byte loop devices
* using /sys/kernel/mm/transparent_hugepage/enabled for the loop device
  and writing a block to the loop device changes the THP setting

It's not just silly. It's abusable (is that a word?). Loop calls
->read_iter() and ->write_iter() of the backing file directly from its
kworker which runs with kernel credentials.

But pseudo files enforce part of their access rules at read and write
against the caller. So dozens of sysfs ->show() and ->store() methods
call capable().

But setting up a loop device requires no capabilities. It only requires
access to the device nodes. So whoever has a loop device skips all of
the capable() checks.

A couple of fun examples:

On v7.4-rc1 uid 0 without any capabilities can't kill a process of uid
1000 and can't poison its memory either:

    $ grep CapEff /proc/self/status
    CapEff: 0000000000000000
    $ kill -9 327
    bash: kill: (327) - Operation not permitted
    $ echo 0x220689000 > /sys/devices/system/memory/hard_offline_page
    bash: echo: write error: Operation not permitted

But put hard_offline_page behind a loop device, write a block
containing 0x220689000 to the loop device and the loop worker happily
does it:

    Memory failure: 0x220689: recovery action for dirty LRU page: Recovered
    MCE: Killing victim:327 due to hardware memory corruption fault at 7f468e972000

That hard_offline_page is a write-only file doesn't stop loop from
using it as a writable backing file either.

Other fun examples:

(1) soft-block radios via /sys/class/rfkill/rfkill*/soft
    (CAP_NET_ADMIN)

(2) change the reboot mode via /sys/kernel/reboot/mode (CAP_SYS_BOOT)

(3) reconfigure md arrays via /sys/block/md*/md/. md_attr_store()
    requires CAP_SYS_ADMIN for every md attribute.

(4) reconfigure scsi disks via /sys/class/scsi_disk/*/allow_restart and
    friends (CAP_SYS_ADMIN)

(5) read dmi-sysfs attributes (CAP_SYS_ADMIN)

And an unprivileged container that was handed a loop device can change
gro_flush_timeout of its own network devices. That usually requires
CAP_NET_ADMIN in the initial user namespace (via sysfs and via netlink).

I've reproduced that all on v7.4-rc1.

Aaaand zloop, the nvme target's file backend, the scsi target's fileio
backend, fuse passthrough and the usb mass storage gadget have the same
problem. erofs takes pseudo files as images for file-backed mounts as
well. It reads them with the mounter's credentials though so that's just
silly and not abusable.

Fwiw, device mapper doesn't need anything. It only takes block devices.
md's deprecated bitmap file is fine as well. It maps the file with
bmap() which no pseudo filesystem implements.

So this series adds SB_I_PSEUDO to state that the regular files of a
filesystem are kernel interfaces and not storage and makes all seven
refuse such files.

I didn't want to sprinkle SB_I_PSEUDO over all pseudo filesystems one by
one. Instead there's now a common initialization point for all of them
via fc_init_pseudo().

init_pseudo() uses it for the internal pseudo filesystems and all
mountable pseudo filesystems call it from their ->init_fs_context().

kernfs does it once in kernfs_get_tree(). It raises SB_I_PSEUDO,
SB_I_NOEXEC and SB_I_NODEV. Pseudo filesystems never hold executables or
device nodes. Some of them raised SB_I_NOEXEC and SB_I_NODEV already,
most didn't.

I went through every single one of them. None of them needs to execute
anything. The files that can be mmap()ed map data and the tracing ring
buffer refuses VM_EXEC anyway.

SB_I_NODEV is cleared again by devpts, binderfs and selinuxfs. The first
two did that already. selinuxfs needs it because Android init opens
/sys/fs/selinux/null by path as /dev/null doesn't exist yet at that
point. Note that systemd mounts most of these filesystems with noexec
and nodev already.

file_check_backing() looks at d_real_inode(). overlayfs happily stacks on
top of sysfs, cgroup2, debugfs, tracefs, configfs and securityfs and
reads of such overlayfs files are served by the pseudo file. Only procfs
and binfmt_misc are refused as they set s_stack_depth to
FILESYSTEM_MAX_STACK_DEPTH.

Whether all pseudo filesystems should refuse stacking is a separate
discussion. overlayfs reads the lower file with the mounter's
credentials so a root-mounted overlayfs on top of a sysfs directory
hands capability gated reads to every reader. With SB_I_PSEUDO overlayfs
could easily refuse them.

The first three patches are independent fixes. Loop never checked
whether its backing file is open for reading. It relied on
vfs_iter_read() refusing such files. Direct I/O never went through
vfs_iter_read() and since v6.15 buffered I/O doesn't either. So whoever
has a loop device can read files they could only open for writing. And
the nvme target's file backend and the scsi target's fileio backend call
->read_iter() and ->write_iter() without checking that they exist.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
Changes in v2:
- Add file_check_backing() and use it in all consumers. It replaces
  file_is_pseudo() and the open-coded file type, open mode and method
  checks.
- nvmet, fileio and zloop refuse everything that isn't a regular file
  or, for nvmet and fileio, a block device.
- fileio: check the protection file as well. (sashiko)
- acct: refuse files on all pseudo filesystems. (Alexander)
- selftests: add nvmet (Bui), fileio, zloop, link, FIFO and character
  device tests.
- Collect tags. They are dropped on the patches that changed.
- Link to v1: https://patch.msgid.link/20261110-work-loop-pseudo-v1-0-4c998976c6c7@kernel.org

---
Christian Brauner (42):
      loop: refuse backing files that aren't open for reading
      nvmet: check that the file backend supports ->{read,write}_iter
      target: fileio: check that the backing file supports ->{read,write}_iter
      fs: add SB_I_PSEUDO
      kernfs: use fc_init_pseudo()
      proc: use fc_init_pseudo()
      binfmt_misc: use fc_init_pseudo()
      mqueue: use fc_init_pseudo()
      bpf: use fc_init_pseudo() for bpffs
      nullfs: use fc_init_pseudo()
      failfs: use fc_init_pseudo()
      rust_binderfs: use fc_init_pseudo()
      devpts: use fc_init_pseudo()
      debugfs: use fc_init_pseudo()
      tracefs: use fc_init_pseudo()
      configfs: use fc_init_pseudo()
      securityfs: use fc_init_pseudo()
      selinux: use fc_init_pseudo() for selinuxfs
      smack: use fc_init_pseudo() for smackfs
      apparmor: use fc_init_pseudo() for apparmorfs
      nfsd: use fc_init_pseudo()
      sunrpc: use fc_init_pseudo() for rpc_pipefs
      fuse: use fc_init_pseudo() for fusectl
      efivarfs: use fc_init_pseudo()
      pstore: use fc_init_pseudo()
      xenfs: use fc_init_pseudo()
      openpromfs: use fc_init_pseudo()
      ocfs2: use fc_init_pseudo() for dlmfs
      s390/hypfs: use fc_init_pseudo()
      powerpc/spufs: use fc_init_pseudo()
      usb: gadget: f_fs: use fc_init_pseudo()
      usb: gadget: gadgetfs: use fc_init_pseudo()
      fs: add file_check_backing()
      loop: refuse files on pseudo filesystems as backing files
      zloop: refuse zone files on pseudo filesystems
      nvmet: refuse files on pseudo filesystems as namespace backing files
      target: fileio: refuse files on pseudo filesystems as backing files
      fuse: refuse files on pseudo filesystems as passthrough backing files
      usb: gadget: f_mass_storage: refuse files on pseudo filesystems
      erofs: refuse files on pseudo filesystems as backing files
      acct: refuse files on pseudo filesystems
      selftests/filesystems: add backing file tests for pseudo files

 arch/powerpc/platforms/cell/spufs/inode.c          |   2 +
 arch/s390/hypfs/inode.c                            |   2 +
 drivers/android/binder/rust_binderfs.c             |   3 +-
 drivers/block/loop.c                               |  14 +-
 drivers/block/zloop.c                              |   5 +-
 drivers/nvme/target/io-cmd-file.c                  |   4 +
 drivers/target/target_core_file.c                  |  14 +
 drivers/usb/gadget/function/f_fs.c                 |   2 +
 drivers/usb/gadget/function/storage_common.c       |  11 +-
 drivers/usb/gadget/legacy/inode.c                  |   2 +
 drivers/xen/xenfs/super.c                          |   2 +
 fs/binfmt_misc.c                                   |   5 +-
 fs/configfs/mount.c                                |   2 +
 fs/debugfs/inode.c                                 |   2 +
 fs/devpts/inode.c                                  |   2 +
 fs/efivarfs/super.c                                |   2 +
 fs/erofs/super.c                                   |   5 +-
 fs/failfs.c                                        |   3 +-
 fs/fuse/backing.c                                  |   4 +
 fs/fuse/control.c                                  |   2 +
 fs/kernfs/mount.c                                  |   4 +-
 fs/libfs.c                                         |   2 +-
 fs/nfsd/nfsctl.c                                   |   2 +
 fs/nullfs.c                                        |   3 +-
 fs/ocfs2/dlmfs/dlmfs.c                             |   2 +
 fs/openpromfs/inode.c                              |   2 +
 fs/proc/root.c                                     |   4 +-
 fs/pstore/inode.c                                  |   2 +
 fs/read_write.c                                    |  48 ++
 fs/tracefs/inode.c                                 |   2 +
 include/linux/fs.h                                 |   2 +
 include/linux/fs/super_types.h                     |   1 +
 include/linux/pseudo_fs.h                          |  11 +
 ipc/mqueue.c                                       |   3 +-
 kernel/acct.c                                      |   6 +-
 kernel/bpf/inode.c                                 |   4 +-
 net/sunrpc/rpc_pipe.c                              |   2 +
 security/apparmor/apparmorfs.c                     |   2 +
 security/inode.c                                   |   2 +
 security/selinux/selinuxfs.c                       |   5 +
 security/smack/smackfs.c                           |   2 +
 tools/testing/selftests/filesystems/.gitignore     |   1 +
 tools/testing/selftests/filesystems/Makefile       |   2 +-
 tools/testing/selftests/filesystems/config         |  14 +
 .../selftests/filesystems/pseudo_backing_test.c    | 570 +++++++++++++++++++++
 45 files changed, 747 insertions(+), 39 deletions(-)
---
base-commit: 6628e7d4c6b25c8d18f1345e3a20d21829aae7e4
change-id: 20261109-work-loop-pseudo-890844168ef1


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 01/42] loop: refuse backing files that aren't open for reading
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
@ 2026-11-14 13:01 ` Christian Brauner
  2026-11-14 13:01 ` [PATCH RFC v2 02/42] nvmet: check that the file backend supports ->{read,write}_iter Christian Brauner
                   ` (40 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:01 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable), stable,
	Alexander Mikhalitsyn

loop_configure() takes any file as long as it implements ->read_iter().
Loop itself never checked whether the file was actually opened for
reading. Buffered I/O went through vfs_iter_read() which refuses files
without FMODE_READ. Direct I/O has called ->read_iter() of the backing
file directly ever since loop grew support for it.

Since commit f2fed441c69b ("loop: stop using vfs_iter_{read,write} for
buffered I/O") buffered I/O calls ->read_iter() directly as well. That
commit was about O_DIRECT handling and the FMODE_READ check went away
as a side effect.

So whoever can set up a loop device can read a file it was only allowed
to open for writing. Open the file O_WRONLY, configure a loop device
with it and read the contents through the loop device.

Refuse backing files that aren't open for reading. Loop always reads
from its backing file so a write-only backing file never made sense in
the first place.

Fixes: bc07c10a3603 ("block: loop: support DIO & AIO")
Fixes: f2fed441c69b ("loop: stop using vfs_iter_{read,write} for buffered I/O")
Cc: stable@vger.kernel.org
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Alexander Mikhalitsyn <alex@amutable.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 drivers/block/loop.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index a3325ceab484a..c96e35c3ef423 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -528,6 +528,9 @@ static void loop_assign_backing_file(struct loop_device *lo, struct file *file)
 
 static int loop_check_backing_file(struct file *file)
 {
+	if (!(file->f_mode & FMODE_READ))
+		return -EBADF;
+
 	if (!file->f_op->read_iter)
 		return -EINVAL;
 

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 02/42] nvmet: check that the file backend supports ->{read,write}_iter
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
  2026-11-14 13:01 ` [PATCH RFC v2 01/42] loop: refuse backing files that aren't open for reading Christian Brauner
@ 2026-11-14 13:01 ` Christian Brauner
  2026-11-14 13:01 ` [PATCH RFC v2 03/42] target: fileio: check that the backing file " Christian Brauner
                   ` (39 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:01 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable)

The file backend calls ->read_iter() and ->write_iter() of the backing
file directly but never checks that they exist. Everything that isn't a
block device ends up in the file backend. So a namespace pointing to a
file without them calls a NULL pointer on its first I/O. Only
buffered_io=1 gets that far as the O_DIRECT open fails for such files.

Refuse them when the namespace is enabled the same way zloop does since
commit 0c10f8a1a7ae ("zloop: check that the zone backing file support
->{read,write}_iter").

Fixes: d5eff33ee6f8 ("nvmet: add simple file backed ns support")
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 drivers/nvme/target/io-cmd-file.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/nvme/target/io-cmd-file.c b/drivers/nvme/target/io-cmd-file.c
index 695963dd932ee..dfa8aa46188c8 100644
--- a/drivers/nvme/target/io-cmd-file.c
+++ b/drivers/nvme/target/io-cmd-file.c
@@ -47,6 +47,11 @@ int nvmet_file_ns_enable(struct nvmet_ns *ns)
 		return ret;
 	}
 
+	if (!ns->file->f_op->read_iter || !ns->file->f_op->write_iter) {
+		ret = -EINVAL;
+		goto err;
+	}
+
 	nvmet_file_ns_revalidate(ns);
 
 	/*

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 03/42] target: fileio: check that the backing file supports ->{read,write}_iter
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
  2026-11-14 13:01 ` [PATCH RFC v2 01/42] loop: refuse backing files that aren't open for reading Christian Brauner
  2026-11-14 13:01 ` [PATCH RFC v2 02/42] nvmet: check that the file backend supports ->{read,write}_iter Christian Brauner
@ 2026-11-14 13:01 ` Christian Brauner
  2026-11-14 13:01 ` [PATCH RFC v2 04/42] fs: add SB_I_PSEUDO Christian Brauner
                   ` (38 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:01 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable)

With fd_async_io=1 the fileio backend calls ->read_iter() and
->write_iter() of the backing file directly. The synchronous path goes
through vfs_iter_read() and vfs_iter_write() which check for them but
the aio path doesn't. So a backing file without them calls a NULL
pointer on its first I/O.

Refuse such files when configuring the device. On the synchronous path
every read or write that needed the missing method failed with EINVAL
anyway.

Fixes: 769031c92c8b ("scsi: target: target/file: Add support of direct and async I/O")
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 drivers/target/target_core_file.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
index ab9824a4852f1..a5391e57e9aa5 100644
--- a/drivers/target/target_core_file.c
+++ b/drivers/target/target_core_file.c
@@ -144,6 +144,14 @@ static int fd_configure_device(struct se_device *dev)
 		goto fail;
 	}
 	fd_dev->fd_file = file;
+
+	if (!file->f_op->read_iter || !file->f_op->write_iter) {
+		pr_err("FILEIO: %s lacks ->read_iter or ->write_iter\n",
+		       fd_dev->fd_dev_name);
+		ret = -EINVAL;
+		goto fail;
+	}
+
 	/*
 	 * If using a block backend with this struct file, we extract
 	 * fd_dev->fd_[block,dev]_size from struct block_device.

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 04/42] fs: add SB_I_PSEUDO
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (2 preceding siblings ...)
  2026-11-14 13:01 ` [PATCH RFC v2 03/42] target: fileio: check that the backing file " Christian Brauner
@ 2026-11-14 13:01 ` Christian Brauner
  2026-11-14 13:01 ` [PATCH RFC v2 05/42] kernfs: use fc_init_pseudo() Christian Brauner
                   ` (37 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:01 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable),
	Alexander Mikhalitsyn

Currently, there's no way to tell whether the files of a filesystem
store data or whether they are kernel interfaces. Files on pseudo
filesystems such as procfs or sysfs generate their contents when they're
read and writes to them are commands to the kernel.

But a few places in the kernel take an arbitrary file and use it as
storage: loop, zloop, the nvme target's file backend, the scsi target's
fileio backend, fuse passthrough, the usb mass storage gadget and erofs
file-backed mounts. At most they check the file type and whether the
file implements ->read_iter() and ->write_iter(). That's not enough.
kernfs provides both for every sysfs attribute for example.

Add SB_I_PSEUDO so a filesystem can state that its regular files are
kernel interfaces and must not be used as storage.

Pseudo filesystems also never hold executables or device nodes. But
currently each of them decides on its own whether to raise SB_I_NOEXEC
and SB_I_NODEV. Some do, most don't. Add fc_init_pseudo() as the common
initialization point for all pseudo filesystems that raises all three
flags and switch init_pseudo() over to it. The following patches
convert the mountable pseudo filesystems.

Nothing checks SB_I_PSEUDO yet so no functional changes.

Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Alexander Mikhalitsyn <alex@amutable.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 fs/libfs.c                     |  2 +-
 include/linux/fs/super_types.h |  1 +
 include/linux/pseudo_fs.h      | 11 +++++++++++
 3 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/fs/libfs.c b/fs/libfs.c
index 96a6e9b1535fb..8c8789489fdf9 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -735,7 +735,7 @@ struct pseudo_fs_context *init_pseudo(struct fs_context *fc,
 		fc->fs_private = ctx;
 		fc->ops = &pseudo_fs_context_ops;
 		fc->sb_flags |= SB_NOUSER;
-		fc->s_iflags |= SB_I_NOEXEC | SB_I_NODEV;
+		fc_init_pseudo(fc);
 		fc->global = true;
 	}
 	return ctx;
diff --git a/include/linux/fs/super_types.h b/include/linux/fs/super_types.h
index 72f4288e16c52..472200bdf081a 100644
--- a/include/linux/fs/super_types.h
+++ b/include/linux/fs/super_types.h
@@ -359,5 +359,6 @@ struct super_block {
 #define SB_I_NOIDMAP	0x00002000	/* No idmapped mounts on this superblock */
 #define SB_I_ALLOW_HSM	0x00004000	/* Allow HSM events on this superblock */
 #define SB_I_NO_DATA_INTEGRITY	0x00008000 /* fs cannot guarantee data persistence on sync */
+#define SB_I_PSEUDO	0x00010000	/* regular files are kernel interfaces, not storage */
 
 #endif /* _LINUX_FS_SUPER_TYPES_H */
diff --git a/include/linux/pseudo_fs.h b/include/linux/pseudo_fs.h
index a651e60d94107..0ca408aa60aff 100644
--- a/include/linux/pseudo_fs.h
+++ b/include/linux/pseudo_fs.h
@@ -2,6 +2,7 @@
 #define __LINUX_PSEUDO_FS__
 
 #include <linux/fs_context.h>
+#include <linux/fs/super_types.h>
 
 struct pseudo_fs_context {
 	const struct super_operations *ops;
@@ -15,4 +16,14 @@ struct pseudo_fs_context {
 struct pseudo_fs_context *init_pseudo(struct fs_context *fc,
 				      unsigned long magic);
 
+/*
+ * Common initialization for all pseudo filesystems, mountable or not. Their
+ * regular files are kernel interfaces. They don't store data and pseudo
+ * filesystems never hold executables or device nodes.
+ */
+static inline void fc_init_pseudo(struct fs_context *fc)
+{
+	fc->s_iflags |= SB_I_PSEUDO | SB_I_NOEXEC | SB_I_NODEV;
+}
+
 #endif

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 05/42] kernfs: use fc_init_pseudo()
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (3 preceding siblings ...)
  2026-11-14 13:01 ` [PATCH RFC v2 04/42] fs: add SB_I_PSEUDO Christian Brauner
@ 2026-11-14 13:01 ` Christian Brauner
  2026-11-14 13:01 ` [PATCH RFC v2 06/42] proc: " Christian Brauner
                   ` (36 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:01 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable),
	Alexander Mikhalitsyn

Initialize all kernfs based filesystems as pseudo filesystems in
kernfs_get_tree() instead of raising SB_I_NOEXEC and SB_I_NODEV by hand
in kernfs_fill_super(). This adds SB_I_PSEUDO for sysfs, cgroupfs and
resctrl.

Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Alexander Mikhalitsyn <alex@amutable.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 fs/kernfs/mount.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c
index a0be784bfb064..6b60d212b003d 100644
--- a/fs/kernfs/mount.c
+++ b/fs/kernfs/mount.c
@@ -8,6 +8,7 @@
  */
 
 #include <linux/fs.h>
+#include <linux/pseudo_fs.h>
 #include <linux/mount.h>
 #include <linux/init.h>
 #include <linux/magic.h>
@@ -298,8 +299,6 @@ static int kernfs_fill_super(struct super_block *sb, struct kernfs_fs_context *k
 	struct dentry *root;
 
 	info->sb = sb;
-	/* Userspace would break if executables or devices appear on sysfs */
-	sb->s_iflags |= SB_I_NOEXEC | SB_I_NODEV;
 	sb->s_blocksize = PAGE_SIZE;
 	sb->s_blocksize_bits = PAGE_SHIFT;
 	sb->s_magic = kfc->magic;
@@ -388,6 +387,7 @@ int kernfs_get_tree(struct fs_context *fc)
 	info->ns = kfc->ns_tag;
 	INIT_LIST_HEAD(&info->node);
 
+	fc_init_pseudo(fc);
 	fc->s_fs_info = info;
 	sb = sget_fc(fc, kernfs_test_super, kernfs_set_super);
 	if (IS_ERR(sb))

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 06/42] proc: use fc_init_pseudo()
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (4 preceding siblings ...)
  2026-11-14 13:01 ` [PATCH RFC v2 05/42] kernfs: use fc_init_pseudo() Christian Brauner
@ 2026-11-14 13:01 ` Christian Brauner
  2026-11-14 13:01 ` [PATCH RFC v2 07/42] binfmt_misc: " Christian Brauner
                   ` (35 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:01 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable),
	Alexander Mikhalitsyn

Initialize procfs as a pseudo filesystem instead of raising
SB_I_NOEXEC and SB_I_NODEV by hand. This adds SB_I_PSEUDO.

Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Alexander Mikhalitsyn <alex@amutable.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 fs/proc/root.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/proc/root.c b/fs/proc/root.c
index 7fbbe92bf73a7..ca0e75081934f 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -17,6 +17,7 @@
 #include <linux/bitops.h>
 #include <linux/user_namespace.h>
 #include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 #include <linux/mount.h>
 #include <linux/pid_namespace.h>
 #include <linux/fs_parser.h>
@@ -265,8 +266,6 @@ static int proc_fill_super(struct super_block *s, struct fs_context *fc)
 	if (ret)
 		return ret;
 
-	/* User space would break if executables or devices appear on proc */
-	s->s_iflags |= SB_I_NOEXEC | SB_I_NODEV;
 	s->s_flags |= SB_NODIRATIME | SB_NOSUID | SB_NOEXEC;
 	s->s_blocksize = 1024;
 	s->s_blocksize_bits = 10;
@@ -350,6 +349,7 @@ static int proc_init_fs_context(struct fs_context *fc)
 	put_user_ns(fc->user_ns);
 	fc->user_ns = get_user_ns(ctx->pid_ns->user_ns);
 	fc->fs_private = ctx;
+	fc_init_pseudo(fc);
 	fc->ops = &proc_fs_context_ops;
 	return 0;
 }

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 07/42] binfmt_misc: use fc_init_pseudo()
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (5 preceding siblings ...)
  2026-11-14 13:01 ` [PATCH RFC v2 06/42] proc: " Christian Brauner
@ 2026-11-14 13:01 ` Christian Brauner
  2026-11-14 13:01 ` [PATCH RFC v2 08/42] mqueue: " Christian Brauner
                   ` (34 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:01 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable),
	Alexander Mikhalitsyn

Initialize binfmt_misc as a pseudo filesystem instead of raising
SB_I_NOEXEC and SB_I_NODEV by hand. This adds SB_I_PSEUDO.

Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Alexander Mikhalitsyn <alex@amutable.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 fs/binfmt_misc.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index d945b4f6e1581..7dc233becd98d 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -22,6 +22,7 @@
 #include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 #include <linux/init.h>
 #include <linux/kstrtox.h>
 #include <linux/limits.h>
@@ -1575,8 +1576,7 @@ static int bm_fill_super(struct super_block *sb, struct fs_context *fc)
 	if (user_ns != current_user_ns())
 		return -EINVAL;
 
-	/* Never exec off this instance and never let anything stack on it. */
-	sb->s_iflags |= SB_I_NOEXEC | SB_I_NODEV;
+	/* Never let anything stack on this instance. */
 	sb->s_stack_depth = FILESYSTEM_MAX_STACK_DEPTH;
 
 	/*
@@ -1660,6 +1660,7 @@ static void bm_kill_sb(struct super_block *sb)
 
 static int bm_init_fs_context(struct fs_context *fc)
 {
+	fc_init_pseudo(fc);
 	fc->ops = &bm_context_ops;
 	return 0;
 }

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 08/42] mqueue: use fc_init_pseudo()
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (6 preceding siblings ...)
  2026-11-14 13:01 ` [PATCH RFC v2 07/42] binfmt_misc: " Christian Brauner
@ 2026-11-14 13:01 ` Christian Brauner
  2026-11-14 13:01 ` [PATCH RFC v2 09/42] bpf: use fc_init_pseudo() for bpffs Christian Brauner
                   ` (33 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:01 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable),
	Alexander Mikhalitsyn

Initialize mqueue as a pseudo filesystem instead of raising
SB_I_NOEXEC and SB_I_NODEV by hand. This adds SB_I_PSEUDO.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Alexander Mikhalitsyn <alex@amutable.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 ipc/mqueue.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 322c3dd98c447..8bbe32d0881f2 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -18,6 +18,7 @@
 #include <linux/file.h>
 #include <linux/mount.h>
 #include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 #include <linux/namei.h>
 #include <linux/sysctl.h>
 #include <linux/poll.h>
@@ -405,7 +406,6 @@ static int mqueue_fill_super(struct super_block *sb, struct fs_context *fc)
 	struct inode *inode;
 	struct ipc_namespace *ns = sb->s_fs_info;
 
-	sb->s_iflags |= SB_I_NOEXEC | SB_I_NODEV;
 	sb->s_blocksize = PAGE_SIZE;
 	sb->s_blocksize_bits = PAGE_SHIFT;
 	sb->s_magic = MQUEUE_MAGIC;
@@ -457,6 +457,7 @@ static int mqueue_init_fs_context(struct fs_context *fc)
 	put_user_ns(fc->user_ns);
 	fc->user_ns = get_user_ns(ctx->ipc_ns->user_ns);
 	fc->fs_private = ctx;
+	fc_init_pseudo(fc);
 	fc->ops = &mqueue_fs_context_ops;
 	return 0;
 }

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 09/42] bpf: use fc_init_pseudo() for bpffs
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (7 preceding siblings ...)
  2026-11-14 13:01 ` [PATCH RFC v2 08/42] mqueue: " Christian Brauner
@ 2026-11-14 13:01 ` Christian Brauner
  2026-11-14 13:01 ` [PATCH RFC v2 10/42] nullfs: use fc_init_pseudo() Christian Brauner
                   ` (32 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:01 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable),
	Alexander Mikhalitsyn

Initialize bpffs as a pseudo filesystem instead of raising
SB_I_NOEXEC and SB_I_NODEV by hand. This adds SB_I_PSEUDO.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Alexander Mikhalitsyn <alex@amutable.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 kernel/bpf/inode.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c
index c6f328e4752e1..57cf3775c0766 100644
--- a/kernel/bpf/inode.c
+++ b/kernel/bpf/inode.c
@@ -15,6 +15,7 @@
 #include <linux/namei.h>
 #include <linux/fs.h>
 #include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 #include <linux/fs_parser.h>
 #include <linux/kdev_t.h>
 #include <linux/filter.h>
@@ -1197,8 +1198,6 @@ static int bpf_fill_super(struct super_block *sb, struct fs_context *fc)
 	sb->s_magic = BPF_FS_MAGIC;
 	sb->s_op = &bpf_super_ops;
 	sb->s_xattr = bpf_fs_xattr_handlers;
-	sb->s_iflags |= SB_I_NOEXEC;
-	sb->s_iflags |= SB_I_NODEV;
 	sb->s_time_gran = 1;
 
 	inode = bpf_get_inode(sb, NULL, S_IFDIR | 0777);
@@ -1261,6 +1260,7 @@ static int bpf_init_fs_context(struct fs_context *fc)
 	opts->delegate_attachs = 0;
 
 	fc->s_fs_info = opts;
+	fc_init_pseudo(fc);
 	fc->ops = &bpf_context_ops;
 	return 0;
 }

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 10/42] nullfs: use fc_init_pseudo()
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (8 preceding siblings ...)
  2026-11-14 13:01 ` [PATCH RFC v2 09/42] bpf: use fc_init_pseudo() for bpffs Christian Brauner
@ 2026-11-14 13:01 ` Christian Brauner
  2026-11-14 13:01 ` [PATCH RFC v2 11/42] failfs: " Christian Brauner
                   ` (31 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:01 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable),
	Alexander Mikhalitsyn

Initialize nullfs as a pseudo filesystem instead of raising
SB_I_NOEXEC and SB_I_NODEV by hand. This adds SB_I_PSEUDO.

Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Alexander Mikhalitsyn <alex@amutable.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 fs/nullfs.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/fs/nullfs.c b/fs/nullfs.c
index 319c2f5c5a671..2fe24cb97160e 100644
--- a/fs/nullfs.c
+++ b/fs/nullfs.c
@@ -2,6 +2,7 @@
 /* Copyright (c) 2026 Christian Brauner <brauner@kernel.org> */
 #include <linux/fs/super_types.h>
 #include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 #include <linux/magic.h>
 #include <linux/splice.h>
 #include <linux/uio.h>
@@ -174,7 +175,7 @@ static int nullfs_init_fs_context(struct fs_context *fc)
 {
 	fc->ops		= &nullfs_fs_context_ops;
 	fc->sb_flags	|= SB_NOUSER;
-	fc->s_iflags	|= SB_I_NOEXEC | SB_I_NODEV;
+	fc_init_pseudo(fc);
 	return 0;
 }
 

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 11/42] failfs: use fc_init_pseudo()
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (9 preceding siblings ...)
  2026-11-14 13:01 ` [PATCH RFC v2 10/42] nullfs: use fc_init_pseudo() Christian Brauner
@ 2026-11-14 13:01 ` Christian Brauner
  2026-11-14 13:01 ` [PATCH RFC v2 12/42] rust_binderfs: " Christian Brauner
                   ` (30 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:01 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable)

Initialize failfs as a pseudo filesystem instead of raising
SB_I_NOEXEC and SB_I_NODEV by hand. This adds SB_I_PSEUDO.

Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 fs/failfs.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/fs/failfs.c b/fs/failfs.c
index 437cdc981c2de..f03334f361c0e 100644
--- a/fs/failfs.c
+++ b/fs/failfs.c
@@ -3,6 +3,7 @@
 #include <linux/fs.h>
 #include <linux/fs/super_types.h>
 #include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 #include <linux/fs_struct.h>
 #include <linux/magic.h>
 #include <linux/mount.h>
@@ -132,7 +133,7 @@ static int failfs_init_fs_context(struct fs_context *fc)
 	fc->ops		= &failfs_context_ops;
 	fc->global	= true;
 	fc->sb_flags	|= SB_NOUSER;
-	fc->s_iflags	|= SB_I_NOEXEC | SB_I_NODEV;
+	fc_init_pseudo(fc);
 	return 0;
 }
 

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 12/42] rust_binderfs: use fc_init_pseudo()
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (10 preceding siblings ...)
  2026-11-14 13:01 ` [PATCH RFC v2 11/42] failfs: " Christian Brauner
@ 2026-11-14 13:01 ` Christian Brauner
  2026-11-14 13:01 ` [PATCH RFC v2 13/42] devpts: " Christian Brauner
                   ` (29 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:01 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable)

Initialize binderfs as a pseudo filesystem instead of raising SB_I_NOEXEC
by hand. This adds SB_I_PSEUDO. binderfs_fill_super() keeps clearing
SB_I_NODEV for the binder device nodes.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 drivers/android/binder/rust_binderfs.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/android/binder/rust_binderfs.c b/drivers/android/binder/rust_binderfs.c
index 5f020226720db..04468c5b5c116 100644
--- a/drivers/android/binder/rust_binderfs.c
+++ b/drivers/android/binder/rust_binderfs.c
@@ -3,6 +3,7 @@
 #include <linux/compiler_types.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
+#include <linux/pseudo_fs.h>
 #include <linux/fsnotify.h>
 #include <linux/gfp.h>
 #include <linux/idr.h>
@@ -667,7 +668,6 @@ static int binderfs_fill_super(struct super_block *sb, struct fs_context *fc)
 	 * necessary and safe.
 	 */
 	sb->s_iflags &= ~SB_I_NODEV;
-	sb->s_iflags |= SB_I_NOEXEC;
 	sb->s_magic = RUST_BINDERFS_SUPER_MAGIC;
 	sb->s_op = &binderfs_super_ops;
 	sb->s_time_gran = 1;
@@ -759,6 +759,7 @@ static int binderfs_init_fs_context(struct fs_context *fc)
 	ctx->stats_mode = binderfs_stats_mode_unset;
 
 	fc->fs_private = ctx;
+	fc_init_pseudo(fc);
 	fc->ops = &binderfs_fs_context_ops;
 
 	return 0;

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 13/42] devpts: use fc_init_pseudo()
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (11 preceding siblings ...)
  2026-11-14 13:01 ` [PATCH RFC v2 12/42] rust_binderfs: " Christian Brauner
@ 2026-11-14 13:01 ` Christian Brauner
  2026-11-14 13:01 ` [PATCH RFC v2 14/42] debugfs: " Christian Brauner
                   ` (28 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:01 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable),
	Alexander Mikhalitsyn

Initialize devpts as a pseudo filesystem. This raises SB_I_PSEUDO and
SB_I_NOEXEC. devpts never holds executables. devpts_fill_super() keeps
clearing SB_I_NODEV for the pty device nodes.

Reviewed-by: Alexander Mikhalitsyn <alex@amutable.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 fs/devpts/inode.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index bd1e8eb26edb7..47ef12241d92d 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 #include <linux/fs_parser.h>
 #include <linux/sched.h>
 #include <linux/namei.h>
@@ -438,6 +439,7 @@ static int devpts_init_fs_context(struct fs_context *fc)
 		fsi->mount_opts.reserve = true;
 
 	fc->s_fs_info = fsi;
+	fc_init_pseudo(fc);
 	fc->ops = &devpts_context_ops;
 	return 0;
 }

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 14/42] debugfs: use fc_init_pseudo()
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (12 preceding siblings ...)
  2026-11-14 13:01 ` [PATCH RFC v2 13/42] devpts: " Christian Brauner
@ 2026-11-14 13:01 ` Christian Brauner
  2026-11-14 13:01 ` [PATCH RFC v2 15/42] tracefs: " Christian Brauner
                   ` (27 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:01 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable),
	Alexander Mikhalitsyn

Initialize debugfs as a pseudo filesystem. This raises SB_I_PSEUDO and
also SB_I_NOEXEC and SB_I_NODEV. debugfs never holds executables or
device nodes.

SB_I_NOEXEC also refuses PROT_EXEC mappings. The debugfs files that
can be mapped, kcov, relay channels and powernv's memtrace, map data.

Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Alexander Mikhalitsyn <alex@amutable.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 fs/debugfs/inode.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index b4915551ad315..f163f0bc5703a 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 #include <linux/fs_parser.h>
 #include <linux/pagemap.h>
 #include <linux/init.h>
@@ -317,6 +318,7 @@ static int debugfs_init_fs_context(struct fs_context *fc)
 	fsi->mode = DEBUGFS_DEFAULT_MODE;
 
 	fc->s_fs_info = fsi;
+	fc_init_pseudo(fc);
 	fc->ops = &debugfs_context_ops;
 	return 0;
 }

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 15/42] tracefs: use fc_init_pseudo()
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (13 preceding siblings ...)
  2026-11-14 13:01 ` [PATCH RFC v2 14/42] debugfs: " Christian Brauner
@ 2026-11-14 13:01 ` Christian Brauner
  2026-11-14 13:01 ` [PATCH RFC v2 16/42] configfs: " Christian Brauner
                   ` (26 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:01 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable),
	Alexander Mikhalitsyn

Initialize tracefs as a pseudo filesystem. This raises SB_I_PSEUDO and
also SB_I_NOEXEC and SB_I_NODEV. tracefs never holds executables or
device nodes.

SB_I_NOEXEC also refuses PROT_EXEC mappings. The only tracefs files
that can be mapped are the ring buffers and __rb_map_vma() refuses
VM_EXEC already.

Reviewed-by: Alexander Mikhalitsyn <alex@amutable.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 fs/tracefs/inode.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c
index 5020365ca7048..e04febd868eb4 100644
--- a/fs/tracefs/inode.c
+++ b/fs/tracefs/inode.c
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 #include <linux/fs_parser.h>
 #include <linux/kobject.h>
 #include <linux/namei.h>
@@ -510,6 +511,7 @@ static int tracefs_init_fs_context(struct fs_context *fc)
 	fsi->mode = TRACEFS_DEFAULT_MODE;
 
 	fc->s_fs_info = fsi;
+	fc_init_pseudo(fc);
 	fc->ops = &tracefs_context_ops;
 	return 0;
 }

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 16/42] configfs: use fc_init_pseudo()
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (14 preceding siblings ...)
  2026-11-14 13:01 ` [PATCH RFC v2 15/42] tracefs: " Christian Brauner
@ 2026-11-14 13:01 ` Christian Brauner
  2026-11-14 13:01 ` [PATCH RFC v2 17/42] securityfs: " Christian Brauner
                   ` (25 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:01 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable), Breno Leitao,
	Alexander Mikhalitsyn

Initialize configfs as a pseudo filesystem. This raises SB_I_PSEUDO and
also SB_I_NOEXEC and SB_I_NODEV. configfs never holds executables or
device nodes.

Reviewed-by: Jan Kara <jack@suse.cz>
Acked-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Alexander Mikhalitsyn <alex@amutable.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 fs/configfs/mount.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c
index d8cac1cbf3bd5..60ba24e7ae2b9 100644
--- a/fs/configfs/mount.c
+++ b/fs/configfs/mount.c
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/mount.h>
 #include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 #include <linux/pagemap.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -106,6 +107,7 @@ static const struct fs_context_operations configfs_context_ops = {
 
 static int configfs_init_fs_context(struct fs_context *fc)
 {
+	fc_init_pseudo(fc);
 	fc->ops = &configfs_context_ops;
 	return 0;
 }

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 17/42] securityfs: use fc_init_pseudo()
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (15 preceding siblings ...)
  2026-11-14 13:01 ` [PATCH RFC v2 16/42] configfs: " Christian Brauner
@ 2026-11-14 13:01 ` Christian Brauner
  2026-11-14 13:01 ` [PATCH RFC v2 18/42] selinux: use fc_init_pseudo() for selinuxfs Christian Brauner
                   ` (24 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:01 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable),
	Alexander Mikhalitsyn

Initialize securityfs as a pseudo filesystem. This raises SB_I_PSEUDO and
also SB_I_NOEXEC and SB_I_NODEV. securityfs never holds executables or
device nodes.

AppArmor puts a .null device node into securityfs but only ever opens
it via dentry_open() which doesn't care about SB_I_NODEV.

Reviewed-by: Alexander Mikhalitsyn <alex@amutable.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 security/inode.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/security/inode.c b/security/inode.c
index 0804023676741..93997a9f16fcb 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -14,6 +14,7 @@
 #include <linux/kobject.h>
 #include <linux/fs.h>
 #include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 #include <linux/mount.h>
 #include <linux/pagemap.h>
 #include <linux/init.h>
@@ -64,6 +65,7 @@ static const struct fs_context_operations securityfs_context_ops = {
 
 static int securityfs_init_fs_context(struct fs_context *fc)
 {
+	fc_init_pseudo(fc);
 	fc->ops = &securityfs_context_ops;
 	return 0;
 }

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 18/42] selinux: use fc_init_pseudo() for selinuxfs
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (16 preceding siblings ...)
  2026-11-14 13:01 ` [PATCH RFC v2 17/42] securityfs: " Christian Brauner
@ 2026-11-14 13:01 ` Christian Brauner
  2026-11-14 13:02 ` [PATCH RFC v2 19/42] smack: use fc_init_pseudo() for smackfs Christian Brauner
                   ` (23 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:01 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable),
	Alexander Mikhalitsyn

Initialize selinuxfs as a pseudo filesystem. This raises SB_I_PSEUDO and
SB_I_NOEXEC. selinuxfs never holds executables. SB_I_NOEXEC also
refuses PROT_EXEC mappings but the status and policy files are only
ever mapped for reading.

But selinuxfs needs device nodes. The kernel replaces file descriptors
with /sys/fs/selinux/null on exec via dentry_open() which doesn't care
about SB_I_NODEV. Android init however opens /sys/fs/selinux/null by
path as /dev/null doesn't exist yet at that point. So clear SB_I_NODEV
again in sel_fill_super().

Reviewed-by: Alexander Mikhalitsyn <alex@amutable.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 security/selinux/selinuxfs.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 310e19efff1d0..d7ae853b6d685 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -18,6 +18,7 @@
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
 #include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 #include <linux/hex.h>
 #include <linux/mount.h>
 #include <linux/mutex.h>
@@ -1852,6 +1853,9 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc)
 		/* last one */ {"", NULL, 0}
 	};
 
+	/* Android init opens the null device below by path. */
+	sb->s_iflags &= ~SB_I_NODEV;
+
 	ret = selinux_fs_info_create(sb);
 	if (ret)
 		goto err;
@@ -1955,6 +1959,7 @@ static const struct fs_context_operations sel_context_ops = {
 
 static int sel_init_fs_context(struct fs_context *fc)
 {
+	fc_init_pseudo(fc);
 	fc->ops = &sel_context_ops;
 	return 0;
 }

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 19/42] smack: use fc_init_pseudo() for smackfs
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (17 preceding siblings ...)
  2026-11-14 13:01 ` [PATCH RFC v2 18/42] selinux: use fc_init_pseudo() for selinuxfs Christian Brauner
@ 2026-11-14 13:02 ` Christian Brauner
  2026-11-14 13:02 ` [PATCH RFC v2 20/42] apparmor: use fc_init_pseudo() for apparmorfs Christian Brauner
                   ` (22 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:02 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable), Casey Schaufler,
	Alexander Mikhalitsyn

Initialize smackfs as a pseudo filesystem. This raises SB_I_PSEUDO and
also SB_I_NOEXEC and SB_I_NODEV. smackfs never holds executables or
device nodes.

Acked-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: Alexander Mikhalitsyn <alex@amutable.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 security/smack/smackfs.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index a72bc7fabea99..4a56bbeaeca37 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -25,6 +25,7 @@
 #include <linux/magic.h>
 #include <linux/mount.h>
 #include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 #include "smack.h"
 
 #define BEBITS	(sizeof(__be32) * 8)
@@ -2880,6 +2881,7 @@ static const struct fs_context_operations smk_context_ops = {
  */
 static int smk_init_fs_context(struct fs_context *fc)
 {
+	fc_init_pseudo(fc);
 	fc->ops = &smk_context_ops;
 	return 0;
 }

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 20/42] apparmor: use fc_init_pseudo() for apparmorfs
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (18 preceding siblings ...)
  2026-11-14 13:02 ` [PATCH RFC v2 19/42] smack: use fc_init_pseudo() for smackfs Christian Brauner
@ 2026-11-14 13:02 ` Christian Brauner
  2026-11-14 13:02 ` [PATCH RFC v2 21/42] nfsd: use fc_init_pseudo() Christian Brauner
                   ` (21 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:02 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable),
	Alexander Mikhalitsyn

Initialize apparmorfs as a pseudo filesystem. This raises SB_I_PSEUDO and
also SB_I_NOEXEC and SB_I_NODEV. apparmorfs never holds executables or
device nodes.

Reviewed-by: Alexander Mikhalitsyn <alex@amutable.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 security/apparmor/apparmorfs.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index a993664672173..351ea3a7120e3 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -21,6 +21,7 @@
 #include <linux/rcupdate.h>
 #include <linux/fs.h>
 #include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 #include <linux/poll.h>
 #include <linux/zstd.h>
 #include <linux/string.h>
@@ -263,6 +264,7 @@ static const struct fs_context_operations apparmorfs_context_ops = {
 
 static int apparmorfs_init_fs_context(struct fs_context *fc)
 {
+	fc_init_pseudo(fc);
 	fc->ops = &apparmorfs_context_ops;
 	return 0;
 }

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 21/42] nfsd: use fc_init_pseudo()
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (19 preceding siblings ...)
  2026-11-14 13:02 ` [PATCH RFC v2 20/42] apparmor: use fc_init_pseudo() for apparmorfs Christian Brauner
@ 2026-11-14 13:02 ` Christian Brauner
  2026-11-14 13:02 ` [PATCH RFC v2 22/42] sunrpc: use fc_init_pseudo() for rpc_pipefs Christian Brauner
                   ` (20 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:02 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable), Chuck Lever

Initialize the nfsd filesystem as a pseudo filesystem. This raises
SB_I_PSEUDO and also SB_I_NOEXEC and SB_I_NODEV. It never holds
executables or device nodes.

Acked-by: Chuck Lever <cel@kernel.org>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 fs/nfsd/nfsctl.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index f32311f2d7cf9..ce2666deddbd9 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -9,6 +9,7 @@
 #include <linux/namei.h>
 #include <linux/ctype.h>
 #include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 
 #include <linux/sunrpc/cache.h>
 #include <linux/sunrpc/svcsock.h>
@@ -1375,6 +1376,7 @@ static int nfsd_init_fs_context(struct fs_context *fc)
 {
 	put_user_ns(fc->user_ns);
 	fc->user_ns = get_user_ns(fc->net_ns->user_ns);
+	fc_init_pseudo(fc);
 	fc->ops = &nfsd_fs_context_ops;
 	return 0;
 }

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 22/42] sunrpc: use fc_init_pseudo() for rpc_pipefs
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (20 preceding siblings ...)
  2026-11-14 13:02 ` [PATCH RFC v2 21/42] nfsd: use fc_init_pseudo() Christian Brauner
@ 2026-11-14 13:02 ` Christian Brauner
  2026-11-14 13:02 ` [PATCH RFC v2 23/42] fuse: use fc_init_pseudo() for fusectl Christian Brauner
                   ` (19 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:02 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable),
	Alexander Mikhalitsyn

Initialize rpc_pipefs as a pseudo filesystem. This raises SB_I_PSEUDO and
also SB_I_NOEXEC and SB_I_NODEV. rpc_pipefs never holds executables or
device nodes.

Reviewed-by: Alexander Mikhalitsyn <alex@amutable.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 net/sunrpc/rpc_pipe.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 9d349cfbc4831..37277a6d24156 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -15,6 +15,7 @@
 #include <linux/pagemap.h>
 #include <linux/mount.h>
 #include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 #include <linux/namei.h>
 #include <linux/fsnotify.h>
 #include <linux/kernel.h>
@@ -1181,6 +1182,7 @@ static int rpc_init_fs_context(struct fs_context *fc)
 {
 	put_user_ns(fc->user_ns);
 	fc->user_ns = get_user_ns(fc->net_ns->user_ns);
+	fc_init_pseudo(fc);
 	fc->ops = &rpc_fs_context_ops;
 	return 0;
 }

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 23/42] fuse: use fc_init_pseudo() for fusectl
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (21 preceding siblings ...)
  2026-11-14 13:02 ` [PATCH RFC v2 22/42] sunrpc: use fc_init_pseudo() for rpc_pipefs Christian Brauner
@ 2026-11-14 13:02 ` Christian Brauner
  2026-11-14 13:02 ` [PATCH RFC v2 24/42] efivarfs: use fc_init_pseudo() Christian Brauner
                   ` (18 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:02 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable),
	Alexander Mikhalitsyn

Initialize fusectl as a pseudo filesystem. This raises SB_I_PSEUDO and
also SB_I_NOEXEC and SB_I_NODEV. fusectl never holds executables or
device nodes.

Reviewed-by: Alexander Mikhalitsyn <alex@amutable.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 fs/fuse/control.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/fs/fuse/control.c b/fs/fuse/control.c
index 21ffde596d611..4497362e7df06 100644
--- a/fs/fuse/control.c
+++ b/fs/fuse/control.c
@@ -10,6 +10,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 #include <linux/namei.h>
 
 #define FUSE_CTL_SUPER_MAGIC 0x65735543
@@ -334,6 +335,7 @@ static const struct fs_context_operations fuse_ctl_context_ops = {
 
 static int fuse_ctl_init_fs_context(struct fs_context *fsc)
 {
+	fc_init_pseudo(fsc);
 	fsc->ops = &fuse_ctl_context_ops;
 	return 0;
 }

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 24/42] efivarfs: use fc_init_pseudo()
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (22 preceding siblings ...)
  2026-11-14 13:02 ` [PATCH RFC v2 23/42] fuse: use fc_init_pseudo() for fusectl Christian Brauner
@ 2026-11-14 13:02 ` Christian Brauner
  2026-11-14 13:02 ` [PATCH RFC v2 25/42] pstore: " Christian Brauner
                   ` (17 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:02 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable),
	Alexander Mikhalitsyn

Initialize efivarfs as a pseudo filesystem. This raises SB_I_PSEUDO and
also SB_I_NOEXEC and SB_I_NODEV. efivarfs never holds executables or
device nodes.

Reviewed-by: Alexander Mikhalitsyn <alex@amutable.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 fs/efivarfs/super.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c
index 12746ced6dc63..e598d42c5f42c 100644
--- a/fs/efivarfs/super.c
+++ b/fs/efivarfs/super.c
@@ -8,6 +8,7 @@
 #include <linux/efi.h>
 #include <linux/fs.h>
 #include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 #include <linux/fs_parser.h>
 #include <linux/module.h>
 #include <linux/pagemap.h>
@@ -554,6 +555,7 @@ static int efivarfs_init_fs_context(struct fs_context *fc)
 	}
 
 	fc->s_fs_info = sfi;
+	fc_init_pseudo(fc);
 	fc->ops = &efivarfs_context_ops;
 
 	return 0;

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 25/42] pstore: use fc_init_pseudo()
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (23 preceding siblings ...)
  2026-11-14 13:02 ` [PATCH RFC v2 24/42] efivarfs: use fc_init_pseudo() Christian Brauner
@ 2026-11-14 13:02 ` Christian Brauner
  2026-11-14 13:02 ` [PATCH RFC v2 26/42] xenfs: " Christian Brauner
                   ` (16 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:02 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable),
	Alexander Mikhalitsyn

Initialize pstore as a pseudo filesystem. This raises SB_I_PSEUDO and
also SB_I_NOEXEC and SB_I_NODEV. pstore never holds executables or
device nodes.

Reviewed-by: Alexander Mikhalitsyn <alex@amutable.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 fs/pstore/inode.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c
index cf499ba727026..4658561cf90b7 100644
--- a/fs/pstore/inode.c
+++ b/fs/pstore/inode.c
@@ -18,6 +18,7 @@
 #include <linux/ramfs.h>
 #include <linux/fs_parser.h>
 #include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 #include <linux/sched.h>
 #include <linux/magic.h>
 #include <linux/pstore.h>
@@ -491,6 +492,7 @@ static int pstore_init_fs_context(struct fs_context *fc)
 	ctx->kmsg_bytes = kmsg_bytes;
 
 	fc->fs_private = ctx;
+	fc_init_pseudo(fc);
 	fc->ops = &pstore_context_ops;
 
 	return 0;

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 26/42] xenfs: use fc_init_pseudo()
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (24 preceding siblings ...)
  2026-11-14 13:02 ` [PATCH RFC v2 25/42] pstore: " Christian Brauner
@ 2026-11-14 13:02 ` Christian Brauner
  2026-11-14 13:02 ` [PATCH RFC v2 27/42] openpromfs: " Christian Brauner
                   ` (15 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:02 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable)

Initialize xenfs as a pseudo filesystem. This raises SB_I_PSEUDO and
also SB_I_NOEXEC and SB_I_NODEV. xenfs never holds executables or
device nodes.

SB_I_NOEXEC also refuses PROT_EXEC mappings. xenfs maps the xenstore
page and guest memory through privcmd, both data.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 drivers/xen/xenfs/super.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/xen/xenfs/super.c b/drivers/xen/xenfs/super.c
index 37ea7c5c03469..aba7d038ed735 100644
--- a/drivers/xen/xenfs/super.c
+++ b/drivers/xen/xenfs/super.c
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 #include <linux/magic.h>
 
 #include <xen/xen.h>
@@ -80,6 +81,7 @@ static const struct fs_context_operations xenfs_context_ops = {
 
 static int xenfs_init_fs_context(struct fs_context *fc)
 {
+	fc_init_pseudo(fc);
 	fc->ops = &xenfs_context_ops;
 	return 0;
 }

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 27/42] openpromfs: use fc_init_pseudo()
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (25 preceding siblings ...)
  2026-11-14 13:02 ` [PATCH RFC v2 26/42] xenfs: " Christian Brauner
@ 2026-11-14 13:02 ` Christian Brauner
  2026-11-14 13:02 ` [PATCH RFC v2 28/42] ocfs2: use fc_init_pseudo() for dlmfs Christian Brauner
                   ` (14 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:02 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable)

Initialize openpromfs as a pseudo filesystem. This raises SB_I_PSEUDO and
also SB_I_NOEXEC and SB_I_NODEV. openpromfs never holds executables or
device nodes.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 fs/openpromfs/inode.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
index fb8d84bdedfb2..6cd02d456bac9 100644
--- a/fs/openpromfs/inode.c
+++ b/fs/openpromfs/inode.c
@@ -10,6 +10,7 @@
 #include <linux/string.h>
 #include <linux/fs.h>
 #include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/seq_file.h>
@@ -419,6 +420,7 @@ static const struct fs_context_operations openpromfs_context_ops = {
 
 static int openpromfs_init_fs_context(struct fs_context *fc)
 {
+	fc_init_pseudo(fc);
 	fc->ops = &openpromfs_context_ops;
 	return 0;
 }

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 28/42] ocfs2: use fc_init_pseudo() for dlmfs
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (26 preceding siblings ...)
  2026-11-14 13:02 ` [PATCH RFC v2 27/42] openpromfs: " Christian Brauner
@ 2026-11-14 13:02 ` Christian Brauner
  2026-11-14 13:02 ` [PATCH RFC v2 29/42] s390/hypfs: use fc_init_pseudo() Christian Brauner
                   ` (13 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:02 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable)

Initialize dlmfs as a pseudo filesystem. This raises SB_I_PSEUDO and
also SB_I_NOEXEC and SB_I_NODEV. dlmfs never holds executables or
device nodes.

Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 fs/ocfs2/dlmfs/dlmfs.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c
index d3bfcada3e3bf..1789ec96dc130 100644
--- a/fs/ocfs2/dlmfs/dlmfs.c
+++ b/fs/ocfs2/dlmfs/dlmfs.c
@@ -21,6 +21,7 @@
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 #include <linux/pagemap.h>
 #include <linux/types.h>
 #include <linux/slab.h>
@@ -563,6 +564,7 @@ static const struct fs_context_operations dlmfs_context_ops = {
 
 static int dlmfs_init_fs_context(struct fs_context *fc)
 {
+	fc_init_pseudo(fc);
 	fc->ops = &dlmfs_context_ops;
 
 	return 0;

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 29/42] s390/hypfs: use fc_init_pseudo()
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (27 preceding siblings ...)
  2026-11-14 13:02 ` [PATCH RFC v2 28/42] ocfs2: use fc_init_pseudo() for dlmfs Christian Brauner
@ 2026-11-14 13:02 ` Christian Brauner
  2026-11-14 13:02 ` [PATCH RFC v2 30/42] powerpc/spufs: " Christian Brauner
                   ` (12 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:02 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable)

Initialize hypfs as a pseudo filesystem. This raises SB_I_PSEUDO and
also SB_I_NOEXEC and SB_I_NODEV. hypfs never holds executables or
device nodes.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 arch/s390/hypfs/inode.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
index 559b011e68800..8662169de477a 100644
--- a/arch/s390/hypfs/inode.c
+++ b/arch/s390/hypfs/inode.c
@@ -12,6 +12,7 @@
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 #include <linux/fs_parser.h>
 #include <linux/namei.h>
 #include <linux/vfs.h>
@@ -301,6 +302,7 @@ static int hypfs_init_fs_context(struct fs_context *fc)
 	sbi->gid = current_gid();
 
 	fc->s_fs_info = sbi;
+	fc_init_pseudo(fc);
 	fc->ops = &hypfs_context_ops;
 	return 0;
 }

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 30/42] powerpc/spufs: use fc_init_pseudo()
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (28 preceding siblings ...)
  2026-11-14 13:02 ` [PATCH RFC v2 29/42] s390/hypfs: use fc_init_pseudo() Christian Brauner
@ 2026-11-14 13:02 ` Christian Brauner
  2026-11-14 13:02 ` [PATCH RFC v2 31/42] usb: gadget: f_fs: " Christian Brauner
                   ` (11 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:02 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable)

Initialize spufs as a pseudo filesystem. This raises SB_I_PSEUDO and
also SB_I_NOEXEC and SB_I_NODEV. spufs never holds executables or
device nodes.

SB_I_NOEXEC also refuses PROT_EXEC mappings. The spufs files that can
be mapped expose local store and problem state areas of the SPU,
nothing the PPU executes.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 arch/powerpc/platforms/cell/spufs/inode.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index f066d9c7344d3..54b45932aecd2 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -11,6 +11,7 @@
 #include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 #include <linux/fs_parser.h>
 #include <linux/fsnotify.h>
 #include <linux/backing-dev.h>
@@ -741,6 +742,7 @@ static int spufs_init_fs_context(struct fs_context *fc)
 
 	fc->fs_private = ctx;
 	fc->s_fs_info = sbi;
+	fc_init_pseudo(fc);
 	fc->ops = &spufs_context_ops;
 	return 0;
 

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 31/42] usb: gadget: f_fs: use fc_init_pseudo()
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (29 preceding siblings ...)
  2026-11-14 13:02 ` [PATCH RFC v2 30/42] powerpc/spufs: " Christian Brauner
@ 2026-11-14 13:02 ` Christian Brauner
  2026-11-14 13:02 ` [PATCH RFC v2 32/42] usb: gadget: gadgetfs: " Christian Brauner
                   ` (10 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:02 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable)

Initialize functionfs as a pseudo filesystem. This raises SB_I_PSEUDO and
also SB_I_NOEXEC and SB_I_NODEV. functionfs never holds executables or
device nodes.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 drivers/usb/gadget/function/f_fs.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index c64a268e98a43..a6b3788399a56 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -15,6 +15,7 @@
 /* #define VERBOSE_DEBUG */
 
 #include <linux/blkdev.h>
+#include <linux/pseudo_fs.h>
 #include <linux/dma-buf.h>
 #include <linux/dma-fence.h>
 #include <linux/dma-resv.h>
@@ -2166,6 +2167,7 @@ static int ffs_fs_init_fs_context(struct fs_context *fc)
 	ctx->no_disconnect = false;
 
 	fc->fs_private = ctx;
+	fc_init_pseudo(fc);
 	fc->ops = &ffs_fs_context_ops;
 	return 0;
 }

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 32/42] usb: gadget: gadgetfs: use fc_init_pseudo()
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (30 preceding siblings ...)
  2026-11-14 13:02 ` [PATCH RFC v2 31/42] usb: gadget: f_fs: " Christian Brauner
@ 2026-11-14 13:02 ` Christian Brauner
  2026-11-14 13:02 ` [PATCH RFC v2 33/42] fs: add file_check_backing() Christian Brauner
                   ` (9 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:02 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable)

Initialize gadgetfs as a pseudo filesystem. This raises SB_I_PSEUDO and
also SB_I_NOEXEC and SB_I_NODEV. gadgetfs never holds executables or
device nodes.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 drivers/usb/gadget/legacy/inode.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
index 7f6d8460152f9..8490e5d0351e1 100644
--- a/drivers/usb/gadget/legacy/inode.c
+++ b/drivers/usb/gadget/legacy/inode.c
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/fs_context.h>
+#include <linux/pseudo_fs.h>
 #include <linux/pagemap.h>
 #include <linux/uts.h>
 #include <linux/wait.h>
@@ -2223,6 +2224,7 @@ static const struct fs_context_operations gadgetfs_context_ops = {
 
 static int gadgetfs_init_fs_context(struct fs_context *fc)
 {
+	fc_init_pseudo(fc);
 	fc->ops = &gadgetfs_context_ops;
 	return 0;
 }

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 33/42] fs: add file_check_backing()
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (31 preceding siblings ...)
  2026-11-14 13:02 ` [PATCH RFC v2 32/42] usb: gadget: gadgetfs: " Christian Brauner
@ 2026-11-14 13:02 ` Christian Brauner
  2026-11-14 13:40   ` sashiko-bot
  2026-11-14 13:02 ` [PATCH RFC v2 34/42] loop: refuse files on pseudo filesystems as backing files Christian Brauner
                   ` (8 subsequent siblings)
  41 siblings, 1 reply; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:02 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable)

Loop, zloop, the nvme target, the scsi target, fuse passthrough, the usb
mass storage gadget, erofs and acct all take a file from userspace and
use it as storage. Currently, each of them has its own idea of what to
check before using a file like that:

- loop and the gadget check for a regular file or a block device, the
  nvme target, the scsi target and zloop take any file type
- loop checks the open mode, the gadget checks FMODE_CAN_READ, the nvme
  target, the scsi target and zloop only check for ->read_iter() and
  ->write_iter()
- apart from acct which refuses procfs and sysfs files none of them
  cares whether the file is a kernel interface

Add a helper that does all of it in one place. It only accepts regular
files and, if the caller passes S_IFBLK, block devices. It refuses files
on pseudo filesystems. And it checks that the file is open for what the
caller is going to do with it and implements ->read_iter() for reading
and ->write_iter() for writing.

O_PATH files are refused unless the caller passes FMODE_PATH. That is
for callers that only need the path of the file. fuse passthrough is
one of them and has accepted O_PATH file descriptors since commit
efad7153bf93 ("fuse: allow O_PATH fd for FUSE_DEV_IOC_BACKING_OPEN").

Block devices are fine even though bdevfs is a pseudo filesystem. A
block device that userspace hands in is a device node on devtmpfs or
some other filesystem. Files on bdevfs only come from
bdev_file_open_by_*() and never end up here.

The pseudo filesystem check looks at the inode that actually provides
the data via d_real_inode(). overlayfs accepts sysfs, cgroup2, debugfs,
tracefs, configfs and securityfs as lower layers and reads of such an
overlayfs file are served by the file on the pseudo filesystem. Checking
the overlayfs inode would miss that.

Note that the file type is taken from the inode of the file and not from
the host of ->f_mapping like loop and the gadget do it. A driver can
point ->f_mapping somewhere else in ->open(). It makes no difference for
block devices as both inodes are block devices.

No functional changes. Nothing calls the helper yet.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 fs/read_write.c    | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/fs.h |  2 ++
 2 files changed, 50 insertions(+)

diff --git a/fs/read_write.c b/fs/read_write.c
index 6767283108991..cedbe654add65 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -866,6 +866,54 @@ static ssize_t do_loop_readv_writev(struct file *filp, struct iov_iter *iter,
 	return ret;
 }
 
+/**
+ * file_check_backing - check that the kernel can use a file as storage
+ * @file: file that userspace handed in
+ * @mode: FMODE_READ and/or FMODE_WRITE the kernel will do I/O with, or
+ *        FMODE_PATH if only the path of @file is used
+ * @type: S_IFBLK if a block device is fine as well, 0 otherwise
+ *
+ * Call this where a file from userspace is taken as a backing file. Only
+ * regular files and, if @type is S_IFBLK, block devices are storage. Files
+ * on pseudo filesystems are kernel interfaces and are refused. The file
+ * must be open for @mode and implement ->read_iter() for reading and
+ * ->write_iter() for writing. O_PATH files are only fine with FMODE_PATH.
+ *
+ * Return: 0 on success, -EBADF if @file isn't open for @mode, -EINVAL if it
+ * can't be used as storage.
+ */
+int file_check_backing(const struct file *file, fmode_t mode, umode_t type)
+{
+	fmode_t io = mode & (FMODE_READ | FMODE_WRITE);
+	/* Drivers may point ->f_mapping at something else. */
+	umode_t fmt = file_inode(file)->i_mode & S_IFMT;
+
+	/* O_PATH files are only fine for callers that just use the path. */
+	if ((file->f_mode & FMODE_PATH) && !(mode & FMODE_PATH))
+		return -EBADF;
+
+	if ((file->f_mode & io) != io)
+		return -EBADF;
+
+	if (fmt != S_IFREG && !(type == S_IFBLK && fmt == S_IFBLK))
+		return -EINVAL;
+
+	/* Look through stacking filesystems at the inode with the data. */
+	if (d_real_inode(file->f_path.dentry)->i_sb->s_iflags & SB_I_PSEUDO)
+		return -EINVAL;
+
+	if ((mode & FMODE_READ) &&
+	    (!(file->f_mode & FMODE_CAN_READ) || !file->f_op->read_iter))
+		return -EINVAL;
+
+	if ((mode & FMODE_WRITE) &&
+	    (!(file->f_mode & FMODE_CAN_WRITE) || !file->f_op->write_iter))
+		return -EINVAL;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(file_check_backing);
+
 ssize_t vfs_iocb_iter_read(struct file *file, struct kiocb *iocb,
 			   struct iov_iter *iter)
 {
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 99caef43ff3c4..b1c7ebafbadbe 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2553,6 +2553,8 @@ static inline const struct inode *file_user_inode(const struct file *f)
 	return file_inode(f);
 }
 
+int file_check_backing(const struct file *file, fmode_t mode, umode_t type);
+
 static inline struct file *file_clone_open(struct file *file)
 {
 	return dentry_open(&file->f_path, file->f_flags, file->f_cred);

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 34/42] loop: refuse files on pseudo filesystems as backing files
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (32 preceding siblings ...)
  2026-11-14 13:02 ` [PATCH RFC v2 33/42] fs: add file_check_backing() Christian Brauner
@ 2026-11-14 13:02 ` Christian Brauner
  2026-11-14 13:02 ` [PATCH RFC v2 35/42] zloop: refuse zone files on pseudo filesystems Christian Brauner
                   ` (7 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:02 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable)

Currently loop accepts any regular file that implements ->read_iter() as
a backing file and any that also implements ->write_iter() as a writable
one. That includes files on procfs, sysfs and other pseudo filesystems.
For example, /proc/kcore attaches read-only as a loop device the size of
the kernel's virtual address space, 64 PiB with 5-level paging. sysfs
attributes attach read-write as 4096 byte loop devices. Writing a block
to the loop device of /sys/kernel/mm/transparent_hugepage/enabled
changes the THP setting.

That's not just nonsensical, it can be abused. Loop calls ->read_iter()
and ->write_iter() of the backing file directly from its worker which
runs with kernel credentials. But pseudo files enforce part of their
access rules at read and write time against current. Dozens of sysfs
->show() and ->store() methods call capable(). Behind a loop device all
of these checks are done against the loop worker instead of the task
that opened the file. And setting up a loop device requires no
capabilities, only access to the device nodes. So on v7.4-rc1:

- uid 0 without any capabilities can't write to /sys/kernel/reboot/mode
  as mode_store() requires CAP_SYS_BOOT. Writing "warm" through a loop
  device works.

- uid 0 without any capabilities can't read the files in
  /sys/firmware/dmi/entries/*/ as dmi_sysfs_attr_show() requires
  CAP_SYS_ADMIN. Reading them through a loop device works.

- An unprivileged container that was handed a loop device can't change
  gro_flush_timeout of its own network devices as
  gro_flush_timeout_store() requires CAP_NET_ADMIN in the initial user
  namespace. Writing it through a loop device works.

The same goes for hard_offline_page, the md and sd attributes, rfkill
and others.

Refuse files on pseudo filesystems as loop backing files by switching to
file_check_backing(). Note that it looks through overlayfs so stacking
overlayfs on top of sysfs doesn't get around this.

The helper also does the file type, open mode and method checks that
loop did itself so far. The check for a regular file or a block device
now happens before the loop device is locked and it looks at the inode
of the file instead of the host of ->f_mapping. For regular files and
block devices both have the same type.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 drivers/block/loop.c | 17 ++++-------------
 1 file changed, 4 insertions(+), 13 deletions(-)

diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index c96e35c3ef423..776bd063f900c 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -492,7 +492,6 @@ static inline int is_loop_device(struct file *file)
 
 static int loop_validate_file(struct file *file, struct block_device *bdev)
 {
-	struct inode	*inode = file->f_mapping->host;
 	struct file	*f = file;
 
 	/* Avoid recursion */
@@ -510,8 +509,6 @@ static int loop_validate_file(struct file *file, struct block_device *bdev)
 		rmb();
 		f = l->lo_backing_file;
 	}
-	if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))
-		return -EINVAL;
 	return 0;
 }
 
@@ -528,16 +525,10 @@ static void loop_assign_backing_file(struct loop_device *lo, struct file *file)
 
 static int loop_check_backing_file(struct file *file)
 {
-	if (!(file->f_mode & FMODE_READ))
-		return -EBADF;
-
-	if (!file->f_op->read_iter)
-		return -EINVAL;
-
-	if ((file->f_mode & FMODE_WRITE) && !file->f_op->write_iter)
-		return -EINVAL;
-
-	return 0;
+	/* A backing file that isn't open for writing gives a read-only device. */
+	return file_check_backing(file,
+				  FMODE_READ | (file->f_mode & FMODE_WRITE),
+				  S_IFBLK);
 }
 
 /* loop sysfs attributes */

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 35/42] zloop: refuse zone files on pseudo filesystems
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (33 preceding siblings ...)
  2026-11-14 13:02 ` [PATCH RFC v2 34/42] loop: refuse files on pseudo filesystems as backing files Christian Brauner
@ 2026-11-14 13:02 ` Christian Brauner
  2026-11-14 13:02 ` [PATCH RFC v2 36/42] nvmet: refuse files on pseudo filesystems as namespace backing files Christian Brauner
                   ` (6 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:02 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable)

zloop opens its zone files by name below the base directory but a bind
mount can put any file there, including a procfs or sysfs file. Refuse
files on pseudo filesystems as zone files just like loop does by
switching to file_check_backing().

Note that the helper only accepts regular files. So far zloop took
anything with ->read_iter() and ->write_iter() as a zone file. That
includes character devices, FIFOs and block devices if someone put them
where zloop expects a zone file. Zone files are created by zloop itself
and zloop truncates them to size and to reset and finish zones which
only works for regular files. So refuse everything else.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 drivers/block/zloop.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/block/zloop.c b/drivers/block/zloop.c
index 65634a39b0bfc..6f79b9ddbbe00 100644
--- a/drivers/block/zloop.c
+++ b/drivers/block/zloop.c
@@ -1132,10 +1132,9 @@ static int zloop_init_zone(struct zloop_device *zlo, struct zloop_options *opts,
 		return PTR_ERR(zone->file);
 	}
 
-	if (!zone->file->f_op->read_iter || !zone->file->f_op->write_iter) {
-		ret = -EINVAL;
+	ret = file_check_backing(zone->file, FMODE_READ | FMODE_WRITE, 0);
+	if (ret)
 		goto out_fput;
-	}
 
 	if (zlo->block_size) {
 		ret = zloop_get_block_size(zlo, zone);

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 36/42] nvmet: refuse files on pseudo filesystems as namespace backing files
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (34 preceding siblings ...)
  2026-11-14 13:02 ` [PATCH RFC v2 35/42] zloop: refuse zone files on pseudo filesystems Christian Brauner
@ 2026-11-14 13:02 ` Christian Brauner
  2026-11-14 13:02 ` [PATCH RFC v2 37/42] target: fileio: refuse files on pseudo filesystems as " Christian Brauner
                   ` (5 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:02 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable)

The file backend takes any file that can be opened for reading and
writing. With buffered_io=1 that includes files on procfs or sysfs which
then get read and written by a kernel worker on behalf of the host.
Refuse files on pseudo filesystems just like loop does by switching to
file_check_backing().

Note that the helper only accepts regular files and block devices. A
block device ends up in the file backend when buffered_io is set. But
so far the file backend also took anything else with ->read_iter() and
->write_iter() such as character devices and FIFOs. The size of the
namespace is the size of the inode which is zero for all of them. So
such a namespace was unusable anyway. Refuse them.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 drivers/nvme/target/io-cmd-file.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/nvme/target/io-cmd-file.c b/drivers/nvme/target/io-cmd-file.c
index dfa8aa46188c8..2249ad3bb46d8 100644
--- a/drivers/nvme/target/io-cmd-file.c
+++ b/drivers/nvme/target/io-cmd-file.c
@@ -47,10 +47,9 @@ int nvmet_file_ns_enable(struct nvmet_ns *ns)
 		return ret;
 	}
 
-	if (!ns->file->f_op->read_iter || !ns->file->f_op->write_iter) {
-		ret = -EINVAL;
+	ret = file_check_backing(ns->file, FMODE_READ | FMODE_WRITE, S_IFBLK);
+	if (ret)
 		goto err;
-	}
 
 	nvmet_file_ns_revalidate(ns);
 

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 37/42] target: fileio: refuse files on pseudo filesystems as backing files
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (35 preceding siblings ...)
  2026-11-14 13:02 ` [PATCH RFC v2 36/42] nvmet: refuse files on pseudo filesystems as namespace backing files Christian Brauner
@ 2026-11-14 13:02 ` Christian Brauner
  2026-11-14 13:02 ` [PATCH RFC v2 38/42] fuse: refuse files on pseudo filesystems as passthrough " Christian Brauner
                   ` (4 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:02 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable), Sashiko

fd_dev_name can name any file including files on procfs or sysfs. The
initiator then gets to read and write kernel interfaces through the LUN
with kernel credentials. Refuse files on pseudo filesystems just like
loop does by switching to file_check_backing().

Do the same for the protection file. With DIF protection enabled the
fileio backend keeps the protection information in a second file. It is
named like the backing file with ".protection" appended and
fd_init_prot() opens it by path. Whatever that path leads to was taken
without any checks.

Note that the helper only accepts regular files and block devices as
backing file and only regular files as protection file. So far the
backing file could be anything with ->read_iter() and ->write_iter()
including character devices and FIFOs.

Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/sashiko-outbox-206765@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 drivers/target/target_core_file.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
index a5391e57e9aa5..c747cc4a647ff 100644
--- a/drivers/target/target_core_file.c
+++ b/drivers/target/target_core_file.c
@@ -145,8 +145,8 @@ static int fd_configure_device(struct se_device *dev)
 	}
 	fd_dev->fd_file = file;
 
-	if (!file->f_op->read_iter || !file->f_op->write_iter) {
-		pr_err("FILEIO: %s lacks ->read_iter or ->write_iter\n",
+	if (file_check_backing(file, FMODE_READ | FMODE_WRITE, S_IFBLK)) {
+		pr_err("FILEIO: %s can't be used as a backing file\n",
 		       fd_dev->fd_dev_name);
 		ret = -EINVAL;
 		goto fail;
@@ -861,6 +861,12 @@ static int fd_init_prot(struct se_device *dev)
 		ret = PTR_ERR(prot_file);
 		return ret;
 	}
+
+	if (file_check_backing(prot_file, FMODE_READ | FMODE_WRITE, 0)) {
+		pr_err("FILEIO: %s can't be used as a protection file\n", buf);
+		filp_close(prot_file, NULL);
+		return -EINVAL;
+	}
 	fd_dev->fd_prot_file = prot_file;
 
 	return 0;

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 38/42] fuse: refuse files on pseudo filesystems as passthrough backing files
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (36 preceding siblings ...)
  2026-11-14 13:02 ` [PATCH RFC v2 37/42] target: fileio: refuse files on pseudo filesystems as " Christian Brauner
@ 2026-11-14 13:02 ` Christian Brauner
  2026-11-14 13:40   ` sashiko-bot
  2026-11-14 13:02 ` [PATCH RFC v2 39/42] usb: gadget: f_mass_storage: refuse files on pseudo filesystems Christian Brauner
                   ` (3 subsequent siblings)
  41 siblings, 1 reply; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:02 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable)

The fuse server can register any regular file as a backing file. procfs
and binfmt_misc files are already refused by the stacking depth check as
both set s_stack_depth to FILESYSTEM_MAX_STACK_DEPTH. sysfs and the
other pseudo filesystems aren't. Reads and writes of the fuse file would
then be done on the pseudo file with the fuse server's credentials.
Refuse files on pseudo filesystems just like loop does.

Note that the backing file is only registered here and opened again for
every fuse file that uses it. Only its path is used and O_PATH file
descriptors are allowed since commit efad7153bf93 ("fuse: allow O_PATH
fd for FUSE_DEV_IOC_BACKING_OPEN"). So pass FMODE_PATH to
file_check_backing() to keep them working.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 fs/fuse/backing.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c
index 8c21a8a74efb9..7527f3ecb90dc 100644
--- a/fs/fuse/backing.c
+++ b/fs/fuse/backing.c
@@ -147,6 +147,10 @@ static int fuse_backing_open_file(struct fuse_conn *fc, struct fuse_backing *fb,
 		if (inode->i_sb->s_stack_depth >= fc->max_stack_depth)
 			return -ELOOP;
 
+		err = file_check_backing(file, FMODE_PATH, 0);
+		if (err)
+			return err;
+
 		fb->type = FUSE_BACKING_PATH;
 		fb->path = file->f_path;
 		path_get(&fb->path);

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 39/42] usb: gadget: f_mass_storage: refuse files on pseudo filesystems
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (37 preceding siblings ...)
  2026-11-14 13:02 ` [PATCH RFC v2 38/42] fuse: refuse files on pseudo filesystems as passthrough " Christian Brauner
@ 2026-11-14 13:02 ` Christian Brauner
  2026-11-14 13:02 ` [PATCH RFC v2 40/42] erofs: refuse files on pseudo filesystems as backing files Christian Brauner
                   ` (2 subsequent siblings)
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:02 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable)

fsg_lun_open() takes any regular file as the backing file of a LUN. The
file-storage kthread then reads and writes it with kernel_read() and
kernel_write() on behalf of the USB host. With a procfs or sysfs file
behind a LUN the host gets to read and write kernel interfaces with
kernel credentials. Refuse files on pseudo filesystems just like loop
does by switching to file_check_backing().

The helper also does the file type and readability checks. So the
messages for an unsuitable backing file become one. It looks at the
inode of the file instead of the host of ->f_mapping. For regular files
and block devices both have the same type. It also wants ->read_iter()
where FMODE_CAN_READ was enough so far. But kernel_read() never worked
without ->read_iter() anyway.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 drivers/usb/gadget/function/storage_common.c | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/gadget/function/storage_common.c b/drivers/usb/gadget/function/storage_common.c
index 75831f2c7abeb..af0c37a9fe029 100644
--- a/drivers/usb/gadget/function/storage_common.c
+++ b/drivers/usb/gadget/function/storage_common.c
@@ -205,23 +205,18 @@ int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
 	if (!(filp->f_mode & FMODE_WRITE))
 		ro = 1;
 
-	inode = filp->f_mapping->host;
-	if ((!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))) {
-		LINFO(curlun, "invalid file type: %s\n", filename);
-		goto out;
-	}
-
 	/*
 	 * If we can't read the file, it's no good.
 	 * If we can't write the file, use it read-only.
 	 */
-	if (!(filp->f_mode & FMODE_CAN_READ)) {
-		LINFO(curlun, "file not readable: %s\n", filename);
+	if (file_check_backing(filp, FMODE_READ, S_IFBLK)) {
+		LINFO(curlun, "invalid backing file: %s\n", filename);
 		goto out;
 	}
 	if (!(filp->f_mode & FMODE_CAN_WRITE))
 		ro = 1;
 
+	inode = filp->f_mapping->host;
 	size = i_size_read(inode);
 	if (size < 0) {
 		LINFO(curlun, "unable to find file size: %s\n", filename);

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 40/42] erofs: refuse files on pseudo filesystems as backing files
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (38 preceding siblings ...)
  2026-11-14 13:02 ` [PATCH RFC v2 39/42] usb: gadget: f_mass_storage: refuse files on pseudo filesystems Christian Brauner
@ 2026-11-14 13:02 ` Christian Brauner
  2026-11-14 13:02 ` [PATCH RFC v2 41/42] acct: refuse files on pseudo filesystems Christian Brauner
  2026-11-14 13:02 ` [PATCH RFC v2 42/42] selftests/filesystems: add backing file tests for pseudo files Christian Brauner
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:02 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable)

File-backed mounts take any regular file as the image and the same goes
for the extra devices of such a mount. erofs reads them with the
credentials of the mounter so this doesn't hand out anything the mounter
couldn't read anyway. But files on pseudo filesystems aren't images.
Refuse them just like loop does.

file_check_backing() also checks that the file is open for reading. So
a source file descriptor that erofs can't read from fails the mount
right away instead of on the first read.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 fs/erofs/super.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/fs/erofs/super.c b/fs/erofs/super.c
index ce05557bd9983..517a289b9395c 100644
--- a/fs/erofs/super.c
+++ b/fs/erofs/super.c
@@ -158,7 +158,7 @@ static int erofs_init_device(struct erofs_buf *buf, struct super_block *sb,
 		if (!erofs_is_fileio_mode(sbi)) {
 			dif->dax_dev = fs_dax_get_by_bdev(file_bdev(file),
 					&dif->dax_part_off, NULL, NULL);
-		} else if (!S_ISREG(file_inode(file)->i_mode)) {
+		} else if (file_check_backing(file, FMODE_READ, 0)) {
 			fput(file);
 			return -EINVAL;
 		}
@@ -835,6 +835,9 @@ static int erofs_file_get_tree(struct fs_context *fc)
 {
 	struct erofs_sb_info *sbi = fc->s_fs_info;
 
+	if (file_check_backing(sbi->dif0.file, FMODE_READ, 0))
+		return invalfc(fc, "source can't be used as a backing file");
+
 	if (!test_opt(&sbi->opt, SUPERBLOCK_SHARE))
 		return get_tree_nodev(fc, erofs_fc_fill_super);
 

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 41/42] acct: refuse files on pseudo filesystems
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (39 preceding siblings ...)
  2026-11-14 13:02 ` [PATCH RFC v2 40/42] erofs: refuse files on pseudo filesystems as backing files Christian Brauner
@ 2026-11-14 13:02 ` Christian Brauner
  2026-11-14 13:02 ` [PATCH RFC v2 42/42] selftests/filesystems: add backing file tests for pseudo files Christian Brauner
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:02 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable),
	Alexander Mikhalitsyn

acct(2) already refuses to write its records to files on kernel internal
filesystems and to procfs and sysfs files. It recognizes the latter two
by FS_USERNS_MOUNT_RESTRICTED which misses every other pseudo
filesystem. So a cgroup2 or binfmt_misc file is accepted as the
accounting file.

The records are written with the credentials of whoever turned on
accounting so this isn't abusable the way loop is. But files on pseudo
filesystems aren't a place to store accounting records. Use
file_check_backing() to refuse all of them.

SB_NOUSER doesn't need to be checked separately anymore. It is only
raised by pseudo filesystems and by tmpfs instances that are either
kernel internal or can't be mounted.

Suggested-by: Alexander Mikhalitsyn <alex@amutable.com>
Link: https://lore.kernel.org/r/ae189903d4cda27130317a9312d94b53d07415ba.camel@amutable.com
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 kernel/acct.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/kernel/acct.c b/kernel/acct.c
index c440d43479ca5..0c502f778fde0 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -245,11 +245,11 @@ static int acct_on(const char __user *name)
 		return -EACCES;
 
 	/* Exclude kernel internal filesystems. */
-	if (file_inode(file)->i_sb->s_flags & (SB_NOUSER | SB_KERNMOUNT))
+	if (file_inode(file)->i_sb->s_flags & SB_KERNMOUNT)
 		return -EINVAL;
 
-	/* Exclude procfs and sysfs. */
-	if (file_inode(file)->i_sb->s_type->fs_flags & FS_USERNS_MOUNT_RESTRICTED)
+	/* Exclude pseudo filesystems. */
+	if (file_check_backing(file, 0, 0))
 		return -EINVAL;
 
 	if (!(file->f_mode & FMODE_CAN_WRITE))

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH RFC v2 42/42] selftests/filesystems: add backing file tests for pseudo files
  2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
                   ` (40 preceding siblings ...)
  2026-11-14 13:02 ` [PATCH RFC v2 41/42] acct: refuse files on pseudo filesystems Christian Brauner
@ 2026-11-14 13:02 ` Christian Brauner
  41 siblings, 0 replies; 45+ messages in thread
From: Christian Brauner @ 2026-11-14 13:02 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-block, linux-kernel, linux-nvme, Alexander Viro, Jan Kara,
	linux-scsi, target-devel, driver-core, linux-mm, bpf,
	linux-security-module, selinux, apparmor, linux-nfs, netdev,
	fuse-devel, linux-efi, xen-devel, ocfs2-devel, linux-s390,
	linuxppc-dev, linux-usb, Amir Goldstein, linux-erofs,
	linux-kselftest, Christian Brauner (Amutable)

Add tests that files on pseudo filesystems can't be used as storage:

- a procfs file attached read-only to a loop device
- sysfs files attached read-only and read-write to a loop device
- a sysfs file behind a lower-only overlayfs attached to a loop device
- a symlink and a magic link to a sysfs file attached to a loop device
- a procfs file as the backing file of an nvme target namespace
- a procfs file as the backing file and as the protection file of a
  fileio device of the scsi target
- a procfs file as a zloop zone file
- a sysfs file as the backing file of a usb mass storage gadget LUN
- a sysfs file as the source of a file-backed erofs mount

Add tests that FIFOs and character devices can't be used as storage by
loop, the nvme target, the fileio backend and zloop either.

And make sure that a memfd and another loop device still work as loop
backing files, that a regular file and a block device still work for
the nvme target and the fileio backend and that loop refuses a backing
file that isn't open for reading.

The nvme target test uses buffered_io as asked for in [1]. Most pseudo
files can't be opened with O_DIRECT and the test would pass without
ever reaching the check.

[1]: https://lore.kernel.org/r/71f76e5e-ce24-4a71-863a-169ad262c510@gmail.com

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 tools/testing/selftests/filesystems/.gitignore     |   1 +
 tools/testing/selftests/filesystems/Makefile       |   2 +-
 tools/testing/selftests/filesystems/config         |  14 +
 .../selftests/filesystems/pseudo_backing_test.c    | 570 +++++++++++++++++++++
 4 files changed, 586 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/filesystems/.gitignore b/tools/testing/selftests/filesystems/.gitignore
index cf79000e4092a..8df38eabb1252 100644
--- a/tools/testing/selftests/filesystems/.gitignore
+++ b/tools/testing/selftests/filesystems/.gitignore
@@ -7,3 +7,4 @@ kernfs_test
 idmapped_tmpfile
 ustat_test
 rw_hint_test
+pseudo_backing_test
diff --git a/tools/testing/selftests/filesystems/Makefile b/tools/testing/selftests/filesystems/Makefile
index fbd5c27505ef5..0ebb9005bcd28 100644
--- a/tools/testing/selftests/filesystems/Makefile
+++ b/tools/testing/selftests/filesystems/Makefile
@@ -2,7 +2,7 @@
 
 CFLAGS += $(KHDR_INCLUDES)
 TEST_GEN_PROGS := devpts_pts anon_inode_test kernfs_test fclog ustat_test rw_hint_test
-TEST_GEN_PROGS += idmapped_tmpfile
+TEST_GEN_PROGS += idmapped_tmpfile pseudo_backing_test
 TEST_GEN_PROGS_EXTENDED := dnotify_test
 
 include ../lib.mk
diff --git a/tools/testing/selftests/filesystems/config b/tools/testing/selftests/filesystems/config
index 9f45bc493a30a..9375164f46d70 100644
--- a/tools/testing/selftests/filesystems/config
+++ b/tools/testing/selftests/filesystems/config
@@ -6,3 +6,17 @@ CONFIG_NET=y
 CONFIG_NET_NS=y
 CONFIG_INET=y
 CONFIG_SYSFS=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_OVERLAY_FS=y
+CONFIG_TMPFS=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_EROFS_FS=y
+CONFIG_EROFS_FS_BACKED_BY_FILE=y
+CONFIG_NVME_TARGET=y
+CONFIG_TARGET_CORE=y
+CONFIG_TCM_FILEIO=y
+CONFIG_BLK_DEV_ZONED=y
+CONFIG_BLK_DEV_ZONED_LOOP=y
diff --git a/tools/testing/selftests/filesystems/pseudo_backing_test.c b/tools/testing/selftests/filesystems/pseudo_backing_test.c
new file mode 100644
index 0000000000000..04315655e0587
--- /dev/null
+++ b/tools/testing/selftests/filesystems/pseudo_backing_test.c
@@ -0,0 +1,570 @@
+// SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sched.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <linux/loop.h>
+#include <linux/magic.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
+
+#include "kselftest_harness.h"
+#include "wrappers.h"
+
+/*
+ * Put @fd behind a free loop device. The device is set up with
+ * LO_FLAGS_AUTOCLEAR and goes away again when it is closed here.
+ */
+static int loop_attach(int fd, bool rw, char *dev, size_t len)
+{
+	struct loop_config cfg = {};
+	int ctl, nr, lfd, ret = 0;
+
+	ctl = open("/dev/loop-control", O_RDWR | O_CLOEXEC);
+	if (ctl < 0)
+		return -errno;
+	nr = ioctl(ctl, LOOP_CTL_GET_FREE);
+	if (nr < 0)
+		ret = -errno;
+	close(ctl);
+	if (ret)
+		return ret;
+
+	snprintf(dev, len, "/dev/loop%d", nr);
+	lfd = open(dev, (rw ? O_RDWR : O_RDONLY) | O_CLOEXEC);
+	if (lfd < 0)
+		return -errno;
+
+	cfg.fd = fd;
+	cfg.info.lo_flags = LO_FLAGS_AUTOCLEAR;
+	if (!rw)
+		cfg.info.lo_flags |= LO_FLAGS_READ_ONLY;
+	if (ioctl(lfd, LOOP_CONFIGURE, &cfg)) {
+		ret = -errno;
+		close(lfd);
+	} else {
+		ret = lfd;
+	}
+	return ret;
+}
+
+static int attach_path(const char *path, bool rw)
+{
+	char dev[PATH_MAX];
+	int fd, ret;
+
+	fd = open(path, (rw ? O_RDWR : O_RDONLY) | O_CLOEXEC);
+	if (fd < 0)
+		return -errno;
+	ret = loop_attach(fd, rw, dev, sizeof(dev));
+	close(fd);
+	if (ret >= 0) {
+		close(ret);
+		ret = 0;
+	}
+	return ret;
+}
+
+static bool can_use_loop(void)
+{
+	return geteuid() == 0 && access("/dev/loop-control", R_OK | W_OK) == 0;
+}
+
+/* A pseudo file that can be opened for reading and writing. */
+#define PSEUDO_FILE "/proc/sys/kernel/hostname"
+
+static int write_string(const char *path, const char *buf)
+{
+	int fd, ret = 0;
+
+	fd = open(path, O_WRONLY | O_CLOEXEC);
+	if (fd < 0)
+		return -errno;
+	if (write(fd, buf, strlen(buf)) < 0)
+		ret = -errno;
+	close(fd);
+	return ret;
+}
+
+static int create_file(const char *path)
+{
+	int fd, ret = 0;
+
+	fd = open(path, O_RDWR | O_CREAT | O_CLOEXEC, 0600);
+	if (fd < 0)
+		return -errno;
+	if (ftruncate(fd, 1 << 20))
+		ret = -errno;
+	close(fd);
+	return ret;
+}
+
+/* Loop device on top of a memfd. It goes away when the fd is closed. */
+static int create_loop_device(char *dev, size_t len)
+{
+	int fd, lfd;
+
+	fd = memfd_create("pseudo_backing_test", MFD_CLOEXEC);
+	if (fd < 0)
+		return -errno;
+	if (ftruncate(fd, 1 << 20)) {
+		lfd = -errno;
+		close(fd);
+		return lfd;
+	}
+	lfd = loop_attach(fd, true, dev, len);
+	close(fd);
+	return lfd;
+}
+
+/* Private tmpfs on /tmp for files, links and FIFOs. */
+static int setup_tmp(void)
+{
+	if (unshare(CLONE_NEWNS))
+		return -errno;
+	if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL))
+		return -errno;
+	if (mount("tmpfs", "/tmp", "tmpfs", 0, NULL))
+		return -errno;
+	return 0;
+}
+
+TEST(memfd_backing_file)
+{
+	char dev[PATH_MAX];
+	int fd, lfd;
+
+	if (!can_use_loop())
+		SKIP(return, "loop devices unavailable");
+
+	fd = memfd_create("pseudo_backing_test", MFD_CLOEXEC);
+	ASSERT_GE(fd, 0);
+	ASSERT_EQ(ftruncate(fd, 1 << 20), 0);
+
+	lfd = loop_attach(fd, true, dev, sizeof(dev));
+	ASSERT_GE(lfd, 0);
+	EXPECT_EQ(close(lfd), 0);
+	EXPECT_EQ(close(fd), 0);
+}
+
+TEST(loop_device_backing_file)
+{
+	char dev[PATH_MAX], dev2[PATH_MAX];
+	int fd, lfd, bfd, lfd2;
+
+	if (!can_use_loop())
+		SKIP(return, "loop devices unavailable");
+
+	fd = memfd_create("pseudo_backing_test", MFD_CLOEXEC);
+	ASSERT_GE(fd, 0);
+	ASSERT_EQ(ftruncate(fd, 1 << 20), 0);
+	lfd = loop_attach(fd, true, dev, sizeof(dev));
+	ASSERT_GE(lfd, 0);
+
+	/* A block device stays fine as a backing file. */
+	bfd = open(dev, O_RDWR | O_CLOEXEC);
+	ASSERT_GE(bfd, 0);
+	lfd2 = loop_attach(bfd, true, dev2, sizeof(dev2));
+	ASSERT_GE(lfd2, 0);
+
+	EXPECT_EQ(close(lfd2), 0);
+	EXPECT_EQ(close(bfd), 0);
+	EXPECT_EQ(close(lfd), 0);
+	EXPECT_EQ(close(fd), 0);
+}
+
+TEST(write_only_backing_file)
+{
+	char dev[PATH_MAX], path[PATH_MAX];
+	int fd, wfd, lfd;
+
+	if (!can_use_loop())
+		SKIP(return, "loop devices unavailable");
+
+	fd = memfd_create("pseudo_backing_test", MFD_CLOEXEC);
+	ASSERT_GE(fd, 0);
+	ASSERT_EQ(ftruncate(fd, 1 << 20), 0);
+
+	/* Loop reads from its backing file so it must be open for reading. */
+	snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
+	wfd = open(path, O_WRONLY | O_CLOEXEC);
+	ASSERT_GE(wfd, 0);
+
+	lfd = loop_attach(wfd, true, dev, sizeof(dev));
+	if (lfd >= 0)
+		close(lfd);
+	EXPECT_EQ(lfd, -EBADF);
+	EXPECT_EQ(close(wfd), 0);
+	EXPECT_EQ(close(fd), 0);
+}
+
+TEST(procfs_backing_file)
+{
+	if (!can_use_loop())
+		SKIP(return, "loop devices unavailable");
+
+	ASSERT_EQ(attach_path("/proc/cpuinfo", false), -EINVAL);
+}
+
+TEST(sysfs_backing_file)
+{
+	if (!can_use_loop())
+		SKIP(return, "loop devices unavailable");
+
+	ASSERT_EQ(attach_path("/sys/kernel/warn_count", false), -EINVAL);
+
+	if (access("/sys/kernel/reboot/mode", F_OK))
+		SKIP(return, "no /sys/kernel/reboot/mode");
+	ASSERT_EQ(attach_path("/sys/kernel/reboot/mode", true), -EINVAL);
+}
+
+TEST(overlayfs_on_sysfs_backing_file)
+{
+	if (!can_use_loop())
+		SKIP(return, "loop devices unavailable");
+
+	ASSERT_EQ(unshare(CLONE_NEWNS), 0);
+	ASSERT_EQ(mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL), 0);
+	ASSERT_EQ(mount("tmpfs", "/tmp", "tmpfs", 0, NULL), 0);
+	ASSERT_EQ(mkdir("/tmp/empty", 0755), 0);
+	ASSERT_EQ(mkdir("/tmp/merged", 0755), 0);
+
+	/* A lower-only overlayfs serves reads from sysfs. */
+	if (mount("overlay", "/tmp/merged", "overlay", MS_RDONLY,
+		  "lowerdir=/sys/kernel:/tmp/empty"))
+		SKIP(return, "no overlayfs on top of sysfs: %s", strerror(errno));
+
+	ASSERT_EQ(attach_path("/tmp/merged/warn_count", false), -EINVAL);
+}
+
+TEST(link_to_sysfs_backing_file)
+{
+	char path[PATH_MAX];
+	int fd;
+
+	if (!can_use_loop())
+		SKIP(return, "loop devices unavailable");
+
+	ASSERT_EQ(setup_tmp(), 0);
+
+	/* Links are followed before the file is checked. */
+	ASSERT_EQ(symlink("/sys/kernel/warn_count", "/tmp/link"), 0);
+	EXPECT_EQ(attach_path("/tmp/link", false), -EINVAL);
+
+	fd = open("/sys/kernel/warn_count", O_RDONLY | O_CLOEXEC);
+	ASSERT_GE(fd, 0);
+	snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
+	EXPECT_EQ(attach_path(path, false), -EINVAL);
+	EXPECT_EQ(close(fd), 0);
+}
+
+TEST(special_file_backing_file)
+{
+	if (!can_use_loop())
+		SKIP(return, "loop devices unavailable");
+
+	ASSERT_EQ(setup_tmp(), 0);
+	ASSERT_EQ(mkfifo("/tmp/fifo", 0600), 0);
+
+	/* Only regular files and block devices are storage. */
+	EXPECT_EQ(attach_path("/tmp/fifo", true), -EINVAL);
+	EXPECT_EQ(attach_path("/dev/null", true), -EINVAL);
+}
+
+#define CONFIGFS_DIR "/sys/kernel/config"
+#define GADGET_DIR CONFIGFS_DIR "/usb_gadget/pseudo_backing_test"
+#define MASS_STORAGE_DIR GADGET_DIR "/functions/mass_storage.0"
+
+TEST(usb_mass_storage_backing_file)
+{
+	const char *path = "/sys/kernel/warn_count";
+	struct statfs sfs;
+	ssize_t ret;
+	int fd, err;
+
+	if (geteuid())
+		SKIP(return, "needs root");
+
+	/* Mounting configfs on top of itself fails with EBUSY. */
+	if (statfs(CONFIGFS_DIR, &sfs) || sfs.f_type != CONFIGFS_MAGIC) {
+		ASSERT_EQ(unshare(CLONE_NEWNS), 0);
+		ASSERT_EQ(mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL), 0);
+		if (mount("configfs", CONFIGFS_DIR, "configfs", 0, NULL))
+			SKIP(return, "no configfs: %s", strerror(errno));
+	}
+
+	if (mkdir(GADGET_DIR, 0755))
+		SKIP(return, "no usb gadget configfs: %s", strerror(errno));
+	if (mkdir(MASS_STORAGE_DIR, 0755)) {
+		err = errno;
+		rmdir(GADGET_DIR);
+		SKIP(return, "no usb mass storage function: %s", strerror(err));
+	}
+
+	/* Writing the path opens the LUN's backing file right away. */
+	fd = open(MASS_STORAGE_DIR "/lun.0/file", O_WRONLY | O_CLOEXEC);
+	EXPECT_GE(fd, 0);
+	if (fd >= 0) {
+		ret = write(fd, path, strlen(path));
+		err = errno;
+		EXPECT_EQ(ret, -1);
+		EXPECT_EQ(err, EINVAL);
+		EXPECT_EQ(close(fd), 0);
+	}
+
+	EXPECT_EQ(rmdir(MASS_STORAGE_DIR), 0);
+	EXPECT_EQ(rmdir(GADGET_DIR), 0);
+}
+
+/* Mounting configfs on top of itself fails with EBUSY. */
+static int setup_configfs(void)
+{
+	struct statfs sfs;
+
+	if (!statfs(CONFIGFS_DIR, &sfs) && sfs.f_type == CONFIGFS_MAGIC)
+		return 0;
+	if (mount("configfs", CONFIGFS_DIR, "configfs", 0, NULL))
+		return -errno;
+	return 0;
+}
+
+#define NVMET_SUBSYS_DIR CONFIGFS_DIR "/nvmet/subsystems/pseudo_backing_test"
+#define NVMET_NS_DIR NVMET_SUBSYS_DIR "/namespaces/1"
+
+static int nvmet_enable(const char *path)
+{
+	int ret;
+
+	ret = write_string(NVMET_NS_DIR "/device_path", path);
+	if (ret)
+		return ret;
+	ret = write_string(NVMET_NS_DIR "/enable", "1");
+	if (!ret)
+		ret = write_string(NVMET_NS_DIR "/enable", "0");
+	return ret;
+}
+
+TEST(nvmet_backing_file)
+{
+	char dev[PATH_MAX];
+	int lfd;
+
+	if (!can_use_loop())
+		SKIP(return, "loop devices unavailable");
+
+	ASSERT_EQ(setup_tmp(), 0);
+	if (setup_configfs())
+		SKIP(return, "no configfs");
+	if (mkdir(NVMET_SUBSYS_DIR, 0755))
+		SKIP(return, "no nvme target: %s", strerror(errno));
+	EXPECT_EQ(mkdir(NVMET_NS_DIR, 0755), 0);
+
+	/* With direct I/O most pseudo files already fail to open. */
+	EXPECT_EQ(write_string(NVMET_NS_DIR "/buffered_io", "1"), 0);
+
+	EXPECT_EQ(create_file("/tmp/file"), 0);
+	EXPECT_EQ(mkfifo("/tmp/fifo", 0600), 0);
+
+	lfd = create_loop_device(dev, sizeof(dev));
+	EXPECT_GE(lfd, 0);
+
+	/* With buffered_io the file backend handles block devices as well. */
+	EXPECT_EQ(nvmet_enable("/tmp/file"), 0);
+	if (lfd >= 0)
+		EXPECT_EQ(nvmet_enable(dev), 0);
+	EXPECT_EQ(nvmet_enable(PSEUDO_FILE), -EINVAL);
+	EXPECT_EQ(nvmet_enable("/tmp/fifo"), -EINVAL);
+	EXPECT_EQ(nvmet_enable("/dev/null"), -EINVAL);
+
+	if (lfd >= 0)
+		EXPECT_EQ(close(lfd), 0);
+	EXPECT_EQ(rmdir(NVMET_NS_DIR), 0);
+	EXPECT_EQ(rmdir(NVMET_SUBSYS_DIR), 0);
+}
+
+#define FILEIO_HBA_DIR CONFIGFS_DIR "/target/core/fileio_4711"
+#define FILEIO_DEV_DIR FILEIO_HBA_DIR "/pseudo_backing_test"
+#define FILEIO_PROT_TYPE FILEIO_DEV_DIR "/attrib/pi_prot_type"
+
+static int fileio_create(const char *path)
+{
+	char buf[PATH_MAX];
+	int ret;
+
+	if (mkdir(FILEIO_DEV_DIR, 0755))
+		return -errno;
+	snprintf(buf, sizeof(buf), "fd_dev_name=%s,fd_dev_size=1048576", path);
+	ret = write_string(FILEIO_DEV_DIR "/control", buf);
+	if (!ret)
+		ret = write_string(FILEIO_DEV_DIR "/enable", "1");
+	if (ret)
+		rmdir(FILEIO_DEV_DIR);
+	return ret;
+}
+
+static int fileio_enable(const char *path)
+{
+	int ret;
+
+	ret = fileio_create(path);
+	if (!ret)
+		rmdir(FILEIO_DEV_DIR);
+	return ret;
+}
+
+TEST(fileio_backing_file)
+{
+	char dev[PATH_MAX];
+	int lfd;
+
+	if (!can_use_loop())
+		SKIP(return, "loop devices unavailable");
+
+	ASSERT_EQ(setup_tmp(), 0);
+	if (setup_configfs())
+		SKIP(return, "no configfs");
+	if (mkdir(FILEIO_HBA_DIR, 0755))
+		SKIP(return, "no fileio backend: %s", strerror(errno));
+
+	EXPECT_EQ(create_file("/tmp/file"), 0);
+	EXPECT_EQ(mkfifo("/tmp/fifo", 0600), 0);
+
+	lfd = create_loop_device(dev, sizeof(dev));
+	EXPECT_GE(lfd, 0);
+
+	EXPECT_EQ(fileio_enable("/tmp/file"), 0);
+	if (lfd >= 0)
+		EXPECT_EQ(fileio_enable(dev), 0);
+	EXPECT_EQ(fileio_enable(PSEUDO_FILE), -EINVAL);
+	EXPECT_EQ(fileio_enable("/tmp/fifo"), -EINVAL);
+	EXPECT_EQ(fileio_enable("/dev/null"), -EINVAL);
+
+	if (lfd >= 0)
+		EXPECT_EQ(close(lfd), 0);
+	EXPECT_EQ(rmdir(FILEIO_HBA_DIR), 0);
+}
+
+TEST(fileio_protection_file)
+{
+	int ret;
+
+	if (geteuid())
+		SKIP(return, "needs root");
+
+	ASSERT_EQ(setup_tmp(), 0);
+	if (setup_configfs())
+		SKIP(return, "no configfs");
+	if (mkdir(FILEIO_HBA_DIR, 0755))
+		SKIP(return, "no fileio backend: %s", strerror(errno));
+
+	EXPECT_EQ(create_file("/tmp/file"), 0);
+	ret = fileio_create("/tmp/file");
+	EXPECT_EQ(ret, 0);
+	if (!ret) {
+		/* Turning on DIF opens the protection file. */
+		EXPECT_EQ(symlink(PSEUDO_FILE, "/tmp/file.protection"), 0);
+		EXPECT_EQ(write_string(FILEIO_PROT_TYPE, "1"), -EINVAL);
+		EXPECT_EQ(unlink("/tmp/file.protection"), 0);
+
+		EXPECT_EQ(mkfifo("/tmp/file.protection", 0600), 0);
+		EXPECT_EQ(write_string(FILEIO_PROT_TYPE, "1"), -EINVAL);
+		EXPECT_EQ(unlink("/tmp/file.protection"), 0);
+
+		EXPECT_EQ(write_string(FILEIO_PROT_TYPE, "1"), 0);
+		EXPECT_EQ(write_string(FILEIO_PROT_TYPE, "0"), 0);
+		EXPECT_EQ(rmdir(FILEIO_DEV_DIR), 0);
+	}
+
+	EXPECT_EQ(rmdir(FILEIO_HBA_DIR), 0);
+}
+
+#define ZLOOP_CTL "/dev/zloop-control"
+
+/* One conventional and two sequential zones in /tmp/@id. */
+static int zloop_add(int id)
+{
+	char buf[128];
+	int ret;
+
+	snprintf(buf, sizeof(buf),
+		 "add id=%d,base_dir=/tmp,capacity_mb=12,zone_size_mb=4,conv_zones=1,buffered_io",
+		 id);
+	ret = write_string(ZLOOP_CTL, buf);
+	if (!ret) {
+		snprintf(buf, sizeof(buf), "remove id=%d", id);
+		ret = write_string(ZLOOP_CTL, buf);
+	}
+	return ret;
+}
+
+TEST(zloop_zone_file)
+{
+	if (geteuid())
+		SKIP(return, "needs root");
+	if (access(ZLOOP_CTL, W_OK))
+		SKIP(return, "no zloop");
+
+	ASSERT_EQ(setup_tmp(), 0);
+
+	ASSERT_EQ(mkdir("/tmp/4711", 0755), 0);
+	EXPECT_EQ(zloop_add(4711), 0);
+
+	/* Zone files that already exist are used as they are. */
+	ASSERT_EQ(mkdir("/tmp/4712", 0755), 0);
+	ASSERT_EQ(symlink(PSEUDO_FILE, "/tmp/4712/seq-000001"), 0);
+	EXPECT_EQ(zloop_add(4712), -EINVAL);
+
+	ASSERT_EQ(mkdir("/tmp/4713", 0755), 0);
+	ASSERT_EQ(mkfifo("/tmp/4713/seq-000001", 0600), 0);
+	EXPECT_EQ(zloop_add(4713), -EINVAL);
+}
+
+TEST(erofs_backing_file)
+{
+	bool refused = false;
+	char buf[256];
+	int fsfd, ret, err;
+	ssize_t n;
+
+	if (geteuid())
+		SKIP(return, "needs root");
+
+	fsfd = sys_fsopen("erofs", FSOPEN_CLOEXEC);
+	if (fsfd < 0)
+		SKIP(return, "no erofs: %s", strerror(errno));
+
+	ASSERT_EQ(sys_fsconfig(fsfd, FSCONFIG_SET_STRING, "source",
+			       "/sys/kernel/warn_count", 0), 0);
+	ret = sys_fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0);
+	err = errno;
+	if (ret && err == ENOTBLK) {
+		close(fsfd);
+		SKIP(return, "no file-backed erofs mounts");
+	}
+	ASSERT_EQ(ret, -1);
+	ASSERT_EQ(err, EINVAL);
+
+	/*
+	 * Something that isn't an erofs image fails with EINVAL as well so
+	 * check that the source itself was refused.
+	 */
+	while ((n = read(fsfd, buf, sizeof(buf) - 1)) > 0) {
+		buf[n] = '\0';
+		if (strstr(buf, "backing file"))
+			refused = true;
+	}
+	EXPECT_TRUE(refused);
+	EXPECT_EQ(close(fsfd), 0);
+}
+
+TEST_HARNESS_MAIN

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* Re: [PATCH RFC v2 33/42] fs: add file_check_backing()
  2026-11-14 13:02 ` [PATCH RFC v2 33/42] fs: add file_check_backing() Christian Brauner
@ 2026-11-14 13:40   ` sashiko-bot
  0 siblings, 0 replies; 45+ messages in thread
From: sashiko-bot @ 2026-11-14 13:40 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-nvme, Alexander Viro, Jan Kara, linux-scsi, target-devel,
	linux-mm, bpf, linux-security-module, selinux, apparmor,
	linux-efi, linux-s390, linux-usb, Amir Goldstein, Chuck Lever,
	Jeff Layton, Anna Schumaker, Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Mark Fasheh,
	Joel Becker, Joseph Qi

Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [Medium] fs: unverified overlayfs O_PATH d_real_inode() call in
  file_check_backing()
--

commit 12b4c886c3329cc29a995a96a698923b0df5e8e2
Author: Christian Brauner <brauner@kernel.org>

fs: add file_check_backing()

This commit adds file_check_backing() to validate whether a userspace
file can be used as backing storage by checking its open mode, file type,
pseudo-filesystem status, and read/write iterator operations.

> diff --git a/fs/read_write.c b/fs/read_write.c
> index 6767283108991..cedbe654add65 100644
> --- a/fs/read_write.c
> +++ b/fs/read_write.c
> @@ -866,6 +866,54 @@ static ssize_t do_loop_readv_writev(struct file *filp, struct iov_iter *iter,
>  	return ret;
>  }
>  
[ ... ]
> +int file_check_backing(const struct file *file, fmode_t mode, umode_t type)
> +{
> +	fmode_t io = mode & (FMODE_READ | FMODE_WRITE);
> +	/* Drivers may point ->f_mapping at something else. */
> +	umode_t fmt = file_inode(file)->i_mode & S_IFMT;
> +
> +	/* O_PATH files are only fine for callers that just use the path. */
> +	if ((file->f_mode & FMODE_PATH) && !(mode & FMODE_PATH))
> +		return -EBADF;
> +
> +	if ((file->f_mode & io) != io)
> +		return -EBADF;
> +
> +	if (fmt != S_IFREG && !(type == S_IFBLK && fmt == S_IFBLK))
> +		return -EINVAL;
> +
> +	/* Look through stacking filesystems at the inode with the data. */
> +	if (d_real_inode(file->f_path.dentry)->i_sb->s_iflags & SB_I_PSEUDO)
> +		return -EINVAL;

[Severity: Medium]
Can calling d_real_inode() on an O_PATH overlayfs file trigger a WARN(1)
in ovl_d_real() and bypass the SB_I_PSEUDO check?

When a file is opened with O_PATH, do_dentry_open() returns before calling
f->f_op->open(), so ovl_open() -> ovl_verify_lowerdata() has not run yet.
When file_check_backing() is called with FMODE_PATH, d_real_inode()
invokes ovl_d_real(dentry, D_REAL_DATA):

fs/overlayfs/super.c:ovl_d_real() {
    ...
	err = ovl_verify_lowerdata(dentry);
	if (err)
		goto bug;
	lower = ovl_dentry_lowerdata(dentry);
	if (!lower)
		goto bug;

real_lower:
	/* Handle recursion into stacked lower fs */
	return d_real(lower, type);

bug:
	WARN(1, "%s(%pd4, %d): real dentry not found\n", __func__, dentry, type);
	return dentry;
}

On an overlayfs mount using data-only lower layers or metacopy verity
validation, ovl_verify_lowerdata() takes the inode lock interruptibly via
ovl_inode_lock_interruptible() and performs lazy lowerdata lookup or
verity checks.  If that fails (for instance with -EINTR from a pending
signal, or -ENOENT / -EIO), ovl_d_real() fires WARN(1) and returns the
overlayfs dentry itself.  Because the overlayfs superblock does not set
SB_I_PSEUDO, the check here passes even if the underlying data layer is a
pseudo filesystem.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261114-work-loop-pseudo-v2-0-98639a2286fb@kernel.org?part=33

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH RFC v2 38/42] fuse: refuse files on pseudo filesystems as passthrough backing files
  2026-11-14 13:02 ` [PATCH RFC v2 38/42] fuse: refuse files on pseudo filesystems as passthrough " Christian Brauner
@ 2026-11-14 13:40   ` sashiko-bot
  0 siblings, 0 replies; 45+ messages in thread
From: sashiko-bot @ 2026-11-14 13:40 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Jann Horn, Chris Mason, Josef Bacik, Christoph Hellwig,
	linux-nvme, Alexander Viro, Jan Kara, linux-scsi, target-devel,
	linux-mm, bpf, linux-security-module, selinux, apparmor,
	linux-efi, linux-s390, linux-usb, Amir Goldstein, Chuck Lever,
	Jeff Layton, Anna Schumaker, Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Mark Fasheh,
	Joel Becker, Joseph Qi

Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [Medium] fuse: file_check_backing() with FMODE_PATH on unverified ovl
  dentry fails open
--

commit 3377a8521784786f7f79c18bd3aafabd17e04633
Author: Christian Brauner <brauner@kernel.org>

fuse: refuse files on pseudo filesystems as passthrough backing files

This commit calls file_check_backing() in fuse_backing_open_file() to
reject regular files on pseudo filesystems when registering FUSE
passthrough backing files.

> diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c
> index 8c21a8a74efb9..7527f3ecb90dc 100644
> --- a/fs/fuse/backing.c
> +++ b/fs/fuse/backing.c
> @@ -147,6 +147,10 @@ static int fuse_backing_open_file(struct fuse_conn *fc, struct fuse_backing *fb,
>  		if (inode->i_sb->s_stack_depth >= fc->max_stack_depth)
>  			return -ELOOP;
>  
> +		err = file_check_backing(file, FMODE_PATH, 0);
> +		if (err)
> +			return err;

[Severity: Medium]
Can calling file_check_backing() with FMODE_PATH on an O_PATH overlayfs
file trigger a WARN(1) in ovl_d_real() and fail open?

Unlike a normal open(), opening with O_PATH returns from do_dentry_open()
before calling ovl_open() -> ovl_verify_lowerdata().  When
file_check_backing() then calls d_real_inode(file->f_path.dentry),
ovl_d_real() runs ovl_verify_lowerdata() on the unverified dentry:

fs/overlayfs/super.c:ovl_d_real() {
    ...
	err = ovl_verify_lowerdata(dentry);
	if (err)
		goto bug;
	lower = ovl_dentry_lowerdata(dentry);
	if (!lower)
		goto bug;

real_lower:
	/* Handle recursion into stacked lower fs */
	return d_real(lower, type);

bug:
	WARN(1, "%s(%pd4, %d): real dentry not found\n", __func__, dentry, type);
	return dentry;
}

If ovl_verify_lowerdata() fails (for example, -ENOENT on a broken metacopy
redirect in a data-only lower layer, -EIO on verity failure, or -EINTR in
ovl_maybe_lookup_lowerdata()), ovl_d_real() hits the WARN(1) and returns
the overlayfs dentry itself.  Because the overlayfs superblock does not
have SB_I_PSEUDO set, file_check_backing() returns 0 and registers
fb->path; if the failure was transient, a later fuse_passthrough_open() ->
backing_file_open() -> vfs_open() -> ovl_open() can still resolve the
lower data dentry on a pseudo filesystem.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261114-work-loop-pseudo-v2-0-98639a2286fb@kernel.org?part=38

^ permalink raw reply	[flat|nested] 45+ messages in thread

end of thread, other threads:[~2026-11-14 13:41 UTC | newest]

Thread overview: 45+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-14 13:01 [PATCH RFC v2 00/42] fs: don't use pseudo filesystem files as storage Christian Brauner
2026-11-14 13:01 ` [PATCH RFC v2 01/42] loop: refuse backing files that aren't open for reading Christian Brauner
2026-11-14 13:01 ` [PATCH RFC v2 02/42] nvmet: check that the file backend supports ->{read,write}_iter Christian Brauner
2026-11-14 13:01 ` [PATCH RFC v2 03/42] target: fileio: check that the backing file " Christian Brauner
2026-11-14 13:01 ` [PATCH RFC v2 04/42] fs: add SB_I_PSEUDO Christian Brauner
2026-11-14 13:01 ` [PATCH RFC v2 05/42] kernfs: use fc_init_pseudo() Christian Brauner
2026-11-14 13:01 ` [PATCH RFC v2 06/42] proc: " Christian Brauner
2026-11-14 13:01 ` [PATCH RFC v2 07/42] binfmt_misc: " Christian Brauner
2026-11-14 13:01 ` [PATCH RFC v2 08/42] mqueue: " Christian Brauner
2026-11-14 13:01 ` [PATCH RFC v2 09/42] bpf: use fc_init_pseudo() for bpffs Christian Brauner
2026-11-14 13:01 ` [PATCH RFC v2 10/42] nullfs: use fc_init_pseudo() Christian Brauner
2026-11-14 13:01 ` [PATCH RFC v2 11/42] failfs: " Christian Brauner
2026-11-14 13:01 ` [PATCH RFC v2 12/42] rust_binderfs: " Christian Brauner
2026-11-14 13:01 ` [PATCH RFC v2 13/42] devpts: " Christian Brauner
2026-11-14 13:01 ` [PATCH RFC v2 14/42] debugfs: " Christian Brauner
2026-11-14 13:01 ` [PATCH RFC v2 15/42] tracefs: " Christian Brauner
2026-11-14 13:01 ` [PATCH RFC v2 16/42] configfs: " Christian Brauner
2026-11-14 13:01 ` [PATCH RFC v2 17/42] securityfs: " Christian Brauner
2026-11-14 13:01 ` [PATCH RFC v2 18/42] selinux: use fc_init_pseudo() for selinuxfs Christian Brauner
2026-11-14 13:02 ` [PATCH RFC v2 19/42] smack: use fc_init_pseudo() for smackfs Christian Brauner
2026-11-14 13:02 ` [PATCH RFC v2 20/42] apparmor: use fc_init_pseudo() for apparmorfs Christian Brauner
2026-11-14 13:02 ` [PATCH RFC v2 21/42] nfsd: use fc_init_pseudo() Christian Brauner
2026-11-14 13:02 ` [PATCH RFC v2 22/42] sunrpc: use fc_init_pseudo() for rpc_pipefs Christian Brauner
2026-11-14 13:02 ` [PATCH RFC v2 23/42] fuse: use fc_init_pseudo() for fusectl Christian Brauner
2026-11-14 13:02 ` [PATCH RFC v2 24/42] efivarfs: use fc_init_pseudo() Christian Brauner
2026-11-14 13:02 ` [PATCH RFC v2 25/42] pstore: " Christian Brauner
2026-11-14 13:02 ` [PATCH RFC v2 26/42] xenfs: " Christian Brauner
2026-11-14 13:02 ` [PATCH RFC v2 27/42] openpromfs: " Christian Brauner
2026-11-14 13:02 ` [PATCH RFC v2 28/42] ocfs2: use fc_init_pseudo() for dlmfs Christian Brauner
2026-11-14 13:02 ` [PATCH RFC v2 29/42] s390/hypfs: use fc_init_pseudo() Christian Brauner
2026-11-14 13:02 ` [PATCH RFC v2 30/42] powerpc/spufs: " Christian Brauner
2026-11-14 13:02 ` [PATCH RFC v2 31/42] usb: gadget: f_fs: " Christian Brauner
2026-11-14 13:02 ` [PATCH RFC v2 32/42] usb: gadget: gadgetfs: " Christian Brauner
2026-11-14 13:02 ` [PATCH RFC v2 33/42] fs: add file_check_backing() Christian Brauner
2026-11-14 13:40   ` sashiko-bot
2026-11-14 13:02 ` [PATCH RFC v2 34/42] loop: refuse files on pseudo filesystems as backing files Christian Brauner
2026-11-14 13:02 ` [PATCH RFC v2 35/42] zloop: refuse zone files on pseudo filesystems Christian Brauner
2026-11-14 13:02 ` [PATCH RFC v2 36/42] nvmet: refuse files on pseudo filesystems as namespace backing files Christian Brauner
2026-11-14 13:02 ` [PATCH RFC v2 37/42] target: fileio: refuse files on pseudo filesystems as " Christian Brauner
2026-11-14 13:02 ` [PATCH RFC v2 38/42] fuse: refuse files on pseudo filesystems as passthrough " Christian Brauner
2026-11-14 13:40   ` sashiko-bot
2026-11-14 13:02 ` [PATCH RFC v2 39/42] usb: gadget: f_mass_storage: refuse files on pseudo filesystems Christian Brauner
2026-11-14 13:02 ` [PATCH RFC v2 40/42] erofs: refuse files on pseudo filesystems as backing files Christian Brauner
2026-11-14 13:02 ` [PATCH RFC v2 41/42] acct: refuse files on pseudo filesystems Christian Brauner
2026-11-14 13:02 ` [PATCH RFC v2 42/42] selftests/filesystems: add backing file tests for pseudo files Christian Brauner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox