Skip to content

Latest commit

 

History

History

CVE-2019-19813

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

CVE-2019-19813

Target

Linux kernel btrfs FileSystem

Linux Version Availablity
5.0.21 True

Bug Type

Use After Free

Abstract

syncfs syscall after some operation(with crafted image) can cause use-after-free vulnerability in mutex_can_spin_on_owner

Reproduce

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

Details

Debug View

─────────────────────────────────────────────────────────── registers ────
$rax   : 0xffff88806c120cc0  →  0xffff888067434a80  →  0xffff888069b6d500 →  0xffff88806a9d4dc0  →  0xffff888069b6d3c0  →  0xffff888066ed24d0  →  0xffff88806a4c7000  →  0xffff888066ed28c0
$rbx   : 0xffff88806774a4c0  →  0xffff88806c120cc0  →  0xffff888067434a80 →  0xffff888069b6d500  →  0xffff88806a9d4dc0  →  0xffff888069b6d3c0  →  0xffff888066ed24d0  →  0xffff88806a4c7000
$rcx   : 0x1ffff1100d82419f  →  0x1ffff1100d82419f
$rdx   : 0x00000000000000fb  →  0x00000000000000fb
$rsp   : 0xffff8880655ff970  →  0x0000000000000000  →  0x0000000000000000
$rbp   : 0xffff8880655ffae0  →  0xffff88806c124c00  →  0x97e0009600000501 →  0x97e0009600000501
$rsi   : 0x0000000000000008  →  0x0000000000000008
$rdi   : 0xffff88806c120cf8  →  0x0000000100000000  →  0x0000000100000000
$rip   : 0xffffffff8367ae8d  →  0xf6a9e9fde9e18ee8  →  0xf6a9e9fde9e18ee8
$r8    : 0xffffed100cee9499  →  0x0000000000000000  →  0x0000000000000000
$r9    : 0xffffed100cee9499  →  0x0000000000000000  →  0x0000000000000000
$r10   : 0x0000000000000001  →  0x0000000000000001
$r11   : 0xffffed100cee9498  →  0x0000000000000000  →  0x0000000000000000
$r12   : 0xffff88806c120cc0  →  0xffff888067434a80  →  0xffff888069b6d500 →  0xffff88806a9d4dc0  →  0xffff888069b6d3c0  →  0xffff888066ed24d0  →  0xffff88806a4c7000  →  0xffff888066ed28c0
$r13   : 0xffff88806c124c80  →  0x0000000000000000  →  0x0000000000000000
$r14   : 0xffff88806c120cc0  →  0xffff888067434a80  →  0xffff888069b6d500 →  0xffff88806a9d4dc0  →  0xffff888069b6d3c0  →  0xffff888066ed24d0  →  0xffff88806a4c7000  →  0xffff888066ed28c0
$r15   : 0xffff888068b0e160  →  0x0000000000000000  →  0x0000000000000000
$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 ────
0xffff8880655ff970│+0x0000: 0x0000000000000000  →  0x0000000000000000	 ← $rsp
0xffff8880655ff978│+0x0008: 0xffffffff8412de5c  →  0x3320342032332031  →0x3320342032332031
0xffff8880655ff980│+0x0010: 0x0000000041b58ab3  →  0x0000000041b58ab3
0xffff8880655ff988│+0x0018: 0x1ffff1100cabff36  →  0x1ffff1100cabff36
0xffff8880655ff990│+0x0020: 0xffffffff81b9daa0  →  0x0000b94856415741  →0x0000b94856415741
0xffff8880655ff998│+0x0028: 0xffff8880655ffac0  →  0x1ffff1100cabff5f  →0x1ffff1100cabff5f
0xffff8880655ff9a0│+0x0030: 0x0000000000000002  →  0x0000000000000002
0xffff8880655ff9a8│+0x0038: 0x4eb1b378b5fc8c00  →  0x4eb1b378b5fc8c00
───────────────────────────────────────────────────────── code:x86:64 ────
   0xffffffff8367ae7e <__mutex_lock.isra.7+2846> jmp    0xffffffff8367a6ca <__mutex_lock+874>
   0xffffffff8367ae83 <__mutex_lock.isra.7+2851> call   0xffffffff815190b0 <__asan_report_store8_noabort>
   0xffffffff8367ae88 <__mutex_lock.isra.7+2856> jmp    0xffffffff8367adc7 <__mutex_lock+2663>
 → 0xffffffff8367ae8d <__mutex_lock.isra.7+2861> call   0xffffffff81519020 <__asan_report_load4_noabort>
   ↳  0xffffffff81519020 <__asan_report_load4_noabort+0> mov    rcx, QWORD PTR [rsp]
      0xffffffff81519024 <__asan_report_load4_noabort+4> xor    edx, edx
      0xffffffff81519026 <__asan_report_load4_noabort+6> mov    esi, 0x4
      0xffffffff8151902b <__asan_report_load4_noabort+11> jmp    0xffffffff815185f0 <kasan_report>
      0xffffffff81519030 <__asan_report_load8_noabort+0> mov    rcx, QWORD PTR [rsp]
      0xffffffff81519034 <__asan_report_load8_noabort+4> xor    edx, edx
