Skip to content
cvekernelext4use-after-free

Linux kernel ext4 use-after-free

6 min read

Overview

umounting after some operations(with crafted image) can cause use-after-free in ext4_put_super function.

it can be not only local(mount ext4 image in local shell), but also remote(mount corrupted(with crafted ext4 image) USB or other storage)

Target

Linux Kernel ext4 FileSystem

Linux Version Availablity
5.0.21 True

Reproduce

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

Root cause

fs/ext4/super.c:1022 (link)

static void dump_orphan_list(struct super_block *sb, struct ext4_sb_info *sbi)
{
	struct list_head *l;
 
	ext4_msg(sb, KERN_ERR, "sb orphan head is %d",
		 le32_to_cpu(sbi->s_es->s_last_orphan));
 
	printk(KERN_ERR "sb_info orphan list:\n");
	list_for_each(l, &sbi->s_orphan) {
		struct inode *inode = orphan_list_entry(l);
		printk(KERN_ERR "  "
[1]		       "inode %s:%lu at %p: mode %o, nlink %d, next %d\n",
		       inode->i_sb->s_id, inode->i_ino, inode,
		       inode->i_mode, inode->i_nlink,
		       NEXT_ORPHAN(inode));
	}
}

local variable inode is already freed.

it occurs use-after-free in inode->i_mode[1].

Debugger / KASAN

Debugger view:

LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────────────────[ REGISTERS ]─────────────────────────────────────────────
 RAX  0x7
 RBX  0xffff88805c795500 —▸ 0xffffffff84a52220 (super_blocks) —▸ 0xffff88805e860000 —▸ 0xffff88805e860880 —▸ 0xffff88805e867700 ◂— ...
 RCX  0x0
 RDX  0xfb
 RDI  0xffff888056ca499c ◂— 0x0
 RSI  0x8
 R8   0xffffed100bdc6061 ◂— 0
 R9   0xffffed100bdc6061 ◂— 0
 R10  0x228
 R11  0xffffed100bdc6060 ◂— 0
 R12  0xdffffc0000000000
 R13  0xffff888056ca49e0 —▸ 0xffff88805c793d88 ◂— 0xffff888056ca49e0
 R14  0xffff88805c793d88 —▸ 0xffff888056ca49e0 ◂— 0xffff88805c793d88
 R15  0xffff88805c793b80 ◂— 0x20 /* ' ' */
 RBP  0xffff88805866fd10 —▸ 0xffff88805866fd40 —▸ 0xffff88805866fd68 —▸ 0xffff88805866fd88 —▸ 0xffff88805866fe28 ◂— ...
 RSP  0xffff88805866fcb0 —▸ 0xffff88805866fca8 —▸ 0xffffffff81b54009 (ext4_put_super+1081) ◂— mov    rdx, r14 /* 0xb848f2894c */
 RIP  0xffffffff81b54822 (ext4_put_super+3154) ◂— 0xfea8e9ffc406e9e8
──────────────────────────────────────────────[ DISASM ]───────────────────────────────────────────────
   0xffffffff81b546c5 <ext4_put_super+2805>    add    eax, 3
   0xffffffff81b546c8 <ext4_put_super+2808>    cmp    al, dl
   0xffffffff81b546ca <ext4_put_super+2810>    jl     ext4_put_super+2820 <0xffffffff81b546d4>

   0xffffffff81b546cc <ext4_put_super+2812>    test   dl, dl
   0xffffffff81b546ce <ext4_put_super+2814>    jne    ext4_put_super+3154 <0xffffffff81b54822>
    ↓
 ► 0xffffffff81b54822 <ext4_put_super+3154>    call   __asan_report_load4_noabort <0xffffffff81794f10>
        rdi: 0xffff888056ca499c ◂— 0x0

   0xffffffff81b54827 <ext4_put_super+3159>    jmp    ext4_put_super+2820 <0xffffffff81b546d4>

   0xffffffff81b5482c <ext4_put_super+3164>    call   __asan_report_load4_noabort <0xffffffff81794f10>

   0xffffffff81b54831 <ext4_put_super+3169>    jmp    ext4_put_super+2858 <0xffffffff81b546fa>

   0xffffffff81b54836 <ext4_put_super+3174>    mov    rdi, r14
   0xffffffff81b54839 <ext4_put_super+3177>    call   __asan_report_load8_noabort <0xffffffff81794f30>
