f2fs: fix to do sanity check with inode.i_inline_xattr_size
authorChao Yu <yuchao0@huawei.com>
Mon, 4 Mar 2019 09:19:04 +0000 (17:19 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Wed, 13 Mar 2019 02:02:26 +0000 (19:02 -0700)
As Paul Bandha reported in bugzilla:

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

When I run the poc on the mounted f2fs img I get a buffer overflow in
read_inline_xattr due to there being no sanity check on the value of
i_inline_xattr_size.

I created the img by just modifying the value of i_inline_xattr_size
in the inode:

i_name                         [test1.txt]
i_ext: fofs:0 blkaddr:0 len:0
i_extra_isize                  [0x      18 : 24]
i_inline_xattr_size            [0x    ffff : 65535]
i_addr[ofs]                    [0x       0 : 0]

mkdir /mnt/f2fs
mount ./f2fs1.img /mnt/f2fs
gcc poc.c -o poc
./poc

int main() {
int y = syscall(SYS_listxattr, "/mnt/f2fs/test1.txt", NULL, 0);
printf("ret %d", y);
printf("errno: %d\n", errno);

}

 BUG: KASAN: slab-out-of-bounds in read_inline_xattr+0x18f/0x260
 Read of size 262140 at addr ffff88011035efd8 by task f2fs1poc/3263

 CPU: 0 PID: 3263 Comm: f2fs1poc Not tainted 4.18.0-custom #1
 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.11.1-0-g0551a4be2c-prebuilt.qemu-project.org 04/01/2014
 Call Trace:
  dump_stack+0x71/0xab
  print_address_description+0x83/0x250
  kasan_report+0x213/0x350
  memcpy+0x1f/0x50
  read_inline_xattr+0x18f/0x260
  read_all_xattrs+0xba/0x190
  f2fs_listxattr+0x9d/0x3f0
  listxattr+0xb2/0xd0
  path_listxattr+0x93/0xe0
  do_syscall_64+0x9d/0x220
  entry_SYSCALL_64_after_hwframe+0x44/0xa9

Let's add sanity check for inode.i_inline_xattr_size during f2fs_iget()
to avoid this issue.

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

index bec52961630b91215eeb107029ad78610779201b..d44e6de70cb377e07991d435f4b4980718241929 100644 (file)
@@ -14,6 +14,7 @@
 #include "f2fs.h"
 #include "node.h"
 #include "segment.h"
+#include "xattr.h"
 
 #include <trace/events/f2fs.h>
 
@@ -248,6 +249,20 @@ static bool sanity_check_inode(struct inode *inode, struct page *node_page)
                return false;
        }
 
+       if (f2fs_has_extra_attr(inode) &&
+               f2fs_sb_has_flexible_inline_xattr(sbi) &&
+               f2fs_has_inline_xattr(inode) &&
+               (!fi->i_inline_xattr_size ||
+               fi->i_inline_xattr_size > MAX_INLINE_XATTR_SIZE)) {
+               set_sbi_flag(sbi, SBI_NEED_FSCK);
+               f2fs_msg(sbi->sb, KERN_WARNING,
+                       "%s: inode (ino=%lx) has corrupted "
+                       "i_inline_xattr_size: %d, max: %zu",
+                       __func__, inode->i_ino, fi->i_inline_xattr_size,
+                       MAX_INLINE_XATTR_SIZE);
+               return false;
+       }
+
        if (F2FS_I(inode)->extent_tree) {
                struct extent_info *ei = &F2FS_I(inode)->extent_tree->largest;
 
index 324938ec95f3e21186c41d1a1e7871f41617bf87..21750df930b3fff49b8c3edd28c8bc6150e1b9bc 100644 (file)
@@ -838,10 +838,7 @@ static int parse_options(struct super_block *sb, char *options)
                }
 
                min_size = sizeof(struct f2fs_xattr_header) / sizeof(__le32);
-               max_size = DEF_ADDRS_PER_INODE -
-                       F2FS_TOTAL_EXTRA_ATTR_SIZE / sizeof(__le32) -
-                       DEF_INLINE_RESERVED_SIZE -
-                       MIN_INLINE_DENTRY_SIZE / sizeof(__le32);
+               max_size = MAX_INLINE_XATTR_SIZE;
 
                if (F2FS_OPTION(sbi).inline_xattr_size < min_size ||
                                F2FS_OPTION(sbi).inline_xattr_size > max_size) {
index 67db134da0f5f6da01ff505d956e60069114767d..9172ee082ca830f9159f5a7ac73b3fca52cfa4e4 100644 (file)
@@ -78,6 +78,12 @@ struct f2fs_xattr_entry {
                                sizeof(struct f2fs_xattr_header) -      \
                                sizeof(struct f2fs_xattr_entry))
 
+#define MAX_INLINE_XATTR_SIZE                                          \
+                       (DEF_ADDRS_PER_INODE -                          \
+                       F2FS_TOTAL_EXTRA_ATTR_SIZE / sizeof(__le32) -   \
+                       DEF_INLINE_RESERVED_SIZE -                      \
+                       MIN_INLINE_DENTRY_SIZE / sizeof(__le32))
+
 /*
  * On-disk structure of f2fs_xattr
  * We use inline xattrs space + 1 block for xattr.