]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
f2fs: fix to do sanity check on free nid
authorChao Yu <yuchao0@huawei.com>
Mon, 15 Apr 2019 07:28:36 +0000 (15:28 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Thu, 9 May 2019 04:23:09 +0000 (21:23 -0700)
As Jungyeon reported in bugzilla:

https://bugzilla.kernel.org/show_bug.cgi?id=203225

- Overview
When mounting the attached crafted image and unmounting it, following errors are reported.
Additionally, it hangs on sync after unmounting.

The image is intentionally fuzzed from a normal f2fs image for testing.
Compile options for F2FS are as follows.
CONFIG_F2FS_FS=y
CONFIG_F2FS_STAT_FS=y
CONFIG_F2FS_FS_XATTR=y
CONFIG_F2FS_FS_POSIX_ACL=y
CONFIG_F2FS_CHECK_FS=y

- Reproduces
mkdir test
mount -t f2fs tmp.img test
touch test/t
umount test
sync

- Messages
 kernel BUG at fs/f2fs/node.c:3073!
 RIP: 0010:f2fs_destroy_node_manager+0x2f0/0x300
 Call Trace:
  f2fs_put_super+0xf4/0x270
  generic_shutdown_super+0x62/0x110
  kill_block_super+0x1c/0x50
  kill_f2fs_super+0xad/0xd0
  deactivate_locked_super+0x35/0x60
  cleanup_mnt+0x36/0x70
  task_work_run+0x75/0x90
  exit_to_usermode_loop+0x93/0xa0
  do_syscall_64+0xba/0xf0
  entry_SYSCALL_64_after_hwframe+0x44/0xa9
 RIP: 0010:f2fs_destroy_node_manager+0x2f0/0x300

NAT table is corrupted, so reserved meta/node inode ids were added into
free list incorrectly, during file creation, since reserved id has cached
in inode hash, so it fails the creation and preallocated nid can not be
released later, result in kernel panic.

To fix this issue, let's do nid boundary check during free nid loading.

Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/node.c

index 5452a6e340daa0f4269317d9b75fac51a02dbf12..e29d5f6735ae9143d70d9d7c75ba1ebee2b011c5 100644 (file)
@@ -2083,6 +2083,9 @@ static bool add_free_nid(struct f2fs_sb_info *sbi,
        if (unlikely(nid == 0))
                return false;
 
+       if (unlikely(f2fs_check_nid_range(sbi, nid)))
+               return false;
+
        i = f2fs_kmem_cache_alloc(free_nid_slab, GFP_NOFS);
        i->nid = nid;
        i->state = FREE_NID;