───────────────────────────────────────────[ SOURCE (CODE) ]───────────────────────────────────────────
In file: /home/phantom/kernel/ubuntu-eoan/fs/ext4/super.c
   932 		 le32_to_cpu(sbi->s_es->s_last_orphan));
   933
   934 	printk(KERN_ERR "sb_info orphan list:\n");
   935 	list_for_each(l, &sbi->s_orphan) {
   936 		struct inode *inode = orphan_list_entry(l);
 ► 937 		printk(KERN_ERR "  "
   938 		       "inode %s:%lu at %p: mode %o, nlink %d, next %d\n",
   939 		       inode->i_sb->s_id, inode->i_ino, inode,
   940 		       inode->i_mode, inode->i_nlink,
   941 		       NEXT_ORPHAN(inode));
   942 	}
───────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────
00:0000│ rsp  0xffff88805866fcb0 —▸ 0xffff88805866fca8 —▸ 0xffffffff81b54009 (ext4_put_super+1081) ◂— mov    rdx, r14 /* 0xb848f2894c */
01:0008│      0xffff88805866fcb8 —▸ 0xffffffff818fe3cd (__sync_blockdev+93) ◂— pop    rbx /* 0x7500023c80c35d5b */
02:0010│      0xffff88805866fcc0 —▸ 0xffff88805c793be8 —▸ 0xffff888058c3b400 ◂— 0x400000001000
03:0018│      0xffff88805866fcc8 —▸ 0xffff88805c793bf0 —▸ 0xffff88805b86b648 ◂— 0x0
04:0020│      0xffff88805866fcd0 —▸ 0xffff88805c793bb0 ◂— 1
05:0028│      0xffff88805866fcd8 —▸ 0xffff88805c7958a8 —▸ 0xffff88805c793b80 ◂— 0x20 /* ' ' */
06:0030│      0xffff88805866fce0 —▸ 0xffff888056ca4a48 ◂— 0xd81a4
07:0038│      0xffff88805866fce8 —▸ 0xffff88805c795500 —▸ 0xffffffff84a52220 (super_blocks) —▸ 0xffff88805e860000 —▸ 0xffff88805e860880 ◂— ...
─────────────────────────────────────────────[ BACKTRACE ]─────────────────────────────────────────────
 ► f 0 ffffffff81b54822 ext4_put_super+3154
   f 1 ffffffff81b54822 ext4_put_super+3154
   f 2 ffffffff81825327 generic_shutdown_super+311
   f 3 ffffffff81827704 kill_block_super+164
   f 4 ffffffff818265f7 deactivate_locked_super+151
   f 5 ffffffff8182763e deactivate_super+350
   f 6 ffffffff8188da72 cleanup_mnt+674
   f 7 ffffffff8188dc62 __cleanup_mnt+18
   f 8 ffffffff81213f5c task_work_run+268
   f 9 ffffffff8100844c exit_to_usermode_loop+444
   f 10 ffffffff8100844c exit_to_usermode_loop+444
───────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg> x/xg $25->i_mode
0x0 <fixed_percpu_data>:	Cannot access memory at address 0x0
pwndbg> x/xg &$25->i_mode
0xffff888056ca499c:	0x0000000000000000

KASAN log on umount (the per-object orphan-list hex dump printed on poc execution is omitted for brevity):

