diff options
| author | Matthias Goergens <matthias.goergens@gmail.com> | 2026-10-01 23:05:58 +0800 |
|---|---|---|
| committer | Namjae Jeon <linkinjeon@kernel.org> | 2026-10-20 18:41:52 +0900 |
| commit | 768c6f5fab58cefa65509dd34b946fdd1071746e (patch) | |
| tree | 8d5963b8f901ac6ce14d604f4440e2c0ed71a441 /scripts/Makefile.thinlto | |
| parent | 8e91379152204a9cc18fa7e16724646ad3aec759 (diff) | |
| download | linux-768c6f5fab58cefa65509dd34b946fdd1071746e.tar.gz linux-768c6f5fab58cefa65509dd34b946fdd1071746e.zip | |
ntfs: hold the runlist lock while expanding a non-resident attribute
ntfs_non_resident_attr_expand() changes ni->runlist.rl while it
allocates clusters: ntfs_attr_map_whole_runlist(), the compressed
branch's ntfs_rl_realloc() and ntfs_runlists_merge() can each kvfree()
the old array. Unless the caller already holds ni->runlist.lock, none
of this happens under it; only the rollback takes it. Callers without
it include the write path, fallocate, ntfs_inode_attr_pwrite() and
ntfs_resident_attr_resize().
Those callers hold mrec_lock, and the write path also inode_lock, but
the iomap read side takes neither: FIEMAP, page faults, readahead and
splice read reach ntfs_read_iomap_begin_non_resident(), which takes only
ni->runlist.lock. A FIEMAP running while write(2) extends the same file
can walk the array that ntfs_runlists_merge() has just freed:
BUG: KASAN: slab-use-after-free in ntfs_attr_vcn_to_rl+0x19b/0x200
A reader that finds a vcn unmapped in the stale array also maps it from
disk into the runlist the writer is changing, which shows up as "Run
lists overlap. Cannot merge!".
Take ni->runlist.lock for writing around the part of the expansion that
changes the runlist and allocated_size, up to and including the mapping
pairs update, as ntfs_non_resident_attr_shrink() does since commit
91709ba5d6d7 ("ntfs: protect runlist updates with the runlist lock"),
and hold it throughout the rollback, where ntfs_cluster_free() requires
it. The lock nests inside mrec_lock, as on the truncate-up path, which
already calls this function with the runlist lock held. Where the
caller says it holds the lock (locked_ni == ni), assert that it holds it
for writing.
For an $ATTRIBUTE_LIST whose lock the caller does not hold, drop the
lock again before the mapping pairs update: that update can resize the
same list through ntfs_attrlist_update_locked(), which returns -ENOSPC
when told that the list's lock is held. Holding it there made punching
holes into a large fragmented file fail with -ENOSPC.
Fixes: 495e90fa3348 ("ntfs: update attrib operations")
Cc: stable@vger.kernel.org
Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
Reviewed-by: Baolin Liu <liubaolin@kylinos.cn>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Diffstat (limited to 'scripts/Makefile.thinlto')
0 files changed, 0 insertions, 0 deletions
