From 1e7830ff166a113a4da18e60951032bfb167cf3a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 2 Jan 2024 15:34:03 +0100 Subject: [PATCH] 5.15-stable patches added patches: mm-filemap-avoid-buffered-read-write-race-to-read-inconsistent-data.patch --- ...write-race-to-read-inconsistent-data.patch | 106 ++++++++++++++++++ queue-5.15/series | 1 + 2 files changed, 107 insertions(+) create mode 100644 queue-5.15/mm-filemap-avoid-buffered-read-write-race-to-read-inconsistent-data.patch diff --git a/queue-5.15/mm-filemap-avoid-buffered-read-write-race-to-read-inconsistent-data.patch b/queue-5.15/mm-filemap-avoid-buffered-read-write-race-to-read-inconsistent-data.patch new file mode 100644 index 00000000000..cbfdc03f783 --- /dev/null +++ b/queue-5.15/mm-filemap-avoid-buffered-read-write-race-to-read-inconsistent-data.patch @@ -0,0 +1,106 @@ +From e2c27b803bb664748e090d99042ac128b3f88d92 Mon Sep 17 00:00:00 2001 +From: Baokun Li +Date: Wed, 13 Dec 2023 14:23:24 +0800 +Subject: mm/filemap: avoid buffered read/write race to read inconsistent data + +From: Baokun Li + +commit e2c27b803bb664748e090d99042ac128b3f88d92 upstream. + +The following concurrency may cause the data read to be inconsistent with +the data on disk: + + cpu1 cpu2 +------------------------------|------------------------------ + // Buffered write 2048 from 0 + ext4_buffered_write_iter + generic_perform_write + copy_page_from_iter_atomic + ext4_da_write_end + ext4_da_do_write_end + block_write_end + __block_commit_write + folio_mark_uptodate +// Buffered read 4096 from 0 smp_wmb() +ext4_file_read_iter set_bit(PG_uptodate, folio_flags) + generic_file_read_iter i_size_write // 2048 + filemap_read unlock_page(page) + filemap_get_pages + filemap_get_read_batch + folio_test_uptodate(folio) + ret = test_bit(PG_uptodate, folio_flags) + if (ret) + smp_rmb(); + // Ensure that the data in page 0-2048 is up-to-date. + + // New buffered write 2048 from 2048 + ext4_buffered_write_iter + generic_perform_write + copy_page_from_iter_atomic + ext4_da_write_end + ext4_da_do_write_end + block_write_end + __block_commit_write + folio_mark_uptodate + smp_wmb() + set_bit(PG_uptodate, folio_flags) + i_size_write // 4096 + unlock_page(page) + + isize = i_size_read(inode) // 4096 + // Read the latest isize 4096, but without smp_rmb(), there may be + // Load-Load disorder resulting in the data in the 2048-4096 range + // in the page is not up-to-date. + copy_page_to_iter + // copyout 4096 + +In the concurrency above, we read the updated i_size, but there is no read +barrier to ensure that the data in the page is the same as the i_size at +this point, so we may copy the unsynchronized page out. Hence adding the +missing read memory barrier to fix this. + +This is a Load-Load reordering issue, which only occurs on some weak +mem-ordering architectures (e.g. ARM64, ALPHA), but not on strong +mem-ordering architectures (e.g. X86). And theoretically the problem +doesn't only happen on ext4, filesystems that call filemap_read() but +don't hold inode lock (e.g. btrfs, f2fs, ubifs ...) will have this +problem, while filesystems with inode lock (e.g. xfs, nfs) won't have +this problem. + +Link: https://lkml.kernel.org/r/20231213062324.739009-1-libaokun1@huawei.com +Signed-off-by: Baokun Li +Reviewed-by: Jan Kara +Cc: Andreas Dilger +Cc: Christoph Hellwig +Cc: Dave Chinner +Cc: Matthew Wilcox (Oracle) +Cc: Ritesh Harjani (IBM) +Cc: Theodore Ts'o +Cc: yangerkun +Cc: Yu Kuai +Cc: Zhang Yi +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + mm/filemap.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/mm/filemap.c ++++ b/mm/filemap.c +@@ -2649,6 +2649,15 @@ ssize_t filemap_read(struct kiocb *iocb, + end_offset = min_t(loff_t, isize, iocb->ki_pos + iter->count); + + /* ++ * Pairs with a barrier in ++ * block_write_end()->mark_buffer_dirty() or other page ++ * dirtying routines like iomap_write_end() to ensure ++ * changes to page contents are visible before we see ++ * increased inode size. ++ */ ++ smp_rmb(); ++ ++ /* + * Once we start copying data, we don't want to be touching any + * cachelines that might be contended: + */ diff --git a/queue-5.15/series b/queue-5.15/series index 37f1c82b636..667253f8b8e 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -83,3 +83,4 @@ smb-client-fix-oob-in-smb2_query_info_init.patch smb-client-fix-oob-in-smbcalcsize.patch bluetooth-af_bluetooth-fix-use-after-free-in-bt_sock.patch device-property-add-const-qualifier-to-device_get_ma.patch +mm-filemap-avoid-buffered-read-write-race-to-read-inconsistent-data.patch -- 2.47.3