From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pj1-f53.google.com (mail-pj1-f53.google.com [209.85.216.53]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C62343B8930 for ; Sun, 3 May 2026 23:43:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.53 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777851831; cv=none; b=XlMHO1ac9X44YGSpikXI2mZ77iaXG+m8gXpFZoJvoiEQVyQ7Hc9p7l6XO2sUP50KP9HUrdDZvnq1ReR8tmCktqdA7T9W2mJ8sPRGGfFG+S2GQY7NrUbY0KpHV5zunGdHfFM7JKHM8NEq/730M9bMGhmwCFZ0CUDRXqDiMG280Z0= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777851831; c=relaxed/simple; bh=TryQAaeaNl/WXC7Qho3o9IsCF/vU53RKO8+s0gaKOHU=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=YU+UFt4PiAU51CgXyfhJWDXQfighYwPYR6bRpHLucu+bErFJHoBggJudadPZNpG3gQ6jey3LPIVxm7YTOylOzv4pmKRoIpfPhE+hsjqfqjEPaNvcYgHM/WkJZkDwBiC8NeAcAH0y1wLgOS8TkY+ajPISvy82Kn52ufC30tLED84= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=O/IruFlj; arc=none smtp.client-ip=209.85.216.53 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="O/IruFlj" Received: by mail-pj1-f53.google.com with SMTP id 98e67ed59e1d1-35f9ab079bdso2705330a91.2 for ; Sun, 03 May 2026 16:43:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1777851829; x=1778456629; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=qxh7Fo/FDfHbi8FcrwiUdR6St43t90VEqeAwgvmBj5A=; b=O/IruFljqz/9VAOV0iUQja8NkHI9OBMWE4bbvH9O1VJREYVlIRB7UfynryP6KFwKqv NKdMmjgovTz6UKk0R2cLIVYbz+RP6D3pvhIxSlGQqJenfrvpJ7JEy2y2YHqiRXFssODu gKs4kylXn0CUGjYQfocmkPtKKhD98ZRbxIvbmnEwohwCeob+iCuxHW9II7XJbuwg4f20 g7U6Y34IR7ud5MX8sdU7Sl84+SOhds9UI4/Eq8IqwkROd0VREAVF57MYZh0uWeA3j7xG KcSZs1MoB8tD595X9Kf239m1T9sdxN72HOGG6JGJW1wiE/Sc0QiaJ9+YwZFNRfRu2BiK mXSg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777851829; x=1778456629; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-gg:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=qxh7Fo/FDfHbi8FcrwiUdR6St43t90VEqeAwgvmBj5A=; b=JdipJnr7l5QlBFP9+kMY8NzbFGtl5XVrj18HbIxpOA7y5sg1IJCWZyX0f4YDLe1Qlq Yg/OqsUJhPz+2ESUt9gOuEUV3Vg8k9CBsA6JBXY0VIGtXbM4+9ASb805gv5RBO+pgzDk 56ne6A9ZdVNKE3oUwOwhhyG6SXK18RMJb+xNF3AxnCNIJeDrD4ZquboujRBJhb0AFt4d 5E/7PP3IdJNp4vGHQ0b0NWO/AmI3wE1IeylmhvK05DT3A1R3ynpbHZ7a3J5jnvytNqez Nhlt85Xy7DRDsLTSiK8kW/uMPOlzrM8xNceweW+q/D0chJQOGwig2XcLlhAL+9oGVGEK 0ILg== X-Forwarded-Encrypted: i=1; AFNElJ+uc40SLU6RtR9MxDeylvB+Zzg7P9ZqKVU3WosxUgwOa9w8pGuni0covDknZ9kq0e6kOjI34kB83t+xnoY=@vger.kernel.org X-Gm-Message-State: AOJu0Yz2hYNS6gKRonS7HCjatN5ndtnQNrRj20M6WoHlUpvNpoSoLWfj 5ZjWCGOoo1NBq+/id8P/EPsu89e94qT9kcRErIQWsvES+U5BtJNK+gEehFl9A4ac X-Gm-Gg: AeBDieskx9V8tDFabKEWsAmgXiQoRZ7ap5UdJ/GSVtKo6Mo4BwTsM30jHLAi9S96vgt fcfhdnrNRtBBp/QW1MhhQQP1GOUtjSJXX3PJG5qw+JKx3HGgRPhl77321pwVoNpx3LvMIqHMEir r869zziQL5KT4OhppUzAadbZJygVYv4eGct96CTNW04jhdcu9m8xzamz8qRU6MZguUa4+lvdOmo aFUYSwd8l1DEd4TCxt4k2v6pmX69DsSdsPIqzmNr82M4OqdCHYU4ah8Olh+/nf9TUlSYIOuN5nx 6ZoWItwNvxXZH6whbNyQZodlNqOiGMDg2XMdqM3ZRlxEzai4GP/PXc3tNuDufCyGYU+lPOWRKjm A3BqBaPunQuT02qemna5JE1Cm+1cIT/4YTXv2PngTytZpgmNgX/QQpIGZCm71tIIzlTBiLjm9r2 CSMz45Dceo7akOCRr66kcTizaQ4pFjbTG3d8M= X-Received: by 2002:a17:90b:3e89:b0:35d:a38a:a117 with SMTP id 98e67ed59e1d1-3650ce235b6mr7192293a91.15.1777851829017; Sun, 03 May 2026 16:43:49 -0700 (PDT) Received: from localhost ([27.122.242.71]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-364d1c70d8csm18522037a91.13.2026.05.03.16.43.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 03 May 2026 16:43:48 -0700 (PDT) Date: Mon, 4 May 2026 08:43:46 +0900 From: Hyunchul Lee To: DaeMyung Kang Cc: Namjae Jeon , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: Re: [PATCH] ntfs: fix copy length in ntfs_bdev_write() for non-page-aligned start Message-ID: References: <20260502004852.491934-1-charsyam@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline In-Reply-To: <20260502004852.491934-1-charsyam@gmail.com> On Sat, May 02, 2026 at 09:48:52AM +0900, DaeMyung Kang wrote: > This is not a normal data I/O hot path. The single in-tree caller is > the $LogFile emptying path used during read-write mount/remount, and > the bug only becomes visible on NTFS volumes whose cluster_size is > strictly smaller than the kernel's PAGE_SIZE (typically 4 KiB on > x86_64). Per Microsoft's format command documentation, NTFS supports > allocation unit sizes starting at 512 bytes, so 512 B, 1 KiB and 2 KiB > clusters are uncommon but valid on-disk configurations. When > cluster_size >= PAGE_SIZE every "start" passed in is page-aligned and > the buggy "from != 0" path is never taken. > > ntfs_bdev_write() splits the write across one or more block-device > folios. Inside the loop, "to" is computed as the *end byte offset* > within the current page (0..PAGE_SIZE), and "from" is the start byte > offset within the page (reset to 0 from the second iteration onward). > The copy length should therefore be "to - from", but the current code > uses "to" directly: > > to = min_t(u32, end - offset, PAGE_SIZE); > memcpy_to_folio(folio, from, buf + buf_off, to); > buf_off += to; > > When "from != 0" (i.e. "start" is not page-aligned) memcpy_to_folio() > copies "from" extra bytes: > > - it reads "from" bytes past the source buffer into kernel heap; > - it writes "from" bytes past the requested range into the next part > of the block-device page (or, if "from + to > PAGE_SIZE", past the > folio boundary entirely, which trips the VM_BUG_ON inside > memcpy_to_folio() on CONFIG_DEBUG_VM=y kernels). > > "buf_off" is then advanced by the wrong amount, so every subsequent > iteration also reads the source buffer at the wrong offset and writes > the wrong content to disk. > > ntfs_empty_logfile() calls > > ntfs_bdev_write(sb, empty_buf, NTFS_CLU_TO_B(vol, lcn), > vol->cluster_size); > > with empty_buf sized to vol->cluster_size. On a sub-PAGE_SIZE-cluster > volume, any $LogFile run whose LCN is not aligned to > PAGE_SIZE / cluster_size reaches the non-page-aligned path. The > over-copy can read beyond empty_buf and overwrite the sectors following > the requested cluster in the block-device page with unrelated kernel > heap contents while $LogFile is being emptied. > > A userspace reducer of the same arithmetic and copy loop confirms the > bug under AddressSanitizer: ASan reports a heap-buffer-overflow read > past the source buffer for the buggy length, and the fixed version is > ASan-clean. > > Compute the copy length as "to - from" and advance buf_off by the same > amount. > > Fixes: 5218cd102aec ("ntfs: update misc operations") > Link: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/format > Signed-off-by: DaeMyung Kang Looks good to me. Reviewed-by: Hyunchul Lee > --- > fs/ntfs/bdev-io.c | 7 +++++-- > 1 file changed, 5 insertions(+), 2 deletions(-) > > diff --git a/fs/ntfs/bdev-io.c b/fs/ntfs/bdev-io.c > index 67e65c88d681..27d7c2767a33 100644 > --- a/fs/ntfs/bdev-io.c > +++ b/fs/ntfs/bdev-io.c > @@ -97,6 +97,8 @@ int ntfs_bdev_write(struct super_block *sb, void *buf, loff_t start, size_t size > idx_end++; > > for (; idx < idx_end; idx++, from = 0) { > + u32 len; > + > folio = read_mapping_folio(sb->s_bdev->bd_mapping, idx, NULL); > if (IS_ERR(folio)) { > ntfs_error(sb, "Unable to read %ld page", idx); > @@ -105,9 +107,10 @@ int ntfs_bdev_write(struct super_block *sb, void *buf, loff_t start, size_t size > > offset = (loff_t)idx << PAGE_SHIFT; > to = min_t(u32, end - offset, PAGE_SIZE); > + len = to - from; > > - memcpy_to_folio(folio, from, buf + buf_off, to); > - buf_off += to; > + memcpy_to_folio(folio, from, buf + buf_off, len); > + buf_off += len; > folio_mark_uptodate(folio); > folio_mark_dirty(folio); > folio_put(folio); > -- > 2.43.0 > -- Thanks, Hyunchul