Re: [PATCH] ovl: disable index and nfs_export with different lower idmaps
From: Amir Goldstein
Date: Sat Sep 12 2026 - 13:01:34 EST
On Fri, Sep 11, 2026 at 9:43 PM Jérémy Jean
<Jeremy.Jean@xxxxxxxxxxxxxxxxx> wrote:
>
> Overlay file handles identify a backing filesystem, but not the lower
> mount used to decode it. If lower layers share a superblock and use
> different idmaps, a file handle can decode through the wrong layer and
> initialize the overlay inode with the wrong owner.
>
> Disable index and nfs_export when this layout is found. Both features
> rely on persistent lower file handles, which cannot distinguish
> same-superblock layers with different idmaps. Without them, OverlayFS
> uses normal path lookup and keeps the layer chosen during lookup.
>
> Fixes: bc70682a497c ("ovl: support idmapped layers")
> Assisted-by: Codex:gpt-5
> Signed-off-by: Jérémy Jean <Jeremy.Jean@xxxxxxxxxxxxxxxxx>
Hi Jeremy,
Nice catch.
Do you have a reproducer which shows privilege escalation?
Please add test cases to selftests/filesystems/overlayfs/idmapped_mounts.c.
> ---
> fs/overlayfs/super.c | 26 +++++++++++++++++++++++++-
> 1 file changed, 25 insertions(+), 1 deletion(-)
>
> diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
> index bd0a3f9039d2..00e1b9fccb4f 100644
> --- a/fs/overlayfs/super.c
> +++ b/fs/overlayfs/super.c
> @@ -944,6 +944,22 @@ static bool ovl_lower_uuid_ok(struct ovl_fs *ofs, const uuid_t *uuid)
> return true;
> }
>
> +static bool ovl_lower_mnt_idmap_mismatch(struct ovl_fs *ofs,
> + const struct path *path)
> +{
> + unsigned int i;
> +
> + for (i = 1; i < ofs->numlayer; i++) {
> + struct vfsmount *mnt = ofs->layers[i].mnt;
> +
> + if (mnt->mnt_sb == path->mnt->mnt_sb &&
> + mnt_idmap(mnt) != mnt_idmap(path->mnt))
> + return true;
> + }
I don't like introducing this potential quadratic search on all ovl mounts.
I prefer to store a lower_idmap field per ovl_sb, which is set to the idmap
of the first lower layer which is found to have this ovl_sb and then
ovl_lower_mnt_idmap_mismatch() only needs to match it.
> +
> + return false;
> +}
> +
> /* Get a unique fsid for the layer */
> static int ovl_get_fsid(struct ovl_fs *ofs, const struct path *path)
> {
> @@ -956,8 +972,16 @@ static int ovl_get_fsid(struct ovl_fs *ofs, const struct path *path)
> bool warn = false;
>
> for (i = 0; i < ofs->numfs; i++) {
> - if (ofs->fs[i].sb == sb)
> + if (ofs->fs[i].sb == sb) {
> + if ((ofs->config.index || ofs->config.nfs_export) &&
> + ovl_lower_mnt_idmap_mismatch(ofs, path)) {
> + ofs->config.index = false;
> + ofs->config.nfs_export = false;
> + pr_warn("different idmaps in same lower fs '%pd2', falling back to index=off,nfs_export=off.\n",
> + path->dentry);
> + }
I *think* there is no justification to disabling index, only nfs_export.
It matters because some distros enable index by default and not
breaking hardlinks on copy up is not a "feature" it is a correctness issue.
While as you write "both features rely on persistent lower file handles"
I cannot think of any case where index=on alone uses decode of
file handles from the wrong layer leads to bypass permission checks on
lower inode -
The index to lower inode is created only on copy up of a lower inode
that has hardlinks.
This copy up is performed on an overlayfs dentry that was composed by
ovl_lookup() through the correct lower layers.
Copy-up reads uid/gid through the lower dentry's layer idmap and writes them
onto the upper/index inode through the upper layer idmap.
After that, overlay ownership comes from the upper, not from lower inode.
It's probably worth adding some test cases to the idmapped_mounts
selftest to cover copy up.
If the same lower inode is visible from different lower layers
with different idmaps I do not consider that overlayfs job to deal with.
Whichever lower inode is copied up first is the metadata that will be copied
to upper inode and to the overlayfs in-core inode.
TBH, I'm not even sure if there is a legit case for overlayfs mount
of lower layers with same sb and mismatching mntid, but there could be.
CC Christian for his thoughts.
Thanks,
Amir.