Re: [PATCH] ntfs: fix out-of-bounds write race in NTFS_IOC_LIST_STREAMS

From: Namjae Jeon

Date: Thu Nov 05 2026 - 07:34:42 EST


On Thu, Nov 5, 2026 at 4:34 PM Xingyuan Mo <hdthky0@xxxxxxxxx> wrote:
>
> NTFS_IOC_LIST_STREAMS walks the base inode's MFT attributes twice:
> a first pass sizes the output buffer, a second pass fills it, both
> times filtering out streams that ntfs_stream_unlinked() reports as
> unlinked. That filter is the culprit: it treats a stream inode that
> is no longer in the inode hash as live, which is precisely the state
> a stream being deleted ends up in.
>
> When a base file is deleted while one of its named streams is still
> open, ntfs_cleanup_deleted_inode() sets NInoStreamUnlinked on the
> stream inode and removes it from the inode hash after dropping the
> MFT record lock. Nothing serializes this against the ioctl's two
> passes, so if the flag and the unhash land between them, the first
> pass excludes the stream while the second pass includes it, and the
> ioctl writes an entry the allocation never accounted for.
>
> The per-entry bounds check cannot catch this divergence, because
> "offset > required - entry_size" underflows when entry_size exceeds
> required. With a 1-character stream sizing the buffer at 48 bytes and
> a 250-character stream surfacing only in the second pass, a 544-byte
> entry is written into the 48-byte kmalloc-64 allocation.
>
> Close the hole in two steps:
>
> - Reject base inodes that are being deleted before walking their
> attributes, like the other named stream entry points in this file
> already do. This also stops the listing from reporting streams of a
> deleted base file as live, which is reproducible even without the
> race.
>
> - Make the bounds check underflow-safe so any remaining divergence
> between the passes can only produce -EOVERFLOW, never an
> out-of-bounds write.
>
> KASAN report from the reproducer (timestamps stripped):
>
> BUG: KASAN: slab-out-of-bounds in ntfs_ioctl_list_streams+0x7a9/0xa00
> Write of size 500 at addr ffff88800b1931a8 by task ntfs_ads_race/305
> CPU: 2 UID: 0 PID: 305 Comm: ntfs_ads_race
> Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
> Call Trace:
> <TASK>
> dump_stack_lvl+0x73/0xb0
> print_report+0xd1/0x610
> kasan_report+0xff/0x130
> kasan_check_range+0x10c/0x1c0
> __asan_memcpy+0x3f/0x70
> ntfs_ioctl_list_streams+0x7a9/0xa00
> ntfs_ioctl+0x3b6/0x420
> __x64_sys_ioctl+0xd1/0x120
> x64_sys_call+0x2a5/0x2220
> do_syscall_64+0x109/0x5e0
> entry_SYSCALL_64_after_hwframe+0x77/0x7f
> </TASK>
>
> Allocated by task 305:
> kasan_save_stack+0x3d/0x60
> kasan_save_track+0x18/0x40
> kasan_save_alloc_info+0x3b/0x50
> __kasan_kmalloc+0x9c/0xa0
> __kvmalloc_node_noprof+0x2dd/0x800
> ntfs_ioctl_list_streams+0x57f/0xa00
> ntfs_ioctl+0x3b6/0x420
> __x64_sys_ioctl+0xd1/0x120
> x64_sys_call+0x2a5/0x2220
> do_syscall_64+0x109/0x5e0
> entry_SYSCALL_64_after_hwframe+0x77/0x7f
>
> The buggy address belongs to the object at ffff88800b193180
> which belongs to the cache kmalloc-64 of size 64
> The buggy address is located 40 bytes inside of
> allocated 48-byte region [ffff88800b193180, ffff88800b1931b0)
>
> Fixes: 48996054b706 ("ntfs: add named stream ioctls support")
> Signed-off-by: Xingyuan Mo <hdthky0@xxxxxxxxx>
Applied it to #ntfs-next.
Thanks!