[PATCH 1/2] ntfs: don't write a compression block after a short copy

From: Zhan Xusheng

Date: Thu Nov 05 2026 - 08:07:29 EST


From: Zhan Xusheng <zhanxusheng@xxxxxxxxxx>

ntfs_compress_write() does not read in the folios of a compression
block that the write covers completely. If the copy from user space
then comes up short, the rest of those folios still holds whatever
the memory held before; ntfs_write_cb() compresses that to disk and
the folios are marked uptodate.

The copy can come up short after fault_in_iov_iter_readable() has
succeeded if the source buffer is unmapped in between. On a volume
with 4K clusters, writing 64K at offset 0 of a compressed file while
another thread unmaps and remaps the last page of the buffer leaves
61440 new bytes followed by 4096 bytes of another process's freed
memory in the file. The write returns -EFAULT.

Treat a short copy into a full block like a copy that made no
progress.

Fixes: 5b676a77f3e4 ("ntfs: skip reads for full compression unit overwrites")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Zhan Xusheng <zhanxusheng@xxxxxxxxxx>
---
Tested in QEMU on ntfs-next with KASAN, 4K clusters, page cache
dropped and freed memory filled with 'Z' before each write:

before: 16 of 41 writes failed, 3 of them changed the file, each
time bytes 61440-65535 read back as 0x5a
after: 286 of 731 writes failed, none changed the file

The same loop on rootfs gives short writes and no corruption. I can
send the reproducer if it helps.

fs/ntfs/compress.c | 10 ++++++++++
1 file changed, 10 insertions(+)

diff --git a/fs/ntfs/compress.c b/fs/ntfs/compress.c
index 82c7c7d29073..287bd47282d9 100644
--- a/fs/ntfs/compress.c
+++ b/fs/ntfs/compress.c
@@ -1567,6 +1567,16 @@ int ntfs_compress_write(struct ntfs_inode *ni, loff_t pos, size_t count,
}
}

+ /*
+ * The folios of a full compression block are not read in, so
+ * after a short copy the rest of the block holds whatever the
+ * folios contained. Don't write that out.
+ */
+ if (full_cb && copied < cb_size) {
+ iov_iter_revert(from, copied);
+ copied = 0;
+ }
+
if (!copied) {
err = -EFAULT;
goto release_pages;

base-commit: 564c7753647731d19170914c1c637d3b33d88d3b
--
2.43.0