─────────────────────────────────────────────────────────── arguments ────
__asan_report_load4_noabort (
   long unsigned int var_0 = 0xffff88806c120cf8 → 0x0000000100000000 → 0x0000000100000000
)
─────────────────────────────────── source:kernel/locking/[...].c+578 ────
    573	 	/*
    574	 	 * As lock holder preemption issue, we both skip spinningif task is not
    575	 	 * on cpu or its cpu is preempted
    576	 	 */
    577	 	if (owner)
 →  578	 		retval = owner->on_cpu && !vcpu_is_preempted(task_cpu(owner));
    579	 	rcu_read_unlock();
    580
    581	 	/*
    582	 	 * If lock->owner is not set, the mutex has been released. Return true
    583	 	 * such that we'll trylock in the spin path, which is a faster option
───────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "", stopped, reason: BREAKPOINT
[#1] Id 2, Name: "", stopped, reason: BREAKPOINT
─────────────────────────────────────────────────────────────── trace ────
[#0] 0xffffffff8367ae8d → mutex_optimistic_spin(waiter=<optimized out>, use_ww_ctx=<optimized out>, ww_ctx=<optimized out>, lock=<optimized out>)
[#1] 0xffffffff8367ae8d → __mutex_lock_common(use_ww_ctx=<optimized out>,ww_ctx=<optimized out>, ip=<optimized out>, nest_lock=<optimized out>, subclass=<optimized out>, state=<optimized out>, lock=<optimized out>)
[#2] 0xffffffff8367ae8d → __mutex_lock(lock=0xffff88806774a4c0, state=<optimized out>, ip=<optimized out>, nest_lock=<optimized out>, subclass=<optimized out>)
[#3] 0xffffffff8367af6a → __mutex_lock_slowpath(lock=<optimized out>)
[#4] 0xffffffff8367b052 → mutex_lock(lock=0xffff88806774a4c0)
[#5] 0xffffffff81b61f8e → btrfs_insert_delayed_items(node=<optimized out>, root=<optimized out>, path=<optimized out>, trans=<optimized out>)
[#6] 0xffffffff81b61f8e → __btrfs_commit_inode_delayed_items(node=<optimized out>, path=<optimized out>, trans=<optimized out>)
[#7] 0xffffffff81b61f8e → __btrfs_run_delayed_items(trans=<optimized out>, nr=<optimized out>)
[#8] 0xffffffff81b644ea → btrfs_run_delayed_items(trans=<optimized out>)
[#9] 0xffffffff81a5ac25 → btrfs_commit_transaction(trans=0xffff888066985498)
──────────────────────────────────────────────────────────────────────────
gef➤

owner->on_cpu occurs use-after-free, local variable struct task_struct owner looks already freed

Bug Causes

kernel/locking/mutex.c:578 (link)

static inline int mutex_can_spin_on_owner(struct mutex *lock)
{
	struct task_struct *owner;
	int retval = 1;

	if (need_resched())
		return 0;

	rcu_read_lock();
[1]	owner = __mutex_owner(lock);

	/*
	 * As lock holder preemption issue, we both skip spinning if task is not
	 * on cpu or its cpu is preempted
	 */
	if (owner)
[2]		retval = owner->on_cpu && !vcpu_is_preempted(task_cpu(owner));
	rcu_read_unlock();

__mutex_owner(lock) returns freed task_struct pointer

KASAN logs

