Skip to content

Commit 45db5af

Browse files
pvts-matPlaidCat
authored andcommitted
ext4: fix out-of-bound read in ext4_xattr_inode_dec_ref_all()
jira VULN-65381 cve CVE-2025-22121 commit-author Ye Bin <yebin10@huawei.com> commit 5701875 There's issue as follows: BUG: KASAN: use-after-free in ext4_xattr_inode_dec_ref_all+0x6ff/0x790 Read of size 4 at addr ffff88807b003000 by task syz-executor.0/15172 CPU: 3 PID: 15172 Comm: syz-executor.0 Call Trace: __dump_stack lib/dump_stack.c:82 [inline] dump_stack+0xbe/0xfd lib/dump_stack.c:123 print_address_description.constprop.0+0x1e/0x280 mm/kasan/report.c:400 __kasan_report.cold+0x6c/0x84 mm/kasan/report.c:560 kasan_report+0x3a/0x50 mm/kasan/report.c:585 ext4_xattr_inode_dec_ref_all+0x6ff/0x790 fs/ext4/xattr.c:1137 ext4_xattr_delete_inode+0x4c7/0xda0 fs/ext4/xattr.c:2896 ext4_evict_inode+0xb3b/0x1670 fs/ext4/inode.c:323 evict+0x39f/0x880 fs/inode.c:622 iput_final fs/inode.c:1746 [inline] iput fs/inode.c:1772 [inline] iput+0x525/0x6c0 fs/inode.c:1758 ext4_orphan_cleanup fs/ext4/super.c:3298 [inline] ext4_fill_super+0x8c57/0xba40 fs/ext4/super.c:5300 mount_bdev+0x355/0x410 fs/super.c:1446 legacy_get_tree+0xfe/0x220 fs/fs_context.c:611 vfs_get_tree+0x8d/0x2f0 fs/super.c:1576 do_new_mount fs/namespace.c:2983 [inline] path_mount+0x119a/0x1ad0 fs/namespace.c:3316 do_mount+0xfc/0x110 fs/namespace.c:3329 __do_sys_mount fs/namespace.c:3540 [inline] __se_sys_mount+0x219/0x2e0 fs/namespace.c:3514 do_syscall_64+0x33/0x40 arch/x86/entry/common.c:46 entry_SYSCALL_64_after_hwframe+0x67/0xd1 Memory state around the buggy address: ffff88807b002f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ffff88807b002f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >ffff88807b003000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ^ ffff88807b003080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ffff88807b003100: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff Above issue happens as ext4_xattr_delete_inode() isn't check xattr is valid if xattr is in inode. To solve above issue call xattr_check_inode() check if xattr if valid in inode. In fact, we can directly verify in ext4_iget_extra_inode(), so that there is no divergent verification. Fixes: e50e512 ("ext4: xattr-in-inode support") Signed-off-by: Ye Bin <yebin10@huawei.com> Reviewed-by: Jan Kara <jack@suse.cz> Link: https://patch.msgid.link/20250208063141.1539283-3-yebin@huaweicloud.com Signed-off-by: Theodore Ts'o <tytso@mit.edu> (cherry picked from commit 5701875) Signed-off-by: Marcin Wcisło <marcin.wcislo@conclusive.pl>
1 parent 2d68915 commit 45db5af

File tree

3 files changed

+13
-25
lines changed

3 files changed

+13
-25
lines changed

