Re: [BUG] adfs: use-after-free in _find_next_bit+0xe2/0x140 during getdents64()
From: Hyungjung Joo
Date: Tue Mar 10 2026 - 01:48:47 EST
Hello,
I am commenting on additional information that reported a filesystem
bug reproduced on current mainline with
KASAN enabled.
Target file: fs/adfs/map.c
Subsystem: fs/adfs
Git head: 5ee8dbf54602dc340d6235b1d6aa17c0f283f48c
Kernel release: 7.0.0-rc2+
Root cause:
`fs/adfs/super.c:324-335` accepts a DR0 image whenever the disc record
passes the shallow `adfs_checkdiscrecord()` checks and `nzones==1`.
`fs/adfs/map.c:356-385` then reads exactly one map sector from block
0, but `adfs_map_layout()` overwrites `dm[0].dm_endbit` with `512 +
(adfs_disc_size(dr) >> dr->log2bpmb)` for the one-zone case
(`fs/adfs/map.c:329-331`) and never checks that this fits inside the
single loaded buffer (`sb->s_blocksize * 8` bits). Later map walkers
trust that oversized bound while reading `dm->dm_bh->b_data`,
producing a live-buffer out-of-bounds read during post-mount map
traversal. For this one-zone path, `disc_size/log2bpmb` is the
decisive inflator; `zone_spare` is not required for the final
`dm_endbit` overwrite.
Reproducer
C reproducer: intentionally omitted from public mail (Not inlining PoC
because the case text indicates direct privilege-escalation risk
beyond a pure KASAN trigger.)
KASAN full log: https://pastebin.com/raw/jgGUJ3ai
Kernel config: https://pastebin.com/raw/rKFNfL51
Key config options:
- CONFIG_KASAN=y
- CONFIG_KASAN_GENERIC=y
- CONFIG_KASAN_MULTI_SHOT=y
- CONFIG_DEBUG_KERNEL=y
- CONFIG_FRAME_POINTER=y
- CONFIG_ADFS_FS=y
- CONFIG_BLK_DEV_LOOP=y
Brief KASAN call trace:
[ 84.944056][ T167] BUG: KASAN: use-after-free in _find_next_bit+0xe2/0x140
[ 84.944056][ T167] Read of size 8 at addr ff1100005b909000 by task
poc-bin/167
[ 84.944056][ T167] Call Trace:
[ 84.944056][ T167] dump_stack_lvl+0x95/0x100
[ 84.944056][ T167] print_address_description.constprop.0+0x2c/0x3c0
[ 84.944056][ T167] print_report+0xb4/0x280
[ 84.944056][ T167] kasan_report+0x9b/0x100
[ 84.944056][ T167] _find_next_bit+0xe2/0x140
[ 84.944056][ T167] scan_map+0x2ac/0x4c0
[ 84.944056][ T167] adfs_map_lookup+0x12e/0x340
[ 84.944056][ T167] adfs_dir_read_buffers+0x282/0x5c0
[ 84.944056][ T167] adfs_f_read+0x76/0x3c0
[ 84.944056][ T167] adfs_dir_read_inode+0x15f/0x2c0
[ 84.944056][ T167] adfs_iterate+0x127/0x480
[ 84.944056][ T167] iterate_dir+0x238/0xa80
Reproducibility notes:
- observed crash: use-after-free in _find_next_bit+0xe2/0x140 during
getdents64()
- rootfs mode: busybox
- guest /init runs the case-specific trigger binary automatically
If you need anything else, please let me know.
Thank you.
Best regards,
Hyungjung Joo, jhj140711@xxxxxxxxx
2026년 3월 8일 (일) PM 5:46, 주형정 <jhj140711@xxxxxxxxx>님이 작성:
>
> Hello,
>
> I am reporting a filesystem bug reproduced on current mainline with
> KASAN enabled.
>
> Target file: fs/adfs/map.c
> Subsystem: fs/adfs
> Git head: 5ee8dbf54602dc340d6235b1d6aa17c0f283f48c
> Kernel release: 7.0.0-rc2+
> Case ID: case-20260306T142346Z-211f
>
> Root cause:
> `fs/adfs/super.c:324-335` accepts a DR0 image whenever the disc record
> passes the shallow `adfs_checkdiscrecord()` checks and `nzones==1`.
> `fs/adfs/map.c:356-385` then reads exactly one map sector from block
> 0, but `adfs_map_layout()` overwrites `dm[0].dm_endbit` with `512 +
> (adfs_disc_size(dr) >> dr->log2bpmb)` for the one-zone case
> (`fs/adfs/map.c:329-331`) and never checks that this fits inside the
> single loaded buffer (`sb->s_blocksize * 8` bits). Later map walkers
> trust that oversized bound while reading `dm->dm_bh->b_data`,
> producing a live-buffer out-of-bounds read during post-mount map
> traversal. For this one-zone path, `disc_size/log2bpmb` is the
> decisive inflator; `zone_spare` is not required for the final
> `dm_endbit` overwrite.
>
> Observed crash: use-after-free in _find_next_bit+0xe2/0x140 during getdents64()
>
> KASAN excerpt:
> [ 83.536813][ T158] ADFS-fs error (device loop0):
> adfs_dir_read_buffers: dir 000200 failed read at offset 0, mapped
> block 0x00013d02
> getdents64: Input/output error
> [ 83.202718][ T142] sh (142): drop_caches: 3
> [ 83.497412][ T158] kobject: 'loop0' (ff11000001433798): kobject_uevent_env
> [ 83.497586][ T158] kobject: 'loop0' (ff11000001433798):
> kobject_uevent_env: uevent_suppress caused the event to drop!
> [ 83.499843][ T158] loop0: detected capacity change from 0 to 8
> [ 83.500351][ T158] kobject: 'loop0' (ff11000001433798): kobject_uevent_env
> [ 83.500422][ T158] kobject: 'loop0' (ff11000001433798):
> kobject_uevent_env: uevent_suppress caused the event to drop!
> [ 83.500473][ T158] kobject: 'loop0' (ff11000001433798): kobject_uevent_env
> [ 83.501083][ T158] kobject: 'loop0' (ff11000001433798):
> fill_kobj_path: path = '/devices/virtual/block/loop0'
> [ 83.536813][ T158] ADFS-fs error (device loop0):
> adfs_dir_read_buffers: dir 000200 failed read at offset 0, mapped
> block 0x00013d02
> [ 83.589296][ T158] kobject: 'loop0' (ff11000001433798): kobject_uevent_env
> [ 83.591287][ T158] kobject: 'loop0' (ff11000001433798):
> fill_kobj_path: path = '/devices/virtual/block/loop0'
> [ 83.591744][ T158] kobject: 'loop0' (ff11000001433798): kobject_uevent_env
> [ 83.592497][ T158] kobject: 'loop0' (ff11000001433798):
> fill_kobj_path: path = '/devices/virtual/block/loop0'
> [*] attempt 3/128
> [ 84.603537][ T142] sh (142): drop_caches: 3
> image=/tmp/adfs-dmendbit.img disc_size=1073741824 dm_endbit=2097664
> bits (262208 bytes max)
> [ 84.901503][ T167] loop0: detected capacity change from 0 to 8
> [ 84.943773][ T167]
> ==================================================================
> [ 84.944056][ T167] BUG: KASAN: use-after-free in _find_next_bit+0xe2/0x140
> [ 84.944056][ T167] Read of size 8 at addr ff1100005b909000 by task
> poc-bin/167
> [ 84.944056][ T167]
> [ 84.944056][ T167] CPU: 0 UID: 0 PID: 167 Comm: poc-bin Tainted: G
> W T 7.0.0-rc2+ #5 PREEMPT(lazy)
> ccfb407f8ed1d19667324f70fc2e5f4a9b6173f6
> [ 84.944056][ T167] Tainted: [W]=WARN, [T]=RANDSTRUCT
> [ 84.944056][ T167] Hardware name: QEMU Standard PC (i440FX + PIIX,
> 1996), BIOS 1.15.0-1 04/01/2014
> [ 84.944056][ T167] Call Trace:
> [ 84.944056][ T167] <TASK>
> [ 84.944056][ T167] dump_stack_lvl+0x95/0x100
> [ 84.944056][ T167] print_address_description.constprop.0+0x2c/0x3c0
> [ 84.944056][ T167] ? _find_next_bit+0xe2/0x140
> [ 84.944056][ T167] print_report+0xb4/0x280
> [ 84.944056][ T167] ? kasan_addr_to_slab+0x27/0x80
> [ 84.944056][ T167] ? kasan_complete_mode_report_info+0xa3/0xc0
> [ 84.944056][ T167] kasan_report+0x9b/0x100
> [ 84.944056][ T167] ? _find_next_bit+0xe2/0x140
> [ 84.944056][ T167] _find_next_bit+0xe2/0x140
> [ 84.944056][ T167] ? find_held_lock+0x32/0xc0
> [ 84.944056][ T167] scan_map+0x2ac/0x4c0
> [ 84.944056][ T167] ? adfs_map_lookup+0x11d/0x340
> [ 84.944056][ T167] adfs_map_lookup+0x12e/0x340
> [ 84.944056][ T167] adfs_dir_read_buffers+0x282/0x5c0
> [ 84.944056][ T167] adfs_f_read+0x76/0x3c0
> [ 84.944056][ T167] ? __down_read_trylock+0x1de/0x480
> [ 84.944056][ T167] adfs_dir_read_inode+0x15f/0x2c0
> [ 84.944056][ T167] adfs_iterate+0x127/0x480
> [ 84.944056][ T167] ? __pfx_adfs_iterate+0x40/0x40
> [ 84.944056][ T167] ? iterate_dir+0x152/0xa80
> [ 84.944056][ T167] ? down_read_killable+0x116/0x380
> [ 84.944056][ T167] ? __pfx_down_read_killable+0x40/0x40
> [ 84.944056][ T167] ? selinux_file_permission+0x3c2/0x500
> [ 84.944056][ T167] iterate_dir+0x238/0xa80
> [ 84.944056][ T167] ? fdget_pos+0x24e/0x340
> [ 84.944056][ T167] __x64_sys_getdents64+0x132/0x240
> [ 84.944056][ T167] ? __pfx___x64_sys_getdents64+0x40/0x40
> [ 84.944056][ T167] ? __pfx_filldir64+0x40/0x40
> [ 84.944056][ T167] do_syscall_64+0x141/0xf40
> [ 84.944056][ T167] entry_SYSCALL_64_after_hwframe+0x77/0x7f
> [ 84.944056][ T167] RIP: 0033:0x448dcd
> [ 84.944056][ T167] Code: 02 b8 ff ff ff ff eb b8 0f 1f 44 00 00 f3
> 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b
> 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 b8 ff ff ff f7 d8
> 64 89 01 48
> [ 84.944056][ T167] RSP: 002b:00007fff97d52248 EFLAGS: 00000246
> ORIG_RAX: 00000000000000d9
> [ 84.944056][ T167] RAX: ffffffffffffffda RBX: 0000000000000005
> RCX: 0000000000448dcd
> [ 84.944056][ T167] RDX: 0000000000002000 RSI: 00007fff97d52390
> RDI: 0000000000000003
> [ 84.944056][ T167] RBP: 0000000000000003 R08: 00007fff97d520e0
> R09: 0000000000000000
> [ 84.944056][ T167] R10: 00000000004b04dd R11: 0000000000000246
> R12: 000000000049900f
> [ 84.944056][ T167] R13: 00007fff97d52390 R14: 000000000049907f
> R15: 00007fff97d52350
> [ 84.944056][ T167] </TASK>
> [ 84.944056][ T167]
> [ 84.944056][ T167] The buggy address belongs to the physical page:
> [ 84.944056][ T167] page: refcount:0 mapcount:0
> mapping:0000000000000000 index:0x215 pfn:0x5b909
> [ 84.944056][ T167] flags: 0xfffffc0000000(node=0|zone=1|lastcpupid=0x1fffff)
> [ 84.944056][ T167] raw: 000fffffc0000000 ffd40000016e5148
> ffd40000016e3e88 0000000000000000
> [ 84.944056][ T167] raw: 0000000000000215 0000000000000000
> 00000000ffffffff 0000000000000000
> [ 84.944056][ T167] page dumped because: kasan: bad access detected
> [ 84.944056][ T167]
> [ 84.944056][ T167] Memory state around the buggy address:
> [ 84.944056][ T167] ff1100005b908f00: 00 00 00 00 00 00 00 00 00
> 00 00 00 00 00 00 00
> [ 84.944056][ T167] ff1100005b908f80: 00 00 00 00 00 00 00 00 00
> 00 00 00 00 00 00 00
> [ 84.944056][ T167] >ff1100005b909000: ff ff ff ff ff ff ff ff ff
> ff ff ff ff ff ff ff
> [ 84.944056][ T167] ^
> [ 84.944056][ T167] ff1100005b909080: ff ff ff ff ff ff ff ff ff
> ff ff ff ff ff ff ff
> [ 84.944056][ T167] ff1100005b909100: ff ff ff ff ff ff ff ff ff
> ff ff ff ff ff ff ff
> [ 84.944056][ T167]
> ==================================================================
> [ 84.957085][ T167] Disabling lock debugging due to kernel taint
> [ 84.957940][ T167] BUG: unable to handle page fault for address:
> ff1100005b909000
> [ 84.958241][ T167] #PF: supervisor read access in kernel mode
> [ 84.958369][ T167] #PF: error_code(0x0000) - not-present page
> [ 84.958604][ T167] PGD 6b201067 P4D 6b202067 PUD 6b205067 PMD
> 7f831067 PTE 800fffffa46f6020
> [ 84.959193][ T167] Oops: Oops: 0000 [#1] SMP DEBUG_PAGEALLOC KASAN NOPTI
> [ 84.959358][ T167] CPU: 0 UID: 0 PID: 167 Comm: poc-bin Tainted: G
> B W T 7.0.0-rc2+ #5 PREEMPT(lazy)
> ccfb407f8ed1d19667324f70fc2e5f4a9b6173f6
> [ 84.959559][ T167] Tainted: [B]=BAD_PAGE, [W]=WARN, [T]=RANDSTRUCT
> [ 84.959692][ T167] Hardware name: QEMU Standard PC (i440FX + PIIX,
> 1996), BIOS 1.15.0-1 04/01/2014
> [ 84.959835][ T167] RIP: 0010:_find_next_bit+0xa3/0x140
> [ 84.959990][ T167] Code: df 4a 8d 6c 2d 08 eb 14 48 83 c3 01 48 83
> c5 08 48 89 da 48 c1 e2 06 48 39 d0 76 2a 48 89 ea 48 c1 ea 03 42 80
> 3c 22 00 75 33 <48> 8b 55 00 48 85 d2 74 d5 48 c1 e3 06 f3 48 0f bc d2
> 48 01 d3 48
> [ 84.960216][ T167] RSP: 0018:ffa00000014e78c8 EFLAGS: 00000246
> [ 84.960354][ T167] RAX: 0000000000200200 RBX: 0000000000000200
> RCX: 0000000000000000
> [ 84.960499][ T167] RDX: 0000000000000000 RSI: 0000000000000000
> RDI: 0000000000000000
> [ 84.960645][ T167] RBP: ff1100005b909000 R08: 0000000000000000
> R09: 0000000000000000
> [ 84.960781][ T167] R10: 0000000000000000 R11: 0000000000000000
> R12: dffffc0000000000
> [ 84.960914][ T167] R13: 0000000000000040 R14: dffffc0000000000
> R15: ff1100005b908000