[  103.624824] ==================================================================
[  103.624824] BUG: KASAN: use-after-free in __mutex_lock.isra.7+0xb32/0xc00
[  103.624824] Read of size 4 at addr ffff88806c120cf8 by task sync/1913
[  103.624824]
[  103.624824] CPU: 1 PID: 1913 Comm: sync Tainted: G      D W         5.0.21 #1
[  103.624824] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014
[  103.624824] Call Trace:
[  103.624824]  dump_stack+0x5b/0x8b
[  103.624824]  print_address_description+0x70/0x280
[  103.624824]  ? __mutex_lock.isra.7+0xb32/0xc00
[  103.624824]  kasan_report+0x13a/0x19b
[  103.624824]  ? __mutex_lock.isra.7+0xb32/0xc00
[  103.624824]  ? __mutex_lock.isra.7+0xb32/0xc00
[  103.624824]  __mutex_lock.isra.7+0xb32/0xc00
[  103.624824]  ? __btrfs_qgroup_free_meta+0x440/0x440
[  103.624824]  ? mutex_trylock+0xa0/0xa0
[  103.624824]  ? btrfs_delayed_inode_release_metadata+0x268/0x320
[  103.624824]  ? btrfs_release_path+0x3e/0x190
[  103.624824]  ? finish_one_item+0x2d/0xa0
[  103.624824]  ? __btrfs_update_delayed_inode+0x3bd/0x540
[  103.624824]  ? _cond_resched+0x12/0x60
[  103.624824]  ? mutex_lock+0xe2/0xf0
[  103.624824]  mutex_lock+0xe2/0xf0
[  103.624824]  ? __mutex_lock_slowpath+0x10/0x10
[  103.624824]  ? mutex_unlock+0x18/0x40
[  103.624824]  ? __btrfs_release_delayed_node+0x30e/0x9f0
[  103.624824]  __btrfs_run_delayed_items+0x23e/0x12c0
[  103.624824]  ? _raw_spin_lock_irqsave+0x84/0xf0
[  103.624824]  ? _raw_write_lock_irqsave+0xf0/0xf0
[  103.624824]  ? __btrfs_kill_delayed_node+0x2e0/0x2e0
[  103.624824]  ? __wake_up_common+0x440/0x440
[  103.624824]  ? _raw_read_lock_irq+0x30/0x30
[  103.624824]  ? __ia32_sys_fdatasync+0x40/0x40
[  103.624824]  btrfs_commit_transaction+0x845/0x2500
[  103.624824]  ? btrfs_apply_pending_changes+0xb0/0xb0
[  103.624824]  ? btrfs_attach_transaction_barrier+0x19/0x70
[  103.624824]  ? btrfs_sync_fs+0x91/0x270
[  103.624824]  ? __ia32_sys_fdatasync+0x40/0x40
[  103.624824]  iterate_supers+0x14e/0x200
[  103.624824]  ksys_sync+0xba/0x160
[  103.624824]  ? __x64_sys_syncfs+0xe0/0xe0
[  103.624824]  ? __do_page_fault+0x42c/0x990
[  103.624824]  __ia32_sys_sync+0x5/0x10
[  103.624824]  do_syscall_64+0x8c/0x280
[  103.624824]  ? page_fault+0x8/0x30
[  103.624824]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[  103.624824] RIP: 0033:0x7f5b3d2437f7
[  103.624824] Code: 83 c4 08 48 3d 01 f0 ff ff 73 01 c3 48 8b 0d 98 76 2b 00 f7 d8 64 89 01 48 83 c8 ff c3 66 0f 1f 44 00 00 b8 a2 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 71 76 2b 00 f7 d8 64 89 01 48
[  103.624824] RSP: 002b:00007ffc14700668 EFLAGS: 00000202 ORIG_RAX: 00000000000000a2
[  103.624824] RAX: ffffffffffffffda RBX: 00007ffc14700798 RCX: 00007f5b3d2437f7
[  103.624824] RDX: 00007f5b3d4fde01 RSI: 00007ffc14700798 RDI: 00007f5b3d2c52b7
[  103.624824] RBP: 0000000000000001 R08: 0000000000000000 R09: 0000000000000000
[  103.624824] R10: 000000000000081f R11: 0000000000000202 R12: 0000000000000001
[  103.624824] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000
[  103.624824]
[  103.624824] Allocated by task 1352:
[  103.624824]  __kasan_kmalloc+0xd5/0xf0
[  103.624824]  kmem_cache_alloc_node+0xeb/0x1b0
[  103.624824]  copy_process.part.55+0x1467/0x60f0
[  103.624824]  _do_fork+0x146/0x7c0
[  103.624824]  do_syscall_64+0x8c/0x280
[  103.624824]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[  103.624824]
[  103.624824] Freed by task 0:
[  103.624824]  __kasan_slab_free+0x132/0x180
[  103.624824]  kmem_cache_free+0x83/0x1a0
[  103.624824]  rcu_process_callbacks+0x5fb/0x14f0
[  103.624824]  __do_softirq+0x1b2/0x5d0
[  103.624824]
[  103.624824] The buggy address belongs to the object at ffff88806c120cc0
[  103.624824]  which belongs to the cache task_struct of size 3136
[  103.624824] The buggy address is located 56 bytes inside of
[  103.624824]  3136-byte region [ffff88806c120cc0, ffff88806c121900)
[  103.624824] The buggy address belongs to the page:
[  103.624824] page:ffffea0001b04800 count:1 mapcount:0 mapping:ffff88806cc96dc0 index:0x0 compound_mapcount: 0
[  103.624824] flags: 0x100000000010200(slab|head)
[  103.624824] raw: 0100000000010200 ffffea0001b18400 0000000300000003 ffff88806cc96dc0
[  103.624824] raw: 0000000000000000 00000000800a000a 00000001ffffffff 0000000000000000
[  103.624824] page dumped because: kasan: bad access detected
[  103.624824]
[  103.624824] Memory state around the buggy address:
[  103.624824]  ffff88806c120b80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[  103.624824]  ffff88806c120c00: 00 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc
[  103.624824] >ffff88806c120c80: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb
[  103.624824]     ^
[  103.624824]  ffff88806c120d00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[  103.624824]  ffff88806c120d80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[  103.624824] ==================================================================

Conclusion

in btrfs_insert_delayed_items function, mutex_lock(&node->mutex) calls mutex_can_spin_on_owner, with freed lock->owner

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.