PT-2026-90483 · Linux · Linux
CVE-2026-89767
·
Published
2026-09-11
·
Updated
2026-09-11
None
No severity ratings or metrics are available. When they are, we'll update the corresponding info on the page.
In the Linux kernel, the following vulnerability has been resolved:
ovl: fix double end creating() on the casefold-mismatch path
ovl create real() releases the new dentry twice when the casefold
consistency check fails. The S IFDIR branch calls end creating() and
sets err, then falls through to the common out: label which calls
end creating() on the same dentry again:
case S IFDIR:
newdentry = ovl do mkdir(ofs, dir, newdentry, attr->mode);
err = PTR ERR OR ZERO(newdentry);
if (!err && ofs->casefold != ovl dentry casefolded(newdentry)) {
pr warn ratelimited(...);
end creating(newdentry); /* first */
err = -EINVAL;
}
break;
...
if (err)
goto out;
...out:
if (err) {
end creating(newdentry); /* second, same dentry */
return ERR PTR(err);
}
end creating() is end dirop(), which does inode unlock() on the parent
and dput() on the dentry, so the parent directory's i rwsem is unlocked
twice and the dentry is put twice. The second unlock releases a lock
that is not held, which is what wedges every later creation under that
parent, and the second dput() drops a reference that was never taken.
The branch was added by commit dfc7da402ccc ("ovl: Check for casefold
consistency when creating new dentries") as a bare dput(), which already
released the reference twice; commit fe497f0759e0 ("VFS: change
vfs mkdir() to unlock on failure.") converted both sites to
end creating(), adding the double unlock.
This is reachable by an unprivileged user. The casefold consistency of
the layers is validated at mount time in ovl parse layer(), and again on
every lookup in ovl lookup single(), but ofs->workdir is the internal
"work" subdirectory created inside the user-supplied workdir, and that
subdirectory is not re-checked. Marking it casefolded after the mount
therefore makes every ovl create temp() inherit the wrong state - and
that path reaches ovl create real() through ovl start creating temp(),
which uses start creating() with a generated name and so never runs the
lookup-time check.
unshare -Urm
mount -t tmpfs -o casefold=utf8-12.1.0 tmpfs mnt
mkdir -p mnt/lower/d mnt/upper mnt/work mnt/merged
mount -t overlay ovl -o lowerdir=mnt/lower,
upperdir=mnt/upper,workdir=mnt/work mnt/merged
chattr +F mnt/work/work
mkdir mnt/merged/d/sub # directory copy-up
overlayfs: wrong inherited casefold (work/#5)
and the next copy-up blocks forever on the parent's i rwsem:
mkdir D start creating+0x65/0xb0
ovl start creating temp+0xb0/0xe0 [overlay]
ovl create temp+0xa3/0x1d0 [overlay]
ovl copy up one+0x1f1c/0x21c0 [overlay]
ovl copy up flags+0xf5/0x140 [overlay]
ovl create object+0xb7/0x220 [overlay]
ovl mkdir+0x23/0x40 [overlay]
Drop the end creating() from the branch and let out: own the cleanup,
which is what every other error path in this function already does.
Found an issue in the description? Have something to add? Feel free to write us 👾
Related Identifiers
Affected Products
Linux