Skip to content

Commit ebc02f3

Browse files
author
CKI KWF Bot
committed
Merge: CVE-2025-22036: exfat: fix random stack corruption after get_block
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-10/-/merge_requests/1087 JIRA: https://issues.redhat.com/browse/RHEL-99440 CVE: CVE-2025-22036 ``` commit 1bb7ff4 Author: Sungjong Seo <sj1557.seo@samsung.com> Date: Fri Mar 21 15:34:42 2025 +0900 exfat: fix random stack corruption after get_block When get_block is called with a buffer_head allocated on the stack, such as do_mpage_readpage, stack corruption due to buffer_head UAF may occur in the following race condition situation. <CPU 0> <CPU 1> mpage_read_folio <<bh on stack>> do_mpage_readpage exfat_get_block bh_read __bh_read get_bh(bh) submit_bh wait_on_buffer ... end_buffer_read_sync __end_buffer_read_notouch unlock_buffer <<keep going>> ... ... ... ... <<bh is not valid out of mpage_read_folio>> . . another_function <<variable A on stack>> put_bh(bh) atomic_dec(bh->b_count) * stack corruption here * This patch returns -EAGAIN if a folio does not have buffers when bh_read needs to be called. By doing this, the caller can fallback to functions like block_read_full_folio(), create a buffer_head in the folio, and then call get_block again. Let's do not call bh_read() with on-stack buffer_head. Fixes: 11a347f ("exfat: change to get file size from DataLength") Cc: stable@vger.kernel.org Tested-by: Yeongjin Gil <youngjin.gil@samsung.com> Signed-off-by: Sungjong Seo <sj1557.seo@samsung.com> Reviewed-by: Yuezhang Mo <Yuezhang.Mo@sony.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org> ``` Signed-off-by: CKI Backport Bot <cki-ci-bot+cki-gitlab-backport-bot@redhat.com> --- <small>Created 2025-06-23 13:51 UTC by backporter - [KWF FAQ](https://red.ht/kernel_workflow_doc) - [Slack #team-kernel-workflow](https://redhat-internal.slack.com/archives/C04LRUPMJQ5) - [Source](https://gitlab.com/cki-project/kernel-workflow/-/blob/main/webhook/utils/backporter.py) - [Documentation](https://gitlab.com/cki-project/kernel-workflow/-/blob/main/docs/README.backporter.md) - [Report an issue](https://issues.redhat.com/secure/CreateIssueDetails!init.jspa?pid=12334433&issuetype=1&priority=4&summary=backporter+webhook+issue&components=kernel-workflow+/+backporter)</small> Approved-by: Pavel Reichl <preichl@redhat.com> Approved-by: Carlos Maiolino <cmaiolino@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: CKI GitLab Kmaint Pipeline Bot <26919896-cki-kmaint-pipeline-bot@users.noreply.gitlab.com>
2 parents c732163 + 6ab3811 commit ebc02f3

File tree

1 file changed

+33
-6
lines changed

1 file changed

+33
-6
lines changed

fs/exfat/inode.c

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,8 @@ static int exfat_get_block(struct inode *inode, sector_t iblock,
344344
* The block has been partially written,
345345
* zero the unwritten part and map the block.
346346
*/
347-
loff_t size, off, pos;
347+
loff_t size, pos;
348+
void *addr;
348349

349350
max_blocks = 1;
350351

@@ -355,17 +356,41 @@ static int exfat_get_block(struct inode *inode, sector_t iblock,
355356
if (!bh_result->b_folio)
356357
goto done;
357358

359+
/*
360+
* No buffer_head is allocated.
361+
* (1) bmap: It's enough to fill bh_result without I/O.
362+
* (2) read: The unwritten part should be filled with 0
363+
* If a folio does not have any buffers,
364+
* let's returns -EAGAIN to fallback to
365+
* per-bh IO like block_read_full_folio().
366+
*/
367+
if (!folio_buffers(bh_result->b_folio)) {
368+
err = -EAGAIN;
369+
goto done;
370+
}
371+
358372
pos = EXFAT_BLK_TO_B(iblock, sb);
359373
size = ei->valid_size - pos;
360-
off = pos & (PAGE_SIZE - 1);
374+
addr = folio_address(bh_result->b_folio) +
375+
offset_in_folio(bh_result->b_folio, pos);
376+
377+
/* Check if bh->b_data points to proper addr in folio */
378+
if (bh_result->b_data != addr) {
379+
exfat_fs_error_ratelimit(sb,
380+
"b_data(%p) != folio_addr(%p)",
381+
bh_result->b_data, addr);
382+
err = -EINVAL;
383+
goto done;
384+
}
361385

362-
folio_set_bh(bh_result, bh_result->b_folio, off);
386+
/* Read a block */
363387
err = bh_read(bh_result, 0);
364388
if (err < 0)
365-
goto unlock_ret;
389+
goto done;
366390

367-
folio_zero_segment(bh_result->b_folio, off + size,
368-
off + sb->s_blocksize);
391+
/* Zero unwritten part of a block */
392+
memset(bh_result->b_data + size, 0,
393+
bh_result->b_size - size);
369394
} else {
370395
/*
371396
* The range has not been written, clear the mapped flag
@@ -376,6 +401,8 @@ static int exfat_get_block(struct inode *inode, sector_t iblock,
376401
}
377402
done:
378403
bh_result->b_size = EXFAT_BLK_TO_B(max_blocks, sb);
404+
if (err < 0)
405+
clear_buffer_mapped(bh_result);
379406
unlock_ret:
380407
mutex_unlock(&sbi->s_lock);
381408
return err;

0 commit comments

Comments
 (0)