fs/ext4/inode.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4788,6 +4788,11 @@ static inline int ext4_iget_extra_inode(struct inode *inode,
47884788
*magic == cpu_to_le32(EXT4_XATTR_MAGIC)) {
47894789
int err;
47904790

4791+
err = xattr_check_inode(inode, IHDR(inode, raw_inode),
4792+
ITAIL(inode, raw_inode));
4793+
if (err)
4794+
return err;
4795+
47914796
ext4_set_inode_state(inode, EXT4_STATE_XATTR);
47924797
err = ext4_find_inline_data_nolock(inode);
47934798
if (!err && ext4_has_inline_data(inode))

fs/ext4/xattr.c

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -308,17 +308,14 @@ __ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh,
308308
__ext4_xattr_check_block((inode), (bh), __func__, __LINE__)
309309

310310

311-
static inline int
311+
int
312312
__xattr_check_inode(struct inode *inode, struct ext4_xattr_ibody_header *header,
313313
void *end, const char *function, unsigned int line)
314314
{
315315
return check_xattrs(inode, NULL, IFIRST(header), end, IFIRST(header),
316316
function, line);
317317
}
318318

319-
#define xattr_check_inode(inode, header, end) \
320-
__xattr_check_inode((inode), (header), (end), __func__, __LINE__)
321-
322319
static int
323320
xattr_find_entry(struct inode *inode, struct ext4_xattr_entry **pentry,
324321
void *end, int name_index, const char *name, int sorted)
@@ -650,9 +647,6 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
650647
raw_inode = ext4_raw_inode(&iloc);
651648
header = IHDR(inode, raw_inode);
652649
end = ITAIL(inode, raw_inode);
653-
error = xattr_check_inode(inode, header, end);
654-
if (error)
655-
goto cleanup;
656650
entry = IFIRST(header);
657651
error = xattr_find_entry(inode, &entry, end, name_index, name, 0);
658652
if (error)
@@ -784,7 +778,6 @@ ext4_xattr_ibody_list(struct dentry *dentry, char *buffer, size_t buffer_size)
784778
struct ext4_xattr_ibody_header *header;
785779
struct ext4_inode *raw_inode;
786780
struct ext4_iloc iloc;
787-
void *end;
788781
int error;
789782

790783
if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR))
@@ -794,14 +787,9 @@ ext4_xattr_ibody_list(struct dentry *dentry, char *buffer, size_t buffer_size)
794787
return error;
795788
raw_inode = ext4_raw_inode(&iloc);
796789
header = IHDR(inode, raw_inode);
797-
end = ITAIL(inode, raw_inode);
798-
error = xattr_check_inode(inode, header, end);
799-
if (error)
800-
goto cleanup;
801790
error = ext4_xattr_list_entries(dentry, IFIRST(header),
802791
buffer, buffer_size);
803792

804-
cleanup:
805793
brelse(iloc.bh);
806794
return error;
807795
}
@@ -869,7 +857,6 @@ int ext4_get_inode_usage(struct inode *inode, qsize_t *usage)
869857
struct ext4_xattr_ibody_header *header;
870858
struct ext4_xattr_entry *entry;
871859
qsize_t ea_inode_refs = 0;
872-
void *end;
873860
int ret;
874861

875862
lockdep_assert_held_read(&EXT4_I(inode)->xattr_sem);
@@ -880,10 +867,6 @@ int ext4_get_inode_usage(struct inode *inode, qsize_t *usage)
880867
goto out;
881868
raw_inode = ext4_raw_inode(&iloc);
882869
header = IHDR(inode, raw_inode);
883-
end = ITAIL(inode, raw_inode);
884-
ret = xattr_check_inode(inode, header, end);
885-
if (ret)
886-
goto out;
887870

888871
for (entry = IFIRST(header); !IS_LAST_ENTRY(entry);
889872
entry = EXT4_XATTR_NEXT(entry))
@@ -2222,9 +2205,6 @@ int ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i,
22222205
is->s.here = is->s.first;
22232206
is->s.end = ITAIL(inode, raw_inode);
22242207
if (ext4_test_inode_state(inode, EXT4_STATE_XATTR)) {
2225-
error = xattr_check_inode(inode, header, is->s.end);
2226-
if (error)
2227-
return error;
22282208
/* Find the named attribute. */
22292209
error = xattr_find_entry(inode, &is->s.here, is->s.end,
22302210
i->name_index, i->name, 0);
@@ -2774,10 +2754,6 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
27742754
min_offs = end - base;
27752755
total_ino = sizeof(struct ext4_xattr_ibody_header) + sizeof(u32);
27762756

2777-
error = xattr_check_inode(inode, header, end);
2778-
if (error)
2779-
goto cleanup;
2780-
27812757
ifree = ext4_xattr_free_space(base, &min_offs, base, &total_ino);
27822758
if (ifree >= isize_diff)
27832759
goto shift;

fs/ext4/xattr.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,13 @@ extern int ext4_xattr_ibody_set(handle_t *handle, struct inode *inode,
210210
extern struct mb_cache *ext4_xattr_create_cache(void);
211211
extern void ext4_xattr_destroy_cache(struct mb_cache *);
212212

213+
extern int
214+
__xattr_check_inode(struct inode *inode, struct ext4_xattr_ibody_header *header,
215+
void *end, const char *function, unsigned int line);
216+
217+
#define xattr_check_inode(inode, header, end) \
218+
__xattr_check_inode((inode), (header), (end), __func__, __LINE__)
219+
213220
#ifdef CONFIG_EXT4_FS_SECURITY
214221
extern int ext4_init_security(handle_t *handle, struct inode *inode,
215222
struct inode *dir, const struct qstr *qstr);

0 commit comments

Comments
 (0)