Skip to content
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
CVE/CVE-2019-19037/
CVE/CVE-2019-19037/

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 

CVE-2019-19037

Target

Linux Kernel 5.3.11 Ext4 FileSystem

Bug Type

Null-Pointer-Dereference

Abstract

mount crafted image and remove directory operation can cause Null-Ptr-Deref

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)

Reproduce

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

Details

Debug View

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax   : 0x0000000000000800  →  0x0000000000000800
$rbx   : 0xffff8880676ba5a8  →  0x00000000000b4c00  →  0x00000000000b4c00
$rcx   : 0xffffffff81439f4f  →  0x0f50433b48f08944  →  0x0f50433b48f08944
$rdx   : 0xdffffc0000000000  →  0xdffffc0000000000
$rsp   : 0xffff8880670f7be8  →  0xffff8880676ba5f8  →  0x0000000000001500  →  0x0000000000001500
$rbp   : 0x0000000000000000  →  0x0000000000000000
$rsi   : 0x0000000000000000  →  0x0000000000000000
$rdi   : 0x0000000000000028  →  0x0000000000000028
$rip   : 0xffffffff81439f63  →  0x7c8b48ffeaa878e8  →  0x7c8b48ffeaa878e8
$r8    : 0xffffed100ced7505  →  0x0000000000000000  →  0x0000000000000000
$r9    : 0x0000000000000000  →  0x0000000000000000
$r10   : 0x0000000000000001  →  0x0000000000000001
$r11   : 0xffffed100ced7504  →  0x0000000000000000  →  0x0000000000000000
$r12   : 0xffff888066968400  →  0x0201000c00000801  →  0x0201000c00000801
$r13   : 0xffff888066968800  →  0x0e42180e41200e46  →  0x0e42180e41200e46
$r14   : 0x0000000000000800  →  0x0000000000000800
$r15   : 0x0000000000000028  →  0x0000000000000028
$eflags: [zero CARRY PARITY adjust SIGN trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x0010 $ss: 0x0018 $ds: 0x0000 $es: 0x0000 $fs: 0x0000 $gs: 0x0000
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0xffff8880670f7be8│+0x0000: 0xffff8880676ba5f8  →  0x0000000000001500  →  0x0000000000001500	 ← $rsp
0xffff8880670f7bf0│+0x0008: 0xffff888064858000  →  0xffffffff833319e0  →  0xffff88806cc20880  →  0xffff88806cc21100  →  0xffff88806cc21980  →  0xffff88806cc24400  →  0xffff88806cc24c80
0xffff8880670f7bf8│+0x0010: 0xffff888064858018  →  0x0000000000000400  →  0x0000000000000400
0xffff8880670f7c00│+0x0018: 0xffff888064858014  →  0x000004000000000a  →  0x000004000000000a
0xffff8880670f7c08│+0x0020: 0x1ffff1100ce1ef82  →  0x1ffff1100ce1ef82
0xffff8880670f7c10│+0x0028: 0x0000000041b58ab3  →  0x0000000041b58ab3
0xffff8880670f7c18│+0x0030: 0xffffffff82f81f36  →  0x3120342032332031  →  0x3120342032332031
0xffff8880670f7c20│+0x0038: 0xffffffff81439cd0  →  0x0000b84856415741  →  0x0000b84856415741
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
   0xffffffff81439f56 <ext4_empty_dir+646> jge    0xffffffff8143a09c <ext4_empty_dir+972>
   0xffffffff81439f5c <ext4_empty_dir+652> lea    r15, [rbp+0x28]
   0xffffffff81439f60 <ext4_empty_dir+656> mov    rdi, r15
 → 0xffffffff81439f63 <ext4_empty_dir+659> 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 = 0x0000000000000028 → 0x0000000000000028
)
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "", stopped, reason: BREAKPOINT
[#1] Id 2, Name: "", stopped, reason: BREAKPOINT
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0xffffffff81439f63 → ext4_empty_dir(inode=0xffff8880676ba5a8)
[#1] 0xffffffff8143b946 → ext4_rmdir(dir=0xffff8880676ba110, dentry=0xffff88806758e300)
[#2] 0xffffffff81306b24 → vfs_rmdir(dir=0xffff8880676ba110, dentry=0xffff88806758e300)
[#3] 0xffffffff8130f98a → do_rmdir(dfd=0xffffff9c, pathname=0x7ffd254e9672 "foo/bar")
[#4] 0xffffffff81003dee → do_syscall_64(nr=0x54, regs=0xffff8880670f7f58)
[#5] 0xffffffff8260008c → entry_SYSCALL_64()
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

$rbp(struct buffer_head *bh, local variable) appears to 0.

Bug Causes

fs/ext4/namei.c:2848 (link)

/*
 * routine to check that the specified directory is empty (for rmdir)
 */
bool ext4_empty_dir(struct inode *inode)
{
	unsigned int offset;
	struct buffer_head *bh;
	struct ext4_dir_entry_2 *de, *de1;
	struct super_block *sb;

	if (ext4_has_inline_data(inode)) {
		int has_inline_data = 1;
		int ret;

		ret = empty_inline_dir(inode, &has_inline_data);
		if (has_inline_data)
			return ret;
	}

	sb = inode->i_sb;
	if (inode->i_size < EXT4_DIR_REC_LEN(1) + EXT4_DIR_REC_LEN(2)) {
		EXT4_ERROR_INODE(inode, "invalid size");
		return true;
	}
	/* The first directory block must not be a hole,
	 * so treat it as DIRENT_HTREE
	 */
	bh = ext4_read_dirblock(inode, 0, DIRENT_HTREE);
	if (IS_ERR(bh))
		return true;

	de = (struct ext4_dir_entry_2 *) bh->b_data;
	de1 = ext4_next_entry(de, sb->s_blocksize);
	if (le32_to_cpu(de->inode) != inode->i_ino ||
			le32_to_cpu(de1->inode) == 0 ||
			strcmp(".", de->name) || strcmp("..", de1->name)) {
		ext4_warning_inode(inode, "directory missing '.' and/or '..'");
		brelse(bh);
		return true;
	}
	offset = ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize) +
		 ext4_rec_len_from_disk(de1->rec_len, sb->s_blocksize);
	de = ext4_next_entry(de1, sb->s_blocksize);
	while (offset < inode->i_size) {
[1]		if ((void *) de >= (void *) (bh->b_data+sb->s_blocksize)) {
			unsigned int lblock;
			brelse(bh);
			lblock = offset >> EXT4_BLOCK_SIZE_BITS(sb);
[2]			bh = ext4_read_dirblock(inode, lblock, EITHER);
			if (bh == NULL) {
				offset += sb->s_blocksize;
				continue;
			}
			if (IS_ERR(bh))
				return true;
			de = (struct ext4_dir_entry_2 *) bh->b_data;
		}
		if (ext4_check_dir_entry(inode, NULL, de, bh,
					 bh->b_data, bh->b_size, offset)) {
			de = (struct ext4_dir_entry_2 *)(bh->b_data +
							 sb->s_blocksize);
			offset = (offset | (sb->s_blocksize - 1)) + 1;
			continue;
		}
		if (le32_to_cpu(de->inode)) {
			brelse(bh);
			return false;
		}
		offset += ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize);
		de = ext4_next_entry(de, sb->s_blocksize);
	}
	brelse(bh);
	return true;
}

in loop [1] (bh->b_data+sb->s_blocksize),[2] function return value is 0, local variable bh can be NULL

KASAN logs

[  176.466778] EXT4-fs error (device loop0): ext4_find_dest_de:1932: inode #2049: block 597: comm 161: bad entry in directory: rec_len % 4 != 0 - offset=48, inode=114, rec_len=15, name_len=0, size=1024
[  177.323761] EXT4-fs error (device loop0): ext4_empty_dir:2862: inode #2049: block 597: comm 161: bad entry in directory: rec_len % 4 != 0 - offset=48, inode=114, rec_len=15, name_len=0, size=1024
[  177.407772] ==================================================================
[  177.407772] BUG: KASAN: null-ptr-deref in ext4_empty_dir+0x298/0x410
[  177.407772] Read of size 8 at addr 0000000000000028 by task 161/200
[  177.407772]
[  177.407772] CPU: 0 PID: 200 Comm: 161 Not tainted 5.3.11 #1
[  177.407772] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014
[  177.407772] Call Trace:
[  177.407772]  dump_stack+0x76/0xab
[  177.407772]  ? ext4_empty_dir+0x298/0x410
[  177.407772]  __kasan_report+0x176/0x19b
[  177.407772]  ? ext4_empty_dir+0x298/0x410
[  177.407772]  ? ext4_empty_dir+0x298/0x410
[  177.407772]  kasan_report+0xe/0x20
[  177.407772]  ext4_empty_dir+0x298/0x410
[  177.407772]  ? ext4_mkdir+0x650/0x650
[  177.407772]  ? avc_has_perm_noaudit+0x210/0x210
[  177.407772]  ? path_parentat+0x30/0x90
[  177.407772]  ? restore_nameidata+0x76/0xa0
[  177.407772]  ext4_rmdir+0x236/0x7b0
[  177.407772]  ? ext4_rename2+0x110/0x110
[  177.407772]  ? selinux_inode_rename+0x3f0/0x3f0
[  177.407772]  ? __d_lookup+0x1fa/0x260
[  177.407772]  ? down_read+0x1d0/0x1d0
[  177.407772]  vfs_rmdir+0xf4/0x1e0
[  177.407772]  do_rmdir+0x24a/0x2a0
[  177.407772]  ? __ia32_sys_mkdir+0x30/0x30
[  177.407772]  ? __sb_end_write+0x31/0x50
[  177.407772]  ? vfs_write+0x1f8/0x250
[  177.407772]  ? switch_fpu_return+0xfe/0x1f0
[  177.407772]  ? fpregs_mark_activate+0xe0/0xe0
[  177.407772]  do_syscall_64+0x5e/0x190
[  177.407772]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[  177.407772] RIP: 0033:0x7fd437afd469
[  177.407772] 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
[  177.407772] RSP: 002b:00007ffffa63fd18 EFLAGS: 00000217 ORIG_RAX: 0000000000000054
[  177.407772] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fd437afd469
[  177.407772] RDX: 00007fd437afd469 RSI: ffffffffffffff98 RDI: 00007ffffa640572
[  177.407772] RBP: 00007ffffa644600 R08: 00007ffffa6446e8 R09: 00007ffffa6446e8
[  177.407772] R10: 00007ffffa6446e8 R11: 0000000000000217 R12: 0000559119ba65d0
[  177.407772] R13: 00007ffffa6446e0 R14: 0000000000000000 R15: 0000000000000000
[  177.407772] ==================================================================
[  177.407772] Disabling lock debugging due to kernel taint
[  177.454308] BUG: kernel NULL pointer dereference, address: 0000000000000028
[  177.454988] #PF: supervisor read access in kernel mode
[  177.454988] #PF: error_code(0x0000) - not-present page
[  177.454988] PGD 0 P4D 0
[  177.454988] Oops: 0000 [#1] SMP KASAN NOPTI
[  177.454988] CPU: 0 PID: 200 Comm: 161 Tainted: G    B             5.3.11 #1
[  177.454988] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014
[  177.454988] RIP: 0010:ext4_empty_dir+0x29d/0x410
[  177.454988] Code: 4c 24 10 48 8b 3c 24 e8 91 a8 ea ff 44 89 f0 48 3b 43 50 0f 8d 40 01 00 00 4c 8d 7d 28 4c 89 ff e8 78 a8 ea ff 48 8b 7c 24 10 <4c> 8b 65 28 e8 6a a8 ea ff 48 8b 4c 24 08 4c 89 e0 48 03 41 18 49
[  177.454988] RSP: 0018:ffff888065b5fbe8 EFLAGS: 00000296
[  177.454988] RAX: 0000000000000000 RBX: ffff888067641c78 RCX: ffffffff8240d4dd
[  177.454988] RDX: 1ffffffff08049e7 RSI: 0000000000000246 RDI: ffff8880668d3318
[  177.454988] RBP: 0000000000000000 R08: fffffbfff07f9a8d R09: fffffbfff07f9a8d
[  177.454988] R10: 0000000000000001 R11: fffffbfff07f9a8c R12: ffff88806399b400
[  177.454988] R13: ffff88806399b800 R14: 0000000000000800 R15: 0000000000000028
[  177.454988] FS:  00007fd437fd6440(0000) GS:ffff88806d400000(0000) knlGS:0000000000000000
[  177.454988] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  177.454988] CR2: 0000000000000028 CR3: 00000000683f8000 CR4: 00000000000006f0
[  177.454988] Call Trace:
[  177.454988]  ? ext4_mkdir+0x650/0x650
[  177.454988]  ? avc_has_perm_noaudit+0x210/0x210
[  177.454988]  ? path_parentat+0x30/0x90
[  177.454988]  ? restore_nameidata+0x76/0xa0
[  177.454988]  ext4_rmdir+0x236/0x7b0
[  177.454988]  ? ext4_rename2+0x110/0x110
[  177.454988]  ? selinux_inode_rename+0x3f0/0x3f0
[  177.454988]  ? __d_lookup+0x1fa/0x260
[  177.454988]  ? down_read+0x1d0/0x1d0
[  177.454988]  vfs_rmdir+0xf4/0x1e0
[  177.454988]  do_rmdir+0x24a/0x2a0
[  177.454988]  ? __ia32_sys_mkdir+0x30/0x30
[  177.454988]  ? __sb_end_write+0x31/0x50
[  177.454988]  ? vfs_write+0x1f8/0x250
[  177.454988]  ? switch_fpu_return+0xfe/0x1f0
[  177.454988]  ? fpregs_mark_activate+0xe0/0xe0
[  177.454988]  do_syscall_64+0x5e/0x190
[  177.454988]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[  177.454988] RIP: 0033:0x7fd437afd469
[  177.454988] 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
[  177.454988] RSP: 002b:00007ffffa63fd18 EFLAGS: 00000217 ORIG_RAX: 0000000000000054
[  177.454988] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fd437afd469
[  177.454988] RDX: 00007fd437afd469 RSI: ffffffffffffff98 RDI: 00007ffffa640572
[  177.454988] RBP: 00007ffffa644600 R08: 00007ffffa6446e8 R09: 00007ffffa6446e8
[  177.454988] R10: 00007ffffa6446e8 R11: 0000000000000217 R12: 0000559119ba65d0
[  177.454988] R13: 00007ffffa6446e0 R14: 0000000000000000 R15: 0000000000000000
[  177.454988] Modules linked in:
[  177.454988] CR2: 0000000000000028
[  177.488637] ---[ end trace 4ce4c1c3e9b58473 ]---
[  177.491538] RIP: 0010:ext4_empty_dir+0x29d/0x410
[  177.494424] Code: 4c 24 10 48 8b 3c 24 e8 91 a8 ea ff 44 89 f0 48 3b 43 50 0f 8d 40 01 00 00 4c 8d 7d 28 4c 89 ff e8 78 a8 ea ff 48 8b 7c 24 10 <4c> 8b 65 28 e8 6a a8 ea ff 48 8b 4c 24 08 4c 89 e0 48 03 41 18 49
[  177.497367] RSP: 0018:ffff888065b5fbe8 EFLAGS: 00000296
[  177.501294] RAX: 0000000000000000 RBX: ffff888067641c78 RCX: ffffffff8240d4dd
[  177.501800] RDX: 1ffffffff08049e7 RSI: 0000000000000246 RDI: ffff8880668d3318
[  177.505206] RBP: 0000000000000000 R08: fffffbfff07f9a8d R09: fffffbfff07f9a8d
[  177.505953] R10: 0000000000000001 R11: fffffbfff07f9a8c R12: ffff88806399b400
[  177.509480] R13: ffff88806399b800 R14: 0000000000000800 R15: 0000000000000028
[  177.509832] FS:  00007fd437fd6440(0000) GS:ffff88806d400000(0000) knlGS:0000000000000000
[  177.510056] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  177.510217] CR2: 0000000000000028 CR3: 00000000683f8000 CR4: 00000000000006f0

Conclusion

crafted image can handle ext4_read_dirblock(inode, 0, EITHER) return value to 0.

it can be danger in other functions

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.