Security
Headlines
HeadlinesLatestCVEs

Headline

CVE-2019-19448: CVE/CVE-2019-19448 at master · bobfuzzer/CVE

In the Linux kernel 5.0.21 and 5.3.11, mounting a crafted btrfs filesystem image, performing some operations, and then making a syncfs system call can lead to a use-after-free in try_merge_free_space in fs/btrfs/free-space-cache.c because the pointer to a left data structure can be the same as the pointer to a right data structure.

CVE
#vulnerability#ios#ubuntu#linux#c++#bios#ssl
  • CVE-2019-19448
    • Target
    • Bug Type
    • Abstract
    • Reproduce
    • Details
      • Debug View
      • Bug Causes
      • KASAN logs
    • Conclusion
    • Discoverer
    • Acknowledgments

Target

Linux kernel btrfs FileSystem

Linux Version

Availablity

5.0.21

True

5.3.11

True

Bug Type

Use After Free

Abstract

syncfs syscall after some operation with crafted image can cause use-after-free vulnerability in try_merge_free_space

Reproduce

gcc -o poc poc_2019_19448.c mkdir mnt mount poc_2019_19448.img ./mnt cp poc ./mnt/ cd mnt ./poc

Details****Debug View

─────────────────────────────────────────────────────────── registers ────
$rax   : 0x0000000000000001  →  0x0000000000000001
$rbx   : 0xffff88806cf59138  →  0x0000000000000000  →  0x0000000000000000
$rcx   : 0xffff888067a6aa80  →  0xffff88806cf59138  →  0x0000000000000000 →  0x0000000000000000
$rdx   : 0x00000000000a17c8  →  0x00000000000a17c8
$rsp   : 0xffff8880649bfa60  →  0x0000000000001001  →  0x0000000000001001
$rbp   : 0xffff88806a2491a0  →  0xffff88806a2491a0  →  [loop detected]
$rsi   : 0xffff88806a6388c0  →  0x0000607f92802900  →  0x0000607f92802900
$rdi   : 0xffff88806cf59168  →  0x0000000000000000  →  0x0000000000000000
$rip   : 0xffffffff81625d82  →  0x7d8349ffcbea59e8  →  0x7d8349ffcbea59e8
$r8    : 0x00000000214fbdaa  →  0x00000000214fbdaa
$r9    : 0xffffed100daa632c  →  0x0000000000000000  →  0x0000000000000000
$r10   : 0x0000000000000001  →  0x0000000000000001
$r11   : 0xffffed100daa632b  →  0x0000000000000000  →  0x0000000000000000
$r12   : 0xffff888067a7c600  →  0x0000000000000001  →  0x0000000000000001
$r13   : 0xffff88806cf59138  →  0x0000000000000000  →  0x0000000000000000
$r14   : 0xffff888067a7c608  →  0xffff88806a2490d0  →  0x0000000000000001 →  0x0000000000000001
$r15   : 0x0000000001c04000  →  0x0000000001c04000
$eflags: [zero carry parity adjust SIGN trap INTERRUPT direction overflowresume virtualx86 identification]
$cs: 0x0010 $ss: 0x0018 $ds: 0x0000 $es: 0x0000 $fs: 0x0000 $gs: 0x0000
─────────────────────────────────────────────────────────────── stack ────
0xffff8880649bfa60│+0x0000: 0x0000000000001001  →  0x0000000000001001    ← $rsp
0xffff8880649bfa68│+0x0008: 0xffff88806a2491c0  →  0x0000000000007000  →0x0000000000007000
0xffff8880649bfa70│+0x0010: 0x000000016a2491a0  →  0x000000016a2491a0
0xffff8880649bfa78│+0x0018: 0xffff88806a2491b8  →  0x0000000001c04000  →0x0000000001c04000
0xffff8880649bfa80│+0x0020: 0xffff88806cf59158  →  0x0000000000006000  →0x0000000000006000
0xffff8880649bfa88│+0x0028: 0xffffffff81625cd2  →  0x5541564118468d48  →0x5541564118468d48
0xffff8880649bfa90│+0x0030: 0xffff888067a7c600  →  0x0000000000000001  →0x0000000000000001
0xffff8880649bfa98│+0x0038: 0xffff88806a2491a0  →  0xffff88806a2491a0  →[loop detected]
───────────────────────────────────────────────────────── code:x86:64 ────
   0xffffffff81625d79 <try_merge_free_space+169> je     0xffffffff81625d92 <try_merge_free_space+194>
   0xffffffff81625d7b <try_merge_free_space+171> lea    rdi, [r13+0x30]
   0xffffffff81625d7f <try_merge_free_space+175> mov    BYTE PTR [rsp], al
 → 0xffffffff81625d82 <try_merge_free_space+178> call   0xffffffff812e47e0 <__asan_load8>
   ↳  0xffffffff812e47e0 <__asan_load8_noabort+0> movabs rax, 0xffff7fffffffffff
      0xffffffff812e47ea <__asan_load8_noabort+10> mov    rcx, QWORD PTR [rsp]
      0xffffffff812e47ee <__asan_load8_noabort+14> cmp    rdi, rax
      0xffffffff812e47f1 <__asan_load8_noabort+17> jbe    0xffffffff812e4824 <__asan_load8+68>
      0xffffffff812e47f3 <__asan_load8_noabort+19> lea    rax, [rdi+0x7]
      0xffffffff812e47f7 <__asan_load8_noabort+23> mov    rdx, rax
