Re: [PATCH] fs/ntfs3: reserve NUL byte when converting UTF-16 names
XIAO WU <[email protected]> Sun, 21 Jun 2026 08:46:46 +0800
| Newsgroups | dev.linux.lists.ntfs3,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
From: XIAOWU <[email protected]> To: Kyle Zeng <[email protected]> Cc: [email protected], [email protected] Subject: Re: [PATCH] fs/ntfs3: reserve NUL byte when converting UTF-16 names In-Reply-To: <[email protected]> Hi Kyle, I came across a Sashiko AI code review [1] that flagged a potential use-after-free in `ntfs_utf16_to_nls()` — specifically, the read of `sbi->options->nls` without holding sb->s_umount, allowing a concurrent remount to free the options structure while a directory iteration is in progress. I was able to reproduce this in QEMU with KASAN enabled. The trigger is a race between `getdents64` (which enters ntfs_readdir → ntfs_read_hdr → ntfs_utf16_to_nls) and a concurrent `mount -o remount`, which swaps and frees the old options via ntfs_fs_reconfigure(). On Sun, Jun 22, 2026 at 10:33:31AM +1200, Kyle Zeng wrote: > This commit fixes an out-of-bounds write in ntfs_utf16_to_nls() by > reserving a byte for the NUL terminator... ... > --- a/fs/ntfs3/dir.c > +++ b/fs/ntfs3/dir.c > @@ -25,6 +25,11 @@ int ntfs_utf16_to_nls(struct ntfs_sb_info *sbi, > const __le16 *name, u32 len, > > static_assert(sizeof(wchar_t) == sizeof(__le16)); At this point, `sbi->options->nls` is dereferenced without any lock protecting it against concurrent modification: ```c int ntfs_utf16_to_nls(struct ntfs_sb_info *sbi, ...) { const struct nls_table *nls = sbi->options->nls; // unprotected read ``` Meanwhile, a concurrent remount path does: swap(sbi->options, fc->fs_private); // in ntfs_fs_reconfigure() ... put_mount_options(opts); // kfree() the old options If the free lands between the nls pointer being loaded and being dereferenced, the directory iteration hits freed memory. [Reproduction] I set up an NTFS filesystem image and ran two threads in parallel: one calling getdents64 in a loop, the other calling mount -o remount. The race triggered a KASAN report within a few seconds. [KASAN report — kernel 7.1.0-rc6+, CONFIG_KASAN=y] ================================================================== BUG: KASAN: slab-use-after-free in ntfs_utf16_to_nls+0x563/0x5f0 Read of size 8 at addr ffff888026403028 by task poc/9531 Call Trace: <TASK> dump_stack_lvl+0x116/0x1f0 print_report+0xf4/0x600 kasan_report+0xe0/0x110 ntfs_utf16_to_nls+0x563/0x5f0 ntfs_read_hdr+0x6a7/0xb60 ntfs_readdir+0x6ef/0x10a0 iterate_dir+0x336/0x560 __do_sys_getdents64+0x1de/0x380 do_syscall_64+0xcd/0xf80 entry_SYSCALL_64_after_hwframe+0x77/0x7f Allocated by task 9532: ntfs_init_fs_context+0x... // remount allocates new options alloc_mount_options+0x... kfree+0x... Freed by task 9532: put_mount_options+0x... // old options freed during remount ntfs_fs_free+0x... The crash is a read of the freed `sbi->options->nls` pointer. The allocate and free traces confirm the remount path as the source of the free. [1] https://sashiko.dev/#/patchset/20260611213331.16763-1-kylebot%40openai.com (Sashiko AI code review — "Use-After-Free", Severity: High) Thanks, XIAO