mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: liubaolin <liubaolin12138@163.com>
To: Xingyuan Mo <hdthky0@gmail.com>,
	Namjae Jeon <linkinjeon@kernel.org>,
	Hyunchul Lee <hyc.lee@gmail.com>
Cc: "open list:NTFS FILESYSTEM" <ntfs@lists.linux.dev>,
	open list <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH] ntfs: fix out-of-bounds write race in NTFS_IOC_LIST_STREAMS
Date: Thu, 5 Nov 2026 17:26:48 +0800	[thread overview]
Message-ID: <470adc85-93ad-4e75-9e72-ab35362373bd@163.com> (raw)
In-Reply-To: <20261105073353.433854-1-hdthky0@gmail.com>



在 2026/11/5 15:34, Xingyuan Mo 写道:
> 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@gmail.com>
> ---
>   fs/ntfs/named_stream.c | 6 +++++-
>   1 file changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/ntfs/named_stream.c b/fs/ntfs/named_stream.c
> index 95a3c05f9821..70c589207713 100644
> --- a/fs/ntfs/named_stream.c
> +++ b/fs/ntfs/named_stream.c
> @@ -1632,6 +1632,10 @@ int ntfs_ioctl_list_streams(struct file *filp, unsigned long arg)
>   	ubuf = (void __user *)arg + sizeof(hdr);
>   
>   	mutex_lock(&ni->mrec_lock);
> +	if (NInoBeingDeleted(ni) || !inode->i_nlink) {
> +		mutex_unlock(&ni->mrec_lock);
> +		return -ENOENT;
> +	}
>   	actx = ntfs_attr_get_search_ctx(ni, NULL);
>   	if (!actx) {
>   		mutex_unlock(&ni->mrec_lock);
> @@ -1731,7 +1735,7 @@ int ntfs_ioctl_list_streams(struct file *filp, unsigned long arg)
>   		}
>   
>   		entry_size = ALIGN(name_offset + name_len, 8);
> -		if (offset > required - entry_size) {
> +		if (offset > required || entry_size > required - offset) {
>   			ret = -EOVERFLOW;
>   			kfree(sn);
>   			sn = NULL;

Looks good to me.

Reviewed-by: Baolin Liu <liubaolin@kylinos.cn>


  reply	other threads:[~2026-11-05  9:27 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-05  7:34 Xingyuan Mo
2026-11-05  9:26 ` liubaolin [this message]
2026-11-05 12:33 ` Namjae Jeon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=470adc85-93ad-4e75-9e72-ab35362373bd@163.com \
    --to=liubaolin12138@163.com \
    --cc=hdthky0@gmail.com \
    --cc=hyc.lee@gmail.com \
    --cc=linkinjeon@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=ntfs@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®