Look up another CVE · open CVE-2026-90131 in the interactive tracker
CVE-2026-90131
ntfs: serialize resident iomap reads with mrec_lock
Published 2026-09-17 (31 days ago) by the Linux kernel CNA. Subsystem fs/ntfs. Debian urgency: unimportant.
What to do, per Debian release
Debian's own status for CVE-2026-90131 in every release this site tracks, and what each one means in practice. Every status below is the one the Debian Security Team publishes for this CVE. source
| Release | Status | Version | What this means |
|---|---|---|---|
| Debian 12bookworm | not affected | 6.1.190-1 | Nothing to do. bookworm never shipped the vulnerable code. |
| Debian 13trixie | not affected | 6.12.113-1 | Nothing to do. trixie never shipped the vulnerable code. |
| Debian 14forky | fixed | 7.2.6-1 | Update the kernel and reboot. Fixed in 7.2.6-1. A running kernel keeps the old code until the machine restarts. |
| Debian unstablesid | fixed | 7.2.6-1 | Update the kernel and reboot. Fixed in 7.2.6-1. A running kernel keeps the old code until the machine restarts. |
The vulnerability
What the bug is
ntfs_read_iomap_begin_resident() walks the MFT record through ntfs_attr_lookup() -> ntfs_attr_find() without taking ni->mrec_lock, while ntfs_attr_record_resize(), ntfs_make_room_for_attr() and ntfs_resident_attr_record_add() memmove() the same base_ni->mrec buffer under that lock. map_mft_record() only takes a reference and does not serialize, so the reader can observe torn attribute length and offset fields while a writer is relocating the records. KCSAN reports the race between the mmap read fault path and both link() and unlink(): BUG: KCSAN: data-race in ntfs_attr_find / ntfs_attr_record_resize write to 0xffff888100af1018 of 4 bytes by task 96 on cpu 1: ntfs_attr_record_resize+0xd2/0x130 ntfs_attr_record_rm+0xad/0x530 ntfs_delete+0x224/0x640 ntfs_unlink+0x14d/0x280 vfs_unlink+0x157/0x520 read to 0xffff888100af1018 of 4 bytes by task 95 on cpu 0: ntfs_attr_find+0x104/0x5b0 ntfs_attr_lookup+0x39c/0x10c0 ntfs_read_iomap_begin_resident+0xc6/0x230 ntfs_read_iomap_begin+0x5d/0xa0 iomap_iter+0x2e2/0x6e0 iomap_read_folio+0x147/0x2a0 ntfs_read_folio+0x108/0x170 filemap_read_folio+0x35/0x100 filemap_fault+0x993/0x1000 value changed: 0x00000250 -> 0x000001f0 The address is mrec + 0x18, i.e. mft_record.bytes_in_use, and the change is the 96 bytes of one $FILE_NAME attribute being removed. Keep base_ni->mrec_lock from the resident read iomap lookup through iomap_end(). This protects both the attribute walk and the subsequent copy from iomap->inline_data, which points into the MFT record. The non-resident path is left alone: ntfs_lookup() already holds the directory inode's mrec_lock when it reads an index folio through read_mapping_folio(), and taking the lock in the shared wrapper deadlocks there with recursive locking on mrec_lock. The comment above the read_mapping_folio() call in fs/ntfs/dir.c notes the same hazard. The seek path uses the same lookup helper but does not dereference iomap->inline_data. Release the lock before returning from that path, whereas the regular read path records base_ni in iomap->private and releases the lock from its iomap_end() callback. Tested with a reproducer that faults in a 16-byte resident file while another thread runs link()/unlink() on it. Before: 40 KCSAN reports in about one second. After: no reports in 180 seconds over 206,090 read iterations and 423,540 link/unlink cycles. A PROVE_LOCKING build shows no lockdep splat with the same reproducer running for 60 seconds.
Where it lives
The fix touches these files. If the subsystem is one you do not use, the practical exposure is lower, though the package is still the vulnerable one.
fs/ntfs/iomap.c
- What this is
- NTFS FILESYSTEMMAINTAINERS section matched on fs/ntfs/ · linux-fsdevel@vger.kernel.org · Maintained
- Kernel module
- ntfs
Check it on the machine
grep -w CONFIG_NTFS_FS /boot/config-$(uname -r)Reads the booted kernel's own configuration, on the machine and nowhere else. =y is built in, =m is a module, and an is not set line means the code is not there.
lsmod | grep -w ntfsPrints a line if that module is loaded right now, and nothing if it is not. One that is not loaded can still be loaded later by anything that needs it.
Show whether Debian builds this, per release
Debian builds this as a loadable module. Every release with an answer below compiles it as a module on every flavour, so whether the code is in the running kernel depends on whether that module is loaded. The build rule could not be established for 2 releases, so nothing is claimed about those.
- bookworm, trixie?
- forky, sidm
- ?
- not established - no Makefile entry for the affected file
- m
- a loadable module on every flavour - check lsmod, can be blacklisted
Where a release above reads "not established", no build rule for the affected file was found in that release's kernel tree. That is a gap in this lookup, not a finding that the code is absent.
- Build switch
- CONFIG_NTFS_FS
From the configuration Debian publishes for every kernel flavour it builds. It covers only the architectures Debian ships a linux-config package for, and nothing about a kernel you built yourself. Debian's own status above stays authoritative about the source package.MAINTAINERS kbuild Makefiles Debian linux-config packages
Signals
- Published
- 2026-09-17 (31 days ago)source
- CVSS
- 7.1 high
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:Hsource recompute it - Attack vector
- local (AV:L)source
- EPSS
- 0.16%, higher than 4.3% of all CVEssource
- CISA KEV
- not listedthe KEV catalogue
- Debian urgency
- unimportantsource
- Subsystem
- fs/ntfs
Upstream fixes
The versions the CNA records as introducing and fixing this, and the commit for each. source
| Introduced | Fixed in | Commit |
|---|---|---|
| 7.1 | 7.2.6 | 0400e0d50eb3 |
| 7.1 | 7.3 | d9e00c457d4a |
Why the CNA scored it this way
Quoted from the kernel CNA's own scoring file, word for word. A highlighted metric carries the most severe value CVSS v3.1 defines for it, which is what pushes the score up. source
- AV:LAttack vector, local
- The raced bytes are the in-memory MFT record (ni->mrec) copied from disk by map_mft_record_folio, not a protocol payload. One thread hits filemap_fault -> ntfs_read_folio -> ntfs_read_iomap_begin_resident -> ntfs_attr_find; the other is local linkat/unlinkat via vfs_link/vfs_unlink -> ntfs_link/ntfs_unlink -> ntfs_attr_record_resize memmove of that same buffer.
- AC:LAttack complexity, low
- The attacker drives both sides: mmap of a resident file so filemap_fault takes ntfs_read_iomap_begin_resident without i_rwsem, while another thread link()/unlink()s so ntfs_attr_record_rm or ntfs_make_room_for_attr memmoves the mrec under mrec_lock. The commit reproducer got 40 KCSAN hits per second on that pair.
- PR:LPrivileges required, low
- ntfs_file_open has no capability check. On an already-mounted writable NTFS volume, an unprivileged user who can mmap a small resident $DATA file and create/remove hard links in a writable directory reaches both the fault path and vfs_link/vfs_unlink. ntfs_fs_type is FS_REQUIRES_DEV without FS_USERNS_MOUNT, so mounting itself needs CAP_SYS_ADMIN but is not required here.
- UI:NUser interaction, none
- The attacker mmap-faults their own resident file while their other thread runs link()/unlink() on it, matching the commit's 16-byte-file reproducer. No victim mount or crafted image is required; a normal NTFS volume with a small file is enough.
- S:UScope, unchanged
- The race is inside fs/ntfs on that inode's kmalloc'd mrec and the faulting file's page-cache folio. It does not cross a KVM, IOMMU, or sandbox boundary.
- C:HConfidentiality impact, high
- ntfs_read_iomap_begin_resident sets iomap->inline_data to ctx->attr plus resident.value_offset with no mrec-size check. ntfs_attr_find computes space from bytes_in_use (KCSAN: 0x250->0x1f0); unsigned underflow plus a torn a->length lets ntfs_resident_attr_value_get accept a value_offset past the kmalloc mft_record_size buffer, and iomap_read_inline_data folio_fill_tail()s that into a folio the attacker reads.
- I:NIntegrity impact, none
- The racy path only reads ni->mrec and copies into the mmapped file's folio via iomap_read_inline_data. ntfs_attr_record_resize's memmove is the legitimate link/unlink writer holding mrec_lock and does not give the attacker an arbitrary kernel write.
- A:HAvailability impact, high
- iomap_read_inline_data copies from a value_offset that can lie tens of kilobytes past the kmalloc'd mrec into unmapped heap, oopsing on the filemap_fault path and taking the kernel down.