─────────────────────────────────────────────────────────── arguments ────
__asan_load8 (
   long unsigned int var_0 = 0xffff88806cf59168 → 0x0000000000000000 → 0x0000000000000000
)
───────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "", stopped, reason: BREAKPOINT
[#1] Id 2, Name: "", stopped, reason: BREAKPOINT
─────────────────────────────────────────────────────────────── trace ────
[#0] 0xffffffff81625d82 → try_merge_free_space(ctl=0xffff888067a7c600, info=0xffff88806a2491a0, update_stat=<optimized out>)
[#1] 0xffffffff81629539 → __btrfs_add_free_space(fs_info=<optimized out>,ctl=0xffff888067a7c600, offset=<optimized out>, bytes=0x1000)
[#2] 0xffffffff81580277 → btrfs_add_free_space(block_group=<optimized out>, block_group=<optimized out>, size=<optimized out>, bytenr=<optimized out>)
[#3] 0xffffffff81580277 → unpin_extent_range(fs_info=0xffff8880650968a0, start=0x1c04000, end=<optimized out>, return_free_space=<optimized out>)
[#4] 0xffffffff815849ba → btrfs_finish_extent_commit(trans=0xffff88806bb3a150)
[#5] 0xffffffff815ae355 → btrfs_commit_transaction(trans=0xffff88806bb3a150)
[#6] 0xffffffff813499e2 → __sync_filesystem(wait=<optimized out>, sb=<optimized out>)
[#7] 0xffffffff813499e2 → sync_filesystem(sb=0xffff88806487f700)
[#8] 0xffffffff81349b07 → __do_sys_syncfs(fd=<optimized out>)
[#9] 0xffffffff81349b07 → __se_sys_syncfs(fd=<optimized out>)
──────────────────────────────────────────────────────────────────────────

Thread 2 hit Breakpoint 1, 0xffffffff81625d82 in try_merge_free_space (ctl=0xffff888067a7c600, info=0xffff88806a2491a0, update_stat=<optimized out>) at fs/btrfs/free-space-cache.c:2191
2191    in fs/btrfs/free-space-cache.c
gef➤  p right_info
$13 = (struct btrfs_free_space *) 0xffff88806cf59138
gef➤  p left_info
$14 = (struct btrfs_free_space *) 0xffff88806cf59138
gef➤

local variable right_info equals left_info.

Bug Causes

fs/btrfs/free-space-cache.c:2191 (link)

static bool try_merge_free_space(struct btrfs_free_space_ctl *ctl, struct btrfs_free_space *info, bool update_stat) { struct btrfs_free_space *left_info; struct btrfs_free_space *right_info; bool merged = false; u64 offset = info->offset; u64 bytes = info->bytes;

/\*
 \* first we want to see if there is free space adjacent to the range we
 \* are adding, if there is remove that struct and add a new one to
 \* cover the entire range
 \*/

[1] right_info = tree_search_offset(ctl, offset + bytes, 0, 0); if (right_info && rb_prev(&right_info->offset_index)) left_info = rb_entry(rb_prev(&right_info->offset_index), struct btrfs_free_space, offset_index); else [1] left_info = tree_search_offset(ctl, offset - 1, 0, 0);

if (right\_info && !right\_info->bitmap) {
    if (update\_stat)
        unlink\_free\_space(ctl, right\_info);
    else
        \_\_unlink\_free\_space(ctl, right\_info);
    info->bytes += right\_info->bytes;

[2] kmem_cache_free(btrfs_free_space_cachep, right_info); merged = true; }

[3] if (left_info && !left_info->bitmap && left_info->offset + left_info->bytes == offset) { if (update_stat) unlink_free_space(ctl, left_info); else __unlink_free_space(ctl, left_info); info->offset = left_info->offset; info->bytes += left_info->bytes; kmem_cache_free(btrfs_free_space_cachep, left_info); merged = true; }

return merged;

}

in [1] tree_search_offset returns same ptr(right_info == left_info), and use left_info[3] after freeing right_info[2]

KASAN logs

[  129.924437] ==================================================================
[  129.924437] BUG: KASAN: use-after-free in try_merge_free_space+0xb7/0x2e0
[  129.924437] Read of size 8 at addr ffff88806cf59168 by task poc/220
[  129.924437]
[  129.924437] CPU: 1 PID: 220 Comm: poc Not tainted 5.3.11 #1
[  129.924437] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014
[  129.924437] Call Trace:
[  129.924437]  dump_stack+0x76/0xab
[  129.924437]  print_address_description+0x70/0x3a0
[  129.924437]  ? try_merge_free_space+0xb7/0x2e0
[  129.924437]  __kasan_report+0x13a/0x19b
[  129.924437]  ? try_merge_free_space+0xb7/0x2e0
[  129.924437]  ? try_merge_free_space+0xb7/0x2e0
[  129.924437]  kasan_report+0xe/0x20
[  129.924437]  try_merge_free_space+0xb7/0x2e0
[  129.924437]  ? try_merge_free_space+0x2/0x2e0
[  129.924437]  __btrfs_add_free_space+0x89/0x5f0
[  129.924437]  ? rb_erase+0x1bd/0x830
[  129.924437]  ? block_group_cache_tree_search+0x12f/0x150
[  129.924437]  unpin_extent_range+0x537/0x930
[  129.924437]  ? __set_extent_bit+0x850/0x850
[  129.924437]  ? __exclude_logged_extent+0x150/0x150
[  129.924437]  ? cache_state_if_flags.part.32+0x10/0x30
[  129.924437]  btrfs_finish_extent_commit+0x13a/0x450
[  129.924437]  ? pagecache_get_page+0x20b/0x330
[  129.924437]  ? __wait_on_bit+0x150/0x150
[  129.924437]  ? btrfs_prepare_extent_commit+0x190/0x190
[  129.924437]  ? __find_get_block+0x40d/0x450
[  129.924437]  ? write_all_supers+0x635/0x1590
[  129.924437]  btrfs_commit_transaction+0xd15/0x1100
[  129.924437]  ? btrfs_apply_pending_changes+0x80/0x80
[  129.924437]  ? btrfs_attach_transaction_barrier+0x19/0x50
[  129.924437]  sync_filesystem+0xd2/0x110
[  129.924437]  __x64_sys_syncfs+0x57/0x90
[  129.924437]  do_syscall_64+0x5e/0x190
[  129.924437]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[  129.924437] RIP: 0033:0x7f6306075469
[  129.924437] Code: 00 f3 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 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 8b 0d ff 49 2b 00 f7 d8 64 89 01 48
[  129.924437] RSP: 002b:00007ffd2a5aeba8 EFLAGS: 00000286 ORIG_RAX: 0000000000000132
[  129.924437] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f6306075469
[  129.924437] RDX: ffffffffffffff98 RSI: 00007f6306075469 RDI: 0000000000000003
[  129.924437] RBP: 00007ffd2a5b2d40 R08: 00007ffd2a5b2e28 R09: 00007ffd2a5b2e28
[  129.924437] R10: 00007ffd2a5b2e28 R11: 0000000000000286 R12: 00005606df5a65d0
[  129.924437] R13: 00007ffd2a5b2e20 R14: 0000000000000000 R15: 0000000000000000
[  129.924437]
[  129.924437] Allocated by task 220:
[  129.924437]  save_stack+0x19/0x80
[  129.924437]  __kasan_kmalloc+0xd5/0xf0
[  129.924437]  kmem_cache_alloc+0xb3/0x1d0
[  129.924437]  __btrfs_add_free_space+0x39/0x5f0
[  129.924437]  unpin_extent_range+0x537/0x930
[  129.924437]  btrfs_finish_extent_commit+0x13a/0x450
[  129.924437]  btrfs_commit_transaction+0xd15/0x1100
[  129.924437]  sync_filesystem+0xd2/0x110
[  129.924437]  __x64_sys_syncfs+0x57/0x90
[  129.924437]  do_syscall_64+0x5e/0x190
[  129.924437]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[  129.924437]
[  129.924437] Freed by task 220:
[  129.924437]  save_stack+0x19/0x80
[  129.924437]  __kasan_slab_free+0x132/0x180
[  129.924437]  kmem_cache_free+0x75/0x280
[  129.924437]  try_merge_free_space+0x276/0x2e0
[  129.924437]  __btrfs_add_free_space+0x89/0x5f0
[  129.924437]  unpin_extent_range+0x537/0x930
[  129.924437]  btrfs_finish_extent_commit+0x13a/0x450
[  129.924437]  btrfs_commit_transaction+0xd15/0x1100
[  129.924437]  sync_filesystem+0xd2/0x110
[  129.924437]  __x64_sys_syncfs+0x57/0x90
[  129.924437]  do_syscall_64+0x5e/0x190
[  129.924437]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[  129.924437]
[  129.924437] The buggy address belongs to the object at ffff88806cf59138
[  129.924437]  which belongs to the cache btrfs_free_space of size 72
[  129.924437] The buggy address is located 48 bytes inside of
[  129.924437]  72-byte region [ffff88806cf59138, ffff88806cf59180)
[  129.924437] The buggy address belongs to the page:
[  129.924437] page:ffffea0001b3d640 refcount:1 mapcount:0 mapping:ffff88806a6388c0 index:0x0
[  129.924437] flags: 0x100000000000200(slab)
[  129.924437] raw: 0100000000000200 dead000000000100 dead000000000122 ffff88806a6388c0
[  129.924437] raw: 0000000000000000 0000000080270027 00000001ffffffff 0000000000000000
[  129.924437] page dumped because: kasan: bad access detected
[  129.924437]
[  129.924437] Memory state around the buggy address:
[  129.924437]  ffff88806cf59000: 00 00 00 00 00 00 00 00 00 fc fc fc fc 00 00 00
[  129.924437]  ffff88806cf59080: 00 00 00 00 00 00 fc fc fc fc 00 00 00 00 00 00
[  129.924437] >ffff88806cf59100: 00 00 00 fc fc fc fc fb fb fb fb fb fb fb fb fb
[  129.924437]                                                           ^
[  129.924437]  ffff88806cf59180: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[  129.924437]  ffff88806cf59200: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[  129.924437] ==================================================================
[  129.924437] Disabling lock debugging due to kernel taint
[  130.400869] WARNING: CPU: 1 PID: 220 at fs/btrfs/free-space-cache.c:1480 tree_insert_offset+0x75/0xe0
[  130.400869] Modules linked in:
[  130.400869] CPU: 1 PID: 220 Comm: poc Tainted: G    B             5.3.11 #1
[  130.400869] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014
[  130.400869] RIP: 0010:tree_insert_offset+0x75/0xe0
[  130.400869] Code: ff 49 8b 1f 48 85 db 74 2a 48 8d 7b 18 e8 e3 ee cb ff 4c 39 63 18 76 bf 4c 8d 7b 10 eb d8 e8 d2 ee cb ff 48 83 7b 30 00 75 ee <0f> 0b b8 ef ff ff ff eb 3e 4c 89 f7 e8 3a ef cb ff 49 8d 7e 08 49
[  130.400869] RSP: 0018:ffff8880649bfa60 EFLAGS: 00000246
[  130.400869] RAX: 0000000000000000 RBX: ffff88806a249068 RCX: ffffffff8162590e
[  130.400869] RDX: dffffc0000000000 RSI: 0000000001c09000 RDI: ffff88806a249098
[  130.400869] RBP: ffff88806a2490d0 R08: 0000000000000000 R09: ffffed100c937f4e
[  130.400869] R10: 0000000000000001 R11: ffffed100c937f4e R12: 0000000001c09000
[  130.400869] R13: 0000000000000000 R14: ffff88806a249270 R15: ffff88806a2490e0
[  130.400869] FS:  00007f630654e440(0000) GS:ffff88806d500000(0000) knlGS:0000000000000000
[  130.400869] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  130.400869] CR2: 00007f07b731d010 CR3: 0000000067834000 CR4: 00000000000006e0
[  130.400869] Call Trace:
[  130.400869]  link_free_space+0x3f/0x80
[  130.400869]  __btrfs_add_free_space+0xb8/0x5f0
[  130.400869]  ? rb_erase+0x1bd/0x830
[  130.400869]  unpin_extent_range+0x537/0x930
[  130.400869]  ? __set_extent_bit+0x850/0x850
[  130.400869]  ? __exclude_logged_extent+0x150/0x150
[  130.400869]  ? cache_state_if_flags.part.32+0x10/0x30
[  130.400869]  btrfs_finish_extent_commit+0x13a/0x450
[  130.400869]  ? pagecache_get_page+0x20b/0x330
[  130.400869]  ? __wait_on_bit+0x150/0x150
[  130.400869]  ? btrfs_prepare_extent_commit+0x190/0x190
[  130.400869]  ? __find_get_block+0x40d/0x450
[  130.400869]  ? write_all_supers+0x635/0x1590
[  130.400869]  btrfs_commit_transaction+0xd15/0x1100
[  130.400869]  ? btrfs_apply_pending_changes+0x80/0x80
[  130.400869]  ? btrfs_attach_transaction_barrier+0x19/0x50
[  130.400869]  sync_filesystem+0xd2/0x110
[  130.400869]  __x64_sys_syncfs+0x57/0x90
[  130.400869]  do_syscall_64+0x5e/0x190
[  130.400869]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[  130.400869] RIP: 0033:0x7f6306075469
[  130.400869] Code: 00 f3 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 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 8b 0d ff 49 2b 00 f7 d8 64 89 01 48
[  130.400869] RSP: 002b:00007ffd2a5aeba8 EFLAGS: 00000286 ORIG_RAX: 0000000000000132
[  130.400869] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f6306075469
[  130.400869] RDX: ffffffffffffff98 RSI: 00007f6306075469 RDI: 0000000000000003
[  130.400869] RBP: 00007ffd2a5b2d40 R08: 00007ffd2a5b2e28 R09: 00007ffd2a5b2e28
[  130.400869] R10: 00007ffd2a5b2e28 R11: 0000000000000286 R12: 00005606df5a65d0
[  130.400869] R13: 00007ffd2a5b2e20 R14: 0000000000000000 R15: 0000000000000000
[  130.400869] ---[ end trace af3d70351e521739 ]---
[  130.451152] BTRFS critical (device loop0): unable to add free space :-17
[  130.512290] BTRFS critical (device loop0): unable to add free space :-17

Conclusion

in try_merge_free_space function, local variable right_info and left_info can be same value.

it can be lead to arbitrary-address-free or double-free vulnerability by attacker.

Discoverer

Team bobfuzzer

Acknowledgments

This Project used ported version(to 5.0.21 and 5.3.14 linux kernel) of filesystem fuzzer ‘JANUS’ which developed by GeorgiaTech Systems Software & Security Lab(SSLab)

Thank you for the excellent fuzzer and paper below.

  • sslab-gatech/janus
  • Fuzzing File Systems via Two-Dimensional Input Space Exploration (IEEE S&P 2019)

CVE: Latest News

CVE-2023-50976: Transactions API Authorization by oleiman · Pull Request #14969 · redpanda-data/redpanda
CVE-2023-6905
CVE-2023-6903
CVE-2023-6904
CVE-2023-3907