Re: [RFC PATCH] fs: allow opening overlayfs/erofs layers through O_ALT
From: Christian Brauner <brauner@kernel.org>
Date: 2026-07-22 15:44:14
Also in:
linux-fsdevel, linux-unionfs
This is a prototype patch. Needs to be split up! 1) O_ALT / OPEN_TREE_ALT These open an alternative namespace rooted at dfd - instead of resolving the path in the real filesystem, it resolves it in a virtual tree that exposes metadata about that file. This is intended to provide an alternative to adding new ioctls: - provides structured namespace - allows accessing data through fs ops Could call this O_META, but O_ALT seems more generic and there could be uses beyond metadata (e.g. seekable, in-place decompression). This has been discussed previously: https://lore.kernel.org/all/CAHk-=wjzLmMRf=QG-n+1HnxWCx4KTQn9+OhVvUSJ=ZCQd6Y1WA@mail.gmail.com/ (local) 2/a) s_op.get_options(), sb_add_option() .get_options() is a generic version of .show_options(). After converting everyting to seq_show_option() the rest is trivial: - change first arg to "struct sb_opt_ctx *ctx" - replace "seq_show_option(m" with "sb_add_option(ctx" 2/b) sb_add_option_path() The last arg is "struct path *". This is for options that designate a path (e.g. stacked fs layers). Will allow opening the path through O_ALT. Ignored when retrieving the string value of the option. 3) MNT_CLONABLE Allow an internal mount to be cloned. Nsfs and pidfs are already special cased, move these over to this flag. Also allow overlayfs layers to be cloned. 4) mnt.mnt_devname -> sb.s_devname This is historical thing, mnt_devname was just copied when cloning the mount, sharing the same value for all mounts belonging to a super block. 5) mount options in metafs Support retrieving mount options through O_ALT opens: mount/options/OPT/N: Nth instance of OPT This will be a symlink pointint to the option value. If the option refers to a path (as per 2/b), following the symlink jumps to the given path. At this point only overlayfs and erofs are converted. Signed-off-by: Miklos Szeredi <redacted>
We've added a primary set of apis to retrieve mount options. I really
dislike the idea of introducing a completely orthogonal layer to do the
same thing (or more) and also make it filesystem based while at it.
The other proposal of moving it into procfs doesn't lower the creepiness
factor. It just paints it a different color. My objection is to the
shape of this not where the entry point lives.
metafs is the same thing in a different color. I really don't see any
way that we would ever merge something like this.
Like, I'm fine having an api where we can use open_tree() to see through
into underlying layers and given the right permission pull a mount out
of it. That seems something we can potentially do.
There's a few issues on top of that. O_ALT is silently ignored unless
you spell the open as openat(dirfd, relative, ...). path_init() only
looks at LOOKUP_ALT in the dirfd branch. open("/abs", O_ALT) and
openat(AT_FDCWD, "rel", O_ALT) fall straight through and open the real
file.
The layer symlinks are an unchecked jump into internal, out-of-namespace
mounts. Following mount/options/upperdir/0 ends in nd_jump_link(). That
doesn't do permission checks and no mnt_ns check.
The overlay upper/lower layers are internal mounts with no mountpoint in
any namespace. So any unprivileged process that can open the overlay
root gets an O_PATH handle to a layer root it has no search-permission
path to and on a mount outside its namespace and can then use it as a
dirfd.
Pulling the mount out is gated by CAP_SYS_ADMIN, but the handle and the
traversal are not. That's exactly Andy's "whose creds" question, it's
inherent to the design, and the procfs variant has it too.
get_options() forks ->show_options() permanently. It's added
alongside the existing method and mnt_show_options() now tries one then
the other.
That leaves the tree split forever or commits us to a flag-day
conversion of everything. The new thig is also heavie and loses the
seq_file overflow-retry. All so the 99% of filesystems that will never
expose a path option can carry a more complicated interface.
mnt_devname to s_devname move is a behavioral change. alloc_super()
records fc->source only on the sb-create path in sget_fc(). Sharing an
existing sb path never updates it. For filesystems that share a
superblock across mounts every mount now reports the first mounter's
source in /proc/self/mountinfo and statmount().
And the smaller details really show how inelegant this model is and why
Al and I have opposed it multiple times before. Scalar options are
modeled as symlinks and non-path options are dangling links whose
readlink still returns the value while for path options readlink returns
the option string but following the link jumps somewhere else entirely.
erofs silently emits a valueless "fsoffset" if the kasprintf fails.
There's no Kconfig at all. metafs is obj-y and kern_mount()ed in every
kernel. I don't want to see this leak into every container going forward
at all with the same hackishness to make it somehow safe in containers.
Like I said before: I'm fine with an API where we can use open_tree() to
see through into underlying layers, and given the right permission pull
a mount out of it. That is a narrow, checkable primitive and it needs
none of this. No new open flag, no second ->show_options, no metafs, no
mnt_devname surgery. That part we can potentially do.
But a generic metadata interface layered on top of yet another magic
filesystem whether it's mounted or hidden behind procfs I feel very
strongly about. I also have great difficulty seeing Al supporting it.
--