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

CVE-2026-89767

Affected Products

Linux