[   71.797689] ==================================================================
[   71.799205] BUG: KASAN: use-after-free in ext4_put_super+0xc57/0xd30
[   71.799205] Read of size 4 at addr ffff88805711a5bc by task umount/327
[   71.799205]
[   71.799205] CPU: 0 PID: 327 Comm: umount Not tainted 5.3.7 #1
[   71.799205] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
[   71.799205] Call Trace:
[   71.799205]  dump_stack+0x7b/0xb5
[   71.799205]  print_address_description+0x7c/0x3b0
[   71.799205]  ? ext4_put_super+0xc57/0xd30
[   71.799205]  __kasan_report+0x134/0x191
[   71.799205]  ? ext4_put_super+0xc57/0xd30
[   71.799205]  ? ext4_put_super+0xc57/0xd30
[   71.799205]  kasan_report+0x12/0x20
[   71.799205]  __asan_report_load4_noabort+0x14/0x20
[   71.799205]  ext4_put_super+0xc57/0xd30
[   71.799205]  ? __sync_blockdev+0x5d/0xb0
[   71.799205]  generic_shutdown_super+0x137/0x380
[   71.799205]  kill_block_super+0xa4/0x1f0
[   71.799205]  deactivate_locked_super+0x97/0xe0
[   71.799205]  deactivate_super+0x15e/0x180
[   71.799205]  ? destroy_unused_super+0xf0/0xf0
[   71.799205]  ? dput+0x5e/0x780
[   71.799205]  cleanup_mnt+0x2a2/0x400
[   71.799205]  __cleanup_mnt+0x12/0x20
[   71.799205]  task_work_run+0x10c/0x180
[   71.799205]  exit_to_usermode_loop+0x1bc/0x280
[   71.799205]  do_syscall_64+0x25b/0x2f0
[   71.799205]  ? prepare_exit_to_usermode+0xf1/0x1a0
[   71.799205]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[   71.799205] RIP: 0033:0x7f2018f8ed77
[   71.799205] Code: 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 31 f6 e9 09 00 00 00 66 0f 1f 84 00 00 00 00 00 b8 a6 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d f1 00 2b 00 f7 d8 64 89 01 48
[   71.799205] RSP: 002b:00007ffecf2bf808 EFLAGS: 00000246 ORIG_RAX: 00000000000000a6
[   71.799205] RAX: 0000000000000000 RBX: 000055ae60680060 RCX: 00007f2018f8ed77
[   71.799205] RDX: 0000000000000001 RSI: 0000000000000000 RDI: 000055ae60686e30
[   71.799205] RBP: 000055ae60686e30 R08: 000055ae60685080 R09: 0000000000000014
[   71.799205] R10: 00000000000006b4 R11: 0000000000000246 R12: 00007f2019490e64
[   71.799205] R13: 0000000000000000 R14: 000055ae60680240 R15: 00007ffecf2bfa90
[   71.799205]
[   71.799205] Allocated by task 324:
[   71.799205]  save_stack+0x21/0x90
[   71.799205]  __kasan_kmalloc+0xcc/0xe0
[   71.799205]  kasan_slab_alloc+0x14/0x20
[   71.799205]  kmem_cache_alloc+0xd3/0x260
[   71.799205]  ext4_alloc_inode+0x1d/0x700
[   71.799205]  alloc_inode+0x60/0x190
[   71.799205]  iget_locked+0x157/0x3f0
[   71.799205]  __ext4_iget+0x210/0x5620
[   71.799205]  ext4_lookup+0x2ad/0x6d0
[   71.799205]  __lookup_slow+0x1af/0x3a0
[   71.799205]  lookup_slow+0x56/0x80
[   71.799205]  walk_component+0x6a5/0xfa0
[   71.799205]  path_lookupat+0x18f/0x8c0
[   71.799205]  filename_lookup+0x183/0x3c0
[   71.799205]  user_path_at_empty+0x36/0x40
[   71.799205]  do_sys_truncate+0x8e/0x120
[   71.799205]  __x64_sys_truncate+0x54/0x80
[   71.799205]  do_syscall_64+0xa5/0x2f0
[   71.799205]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[   71.799205]
[   71.799205] Freed by task 9:
[   71.799205]  save_stack+0x21/0x90
[   71.799205]  __kasan_slab_free+0x137/0x180
[   71.799205]  kasan_slab_free+0xe/0x10
[   71.799205]  kmem_cache_free+0xe3/0x2e0
[   71.799205]  ext4_free_in_core_inode+0x25/0x30
[   71.799205]  i_callback+0x44/0x70
[   71.799205]  rcu_core+0x414/0xe90
[   71.799205]  rcu_core_si+0xe/0x10
[   71.799205]  __do_softirq+0x1b2/0x605
[   71.799205]
[   71.799205] The buggy address belongs to the object at ffff88805711a580
[   71.799205]  which belongs to the cache ext4_inode_cache of size 1072
[   71.799205] The buggy address is located 60 bytes inside of
[   71.799205]  1072-byte region [ffff88805711a580, ffff88805711a9b0)
[   71.799205] The buggy address belongs to the page:
[   71.799205] page:ffffea00015c4600 refcount:1 mapcount:0 mapping:ffff88805c8c6600 index:0x0 compound_mapcount: 0
[   71.799205] flags: 0xfffffc0010200(slab|head)
[   71.799205] raw: 000fffffc0010200 dead000000000100 dead000000000122 ffff88805c8c6600
[   71.799205] raw: 0000000000000000 00000000800d000d 00000001ffffffff 0000000000000000
[   71.799205] page dumped because: kasan: bad access detected
[   71.799205]
[   71.799205] Memory state around the buggy address:
[   71.799205]  ffff88805711a480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[   71.799205]  ffff88805711a500: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[   71.799205] >ffff88805711a580: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[   71.799205]                                         ^
[   71.799205]  ffff88805711a600: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[   71.799205]  ffff88805711a680: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[   71.799205] ==================================================================
[   71.799205] Disabling lock debugging due to kernel taint
[   71.841308]   inode loop0:16 at 000000003fa23361: mode 100644, nlink 1, next 0
[   71.843393] ------------[ cut here ]------------
[   71.843657] kernel BUG at fs/ext4/super.c:1028!
...

Details

CVSS 7.8 (CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H), CWE-416, published 2019-12-08, last modified 2024-11-21.

Attribution

Found as part of the Best of the Best (BoB) 8th bobfuzzer team project — a five-person team that ported the JANUS file-system fuzzer. This is team work, not sole authorship.

References