mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 02:17:36 -04:00
xfs: tie zoned sysfs lifetime to zone info
The zoned sysfs directory is currently registered as part of the generic
per-mount sysfs setup, but the data exposed by nr_open_zones has a
narrower lifetime. mp->m_zone_info is allocated by xfs_mount_zones() and
freed by xfs_unmount_zones(), while the zoned sysfs kobject remained
registered until xfs_mount_sysfs_del().
A read of nr_open_zones can therefore enter through the still-live sysfs
kobject after xfs_unmount_zones() has freed mp->m_zone_info, leading to a
use-after-free in nr_open_zones_show().
Make the zoned sysfs lifetime match the zone-info lifetime inside the zone
allocator. Create the zoned sysfs directory from xfs_mount_zones() after
the zone allocator has finished setting up, and remove it as the first
step of xfs_unmount_zones(), before any zone allocator teardown can free
m_zone_info.
Sysfs removal deactivates the kernfs nodes and waits for active callbacks
to drain before returning, so this also protects a reader that has already
entered nr_open_zones_show() but has not yet dereferenced m_zone_info.
Validation reproduced this kernel report:
BUG: KASAN: slab-use-after-free in nr_open_zones_show+0x86/0x90
The buggy address belongs to the object at ffff88810b177800 which belongs
to the cache kmalloc-1k of size 1024
The buggy address is located 160 bytes inside of freed 1024-byte region
[ffff88810b177800, ffff88810b177c00)
Read of size 4
Call trace:
print_report+0xcd/0x620
nr_open_zones_show+0x86/0x90 (fs/xfs/xfs_sysfs.c:724)
srso_alias_return_thunk+0x5/0xfbef5
__virt_addr_valid+0x20c/0x410
kasan_report+0xdd/0x110
sysfs_kf_seq_show+0x1bd/0x380
seq_read_iter+0x40f/0x11b0
lock_release+0xba/0x260
mark_held_locks+0x40/0x70
vfs_read+0x717/0xce0
__up_read+0x319/0x900
ksys_read+0xf8/0x1c0
do_user_addr_fault+0x3d0/0xbc0
trace_hardirqs_on_prepare+0x23/0xf0
do_syscall_64+0xc8/0x530 (arch/x86/entry/syscall_64.c:87)
entry_SYSCALL_64_after_hwframe+0x74/0x7c
Allocated by task stack:
kasan_save_stack+0x33/0x60
kasan_save_track+0x14/0x30
__kasan_kmalloc+0xaa/0xb0
__kmalloc_cache_noprof+0x205/0x460
xfs_mount_zones+0x34c/0x2650
xfs_mountfs+0x1b97/0x1eb0
xfs_fs_fill_super+0xf2b/0x18a0
get_tree_bdev_flags+0x310/0x590
vfs_get_tree+0x8d/0x2e0
__x64_sys_fsconfig+0x61c/0xbc0
do_syscall_64+0xc8/0x530 (arch/x86/entry/syscall_64.c:87)
entry_SYSCALL_64_after_hwframe+0x74/0x7c
Freed by task stack:
kasan_save_stack+0x33/0x60
kasan_save_track+0x14/0x30
kasan_save_free_info+0x3b/0x60
__kasan_slab_free+0x5f/0x80
kfree+0x20e/0x4c0
xfs_unmountfs+0x2fd/0x390
xfs_fs_put_super+0x60/0x110
generic_shutdown_super+0x143/0x4b0
kill_block_super+0x3b/0x90
xfs_kill_sb+0x12/0x50
deactivate_locked_super+0xa7/0x160
cleanup_mnt+0x218/0x420
task_work_run+0x11a/0x1f0
exit_to_user_mode_loop+0x13c/0x4f0
do_syscall_64+0x4a9/0x530 (arch/x86/entry/syscall_64.c:87)
entry_SYSCALL_64_after_hwframe+0x74/0x7c
Fixes: 62c89988dc ("xfs: expose the number of open zones in sysfs")
Assisted-by: Codex:gpt-5.5
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
This commit is contained in:
committed by
Carlos Maiolino
parent
2094dab19d
commit
d128ffd2ba
@@ -780,6 +780,23 @@ static const struct kobj_type xfs_zoned_ktype = {
|
||||
.default_groups = xfs_zoned_groups,
|
||||
};
|
||||
|
||||
int
|
||||
xfs_zoned_sysfs_init(struct xfs_mount *mp)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_XFS_RT) || !xfs_has_zoned(mp))
|
||||
return 0;
|
||||
|
||||
return xfs_sysfs_init(&mp->m_zoned_kobj, &xfs_zoned_ktype,
|
||||
&mp->m_kobj, "zoned");
|
||||
}
|
||||
|
||||
void
|
||||
xfs_zoned_sysfs_del(struct xfs_mount *mp)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_XFS_RT) && xfs_has_zoned(mp))
|
||||
xfs_sysfs_del(&mp->m_zoned_kobj);
|
||||
}
|
||||
|
||||
int
|
||||
xfs_mount_sysfs_init(
|
||||
struct xfs_mount *mp)
|
||||
@@ -820,14 +837,6 @@ xfs_mount_sysfs_init(
|
||||
if (error)
|
||||
goto out_remove_error_dir;
|
||||
|
||||
if (IS_ENABLED(CONFIG_XFS_RT) && xfs_has_zoned(mp)) {
|
||||
/* .../xfs/<dev>/zoned/ */
|
||||
error = xfs_sysfs_init(&mp->m_zoned_kobj, &xfs_zoned_ktype,
|
||||
&mp->m_kobj, "zoned");
|
||||
if (error)
|
||||
goto out_remove_error_dir;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_remove_error_dir:
|
||||
@@ -846,9 +855,6 @@ xfs_mount_sysfs_del(
|
||||
struct xfs_error_cfg *cfg;
|
||||
int i, j;
|
||||
|
||||
if (IS_ENABLED(CONFIG_XFS_RT) && xfs_has_zoned(mp))
|
||||
xfs_sysfs_del(&mp->m_zoned_kobj);
|
||||
|
||||
for (i = 0; i < XFS_ERR_CLASS_MAX; i++) {
|
||||
for (j = 0; j < XFS_ERR_ERRNO_MAX; j++) {
|
||||
cfg = &mp->m_error_cfg[i][j];
|
||||
|
||||
@@ -53,6 +53,8 @@ xfs_sysfs_del(
|
||||
}
|
||||
|
||||
int xfs_mount_sysfs_init(struct xfs_mount *mp);
|
||||
int xfs_zoned_sysfs_init(struct xfs_mount *mp);
|
||||
void xfs_zoned_sysfs_del(struct xfs_mount *mp);
|
||||
void xfs_mount_sysfs_del(struct xfs_mount *mp);
|
||||
|
||||
#endif /* __XFS_SYSFS_H__ */
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "xfs_rtbitmap.h"
|
||||
#include "xfs_rtrmap_btree.h"
|
||||
#include "xfs_zone_alloc.h"
|
||||
#include "xfs_sysfs.h"
|
||||
#include "xfs_zone_priv.h"
|
||||
#include "xfs_zones.h"
|
||||
#include "xfs_trace.h"
|
||||
@@ -1420,11 +1421,17 @@ xfs_mount_zones(
|
||||
if (error)
|
||||
goto out_free_zone_info;
|
||||
|
||||
error = xfs_zoned_sysfs_init(mp);
|
||||
if (error)
|
||||
goto out_zone_gc_unmount;
|
||||
|
||||
xfs_info(mp, "%u zones of %u blocks (%u max open zones)",
|
||||
mp->m_sb.sb_rgcount, iz.zone_capacity, mp->m_max_open_zones);
|
||||
trace_xfs_zones_mount(mp);
|
||||
return 0;
|
||||
|
||||
out_zone_gc_unmount:
|
||||
xfs_zone_gc_unmount(mp);
|
||||
out_free_zone_info:
|
||||
xfs_free_zone_info(mp->m_zone_info);
|
||||
return error;
|
||||
@@ -1434,6 +1441,7 @@ void
|
||||
xfs_unmount_zones(
|
||||
struct xfs_mount *mp)
|
||||
{
|
||||
xfs_zoned_sysfs_del(mp);
|
||||
xfs_zone_gc_unmount(mp);
|
||||
xfs_free_zone_info(mp->m_zone_info);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user