CVE-2026-98539: fs/ntfs3: use d_instantiate_new() in ntfs_create_inode() and murder syzbot's "WARNING in do_new_mount" saga
In the Linux kernel, the following vulnerability has been resolved:
fs/ntfs3: use dinstantiatenew() in ntfscreateinode() and murder syzbot's "WARNING in donewmount" saga
ntfscreateinode() creates a new inode via ntfsnewinode(). It hashes it with insertinodelocked() and so it's marked as INEW until unlocknewinode().
ntfs 3 calls dinstantiate() in between though... Since the dentry was already hashed by the lookup before the create any path walk finds it without touching the parent's irwsem and so can lock the inode.
If the inode is a directory unlocknewinode() calls lockdepannotateinodemutexkey() and marks irwsem with the imutexdirkey class.
That resets the count and the owner of a lock somebody else may already hold by now...
syzbot has been spamming us with the same godforsaken bug
"WARNING in donewmount"
since 2023. I can't take it anymore so I went looking. Afaict, syzbot's executor chdirs into a freshly mounted ntfs3 image, creates a directory and then mounts some pseudofs on it. Everytime the mkdir() takes longer than syzbot waits mount() runs concurrently:
mkdir("./sys") mount(NULL, "./sys", "sysfs") ntfscreateinode() dinstantiate() userpathat() finds the dentry dolockmount() inodelock(inode) namespacelock() unlocknewinode() lockdepannotateinodemutexkey() initrwsem(&inode->irwsem) unlockmount() inodeunlock(inode)
The mount side then releases a lock that according to the rwsem nobody holds:
DEBUGRWSEMSWARNON((rwsemowner(sem) != current) && ...): count = 0x0, magic = 0xffff888043a854e8, owner = 0x0, curr 0xffff888000244880, list empty WARNING: CPU: 0 PID: 5346 at kernel/locking/rwsem.c:1368 upwrite Call Trace: inodeunlock include/linux/fs.h:877 [inline] unlockmount fs/namespace.c:2892 [inline] donewmountfc fs/namespace.c:3828 [inline] donewmount+0x777/0xa40 fs/namespace.c:3887
On PREEMPTRT the same thing shows up as
DEBUGLOCKSWARNON(rtmutexowner(lock) != current) WARNING: kernel/locking/rtmutexcommon.h:193 at rtmutexslowunlock
The upwrite() underflows the reset count. A following inodelock() on that directory then never returns. A path walk into the new directory racing with the mkdir() corrupts the lock the same way via inodelockshared() in lookupslow().
Switch to dinstantiatenew() and drop the trailing unlocknewinode(). All error paths bail out before that point with INEW still set and keep using discardnewinode().
May we never see this fscking bug report again.
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Compensating control
In fs/ntfs3, update ntfs_create_inode() to use d_instantiate_new() instead of d_instantiate() and remove the trailing unlock_new_inode() call.