Skip to content

Commit 66f28ff

Browse files
zhangyi089akpm00
authored andcommitted
mm/truncate: fix out-of-bounds when doing a right-aligned split
When performing a right split on a folio, the split_at2 may point to a not-present page if the offset + length equals the original folio size, which will trigger the following error: BUG: unable to handle page fault for address: ffffea0006000008 #PF: supervisor read access in kernel mode #PF: error_code(0x0000) - not-present page PGD 143ffb9067 P4D 143ffb9067 PUD 143ffb8067 PMD 0 Oops: Oops: 0000 [#1] SMP PTI CPU: 0 UID: 0 PID: 502640 Comm: fsx Not tainted 6.15.0-rc3-gc6156189fc6b #889 PR Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-2.fc40 04/01/4 RIP: 0010:truncate_inode_partial_folio+0x208/0x620 Code: ff 03 48 01 da e8 78 7e 13 00 48 83 05 10 b5 5a 0c 01 85 c0 0f 85 1c 02 001 RSP: 0018:ffffc90005bafab0 EFLAGS: 00010286 RAX: 0000000000000000 RBX: ffffea0005ffff00 RCX: 0000000000000002 RDX: 000000000000000c RSI: 0000000000013975 RDI: ffffc90005bafa30 RBP: ffffea0006000000 R08: 0000000000000000 R09: 00000000000009bf R10: 00000000000007e0 R11: 0000000000000000 R12: 0000000000001633 R13: 0000000000000000 R14: ffffea0005ffff00 R15: fffffffffffffffe FS: 00007f9f9a161740(0000) GS:ffff8894971fd000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: ffffea0006000008 CR3: 000000017c2ae000 CR4: 00000000000006f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: <TASK> truncate_inode_pages_range+0x226/0x720 truncate_pagecache+0x57/0x90 ... Fix this issue by skipping the split if truncation aligns with the folio size, make sure the split page number lies within the folio. Link: https://lkml.kernel.org/r/[email protected] Fixes: 7460b47 ("mm/truncate: use folio_split() in truncate operation") Signed-off-by: Zhang Yi <[email protected]> Reviewed-by: Zi Yan <[email protected]> Cc: ErKun Yang <[email protected]> Cc: Kefeng Wang <[email protected]> Cc: Matthew Wilcox (Oracle) <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 41f36b3 commit 66f28ff

File tree

1 file changed

+12
-8
lines changed

1 file changed

+12
-8
lines changed

mm/truncate.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -191,21 +191,21 @@ int truncate_inode_folio(struct address_space *mapping, struct folio *folio)
191191
bool truncate_inode_partial_folio(struct folio *folio, loff_t start, loff_t end)
192192
{
193193
loff_t pos = folio_pos(folio);
194+
size_t size = folio_size(folio);
194195
unsigned int offset, length;
195196
struct page *split_at, *split_at2;
196197

197198
if (pos < start)
198199
offset = start - pos;
199200
else
200201
offset = 0;
201-
length = folio_size(folio);
202-
if (pos + length <= (u64)end)
203-
length = length - offset;
202+
if (pos + size <= (u64)end)
203+
length = size - offset;
204204
else
205205
length = end + 1 - pos - offset;
206206

207207
folio_wait_writeback(folio);
208-
if (length == folio_size(folio)) {
208+
if (length == size) {
209209
truncate_inode_folio(folio->mapping, folio);
210210
return true;
211211
}
@@ -224,16 +224,20 @@ bool truncate_inode_partial_folio(struct folio *folio, loff_t start, loff_t end)
224224
return true;
225225

226226
split_at = folio_page(folio, PAGE_ALIGN_DOWN(offset) / PAGE_SIZE);
227-
split_at2 = folio_page(folio,
228-
PAGE_ALIGN_DOWN(offset + length) / PAGE_SIZE);
229-
230227
if (!try_folio_split(folio, split_at, NULL)) {
231228
/*
232229
* try to split at offset + length to make sure folios within
233230
* the range can be dropped, especially to avoid memory waste
234231
* for shmem truncate
235232
*/
236-
struct folio *folio2 = page_folio(split_at2);
233+
struct folio *folio2;
234+
235+
if (offset + length == size)
236+
goto no_split;
237+
238+
split_at2 = folio_page(folio,
239+
PAGE_ALIGN_DOWN(offset + length) / PAGE_SIZE);
240+
folio2 = page_folio(split_at2);
237241

238242
if (!folio_try_get(folio2))
239243
goto no_split;

0 commit comments

Comments
 (0)