release 6.14.1
This commit is contained in:
122
debian/patches/patchset-pf/exfat/0001-exfat-fix-random-stack-corruption-after-get_block.patch
vendored
Normal file
122
debian/patches/patchset-pf/exfat/0001-exfat-fix-random-stack-corruption-after-get_block.patch
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
From 99d63b3e3be79190d3bb4759bfb3a47fd00cfdbe Mon Sep 17 00:00:00 2001
|
||||
From: Sungjong Seo <sj1557.seo@samsung.com>
|
||||
Date: Fri, 21 Mar 2025 15:34:42 +0900
|
||||
Subject: 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: 11a347fb6cef ("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>
|
||||
---
|
||||
fs/exfat/inode.c | 39 +++++++++++++++++++++++++++++++++------
|
||||
1 file changed, 33 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/fs/exfat/inode.c
|
||||
+++ b/fs/exfat/inode.c
|
||||
@@ -344,7 +344,8 @@ static int exfat_get_block(struct inode
|
||||
* The block has been partially written,
|
||||
* zero the unwritten part and map the block.
|
||||
*/
|
||||
- loff_t size, off, pos;
|
||||
+ loff_t size, pos;
|
||||
+ void *addr;
|
||||
|
||||
max_blocks = 1;
|
||||
|
||||
@@ -355,17 +356,41 @@ static int exfat_get_block(struct inode
|
||||
if (!bh_result->b_folio)
|
||||
goto done;
|
||||
|
||||
+ /*
|
||||
+ * No buffer_head is allocated.
|
||||
+ * (1) bmap: It's enough to fill bh_result without I/O.
|
||||
+ * (2) read: The unwritten part should be filled with 0
|
||||
+ * If a folio does not have any buffers,
|
||||
+ * let's returns -EAGAIN to fallback to
|
||||
+ * per-bh IO like block_read_full_folio().
|
||||
+ */
|
||||
+ if (!folio_buffers(bh_result->b_folio)) {
|
||||
+ err = -EAGAIN;
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
pos = EXFAT_BLK_TO_B(iblock, sb);
|
||||
size = ei->valid_size - pos;
|
||||
- off = pos & (PAGE_SIZE - 1);
|
||||
+ addr = folio_address(bh_result->b_folio) +
|
||||
+ offset_in_folio(bh_result->b_folio, pos);
|
||||
|
||||
- folio_set_bh(bh_result, bh_result->b_folio, off);
|
||||
+ /* Check if bh->b_data points to proper addr in folio */
|
||||
+ if (bh_result->b_data != addr) {
|
||||
+ exfat_fs_error_ratelimit(sb,
|
||||
+ "b_data(%p) != folio_addr(%p)",
|
||||
+ bh_result->b_data, addr);
|
||||
+ err = -EINVAL;
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ /* Read a block */
|
||||
err = bh_read(bh_result, 0);
|
||||
if (err < 0)
|
||||
- goto unlock_ret;
|
||||
+ goto done;
|
||||
|
||||
- folio_zero_segment(bh_result->b_folio, off + size,
|
||||
- off + sb->s_blocksize);
|
||||
+ /* Zero unwritten part of a block */
|
||||
+ memset(bh_result->b_data + size, 0,
|
||||
+ bh_result->b_size - size);
|
||||
} else {
|
||||
/*
|
||||
* The range has not been written, clear the mapped flag
|
||||
@@ -376,6 +401,8 @@ static int exfat_get_block(struct inode
|
||||
}
|
||||
done:
|
||||
bh_result->b_size = EXFAT_BLK_TO_B(max_blocks, sb);
|
||||
+ if (err < 0)
|
||||
+ clear_buffer_mapped(bh_result);
|
||||
unlock_ret:
|
||||
mutex_unlock(&sbi->s_lock);
|
||||
return err;
|
30
debian/patches/patchset-pf/exfat/0002-exfat-fix-potential-wrong-error-return-from-get_bloc.patch
vendored
Normal file
30
debian/patches/patchset-pf/exfat/0002-exfat-fix-potential-wrong-error-return-from-get_bloc.patch
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
From 8a19bb487633ff4dcf9c247cd3913ea4db26abca Mon Sep 17 00:00:00 2001
|
||||
From: Sungjong Seo <sj1557.seo@samsung.com>
|
||||
Date: Wed, 26 Mar 2025 23:48:48 +0900
|
||||
Subject: exfat: fix potential wrong error return from get_block
|
||||
|
||||
If there is no error, get_block() should return 0. However, when bh_read()
|
||||
returns 1, get_block() also returns 1 in the same manner.
|
||||
|
||||
Let's set err to 0, if there is no error from bh_read()
|
||||
|
||||
Fixes: 11a347fb6cef ("exfat: change to get file size from DataLength")
|
||||
Cc: stable@vger.kernel.org
|
||||
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>
|
||||
---
|
||||
fs/exfat/inode.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
--- a/fs/exfat/inode.c
|
||||
+++ b/fs/exfat/inode.c
|
||||
@@ -391,6 +391,8 @@ static int exfat_get_block(struct inode
|
||||
/* Zero unwritten part of a block */
|
||||
memset(bh_result->b_data + size, 0,
|
||||
bh_result->b_size - size);
|
||||
+
|
||||
+ err = 0;
|
||||
} else {
|
||||
/*
|
||||
* The range has not been written, clear the mapped flag
|
Reference in New Issue
Block a user