* [PATCH 5.4 0/2] CVE-2024-49884
@ 2025-01-25 0:31 Shaoying Xu
2025-01-25 0:31 ` [PATCH 5.4 1/2] ext4: avoid ext4_error()'s caused by ENOMEM in the truncate path Shaoying Xu
2025-01-25 0:31 ` [PATCH 5.4 2/2] ext4: fix slab-use-after-free in ext4_split_extent_at() Shaoying Xu
0 siblings, 2 replies; 5+ messages in thread
From: Shaoying Xu @ 2025-01-25 0:31 UTC (permalink / raw)
To: stable; +Cc: shaoyi
Backport CVE-2024-49884 fixes to stable 5.4.
Baokun Li (1):
ext4: fix slab-use-after-free in ext4_split_extent_at()
Theodore Ts'o (1):
ext4: avoid ext4_error()'s caused by ENOMEM in the truncate path
fs/ext4/ext4.h | 1 +
fs/ext4/extents.c | 64 +++++++++++++++++++++++++++++++++++++++--------
2 files changed, 54 insertions(+), 11 deletions(-)
--
2.40.1
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 5.4 1/2] ext4: avoid ext4_error()'s caused by ENOMEM in the truncate path
2025-01-25 0:31 [PATCH 5.4 0/2] CVE-2024-49884 Shaoying Xu
@ 2025-01-25 0:31 ` Shaoying Xu
2025-01-25 14:03 ` Sasha Levin
2025-01-25 0:31 ` [PATCH 5.4 2/2] ext4: fix slab-use-after-free in ext4_split_extent_at() Shaoying Xu
1 sibling, 1 reply; 5+ messages in thread
From: Shaoying Xu @ 2025-01-25 0:31 UTC (permalink / raw)
To: stable; +Cc: shaoyi, Theodore Ts'o, Anna Pendleton, Harshad Shirwadkar
From: Theodore Ts'o <tytso@mit.edu>
[ Upstream commit 73c384c0cdaa8ea9ca9ef2d0cff6a25930f1648e ]
We can't fail in the truncate path without requiring an fsck.
Add work around for this by using a combination of retry loops
and the __GFP_NOFAIL flag.
From: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Anna Pendleton <pendleton@google.com>
Reviewed-by: Harshad Shirwadkar <harshadshirwadkar@gmail.com>
Link: https://lore.kernel.org/r/20200507175028.15061-1-pendleton@google.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Stable-dep-of: c26ab35702f8 ("ext4: fix slab-use-after-free in ext4_split_extent_at()")
[v5.4: resolved contextual conflict in __read_extent_tree_block]
Signed-off-by: Shaoying Xu <shaoyi@amazon.com>
---
fs/ext4/ext4.h | 1 +
fs/ext4/extents.c | 43 +++++++++++++++++++++++++++++++++----------
2 files changed, 34 insertions(+), 10 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 4d02116193de..44bfa589ed36 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -628,6 +628,7 @@ enum {
*/
#define EXT4_EX_NOCACHE 0x40000000
#define EXT4_EX_FORCE_CACHE 0x20000000
+#define EXT4_EX_NOFAIL 0x10000000
/*
* Flags used by ext4_free_blocks
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 0d692025f923..0e16e7c08a42 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -304,11 +304,14 @@ ext4_force_split_extent_at(handle_t *handle, struct inode *inode,
{
struct ext4_ext_path *path = *ppath;
int unwritten = ext4_ext_is_unwritten(path[path->p_depth].p_ext);
+ int flags = EXT4_EX_NOCACHE | EXT4_GET_BLOCKS_PRE_IO;
+
+ if (nofail)
+ flags |= EXT4_GET_BLOCKS_METADATA_NOFAIL | EXT4_EX_NOFAIL;
return ext4_split_extent_at(handle, inode, ppath, lblk, unwritten ?
EXT4_EXT_MARK_UNWRIT1|EXT4_EXT_MARK_UNWRIT2 : 0,
- EXT4_EX_NOCACHE | EXT4_GET_BLOCKS_PRE_IO |
- (nofail ? EXT4_GET_BLOCKS_METADATA_NOFAIL:0));
+ flags);
}
/*
@@ -572,9 +575,13 @@ __read_extent_tree_block(const char *function, unsigned int line,
struct buffer_head *bh;
int err;
ext4_fsblk_t pblk;
+ gfp_t gfp_flags = __GFP_MOVABLE | GFP_NOFS;
+
+ if (flags & EXT4_EX_NOFAIL)
+ gfp_flags |= __GFP_NOFAIL;
pblk = ext4_idx_pblock(idx);
- bh = sb_getblk_gfp(inode->i_sb, pblk, __GFP_MOVABLE | GFP_NOFS);
+ bh = sb_getblk_gfp(inode->i_sb, pblk, gfp_flags);
if (unlikely(!bh))
return ERR_PTR(-ENOMEM);
@@ -919,6 +926,10 @@ ext4_find_extent(struct inode *inode, ext4_lblk_t block,
struct ext4_ext_path *path = orig_path ? *orig_path : NULL;
short int depth, i, ppos = 0;
int ret;
+ gfp_t gfp_flags = GFP_NOFS;
+
+ if (flags & EXT4_EX_NOFAIL)
+ gfp_flags |= __GFP_NOFAIL;
eh = ext_inode_hdr(inode);
depth = ext_depth(inode);
@@ -939,7 +950,7 @@ ext4_find_extent(struct inode *inode, ext4_lblk_t block,
if (!path) {
/* account possible depth increase */
path = kcalloc(depth + 2, sizeof(struct ext4_ext_path),
- GFP_NOFS);
+ gfp_flags);
if (unlikely(!path))
return ERR_PTR(-ENOMEM);
path[0].p_maxdepth = depth + 1;
@@ -1088,9 +1099,13 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
ext4_fsblk_t newblock, oldblock;
__le32 border;
ext4_fsblk_t *ablocks = NULL; /* array of allocated blocks */
+ gfp_t gfp_flags = GFP_NOFS;
int err = 0;
size_t ext_size = 0;
+ if (flags & EXT4_EX_NOFAIL)
+ gfp_flags |= __GFP_NOFAIL;
+
/* make decision: where to split? */
/* FIXME: now decision is simplest: at current extent */
@@ -1124,7 +1139,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
* We need this to handle errors and free blocks
* upon them.
*/
- ablocks = kcalloc(depth, sizeof(ext4_fsblk_t), GFP_NOFS);
+ ablocks = kcalloc(depth, sizeof(ext4_fsblk_t), gfp_flags);
if (!ablocks)
return -ENOMEM;
@@ -2110,7 +2125,7 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
if (next != EXT_MAX_BLOCKS) {
ext_debug("next leaf block - %u\n", next);
BUG_ON(npath != NULL);
- npath = ext4_find_extent(inode, next, NULL, 0);
+ npath = ext4_find_extent(inode, next, NULL, gb_flags);
if (IS_ERR(npath))
return PTR_ERR(npath);
BUG_ON(npath->p_depth != path->p_depth);
@@ -3018,7 +3033,8 @@ int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
ext4_fsblk_t pblk;
/* find extent for or closest extent to this block */
- path = ext4_find_extent(inode, end, NULL, EXT4_EX_NOCACHE);
+ path = ext4_find_extent(inode, end, NULL,
+ EXT4_EX_NOCACHE | EXT4_EX_NOFAIL);
if (IS_ERR(path)) {
ext4_journal_stop(handle);
return PTR_ERR(path);
@@ -3104,7 +3120,7 @@ int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
le16_to_cpu(path[k].p_hdr->eh_entries)+1;
} else {
path = kcalloc(depth + 1, sizeof(struct ext4_ext_path),
- GFP_NOFS);
+ GFP_NOFS | __GFP_NOFAIL);
if (path == NULL) {
ext4_journal_stop(handle);
return -ENOMEM;
@@ -3528,7 +3544,7 @@ static int ext4_split_extent(handle_t *handle,
* Update path is required because previous ext4_split_extent_at() may
* result in split of original leaf or extent zeroout.
*/
- path = ext4_find_extent(inode, map->m_lblk, ppath, 0);
+ path = ext4_find_extent(inode, map->m_lblk, ppath, flags);
if (IS_ERR(path))
return PTR_ERR(path);
depth = ext_depth(inode);
@@ -4650,7 +4666,14 @@ int ext4_ext_truncate(handle_t *handle, struct inode *inode)
}
if (err)
return err;
- return ext4_ext_remove_space(inode, last_block, EXT_MAX_BLOCKS - 1);
+retry_remove_space:
+ err = ext4_ext_remove_space(inode, last_block, EXT_MAX_BLOCKS - 1);
+ if (err == -ENOMEM) {
+ cond_resched();
+ congestion_wait(BLK_RW_ASYNC, HZ/50);
+ goto retry_remove_space;
+ }
+ return err;
}
static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset,
--
2.40.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 5.4 2/2] ext4: fix slab-use-after-free in ext4_split_extent_at()
2025-01-25 0:31 [PATCH 5.4 0/2] CVE-2024-49884 Shaoying Xu
2025-01-25 0:31 ` [PATCH 5.4 1/2] ext4: avoid ext4_error()'s caused by ENOMEM in the truncate path Shaoying Xu
@ 2025-01-25 0:31 ` Shaoying Xu
2025-01-25 14:03 ` Sasha Levin
1 sibling, 1 reply; 5+ messages in thread
From: Shaoying Xu @ 2025-01-25 0:31 UTC (permalink / raw)
To: stable
Cc: shaoyi, Baokun Li, stable, Jan Kara, Ojaswin Mujoo,
Theodore Ts'o
From: Baokun Li <libaokun1@huawei.com>
[ Upstream commit c26ab35702f8cd0cdc78f96aa5856bfb77be798f ]
We hit the following use-after-free:
==================================================================
BUG: KASAN: slab-use-after-free in ext4_split_extent_at+0xba8/0xcc0
Read of size 2 at addr ffff88810548ed08 by task kworker/u20:0/40
CPU: 0 PID: 40 Comm: kworker/u20:0 Not tainted 6.9.0-dirty #724
Call Trace:
<TASK>
kasan_report+0x93/0xc0
ext4_split_extent_at+0xba8/0xcc0
ext4_split_extent.isra.0+0x18f/0x500
ext4_split_convert_extents+0x275/0x750
ext4_ext_handle_unwritten_extents+0x73e/0x1580
ext4_ext_map_blocks+0xe20/0x2dc0
ext4_map_blocks+0x724/0x1700
ext4_do_writepages+0x12d6/0x2a70
[...]
Allocated by task 40:
__kmalloc_noprof+0x1ac/0x480
ext4_find_extent+0xf3b/0x1e70
ext4_ext_map_blocks+0x188/0x2dc0
ext4_map_blocks+0x724/0x1700
ext4_do_writepages+0x12d6/0x2a70
[...]
Freed by task 40:
kfree+0xf1/0x2b0
ext4_find_extent+0xa71/0x1e70
ext4_ext_insert_extent+0xa22/0x3260
ext4_split_extent_at+0x3ef/0xcc0
ext4_split_extent.isra.0+0x18f/0x500
ext4_split_convert_extents+0x275/0x750
ext4_ext_handle_unwritten_extents+0x73e/0x1580
ext4_ext_map_blocks+0xe20/0x2dc0
ext4_map_blocks+0x724/0x1700
ext4_do_writepages+0x12d6/0x2a70
[...]
==================================================================
The flow of issue triggering is as follows:
ext4_split_extent_at
path = *ppath
ext4_ext_insert_extent(ppath)
ext4_ext_create_new_leaf(ppath)
ext4_find_extent(orig_path)
path = *orig_path
read_extent_tree_block
// return -ENOMEM or -EIO
ext4_free_ext_path(path)
kfree(path)
*orig_path = NULL
a. If err is -ENOMEM:
ext4_ext_dirty(path + path->p_depth)
// path use-after-free !!!
b. If err is -EIO and we have EXT_DEBUG defined:
ext4_ext_show_leaf(path)
eh = path[depth].p_hdr
// path also use-after-free !!!
So when trying to zeroout or fix the extent length, call ext4_find_extent()
to update the path.
In addition we use *ppath directly as an ext4_ext_show_leaf() input to
avoid possible use-after-free when EXT_DEBUG is defined, and to avoid
unnecessary path updates.
Fixes: dfe5080939ea ("ext4: drop EXT4_EX_NOFREE_ON_ERR from rest of extents handling code")
Cc: stable@kernel.org
Signed-off-by: Baokun Li <libaokun1@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Tested-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Link: https://patch.msgid.link/20240822023545.1994557-4-libaokun@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Shaoying Xu <shaoyi@amazon.com>
---
fs/ext4/extents.c | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 0e16e7c08a42..5c0ef7a04169 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -3440,6 +3440,25 @@ static int ext4_split_extent_at(handle_t *handle,
if (err != -ENOSPC && err != -EDQUOT && err != -ENOMEM)
goto out;
+ /*
+ * Update path is required because previous ext4_ext_insert_extent()
+ * may have freed or reallocated the path. Using EXT4_EX_NOFAIL
+ * guarantees that ext4_find_extent() will not return -ENOMEM,
+ * otherwise -ENOMEM will cause a retry in do_writepages(), and a
+ * WARN_ON may be triggered in ext4_da_update_reserve_space() due to
+ * an incorrect ee_len causing the i_reserved_data_blocks exception.
+ */
+ path = ext4_find_extent(inode, ee_block, ppath,
+ flags | EXT4_EX_NOFAIL);
+ if (IS_ERR(path)) {
+ EXT4_ERROR_INODE(inode, "Failed split extent on %u, err %ld",
+ split, PTR_ERR(path));
+ return PTR_ERR(path);
+ }
+ depth = ext_depth(inode);
+ ex = path[depth].p_ext;
+ *ppath = path;
+
if (EXT4_EXT_MAY_ZEROOUT & split_flag) {
if (split_flag & (EXT4_EXT_DATA_VALID1|EXT4_EXT_DATA_VALID2)) {
if (split_flag & EXT4_EXT_DATA_VALID1) {
@@ -3488,7 +3507,7 @@ static int ext4_split_extent_at(handle_t *handle,
ext4_ext_dirty(handle, inode, path + path->p_depth);
return err;
out:
- ext4_ext_show_leaf(inode, path);
+ ext4_ext_show_leaf(inode, *ppath);
return err;
}
--
2.40.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 5.4 1/2] ext4: avoid ext4_error()'s caused by ENOMEM in the truncate path
2025-01-25 0:31 ` [PATCH 5.4 1/2] ext4: avoid ext4_error()'s caused by ENOMEM in the truncate path Shaoying Xu
@ 2025-01-25 14:03 ` Sasha Levin
0 siblings, 0 replies; 5+ messages in thread
From: Sasha Levin @ 2025-01-25 14:03 UTC (permalink / raw)
To: stable; +Cc: Shaoying Xu, Sasha Levin
[ Sasha's backport helper bot ]
Hi,
The upstream commit SHA1 provided is correct: 73c384c0cdaa8ea9ca9ef2d0cff6a25930f1648e
WARNING: Author mismatch between patch and upstream commit:
Backport author: Shaoying Xu<shaoyi@amazon.com>
Commit author: Theodore Ts'o<tytso@mit.edu>
Status in newer kernel trees:
6.12.y | Present (exact SHA1)
6.6.y | Present (exact SHA1)
6.1.y | Present (exact SHA1)
5.15.y | Present (exact SHA1)
5.10.y | Present (exact SHA1)
5.4.y | Not found
Note: The patch differs from the upstream commit:
---
1: 73c384c0cdaa8 ! 1: ad990516172ca ext4: avoid ext4_error()'s caused by ENOMEM in the truncate path
@@ Metadata
## Commit message ##
ext4: avoid ext4_error()'s caused by ENOMEM in the truncate path
+ [ Upstream commit 73c384c0cdaa8ea9ca9ef2d0cff6a25930f1648e ]
+
We can't fail in the truncate path without requiring an fsck.
Add work around for this by using a combination of retry loops
and the __GFP_NOFAIL flag.
@@ Commit message
Reviewed-by: Harshad Shirwadkar <harshadshirwadkar@gmail.com>
Link: https://lore.kernel.org/r/20200507175028.15061-1-pendleton@google.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+ Stable-dep-of: c26ab35702f8 ("ext4: fix slab-use-after-free in ext4_split_extent_at()")
+ [v5.4: resolved contextual conflict in __read_extent_tree_block]
+ Signed-off-by: Shaoying Xu <shaoyi@amazon.com>
## fs/ext4/ext4.h ##
@@ fs/ext4/ext4.h: enum {
@@ fs/ext4/extents.c: ext4_force_split_extent_at(handle_t *handle, struct inode *in
+ flags);
}
- static int
+ /*
@@ fs/ext4/extents.c: __read_extent_tree_block(const char *function, unsigned int line,
- {
struct buffer_head *bh;
int err;
-+ gfp_t gfp_flags = __GFP_MOVABLE | GFP_NOFS;
+ ext4_fsblk_t pblk;
++ gfp_t gfp_flags = __GFP_MOVABLE | GFP_NOFS;
+
+ if (flags & EXT4_EX_NOFAIL)
-+ gfp_flags |= __GFP_NOFAIL;
++ gfp_flags |= __GFP_NOFAIL;
+ pblk = ext4_idx_pblock(idx);
- bh = sb_getblk_gfp(inode->i_sb, pblk, __GFP_MOVABLE | GFP_NOFS);
+ bh = sb_getblk_gfp(inode->i_sb, pblk, gfp_flags);
if (unlikely(!bh))
---
Results of testing on various branches:
| Branch | Patch Apply | Build Test |
|---------------------------|-------------|------------|
| stable/linux-5.4.y | Success | Success |
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 5.4 2/2] ext4: fix slab-use-after-free in ext4_split_extent_at()
2025-01-25 0:31 ` [PATCH 5.4 2/2] ext4: fix slab-use-after-free in ext4_split_extent_at() Shaoying Xu
@ 2025-01-25 14:03 ` Sasha Levin
0 siblings, 0 replies; 5+ messages in thread
From: Sasha Levin @ 2025-01-25 14:03 UTC (permalink / raw)
To: stable; +Cc: Shaoying Xu, Sasha Levin
[ Sasha's backport helper bot ]
Hi,
The upstream commit SHA1 provided is correct: c26ab35702f8cd0cdc78f96aa5856bfb77be798f
WARNING: Author mismatch between patch and upstream commit:
Backport author: Shaoying Xu<shaoyi@amazon.com>
Commit author: Baokun Li<libaokun1@huawei.com>
Status in newer kernel trees:
6.12.y | Present (exact SHA1)
6.6.y | Present (different SHA1: 8fe117790b37)
6.1.y | Present (different SHA1: a5401d4c3e2a)
5.15.y | Present (different SHA1: cafcc1bd6293)
5.10.y | Present (different SHA1: e52f933598b7)
5.4.y | Not found
Note: The patch differs from the upstream commit:
---
1: c26ab35702f8c ! 1: 2df1566f67dbb ext4: fix slab-use-after-free in ext4_split_extent_at()
@@ Metadata
## Commit message ##
ext4: fix slab-use-after-free in ext4_split_extent_at()
+ [ Upstream commit c26ab35702f8cd0cdc78f96aa5856bfb77be798f ]
+
We hit the following use-after-free:
==================================================================
@@ Commit message
Tested-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Link: https://patch.msgid.link/20240822023545.1994557-4-libaokun@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+ Signed-off-by: Shaoying Xu <shaoyi@amazon.com>
## fs/ext4/extents.c ##
@@ fs/ext4/extents.c: static int ext4_split_extent_at(handle_t *handle,
---
Results of testing on various branches:
| Branch | Patch Apply | Build Test |
|---------------------------|-------------|------------|
| stable/linux-5.4.y | Success | Success |
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2025-01-25 14:03 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-01-25 0:31 [PATCH 5.4 0/2] CVE-2024-49884 Shaoying Xu
2025-01-25 0:31 ` [PATCH 5.4 1/2] ext4: avoid ext4_error()'s caused by ENOMEM in the truncate path Shaoying Xu
2025-01-25 14:03 ` Sasha Levin
2025-01-25 0:31 ` [PATCH 5.4 2/2] ext4: fix slab-use-after-free in ext4_split_extent_at() Shaoying Xu
2025-01-25 14:03 ` Sasha Levin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).