--- /dev/null
+From 24fc426c29e8caa7e8f69d3e5ca7a7440f0c9976 Mon Sep 17 00:00:00 2001
+From: Alexei Starovoitov <ast@kernel.org>
+Date: Tue, 15 May 2018 09:27:05 -0700
+Subject: bpf: Prevent memory disambiguation attack
+
+commit af86ca4e3088fe5eacf2f7e58c01fa68ca067672 upstream.
+
+Detect code patterns where malicious 'speculative store bypass' can be used
+and sanitize such patterns.
+
+ 39: (bf) r3 = r10
+ 40: (07) r3 += -216
+ 41: (79) r8 = *(u64 *)(r7 +0) // slow read
+ 42: (7a) *(u64 *)(r10 -72) = 0 // verifier inserts this instruction
+ 43: (7b) *(u64 *)(r8 +0) = r3 // this store becomes slow due to r8
+ 44: (79) r1 = *(u64 *)(r6 +0) // cpu speculatively executes this load
+ 45: (71) r2 = *(u8 *)(r1 +0) // speculatively arbitrary 'load byte'
+ // is now sanitized
+
+Above code after x86 JIT becomes:
+ e5: mov %rbp,%rdx
+ e8: add $0xffffffffffffff28,%rdx
+ ef: mov 0x0(%r13),%r14
+ f3: movq $0x0,-0x48(%rbp)
+ fb: mov %rdx,0x0(%r14)
+ ff: mov 0x0(%rbx),%rdi
+103: movzbq 0x0(%rdi),%rsi
+
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+[bwh: Backported to 4.14:
+ - Add bpf_verifier_env parameter to check_stack_write()
+ - Look up stack slot_types with state->stack_slot_type[] rather than
+ state->stack[].slot_type[]
+ - Drop bpf_verifier_env argument to verbose()
+ - Adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/bpf_verifier.h | 1 +
+ kernel/bpf/verifier.c | 62 +++++++++++++++++++++++++++++++++---
+ 2 files changed, 59 insertions(+), 4 deletions(-)
+
+diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
+index a3333004fd2b..8458cc5fbce5 100644
+--- a/include/linux/bpf_verifier.h
++++ b/include/linux/bpf_verifier.h
+@@ -113,6 +113,7 @@ struct bpf_insn_aux_data {
+ struct bpf_map *map_ptr; /* pointer for call insn into lookup_elem */
+ };
+ int ctx_field_size; /* the ctx field size for load insn, maybe 0 */
++ int sanitize_stack_off; /* stack slot to be cleared */
+ bool seen; /* this insn was processed by the verifier */
+ };
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 013b0cd1958e..f6755fd5bae2 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -717,8 +717,9 @@ static bool is_spillable_regtype(enum bpf_reg_type type)
+ /* check_stack_read/write functions track spill/fill of registers,
+ * stack boundary and alignment are checked in check_mem_access()
+ */
+-static int check_stack_write(struct bpf_verifier_state *state, int off,
+- int size, int value_regno)
++static int check_stack_write(struct bpf_verifier_env *env,
++ struct bpf_verifier_state *state, int off,
++ int size, int value_regno, int insn_idx)
+ {
+ int i, spi = (MAX_BPF_STACK + off) / BPF_REG_SIZE;
+ /* caller checked that off % size == 0 and -MAX_BPF_STACK <= off < 0,
+@@ -738,8 +739,32 @@ static int check_stack_write(struct bpf_verifier_state *state, int off,
+ state->spilled_regs[spi] = state->regs[value_regno];
+ state->spilled_regs[spi].live |= REG_LIVE_WRITTEN;
+
+- for (i = 0; i < BPF_REG_SIZE; i++)
++ for (i = 0; i < BPF_REG_SIZE; i++) {
++ if (state->stack_slot_type[MAX_BPF_STACK + off + i] == STACK_MISC &&
++ !env->allow_ptr_leaks) {
++ int *poff = &env->insn_aux_data[insn_idx].sanitize_stack_off;
++ int soff = (-spi - 1) * BPF_REG_SIZE;
++
++ /* detected reuse of integer stack slot with a pointer
++ * which means either llvm is reusing stack slot or
++ * an attacker is trying to exploit CVE-2018-3639
++ * (speculative store bypass)
++ * Have to sanitize that slot with preemptive
++ * store of zero.
++ */
++ if (*poff && *poff != soff) {
++ /* disallow programs where single insn stores
++ * into two different stack slots, since verifier
++ * cannot sanitize them
++ */
++ verbose("insn %d cannot access two stack slots fp%d and fp%d",
++ insn_idx, *poff, soff);
++ return -EINVAL;
++ }
++ *poff = soff;
++ }
+ state->stack_slot_type[MAX_BPF_STACK + off + i] = STACK_SPILL;
++ }
+ } else {
+ /* regular write of data into stack */
+ state->spilled_regs[spi] = (struct bpf_reg_state) {};
+@@ -1216,7 +1241,8 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
+ verbose("attempt to corrupt spilled pointer on stack\n");
+ return -EACCES;
+ }
+- err = check_stack_write(state, off, size, value_regno);
++ err = check_stack_write(env, state, off, size,
++ value_regno, insn_idx);
+ } else {
+ err = check_stack_read(state, off, size, value_regno);
+ }
+@@ -4270,6 +4296,34 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
+ else
+ continue;
+
++ if (type == BPF_WRITE &&
++ env->insn_aux_data[i + delta].sanitize_stack_off) {
++ struct bpf_insn patch[] = {
++ /* Sanitize suspicious stack slot with zero.
++ * There are no memory dependencies for this store,
++ * since it's only using frame pointer and immediate
++ * constant of zero
++ */
++ BPF_ST_MEM(BPF_DW, BPF_REG_FP,
++ env->insn_aux_data[i + delta].sanitize_stack_off,
++ 0),
++ /* the original STX instruction will immediately
++ * overwrite the same stack slot with appropriate value
++ */
++ *insn,
++ };
++
++ cnt = ARRAY_SIZE(patch);
++ new_prog = bpf_patch_insn_data(env, i + delta, patch, cnt);
++ if (!new_prog)
++ return -ENOMEM;
++
++ delta += cnt - 1;
++ env->prog = new_prog;
++ insn = new_prog->insnsi + i + delta;
++ continue;
++ }
++
+ if (env->insn_aux_data[i + delta].ptr_type != PTR_TO_CTX)
+ continue;
+
+--
+2.17.1
+
--- /dev/null
+From 45c4c6911e3d2c7198404928beb1deca7fca8931 Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <quwenruo.btrfs@gmx.com>
+Date: Wed, 23 Aug 2017 16:57:59 +0900
+Subject: btrfs: Add checker for EXTENT_CSUM
+
+commit 4b865cab96fe2a30ed512cf667b354bd291b3b0a upstream.
+
+EXTENT_CSUM checker is a relatively easy one, only needs to check:
+
+1) Objectid
+ Fixed to BTRFS_EXTENT_CSUM_OBJECTID
+
+2) Key offset alignment
+ Must be aligned to sectorsize
+
+3) Item size alignedment
+ Must be aligned to csum size
+
+Signed-off-by: Qu Wenruo <quwenruo.btrfs@gmx.com>
+Reviewed-by: Nikolay Borisov <nborisov@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/disk-io.c | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
+index ab8925b2efd1..53841d773a40 100644
+--- a/fs/btrfs/disk-io.c
++++ b/fs/btrfs/disk-io.c
+@@ -627,6 +627,27 @@ static int check_extent_data_item(struct btrfs_root *root,
+ return 0;
+ }
+
++static int check_csum_item(struct btrfs_root *root, struct extent_buffer *leaf,
++ struct btrfs_key *key, int slot)
++{
++ u32 sectorsize = root->fs_info->sectorsize;
++ u32 csumsize = btrfs_super_csum_size(root->fs_info->super_copy);
++
++ if (key->objectid != BTRFS_EXTENT_CSUM_OBJECTID) {
++ CORRUPT("invalid objectid for csum item", leaf, root, slot);
++ return -EUCLEAN;
++ }
++ if (!IS_ALIGNED(key->offset, sectorsize)) {
++ CORRUPT("unaligned key offset for csum item", leaf, root, slot);
++ return -EUCLEAN;
++ }
++ if (!IS_ALIGNED(btrfs_item_size_nr(leaf, slot), csumsize)) {
++ CORRUPT("unaligned csum item size", leaf, root, slot);
++ return -EUCLEAN;
++ }
++ return 0;
++}
++
+ /*
+ * Common point to switch the item-specific validation.
+ */
+@@ -640,6 +661,9 @@ static int check_leaf_item(struct btrfs_root *root,
+ case BTRFS_EXTENT_DATA_KEY:
+ ret = check_extent_data_item(root, leaf, key, slot);
+ break;
++ case BTRFS_EXTENT_CSUM_KEY:
++ ret = check_csum_item(root, leaf, key, slot);
++ break;
+ }
+ return ret;
+ }
+--
+2.17.1
+
--- /dev/null
+From 1776d7d1c91f2c6166e91eee40686610287b0ad8 Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <quwenruo.btrfs@gmx.com>
+Date: Wed, 23 Aug 2017 16:57:58 +0900
+Subject: btrfs: Add sanity check for EXTENT_DATA when reading out leaf
+
+commit 40c3c40947324d9f40bf47830c92c59a9bbadf4a upstream.
+
+Add extra checks for item with EXTENT_DATA type. This checks the
+following thing:
+
+0) Key offset
+ All key offsets must be aligned to sectorsize.
+ Inline extent must have 0 for key offset.
+
+1) Item size
+ Uncompressed inline file extent size must match item size.
+ (Compressed inline file extent has no information about its on-disk size.)
+ Regular/preallocated file extent size must be a fixed value.
+
+2) Every member of regular file extent item
+ Including alignment for bytenr and offset, possible value for
+ compression/encryption/type.
+
+3) Type/compression/encode must be one of the valid values.
+
+This should be the most comprehensive and strict check in the context
+of btrfs_item for EXTENT_DATA.
+
+Signed-off-by: Qu Wenruo <quwenruo.btrfs@gmx.com>
+Reviewed-by: Nikolay Borisov <nborisov@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+[ switch to BTRFS_FILE_EXTENT_TYPES, similar to what
+ BTRFS_COMPRESS_TYPES does ]
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/disk-io.c | 103 ++++++++++++++++++++++++++++++++
+ include/uapi/linux/btrfs_tree.h | 1 +
+ 2 files changed, 104 insertions(+)
+
+diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
+index da7b2039e4cb..ab8925b2efd1 100644
+--- a/fs/btrfs/disk-io.c
++++ b/fs/btrfs/disk-io.c
+@@ -550,6 +550,100 @@ static int check_tree_block_fsid(struct btrfs_fs_info *fs_info,
+ btrfs_header_level(eb) == 0 ? "leaf" : "node", \
+ reason, btrfs_header_bytenr(eb), root->objectid, slot)
+
++static int check_extent_data_item(struct btrfs_root *root,
++ struct extent_buffer *leaf,
++ struct btrfs_key *key, int slot)
++{
++ struct btrfs_file_extent_item *fi;
++ u32 sectorsize = root->fs_info->sectorsize;
++ u32 item_size = btrfs_item_size_nr(leaf, slot);
++
++ if (!IS_ALIGNED(key->offset, sectorsize)) {
++ CORRUPT("unaligned key offset for file extent",
++ leaf, root, slot);
++ return -EUCLEAN;
++ }
++
++ fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
++
++ if (btrfs_file_extent_type(leaf, fi) > BTRFS_FILE_EXTENT_TYPES) {
++ CORRUPT("invalid file extent type", leaf, root, slot);
++ return -EUCLEAN;
++ }
++
++ /*
++ * Support for new compression/encrption must introduce incompat flag,
++ * and must be caught in open_ctree().
++ */
++ if (btrfs_file_extent_compression(leaf, fi) > BTRFS_COMPRESS_TYPES) {
++ CORRUPT("invalid file extent compression", leaf, root, slot);
++ return -EUCLEAN;
++ }
++ if (btrfs_file_extent_encryption(leaf, fi)) {
++ CORRUPT("invalid file extent encryption", leaf, root, slot);
++ return -EUCLEAN;
++ }
++ if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) {
++ /* Inline extent must have 0 as key offset */
++ if (key->offset) {
++ CORRUPT("inline extent has non-zero key offset",
++ leaf, root, slot);
++ return -EUCLEAN;
++ }
++
++ /* Compressed inline extent has no on-disk size, skip it */
++ if (btrfs_file_extent_compression(leaf, fi) !=
++ BTRFS_COMPRESS_NONE)
++ return 0;
++
++ /* Uncompressed inline extent size must match item size */
++ if (item_size != BTRFS_FILE_EXTENT_INLINE_DATA_START +
++ btrfs_file_extent_ram_bytes(leaf, fi)) {
++ CORRUPT("plaintext inline extent has invalid size",
++ leaf, root, slot);
++ return -EUCLEAN;
++ }
++ return 0;
++ }
++
++ /* Regular or preallocated extent has fixed item size */
++ if (item_size != sizeof(*fi)) {
++ CORRUPT(
++ "regluar or preallocated extent data item size is invalid",
++ leaf, root, slot);
++ return -EUCLEAN;
++ }
++ if (!IS_ALIGNED(btrfs_file_extent_ram_bytes(leaf, fi), sectorsize) ||
++ !IS_ALIGNED(btrfs_file_extent_disk_bytenr(leaf, fi), sectorsize) ||
++ !IS_ALIGNED(btrfs_file_extent_disk_num_bytes(leaf, fi), sectorsize) ||
++ !IS_ALIGNED(btrfs_file_extent_offset(leaf, fi), sectorsize) ||
++ !IS_ALIGNED(btrfs_file_extent_num_bytes(leaf, fi), sectorsize)) {
++ CORRUPT(
++ "regular or preallocated extent data item has unaligned value",
++ leaf, root, slot);
++ return -EUCLEAN;
++ }
++
++ return 0;
++}
++
++/*
++ * Common point to switch the item-specific validation.
++ */
++static int check_leaf_item(struct btrfs_root *root,
++ struct extent_buffer *leaf,
++ struct btrfs_key *key, int slot)
++{
++ int ret = 0;
++
++ switch (key->type) {
++ case BTRFS_EXTENT_DATA_KEY:
++ ret = check_extent_data_item(root, leaf, key, slot);
++ break;
++ }
++ return ret;
++}
++
+ static noinline int check_leaf(struct btrfs_root *root,
+ struct extent_buffer *leaf)
+ {
+@@ -606,9 +700,13 @@ static noinline int check_leaf(struct btrfs_root *root,
+ * 1) key order
+ * 2) item offset and size
+ * No overlap, no hole, all inside the leaf.
++ * 3) item content
++ * If possible, do comprehensive sanity check.
++ * NOTE: All checks must only rely on the item data itself.
+ */
+ for (slot = 0; slot < nritems; slot++) {
+ u32 item_end_expected;
++ int ret;
+
+ btrfs_item_key_to_cpu(leaf, &key, slot);
+
+@@ -651,6 +749,11 @@ static noinline int check_leaf(struct btrfs_root *root,
+ return -EUCLEAN;
+ }
+
++ /* Check if the item size and content meet other criteria */
++ ret = check_leaf_item(root, leaf, &key, slot);
++ if (ret < 0)
++ return ret;
++
+ prev_key.objectid = key.objectid;
+ prev_key.type = key.type;
+ prev_key.offset = key.offset;
+diff --git a/include/uapi/linux/btrfs_tree.h b/include/uapi/linux/btrfs_tree.h
+index 7115838fbf2a..38ab0e06259a 100644
+--- a/include/uapi/linux/btrfs_tree.h
++++ b/include/uapi/linux/btrfs_tree.h
+@@ -734,6 +734,7 @@ struct btrfs_balance_item {
+ #define BTRFS_FILE_EXTENT_INLINE 0
+ #define BTRFS_FILE_EXTENT_REG 1
+ #define BTRFS_FILE_EXTENT_PREALLOC 2
++#define BTRFS_FILE_EXTENT_TYPES 2
+
+ struct btrfs_file_extent_item {
+ /*
+--
+2.17.1
+
--- /dev/null
+From 712e44f4d7a2e30a87cc97bf043607ea01d0a39b Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <quwenruo.btrfs@gmx.com>
+Date: Wed, 23 Aug 2017 16:57:57 +0900
+Subject: btrfs: Check if item pointer overlaps with the item itself
+
+commit 7f43d4affb2a254d421ab20b0cf65ac2569909fb upstream.
+
+Function check_leaf() checks if any item pointer points outside of the
+leaf, but it doesn't check if the pointer overlaps with the item itself.
+
+Normally only the last item may be the victim, but adding such check is
+never a bad idea anyway.
+
+Signed-off-by: Qu Wenruo <quwenruo.btrfs@gmx.com>
+Reviewed-by: Nikolay Borisov <nborisov@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/disk-io.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
+index 4a1e63df1183..da7b2039e4cb 100644
+--- a/fs/btrfs/disk-io.c
++++ b/fs/btrfs/disk-io.c
+@@ -644,6 +644,13 @@ static noinline int check_leaf(struct btrfs_root *root,
+ return -EUCLEAN;
+ }
+
++ /* Also check if the item pointer overlaps with btrfs item. */
++ if (btrfs_item_nr_offset(slot) + sizeof(struct btrfs_item) >
++ btrfs_item_ptr_offset(leaf, slot)) {
++ CORRUPT("slot overlap with its data", leaf, root, slot);
++ return -EUCLEAN;
++ }
++
+ prev_key.objectid = key.objectid;
+ prev_key.type = key.type;
+ prev_key.offset = key.offset;
+--
+2.17.1
+
--- /dev/null
+From 42ed835b434453459cc94a951a2f51db4ce38aa7 Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <wqu@suse.com>
+Date: Wed, 1 Aug 2018 10:37:16 +0800
+Subject: btrfs: Check that each block group has corresponding chunk at mount
+ time
+
+commit 514c7dca85a0bf40be984dab0b477403a6db901f upstream.
+
+A crafted btrfs image with incorrect chunk<->block group mapping will
+trigger a lot of unexpected things as the mapping is essential.
+
+Although the problem can be caught by block group item checker
+added in "btrfs: tree-checker: Verify block_group_item", it's still not
+sufficient. A sufficiently valid block group item can pass the check
+added by the mentioned patch but could fail to match the existing chunk.
+
+This patch will add extra block group -> chunk mapping check, to ensure
+we have a completely matching (start, len, flags) chunk for each block
+group at mount time.
+
+Here we reuse the original helper find_first_block_group(), which is
+already doing the basic bg -> chunk checks, adding further checks of the
+start/len and type flags.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=199837
+Reported-by: Xu Wen <wen.xu@gatech.edu>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Reviewed-by: Su Yue <suy.fnst@cn.fujitsu.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/extent-tree.c | 28 +++++++++++++++++++++++++++-
+ 1 file changed, 27 insertions(+), 1 deletion(-)
+
+diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
+index fdc42eddccc2..83791d13c204 100644
+--- a/fs/btrfs/extent-tree.c
++++ b/fs/btrfs/extent-tree.c
+@@ -9828,6 +9828,8 @@ static int find_first_block_group(struct btrfs_fs_info *fs_info,
+ int ret = 0;
+ struct btrfs_key found_key;
+ struct extent_buffer *leaf;
++ struct btrfs_block_group_item bg;
++ u64 flags;
+ int slot;
+
+ ret = btrfs_search_slot(NULL, root, key, path, 0, 0);
+@@ -9862,8 +9864,32 @@ static int find_first_block_group(struct btrfs_fs_info *fs_info,
+ "logical %llu len %llu found bg but no related chunk",
+ found_key.objectid, found_key.offset);
+ ret = -ENOENT;
++ } else if (em->start != found_key.objectid ||
++ em->len != found_key.offset) {
++ btrfs_err(fs_info,
++ "block group %llu len %llu mismatch with chunk %llu len %llu",
++ found_key.objectid, found_key.offset,
++ em->start, em->len);
++ ret = -EUCLEAN;
+ } else {
+- ret = 0;
++ read_extent_buffer(leaf, &bg,
++ btrfs_item_ptr_offset(leaf, slot),
++ sizeof(bg));
++ flags = btrfs_block_group_flags(&bg) &
++ BTRFS_BLOCK_GROUP_TYPE_MASK;
++
++ if (flags != (em->map_lookup->type &
++ BTRFS_BLOCK_GROUP_TYPE_MASK)) {
++ btrfs_err(fs_info,
++"block group %llu len %llu type flags 0x%llx mismatch with chunk type flags 0x%llx",
++ found_key.objectid,
++ found_key.offset, flags,
++ (BTRFS_BLOCK_GROUP_TYPE_MASK &
++ em->map_lookup->type));
++ ret = -EUCLEAN;
++ } else {
++ ret = 0;
++ }
+ }
+ free_extent_map(em);
+ goto out;
+--
+2.17.1
+
--- /dev/null
+From be96701e27044da9dc0d219df741b7b26fbc0e64 Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <quwenruo.btrfs@gmx.com>
+Date: Mon, 9 Oct 2017 01:51:02 +0000
+Subject: btrfs: Move leaf and node validation checker to tree-checker.c
+
+commit 557ea5dd003d371536f6b4e8f7c8209a2b6fd4e3 upstream.
+
+It's no doubt the comprehensive tree block checker will become larger,
+so moving them into their own files is quite reasonable.
+
+Signed-off-by: Qu Wenruo <quwenruo.btrfs@gmx.com>
+[ wording adjustments ]
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/Makefile | 2 +-
+ fs/btrfs/disk-io.c | 285 +-----------------------------------
+ fs/btrfs/tree-checker.c | 309 ++++++++++++++++++++++++++++++++++++++++
+ fs/btrfs/tree-checker.h | 26 ++++
+ 4 files changed, 340 insertions(+), 282 deletions(-)
+ create mode 100644 fs/btrfs/tree-checker.c
+ create mode 100644 fs/btrfs/tree-checker.h
+
+diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile
+index f2cd9dedb037..195229df5ba0 100644
+--- a/fs/btrfs/Makefile
++++ b/fs/btrfs/Makefile
+@@ -10,7 +10,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
+ export.o tree-log.o free-space-cache.o zlib.o lzo.o zstd.o \
+ compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \
+ reada.o backref.o ulist.o qgroup.o send.o dev-replace.o raid56.o \
+- uuid-tree.o props.o hash.o free-space-tree.o
++ uuid-tree.o props.o hash.o free-space-tree.o tree-checker.o
+
+ btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
+ btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
+diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
+index 53841d773a40..2df5e906db08 100644
+--- a/fs/btrfs/disk-io.c
++++ b/fs/btrfs/disk-io.c
+@@ -50,6 +50,7 @@
+ #include "sysfs.h"
+ #include "qgroup.h"
+ #include "compression.h"
++#include "tree-checker.h"
+
+ #ifdef CONFIG_X86
+ #include <asm/cpufeature.h>
+@@ -544,284 +545,6 @@ static int check_tree_block_fsid(struct btrfs_fs_info *fs_info,
+ return ret;
+ }
+
+-#define CORRUPT(reason, eb, root, slot) \
+- btrfs_crit(root->fs_info, \
+- "corrupt %s, %s: block=%llu, root=%llu, slot=%d", \
+- btrfs_header_level(eb) == 0 ? "leaf" : "node", \
+- reason, btrfs_header_bytenr(eb), root->objectid, slot)
+-
+-static int check_extent_data_item(struct btrfs_root *root,
+- struct extent_buffer *leaf,
+- struct btrfs_key *key, int slot)
+-{
+- struct btrfs_file_extent_item *fi;
+- u32 sectorsize = root->fs_info->sectorsize;
+- u32 item_size = btrfs_item_size_nr(leaf, slot);
+-
+- if (!IS_ALIGNED(key->offset, sectorsize)) {
+- CORRUPT("unaligned key offset for file extent",
+- leaf, root, slot);
+- return -EUCLEAN;
+- }
+-
+- fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
+-
+- if (btrfs_file_extent_type(leaf, fi) > BTRFS_FILE_EXTENT_TYPES) {
+- CORRUPT("invalid file extent type", leaf, root, slot);
+- return -EUCLEAN;
+- }
+-
+- /*
+- * Support for new compression/encrption must introduce incompat flag,
+- * and must be caught in open_ctree().
+- */
+- if (btrfs_file_extent_compression(leaf, fi) > BTRFS_COMPRESS_TYPES) {
+- CORRUPT("invalid file extent compression", leaf, root, slot);
+- return -EUCLEAN;
+- }
+- if (btrfs_file_extent_encryption(leaf, fi)) {
+- CORRUPT("invalid file extent encryption", leaf, root, slot);
+- return -EUCLEAN;
+- }
+- if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) {
+- /* Inline extent must have 0 as key offset */
+- if (key->offset) {
+- CORRUPT("inline extent has non-zero key offset",
+- leaf, root, slot);
+- return -EUCLEAN;
+- }
+-
+- /* Compressed inline extent has no on-disk size, skip it */
+- if (btrfs_file_extent_compression(leaf, fi) !=
+- BTRFS_COMPRESS_NONE)
+- return 0;
+-
+- /* Uncompressed inline extent size must match item size */
+- if (item_size != BTRFS_FILE_EXTENT_INLINE_DATA_START +
+- btrfs_file_extent_ram_bytes(leaf, fi)) {
+- CORRUPT("plaintext inline extent has invalid size",
+- leaf, root, slot);
+- return -EUCLEAN;
+- }
+- return 0;
+- }
+-
+- /* Regular or preallocated extent has fixed item size */
+- if (item_size != sizeof(*fi)) {
+- CORRUPT(
+- "regluar or preallocated extent data item size is invalid",
+- leaf, root, slot);
+- return -EUCLEAN;
+- }
+- if (!IS_ALIGNED(btrfs_file_extent_ram_bytes(leaf, fi), sectorsize) ||
+- !IS_ALIGNED(btrfs_file_extent_disk_bytenr(leaf, fi), sectorsize) ||
+- !IS_ALIGNED(btrfs_file_extent_disk_num_bytes(leaf, fi), sectorsize) ||
+- !IS_ALIGNED(btrfs_file_extent_offset(leaf, fi), sectorsize) ||
+- !IS_ALIGNED(btrfs_file_extent_num_bytes(leaf, fi), sectorsize)) {
+- CORRUPT(
+- "regular or preallocated extent data item has unaligned value",
+- leaf, root, slot);
+- return -EUCLEAN;
+- }
+-
+- return 0;
+-}
+-
+-static int check_csum_item(struct btrfs_root *root, struct extent_buffer *leaf,
+- struct btrfs_key *key, int slot)
+-{
+- u32 sectorsize = root->fs_info->sectorsize;
+- u32 csumsize = btrfs_super_csum_size(root->fs_info->super_copy);
+-
+- if (key->objectid != BTRFS_EXTENT_CSUM_OBJECTID) {
+- CORRUPT("invalid objectid for csum item", leaf, root, slot);
+- return -EUCLEAN;
+- }
+- if (!IS_ALIGNED(key->offset, sectorsize)) {
+- CORRUPT("unaligned key offset for csum item", leaf, root, slot);
+- return -EUCLEAN;
+- }
+- if (!IS_ALIGNED(btrfs_item_size_nr(leaf, slot), csumsize)) {
+- CORRUPT("unaligned csum item size", leaf, root, slot);
+- return -EUCLEAN;
+- }
+- return 0;
+-}
+-
+-/*
+- * Common point to switch the item-specific validation.
+- */
+-static int check_leaf_item(struct btrfs_root *root,
+- struct extent_buffer *leaf,
+- struct btrfs_key *key, int slot)
+-{
+- int ret = 0;
+-
+- switch (key->type) {
+- case BTRFS_EXTENT_DATA_KEY:
+- ret = check_extent_data_item(root, leaf, key, slot);
+- break;
+- case BTRFS_EXTENT_CSUM_KEY:
+- ret = check_csum_item(root, leaf, key, slot);
+- break;
+- }
+- return ret;
+-}
+-
+-static noinline int check_leaf(struct btrfs_root *root,
+- struct extent_buffer *leaf)
+-{
+- struct btrfs_fs_info *fs_info = root->fs_info;
+- /* No valid key type is 0, so all key should be larger than this key */
+- struct btrfs_key prev_key = {0, 0, 0};
+- struct btrfs_key key;
+- u32 nritems = btrfs_header_nritems(leaf);
+- int slot;
+-
+- /*
+- * Extent buffers from a relocation tree have a owner field that
+- * corresponds to the subvolume tree they are based on. So just from an
+- * extent buffer alone we can not find out what is the id of the
+- * corresponding subvolume tree, so we can not figure out if the extent
+- * buffer corresponds to the root of the relocation tree or not. So skip
+- * this check for relocation trees.
+- */
+- if (nritems == 0 && !btrfs_header_flag(leaf, BTRFS_HEADER_FLAG_RELOC)) {
+- struct btrfs_root *check_root;
+-
+- key.objectid = btrfs_header_owner(leaf);
+- key.type = BTRFS_ROOT_ITEM_KEY;
+- key.offset = (u64)-1;
+-
+- check_root = btrfs_get_fs_root(fs_info, &key, false);
+- /*
+- * The only reason we also check NULL here is that during
+- * open_ctree() some roots has not yet been set up.
+- */
+- if (!IS_ERR_OR_NULL(check_root)) {
+- struct extent_buffer *eb;
+-
+- eb = btrfs_root_node(check_root);
+- /* if leaf is the root, then it's fine */
+- if (leaf != eb) {
+- CORRUPT("non-root leaf's nritems is 0",
+- leaf, check_root, 0);
+- free_extent_buffer(eb);
+- return -EUCLEAN;
+- }
+- free_extent_buffer(eb);
+- }
+- return 0;
+- }
+-
+- if (nritems == 0)
+- return 0;
+-
+- /*
+- * Check the following things to make sure this is a good leaf, and
+- * leaf users won't need to bother with similar sanity checks:
+- *
+- * 1) key order
+- * 2) item offset and size
+- * No overlap, no hole, all inside the leaf.
+- * 3) item content
+- * If possible, do comprehensive sanity check.
+- * NOTE: All checks must only rely on the item data itself.
+- */
+- for (slot = 0; slot < nritems; slot++) {
+- u32 item_end_expected;
+- int ret;
+-
+- btrfs_item_key_to_cpu(leaf, &key, slot);
+-
+- /* Make sure the keys are in the right order */
+- if (btrfs_comp_cpu_keys(&prev_key, &key) >= 0) {
+- CORRUPT("bad key order", leaf, root, slot);
+- return -EUCLEAN;
+- }
+-
+- /*
+- * Make sure the offset and ends are right, remember that the
+- * item data starts at the end of the leaf and grows towards the
+- * front.
+- */
+- if (slot == 0)
+- item_end_expected = BTRFS_LEAF_DATA_SIZE(fs_info);
+- else
+- item_end_expected = btrfs_item_offset_nr(leaf,
+- slot - 1);
+- if (btrfs_item_end_nr(leaf, slot) != item_end_expected) {
+- CORRUPT("slot offset bad", leaf, root, slot);
+- return -EUCLEAN;
+- }
+-
+- /*
+- * Check to make sure that we don't point outside of the leaf,
+- * just in case all the items are consistent to each other, but
+- * all point outside of the leaf.
+- */
+- if (btrfs_item_end_nr(leaf, slot) >
+- BTRFS_LEAF_DATA_SIZE(fs_info)) {
+- CORRUPT("slot end outside of leaf", leaf, root, slot);
+- return -EUCLEAN;
+- }
+-
+- /* Also check if the item pointer overlaps with btrfs item. */
+- if (btrfs_item_nr_offset(slot) + sizeof(struct btrfs_item) >
+- btrfs_item_ptr_offset(leaf, slot)) {
+- CORRUPT("slot overlap with its data", leaf, root, slot);
+- return -EUCLEAN;
+- }
+-
+- /* Check if the item size and content meet other criteria */
+- ret = check_leaf_item(root, leaf, &key, slot);
+- if (ret < 0)
+- return ret;
+-
+- prev_key.objectid = key.objectid;
+- prev_key.type = key.type;
+- prev_key.offset = key.offset;
+- }
+-
+- return 0;
+-}
+-
+-static int check_node(struct btrfs_root *root, struct extent_buffer *node)
+-{
+- unsigned long nr = btrfs_header_nritems(node);
+- struct btrfs_key key, next_key;
+- int slot;
+- u64 bytenr;
+- int ret = 0;
+-
+- if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root->fs_info)) {
+- btrfs_crit(root->fs_info,
+- "corrupt node: block %llu root %llu nritems %lu",
+- node->start, root->objectid, nr);
+- return -EIO;
+- }
+-
+- for (slot = 0; slot < nr - 1; slot++) {
+- bytenr = btrfs_node_blockptr(node, slot);
+- btrfs_node_key_to_cpu(node, &key, slot);
+- btrfs_node_key_to_cpu(node, &next_key, slot + 1);
+-
+- if (!bytenr) {
+- CORRUPT("invalid item slot", node, root, slot);
+- ret = -EIO;
+- goto out;
+- }
+-
+- if (btrfs_comp_cpu_keys(&key, &next_key) >= 0) {
+- CORRUPT("bad key order", node, root, slot);
+- ret = -EIO;
+- goto out;
+- }
+- }
+-out:
+- return ret;
+-}
+-
+ static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
+ u64 phy_offset, struct page *page,
+ u64 start, u64 end, int mirror)
+@@ -887,12 +610,12 @@ static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
+ * that we don't try and read the other copies of this block, just
+ * return -EIO.
+ */
+- if (found_level == 0 && check_leaf(root, eb)) {
++ if (found_level == 0 && btrfs_check_leaf(root, eb)) {
+ set_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags);
+ ret = -EIO;
+ }
+
+- if (found_level > 0 && check_node(root, eb))
++ if (found_level > 0 && btrfs_check_node(root, eb))
+ ret = -EIO;
+
+ if (!ret)
+@@ -4147,7 +3870,7 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
+ buf->len,
+ fs_info->dirty_metadata_batch);
+ #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
+- if (btrfs_header_level(buf) == 0 && check_leaf(root, buf)) {
++ if (btrfs_header_level(buf) == 0 && btrfs_check_leaf(root, buf)) {
+ btrfs_print_leaf(buf);
+ ASSERT(0);
+ }
+diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
+new file mode 100644
+index 000000000000..56e25a630103
+--- /dev/null
++++ b/fs/btrfs/tree-checker.c
+@@ -0,0 +1,309 @@
++/*
++ * Copyright (C) Qu Wenruo 2017. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public
++ * License v2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public
++ * License along with this program.
++ */
++
++/*
++ * The module is used to catch unexpected/corrupted tree block data.
++ * Such behavior can be caused either by a fuzzed image or bugs.
++ *
++ * The objective is to do leaf/node validation checks when tree block is read
++ * from disk, and check *every* possible member, so other code won't
++ * need to checking them again.
++ *
++ * Due to the potential and unwanted damage, every checker needs to be
++ * carefully reviewed otherwise so it does not prevent mount of valid images.
++ */
++
++#include "ctree.h"
++#include "tree-checker.h"
++#include "disk-io.h"
++#include "compression.h"
++
++#define CORRUPT(reason, eb, root, slot) \
++ btrfs_crit(root->fs_info, \
++ "corrupt %s, %s: block=%llu, root=%llu, slot=%d", \
++ btrfs_header_level(eb) == 0 ? "leaf" : "node", \
++ reason, btrfs_header_bytenr(eb), root->objectid, slot)
++
++static int check_extent_data_item(struct btrfs_root *root,
++ struct extent_buffer *leaf,
++ struct btrfs_key *key, int slot)
++{
++ struct btrfs_file_extent_item *fi;
++ u32 sectorsize = root->fs_info->sectorsize;
++ u32 item_size = btrfs_item_size_nr(leaf, slot);
++
++ if (!IS_ALIGNED(key->offset, sectorsize)) {
++ CORRUPT("unaligned key offset for file extent",
++ leaf, root, slot);
++ return -EUCLEAN;
++ }
++
++ fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
++
++ if (btrfs_file_extent_type(leaf, fi) > BTRFS_FILE_EXTENT_TYPES) {
++ CORRUPT("invalid file extent type", leaf, root, slot);
++ return -EUCLEAN;
++ }
++
++ /*
++ * Support for new compression/encrption must introduce incompat flag,
++ * and must be caught in open_ctree().
++ */
++ if (btrfs_file_extent_compression(leaf, fi) > BTRFS_COMPRESS_TYPES) {
++ CORRUPT("invalid file extent compression", leaf, root, slot);
++ return -EUCLEAN;
++ }
++ if (btrfs_file_extent_encryption(leaf, fi)) {
++ CORRUPT("invalid file extent encryption", leaf, root, slot);
++ return -EUCLEAN;
++ }
++ if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) {
++ /* Inline extent must have 0 as key offset */
++ if (key->offset) {
++ CORRUPT("inline extent has non-zero key offset",
++ leaf, root, slot);
++ return -EUCLEAN;
++ }
++
++ /* Compressed inline extent has no on-disk size, skip it */
++ if (btrfs_file_extent_compression(leaf, fi) !=
++ BTRFS_COMPRESS_NONE)
++ return 0;
++
++ /* Uncompressed inline extent size must match item size */
++ if (item_size != BTRFS_FILE_EXTENT_INLINE_DATA_START +
++ btrfs_file_extent_ram_bytes(leaf, fi)) {
++ CORRUPT("plaintext inline extent has invalid size",
++ leaf, root, slot);
++ return -EUCLEAN;
++ }
++ return 0;
++ }
++
++ /* Regular or preallocated extent has fixed item size */
++ if (item_size != sizeof(*fi)) {
++ CORRUPT(
++ "regluar or preallocated extent data item size is invalid",
++ leaf, root, slot);
++ return -EUCLEAN;
++ }
++ if (!IS_ALIGNED(btrfs_file_extent_ram_bytes(leaf, fi), sectorsize) ||
++ !IS_ALIGNED(btrfs_file_extent_disk_bytenr(leaf, fi), sectorsize) ||
++ !IS_ALIGNED(btrfs_file_extent_disk_num_bytes(leaf, fi), sectorsize) ||
++ !IS_ALIGNED(btrfs_file_extent_offset(leaf, fi), sectorsize) ||
++ !IS_ALIGNED(btrfs_file_extent_num_bytes(leaf, fi), sectorsize)) {
++ CORRUPT(
++ "regular or preallocated extent data item has unaligned value",
++ leaf, root, slot);
++ return -EUCLEAN;
++ }
++
++ return 0;
++}
++
++static int check_csum_item(struct btrfs_root *root, struct extent_buffer *leaf,
++ struct btrfs_key *key, int slot)
++{
++ u32 sectorsize = root->fs_info->sectorsize;
++ u32 csumsize = btrfs_super_csum_size(root->fs_info->super_copy);
++
++ if (key->objectid != BTRFS_EXTENT_CSUM_OBJECTID) {
++ CORRUPT("invalid objectid for csum item", leaf, root, slot);
++ return -EUCLEAN;
++ }
++ if (!IS_ALIGNED(key->offset, sectorsize)) {
++ CORRUPT("unaligned key offset for csum item", leaf, root, slot);
++ return -EUCLEAN;
++ }
++ if (!IS_ALIGNED(btrfs_item_size_nr(leaf, slot), csumsize)) {
++ CORRUPT("unaligned csum item size", leaf, root, slot);
++ return -EUCLEAN;
++ }
++ return 0;
++}
++
++/*
++ * Common point to switch the item-specific validation.
++ */
++static int check_leaf_item(struct btrfs_root *root,
++ struct extent_buffer *leaf,
++ struct btrfs_key *key, int slot)
++{
++ int ret = 0;
++
++ switch (key->type) {
++ case BTRFS_EXTENT_DATA_KEY:
++ ret = check_extent_data_item(root, leaf, key, slot);
++ break;
++ case BTRFS_EXTENT_CSUM_KEY:
++ ret = check_csum_item(root, leaf, key, slot);
++ break;
++ }
++ return ret;
++}
++
++int btrfs_check_leaf(struct btrfs_root *root, struct extent_buffer *leaf)
++{
++ struct btrfs_fs_info *fs_info = root->fs_info;
++ /* No valid key type is 0, so all key should be larger than this key */
++ struct btrfs_key prev_key = {0, 0, 0};
++ struct btrfs_key key;
++ u32 nritems = btrfs_header_nritems(leaf);
++ int slot;
++
++ /*
++ * Extent buffers from a relocation tree have a owner field that
++ * corresponds to the subvolume tree they are based on. So just from an
++ * extent buffer alone we can not find out what is the id of the
++ * corresponding subvolume tree, so we can not figure out if the extent
++ * buffer corresponds to the root of the relocation tree or not. So
++ * skip this check for relocation trees.
++ */
++ if (nritems == 0 && !btrfs_header_flag(leaf, BTRFS_HEADER_FLAG_RELOC)) {
++ struct btrfs_root *check_root;
++
++ key.objectid = btrfs_header_owner(leaf);
++ key.type = BTRFS_ROOT_ITEM_KEY;
++ key.offset = (u64)-1;
++
++ check_root = btrfs_get_fs_root(fs_info, &key, false);
++ /*
++ * The only reason we also check NULL here is that during
++ * open_ctree() some roots has not yet been set up.
++ */
++ if (!IS_ERR_OR_NULL(check_root)) {
++ struct extent_buffer *eb;
++
++ eb = btrfs_root_node(check_root);
++ /* if leaf is the root, then it's fine */
++ if (leaf != eb) {
++ CORRUPT("non-root leaf's nritems is 0",
++ leaf, check_root, 0);
++ free_extent_buffer(eb);
++ return -EUCLEAN;
++ }
++ free_extent_buffer(eb);
++ }
++ return 0;
++ }
++
++ if (nritems == 0)
++ return 0;
++
++ /*
++ * Check the following things to make sure this is a good leaf, and
++ * leaf users won't need to bother with similar sanity checks:
++ *
++ * 1) key ordering
++ * 2) item offset and size
++ * No overlap, no hole, all inside the leaf.
++ * 3) item content
++ * If possible, do comprehensive sanity check.
++ * NOTE: All checks must only rely on the item data itself.
++ */
++ for (slot = 0; slot < nritems; slot++) {
++ u32 item_end_expected;
++ int ret;
++
++ btrfs_item_key_to_cpu(leaf, &key, slot);
++
++ /* Make sure the keys are in the right order */
++ if (btrfs_comp_cpu_keys(&prev_key, &key) >= 0) {
++ CORRUPT("bad key order", leaf, root, slot);
++ return -EUCLEAN;
++ }
++
++ /*
++ * Make sure the offset and ends are right, remember that the
++ * item data starts at the end of the leaf and grows towards the
++ * front.
++ */
++ if (slot == 0)
++ item_end_expected = BTRFS_LEAF_DATA_SIZE(fs_info);
++ else
++ item_end_expected = btrfs_item_offset_nr(leaf,
++ slot - 1);
++ if (btrfs_item_end_nr(leaf, slot) != item_end_expected) {
++ CORRUPT("slot offset bad", leaf, root, slot);
++ return -EUCLEAN;
++ }
++
++ /*
++ * Check to make sure that we don't point outside of the leaf,
++ * just in case all the items are consistent to each other, but
++ * all point outside of the leaf.
++ */
++ if (btrfs_item_end_nr(leaf, slot) >
++ BTRFS_LEAF_DATA_SIZE(fs_info)) {
++ CORRUPT("slot end outside of leaf", leaf, root, slot);
++ return -EUCLEAN;
++ }
++
++ /* Also check if the item pointer overlaps with btrfs item. */
++ if (btrfs_item_nr_offset(slot) + sizeof(struct btrfs_item) >
++ btrfs_item_ptr_offset(leaf, slot)) {
++ CORRUPT("slot overlap with its data", leaf, root, slot);
++ return -EUCLEAN;
++ }
++
++ /* Check if the item size and content meet other criteria */
++ ret = check_leaf_item(root, leaf, &key, slot);
++ if (ret < 0)
++ return ret;
++
++ prev_key.objectid = key.objectid;
++ prev_key.type = key.type;
++ prev_key.offset = key.offset;
++ }
++
++ return 0;
++}
++
++int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node)
++{
++ unsigned long nr = btrfs_header_nritems(node);
++ struct btrfs_key key, next_key;
++ int slot;
++ u64 bytenr;
++ int ret = 0;
++
++ if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root->fs_info)) {
++ btrfs_crit(root->fs_info,
++ "corrupt node: block %llu root %llu nritems %lu",
++ node->start, root->objectid, nr);
++ return -EIO;
++ }
++
++ for (slot = 0; slot < nr - 1; slot++) {
++ bytenr = btrfs_node_blockptr(node, slot);
++ btrfs_node_key_to_cpu(node, &key, slot);
++ btrfs_node_key_to_cpu(node, &next_key, slot + 1);
++
++ if (!bytenr) {
++ CORRUPT("invalid item slot", node, root, slot);
++ ret = -EIO;
++ goto out;
++ }
++
++ if (btrfs_comp_cpu_keys(&key, &next_key) >= 0) {
++ CORRUPT("bad key order", node, root, slot);
++ ret = -EIO;
++ goto out;
++ }
++ }
++out:
++ return ret;
++}
+diff --git a/fs/btrfs/tree-checker.h b/fs/btrfs/tree-checker.h
+new file mode 100644
+index 000000000000..96c486e95d70
+--- /dev/null
++++ b/fs/btrfs/tree-checker.h
+@@ -0,0 +1,26 @@
++/*
++ * Copyright (C) Qu Wenruo 2017. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public
++ * License v2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public
++ * License along with this program.
++ */
++
++#ifndef __BTRFS_TREE_CHECKER__
++#define __BTRFS_TREE_CHECKER__
++
++#include "ctree.h"
++#include "extent_io.h"
++
++int btrfs_check_leaf(struct btrfs_root *root, struct extent_buffer *leaf);
++int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node);
++
++#endif
+--
+2.17.1
+
--- /dev/null
+From 0bcc74f859da60de8ae0fcd116bead1cb0f30ae0 Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <quwenruo.btrfs@gmx.com>
+Date: Wed, 23 Aug 2017 16:57:56 +0900
+Subject: btrfs: Refactor check_leaf function for later expansion
+
+commit c3267bbaa9cae09b62960eafe33ad19196803285 upstream.
+
+Current check_leaf() function does a good job checking key order and
+item offset/size.
+
+However it only checks from slot 0 to the last but one slot, this is
+good but makes later expansion hard.
+
+So this refactoring iterates from slot 0 to the last slot.
+For key comparison, it uses a key with all 0 as initial key, so all
+valid keys should be larger than that.
+
+And for item size/offset checks, it compares current item end with
+previous item offset.
+For slot 0, use leaf end as a special case.
+
+This makes later item/key offset checks and item size checks easier to
+be implemented.
+
+Also, makes check_leaf() to return -EUCLEAN other than -EIO to indicate
+error.
+
+Signed-off-by: Qu Wenruo <quwenruo.btrfs@gmx.com>
+Reviewed-by: Nikolay Borisov <nborisov@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/disk-io.c | 50 +++++++++++++++++++++++++---------------------
+ 1 file changed, 27 insertions(+), 23 deletions(-)
+
+diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
+index 0e67cee73c53..4a1e63df1183 100644
+--- a/fs/btrfs/disk-io.c
++++ b/fs/btrfs/disk-io.c
+@@ -554,8 +554,9 @@ static noinline int check_leaf(struct btrfs_root *root,
+ struct extent_buffer *leaf)
+ {
+ struct btrfs_fs_info *fs_info = root->fs_info;
++ /* No valid key type is 0, so all key should be larger than this key */
++ struct btrfs_key prev_key = {0, 0, 0};
+ struct btrfs_key key;
+- struct btrfs_key leaf_key;
+ u32 nritems = btrfs_header_nritems(leaf);
+ int slot;
+
+@@ -588,7 +589,7 @@ static noinline int check_leaf(struct btrfs_root *root,
+ CORRUPT("non-root leaf's nritems is 0",
+ leaf, check_root, 0);
+ free_extent_buffer(eb);
+- return -EIO;
++ return -EUCLEAN;
+ }
+ free_extent_buffer(eb);
+ }
+@@ -598,28 +599,23 @@ static noinline int check_leaf(struct btrfs_root *root,
+ if (nritems == 0)
+ return 0;
+
+- /* Check the 0 item */
+- if (btrfs_item_offset_nr(leaf, 0) + btrfs_item_size_nr(leaf, 0) !=
+- BTRFS_LEAF_DATA_SIZE(fs_info)) {
+- CORRUPT("invalid item offset size pair", leaf, root, 0);
+- return -EIO;
+- }
+-
+ /*
+- * Check to make sure each items keys are in the correct order and their
+- * offsets make sense. We only have to loop through nritems-1 because
+- * we check the current slot against the next slot, which verifies the
+- * next slot's offset+size makes sense and that the current's slot
+- * offset is correct.
++ * Check the following things to make sure this is a good leaf, and
++ * leaf users won't need to bother with similar sanity checks:
++ *
++ * 1) key order
++ * 2) item offset and size
++ * No overlap, no hole, all inside the leaf.
+ */
+- for (slot = 0; slot < nritems - 1; slot++) {
+- btrfs_item_key_to_cpu(leaf, &leaf_key, slot);
+- btrfs_item_key_to_cpu(leaf, &key, slot + 1);
++ for (slot = 0; slot < nritems; slot++) {
++ u32 item_end_expected;
++
++ btrfs_item_key_to_cpu(leaf, &key, slot);
+
+ /* Make sure the keys are in the right order */
+- if (btrfs_comp_cpu_keys(&leaf_key, &key) >= 0) {
++ if (btrfs_comp_cpu_keys(&prev_key, &key) >= 0) {
+ CORRUPT("bad key order", leaf, root, slot);
+- return -EIO;
++ return -EUCLEAN;
+ }
+
+ /*
+@@ -627,10 +623,14 @@ static noinline int check_leaf(struct btrfs_root *root,
+ * item data starts at the end of the leaf and grows towards the
+ * front.
+ */
+- if (btrfs_item_offset_nr(leaf, slot) !=
+- btrfs_item_end_nr(leaf, slot + 1)) {
++ if (slot == 0)
++ item_end_expected = BTRFS_LEAF_DATA_SIZE(fs_info);
++ else
++ item_end_expected = btrfs_item_offset_nr(leaf,
++ slot - 1);
++ if (btrfs_item_end_nr(leaf, slot) != item_end_expected) {
+ CORRUPT("slot offset bad", leaf, root, slot);
+- return -EIO;
++ return -EUCLEAN;
+ }
+
+ /*
+@@ -641,8 +641,12 @@ static noinline int check_leaf(struct btrfs_root *root,
+ if (btrfs_item_end_nr(leaf, slot) >
+ BTRFS_LEAF_DATA_SIZE(fs_info)) {
+ CORRUPT("slot end outside of leaf", leaf, root, slot);
+- return -EIO;
++ return -EUCLEAN;
+ }
++
++ prev_key.objectid = key.objectid;
++ prev_key.type = key.type;
++ prev_key.offset = key.offset;
+ }
+
+ return 0;
+--
+2.17.1
+
--- /dev/null
+From 70e47c83b8c7ff52cfa24011a60f3ef7ac9ad797 Mon Sep 17 00:00:00 2001
+From: David Sterba <dsterba@suse.com>
+Date: Wed, 10 Jan 2018 15:13:07 +0100
+Subject: btrfs: tree-check: reduce stack consumption in check_dir_item
+
+commit e2683fc9d219430f5b78889b50cde7f40efeba7b upstream.
+
+I've noticed that the updated item checker stack consumption increased
+dramatically in 542f5385e20cf97447 ("btrfs: tree-checker: Add checker
+for dir item")
+
+tree-checker.c:check_leaf +552 (176 -> 728)
+
+The array is 255 bytes long, dynamic allocation would slow down the
+sanity checks so it's more reasonable to keep it on-stack. Moving the
+variable to the scope of use reduces the stack usage again
+
+tree-checker.c:check_leaf -264 (728 -> 464)
+
+Reviewed-by: Josef Bacik <jbacik@fb.com>
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/tree-checker.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
+index 9376739a4cc8..f7e7a455b710 100644
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -212,7 +212,6 @@ static int check_dir_item(struct btrfs_root *root,
+
+ di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
+ while (cur < item_size) {
+- char namebuf[max(BTRFS_NAME_LEN, XATTR_NAME_MAX)];
+ u32 name_len;
+ u32 data_len;
+ u32 max_name_len;
+@@ -295,6 +294,8 @@ static int check_dir_item(struct btrfs_root *root,
+ */
+ if (key->type == BTRFS_DIR_ITEM_KEY ||
+ key->type == BTRFS_XATTR_ITEM_KEY) {
++ char namebuf[max(BTRFS_NAME_LEN, XATTR_NAME_MAX)];
++
+ read_extent_buffer(leaf, namebuf,
+ (unsigned long)(di + 1), name_len);
+ name_hash = btrfs_name_hash(namebuf, name_len);
+--
+2.17.1
+
--- /dev/null
+From 02e824b52c042ed07e5658e87a6bd0e4291480d3 Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <wqu@suse.com>
+Date: Wed, 8 Nov 2017 08:54:25 +0800
+Subject: btrfs: tree-checker: Add checker for dir item
+
+commit ad7b0368f33cffe67fecd302028915926e50ef7e upstream.
+
+Add checker for dir item, for key types DIR_ITEM, DIR_INDEX and
+XATTR_ITEM.
+
+This checker does comprehensive checks for:
+
+1) dir_item header and its data size
+ Against item boundary and maximum name/xattr length.
+ This part is mostly the same as old verify_dir_item().
+
+2) dir_type
+ Against maximum file types, and against key type.
+ Since XATTR key should only have FT_XATTR dir item, and normal dir
+ item type should not have XATTR key.
+
+ The check between key->type and dir_type is newly introduced by this
+ patch.
+
+3) name hash
+ For XATTR and DIR_ITEM key, key->offset is name hash (crc32c).
+ Check the hash of the name against the key to ensure it's correct.
+
+ The name hash check is only found in btrfs-progs before this patch.
+
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Reviewed-by: Nikolay Borisov <nborisov@suse.com>
+Reviewed-by: Su Yue <suy.fnst@cn.fujitsu.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/tree-checker.c | 141 ++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 141 insertions(+)
+
+diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
+index ff4fa8f905d3..b32df86de9bf 100644
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -30,6 +30,7 @@
+ #include "tree-checker.h"
+ #include "disk-io.h"
+ #include "compression.h"
++#include "hash.h"
+
+ #define CORRUPT(reason, eb, root, slot) \
+ btrfs_crit(root->fs_info, \
+@@ -175,6 +176,141 @@ static int check_csum_item(struct btrfs_root *root, struct extent_buffer *leaf,
+ return 0;
+ }
+
++/*
++ * Customized reported for dir_item, only important new info is key->objectid,
++ * which represents inode number
++ */
++__printf(4, 5)
++static void dir_item_err(const struct btrfs_root *root,
++ const struct extent_buffer *eb, int slot,
++ const char *fmt, ...)
++{
++ struct btrfs_key key;
++ struct va_format vaf;
++ va_list args;
++
++ btrfs_item_key_to_cpu(eb, &key, slot);
++ va_start(args, fmt);
++
++ vaf.fmt = fmt;
++ vaf.va = &args;
++
++ btrfs_crit(root->fs_info,
++ "corrupt %s: root=%llu block=%llu slot=%d ino=%llu, %pV",
++ btrfs_header_level(eb) == 0 ? "leaf" : "node", root->objectid,
++ btrfs_header_bytenr(eb), slot, key.objectid, &vaf);
++ va_end(args);
++}
++
++static int check_dir_item(struct btrfs_root *root,
++ struct extent_buffer *leaf,
++ struct btrfs_key *key, int slot)
++{
++ struct btrfs_dir_item *di;
++ u32 item_size = btrfs_item_size_nr(leaf, slot);
++ u32 cur = 0;
++
++ di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
++ while (cur < item_size) {
++ char namebuf[max(BTRFS_NAME_LEN, XATTR_NAME_MAX)];
++ u32 name_len;
++ u32 data_len;
++ u32 max_name_len;
++ u32 total_size;
++ u32 name_hash;
++ u8 dir_type;
++
++ /* header itself should not cross item boundary */
++ if (cur + sizeof(*di) > item_size) {
++ dir_item_err(root, leaf, slot,
++ "dir item header crosses item boundary, have %lu boundary %u",
++ cur + sizeof(*di), item_size);
++ return -EUCLEAN;
++ }
++
++ /* dir type check */
++ dir_type = btrfs_dir_type(leaf, di);
++ if (dir_type >= BTRFS_FT_MAX) {
++ dir_item_err(root, leaf, slot,
++ "invalid dir item type, have %u expect [0, %u)",
++ dir_type, BTRFS_FT_MAX);
++ return -EUCLEAN;
++ }
++
++ if (key->type == BTRFS_XATTR_ITEM_KEY &&
++ dir_type != BTRFS_FT_XATTR) {
++ dir_item_err(root, leaf, slot,
++ "invalid dir item type for XATTR key, have %u expect %u",
++ dir_type, BTRFS_FT_XATTR);
++ return -EUCLEAN;
++ }
++ if (dir_type == BTRFS_FT_XATTR &&
++ key->type != BTRFS_XATTR_ITEM_KEY) {
++ dir_item_err(root, leaf, slot,
++ "xattr dir type found for non-XATTR key");
++ return -EUCLEAN;
++ }
++ if (dir_type == BTRFS_FT_XATTR)
++ max_name_len = XATTR_NAME_MAX;
++ else
++ max_name_len = BTRFS_NAME_LEN;
++
++ /* Name/data length check */
++ name_len = btrfs_dir_name_len(leaf, di);
++ data_len = btrfs_dir_data_len(leaf, di);
++ if (name_len > max_name_len) {
++ dir_item_err(root, leaf, slot,
++ "dir item name len too long, have %u max %u",
++ name_len, max_name_len);
++ return -EUCLEAN;
++ }
++ if (name_len + data_len > BTRFS_MAX_XATTR_SIZE(root->fs_info)) {
++ dir_item_err(root, leaf, slot,
++ "dir item name and data len too long, have %u max %u",
++ name_len + data_len,
++ BTRFS_MAX_XATTR_SIZE(root->fs_info));
++ return -EUCLEAN;
++ }
++
++ if (data_len && dir_type != BTRFS_FT_XATTR) {
++ dir_item_err(root, leaf, slot,
++ "dir item with invalid data len, have %u expect 0",
++ data_len);
++ return -EUCLEAN;
++ }
++
++ total_size = sizeof(*di) + name_len + data_len;
++
++ /* header and name/data should not cross item boundary */
++ if (cur + total_size > item_size) {
++ dir_item_err(root, leaf, slot,
++ "dir item data crosses item boundary, have %u boundary %u",
++ cur + total_size, item_size);
++ return -EUCLEAN;
++ }
++
++ /*
++ * Special check for XATTR/DIR_ITEM, as key->offset is name
++ * hash, should match its name
++ */
++ if (key->type == BTRFS_DIR_ITEM_KEY ||
++ key->type == BTRFS_XATTR_ITEM_KEY) {
++ read_extent_buffer(leaf, namebuf,
++ (unsigned long)(di + 1), name_len);
++ name_hash = btrfs_name_hash(namebuf, name_len);
++ if (key->offset != name_hash) {
++ dir_item_err(root, leaf, slot,
++ "name hash mismatch with key, have 0x%016x expect 0x%016llx",
++ name_hash, key->offset);
++ return -EUCLEAN;
++ }
++ }
++ cur += total_size;
++ di = (struct btrfs_dir_item *)((void *)di + total_size);
++ }
++ return 0;
++}
++
+ /*
+ * Common point to switch the item-specific validation.
+ */
+@@ -191,6 +327,11 @@ static int check_leaf_item(struct btrfs_root *root,
+ case BTRFS_EXTENT_CSUM_KEY:
+ ret = check_csum_item(root, leaf, key, slot);
+ break;
++ case BTRFS_DIR_ITEM_KEY:
++ case BTRFS_DIR_INDEX_KEY:
++ case BTRFS_XATTR_ITEM_KEY:
++ ret = check_dir_item(root, leaf, key, slot);
++ break;
+ }
+ return ret;
+ }
+--
+2.17.1
+
--- /dev/null
+From f6ae0283f3ec4931e03f5ba2f6a5fce995f156b3 Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <wqu@suse.com>
+Date: Fri, 28 Sep 2018 07:59:34 +0800
+Subject: btrfs: tree-checker: Check level for leaves and nodes
+
+commit f556faa46eb4e96d0d0772e74ecf66781e132f72 upstream.
+
+Although we have tree level check at tree read runtime, it's completely
+based on its parent level.
+We still need to do accurate level check to avoid invalid tree blocks
+sneak into kernel space.
+
+The check itself is simple, for leaf its level should always be 0.
+For nodes its level should be in range [1, BTRFS_MAX_LEVEL - 1].
+
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Reviewed-by: Su Yue <suy.fnst@cn.fujitsu.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+[bwh: Backported to 4.14:
+ - Pass root instead of fs_info to generic_err()
+ - Adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/tree-checker.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
+index 31756bac75b4..fa8f64119e6f 100644
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -447,6 +447,13 @@ static int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf,
+ u32 nritems = btrfs_header_nritems(leaf);
+ int slot;
+
++ if (btrfs_header_level(leaf) != 0) {
++ generic_err(root, leaf, 0,
++ "invalid level for leaf, have %d expect 0",
++ btrfs_header_level(leaf));
++ return -EUCLEAN;
++ }
++
+ /*
+ * Extent buffers from a relocation tree have a owner field that
+ * corresponds to the subvolume tree they are based on. So just from an
+@@ -589,9 +596,16 @@ int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node)
+ unsigned long nr = btrfs_header_nritems(node);
+ struct btrfs_key key, next_key;
+ int slot;
++ int level = btrfs_header_level(node);
+ u64 bytenr;
+ int ret = 0;
+
++ if (level <= 0 || level >= BTRFS_MAX_LEVEL) {
++ generic_err(root, node, 0,
++ "invalid level for node, have %d expect [1, %d]",
++ level, BTRFS_MAX_LEVEL - 1);
++ return -EUCLEAN;
++ }
+ if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root->fs_info)) {
+ btrfs_crit(root->fs_info,
+ "corrupt node: root=%llu block=%llu, nritems too %s, have %lu expect range [1,%u]",
+--
+2.17.1
+
--- /dev/null
+From b052353d845bb223565a30201c705d5a37b40c91 Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <wqu@suse.com>
+Date: Tue, 3 Jul 2018 17:10:06 +0800
+Subject: btrfs: tree-checker: Detect invalid and empty essential trees
+
+commit ba480dd4db9f1798541eb2d1c423fc95feee8d36 upstream.
+
+A crafted image has empty root tree block, which will later cause NULL
+pointer dereference.
+
+The following trees should never be empty:
+1) Tree root
+ Must contain at least root items for extent tree, device tree and fs
+ tree
+
+2) Chunk tree
+ Or we can't even bootstrap as it contains the mapping.
+
+3) Fs tree
+ At least inode item for top level inode (.).
+
+4) Device tree
+ Dev extents for chunks
+
+5) Extent tree
+ Must have corresponding extent for each chunk.
+
+If any of them is empty, we are sure the fs is corrupted and no need to
+mount it.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=199847
+Reported-by: Xu Wen <wen.xu@gatech.edu>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Tested-by: Gu Jinxiang <gujx@cn.fujitsu.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+[bwh: Backported to 4.14: Pass root instead of fs_info to generic_err()]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/tree-checker.c | 15 ++++++++++++++-
+ 1 file changed, 14 insertions(+), 1 deletion(-)
+
+diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
+index cf9b10a07134..31756bac75b4 100644
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -456,9 +456,22 @@ static int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf,
+ * skip this check for relocation trees.
+ */
+ if (nritems == 0 && !btrfs_header_flag(leaf, BTRFS_HEADER_FLAG_RELOC)) {
++ u64 owner = btrfs_header_owner(leaf);
+ struct btrfs_root *check_root;
+
+- key.objectid = btrfs_header_owner(leaf);
++ /* These trees must never be empty */
++ if (owner == BTRFS_ROOT_TREE_OBJECTID ||
++ owner == BTRFS_CHUNK_TREE_OBJECTID ||
++ owner == BTRFS_EXTENT_TREE_OBJECTID ||
++ owner == BTRFS_DEV_TREE_OBJECTID ||
++ owner == BTRFS_FS_TREE_OBJECTID ||
++ owner == BTRFS_DATA_RELOC_TREE_OBJECTID) {
++ generic_err(root, leaf, 0,
++ "invalid root, root %llu must never be empty",
++ owner);
++ return -EUCLEAN;
++ }
++ key.objectid = owner;
+ key.type = BTRFS_ROOT_ITEM_KEY;
+ key.offset = (u64)-1;
+
+--
+2.17.1
+
--- /dev/null
+From 22251244069d0801d767fc7539c44971cd8e9574 Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <quwenruo.btrfs@gmx.com>
+Date: Mon, 9 Oct 2017 01:51:03 +0000
+Subject: btrfs: tree-checker: Enhance btrfs_check_node output
+
+commit bba4f29896c986c4cec17bc0f19f2ce644fceae1 upstream.
+
+Use inline function to replace macro since we don't need
+stringification.
+(Macro still exists until all callers get updated)
+
+And add more info about the error, and replace EIO with EUCLEAN.
+
+For nr_items error, report if it's too large or too small, and output
+the valid value range.
+
+For node block pointer, added a new alignment checker.
+
+For key order, also output the next key to make the problem more
+obvious.
+
+Signed-off-by: Qu Wenruo <quwenruo.btrfs@gmx.com>
+[ wording adjustments, unindented long strings ]
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/tree-checker.c | 68 ++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 61 insertions(+), 7 deletions(-)
+
+diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
+index 56e25a630103..5acdf3355a3f 100644
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -37,6 +37,46 @@
+ btrfs_header_level(eb) == 0 ? "leaf" : "node", \
+ reason, btrfs_header_bytenr(eb), root->objectid, slot)
+
++/*
++ * Error message should follow the following format:
++ * corrupt <type>: <identifier>, <reason>[, <bad_value>]
++ *
++ * @type: leaf or node
++ * @identifier: the necessary info to locate the leaf/node.
++ * It's recommened to decode key.objecitd/offset if it's
++ * meaningful.
++ * @reason: describe the error
++ * @bad_value: optional, it's recommened to output bad value and its
++ * expected value (range).
++ *
++ * Since comma is used to separate the components, only space is allowed
++ * inside each component.
++ */
++
++/*
++ * Append generic "corrupt leaf/node root=%llu block=%llu slot=%d: " to @fmt.
++ * Allows callers to customize the output.
++ */
++__printf(4, 5)
++static void generic_err(const struct btrfs_root *root,
++ const struct extent_buffer *eb, int slot,
++ const char *fmt, ...)
++{
++ struct va_format vaf;
++ va_list args;
++
++ va_start(args, fmt);
++
++ vaf.fmt = fmt;
++ vaf.va = &args;
++
++ btrfs_crit(root->fs_info,
++ "corrupt %s: root=%llu block=%llu slot=%d, %pV",
++ btrfs_header_level(eb) == 0 ? "leaf" : "node",
++ root->objectid, btrfs_header_bytenr(eb), slot, &vaf);
++ va_end(args);
++}
++
+ static int check_extent_data_item(struct btrfs_root *root,
+ struct extent_buffer *leaf,
+ struct btrfs_key *key, int slot)
+@@ -282,9 +322,11 @@ int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node)
+
+ if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root->fs_info)) {
+ btrfs_crit(root->fs_info,
+- "corrupt node: block %llu root %llu nritems %lu",
+- node->start, root->objectid, nr);
+- return -EIO;
++"corrupt node: root=%llu block=%llu, nritems too %s, have %lu expect range [1,%u]",
++ root->objectid, node->start,
++ nr == 0 ? "small" : "large", nr,
++ BTRFS_NODEPTRS_PER_BLOCK(root->fs_info));
++ return -EUCLEAN;
+ }
+
+ for (slot = 0; slot < nr - 1; slot++) {
+@@ -293,14 +335,26 @@ int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node)
+ btrfs_node_key_to_cpu(node, &next_key, slot + 1);
+
+ if (!bytenr) {
+- CORRUPT("invalid item slot", node, root, slot);
+- ret = -EIO;
++ generic_err(root, node, slot,
++ "invalid NULL node pointer");
++ ret = -EUCLEAN;
++ goto out;
++ }
++ if (!IS_ALIGNED(bytenr, root->fs_info->sectorsize)) {
++ generic_err(root, node, slot,
++ "unaligned pointer, have %llu should be aligned to %u",
++ bytenr, root->fs_info->sectorsize);
++ ret = -EUCLEAN;
+ goto out;
+ }
+
+ if (btrfs_comp_cpu_keys(&key, &next_key) >= 0) {
+- CORRUPT("bad key order", node, root, slot);
+- ret = -EIO;
++ generic_err(root, node, slot,
++ "bad key order, current (%llu %u %llu) next (%llu %u %llu)",
++ key.objectid, key.type, key.offset,
++ next_key.objectid, next_key.type,
++ next_key.offset);
++ ret = -EUCLEAN;
+ goto out;
+ }
+ }
+--
+2.17.1
+
--- /dev/null
+From ee3011e4d4a6962b1f161a1b6055b727358d628a Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <wqu@suse.com>
+Date: Wed, 8 Nov 2017 08:54:24 +0800
+Subject: btrfs: tree-checker: Fix false panic for sanity test
+
+commit 69fc6cbbac542c349b3d350d10f6e394c253c81d upstream.
+
+[BUG]
+If we run btrfs with CONFIG_BTRFS_FS_RUN_SANITY_TESTS=y, it will
+instantly cause kernel panic like:
+
+------
+...
+assertion failed: 0, file: fs/btrfs/disk-io.c, line: 3853
+...
+Call Trace:
+ btrfs_mark_buffer_dirty+0x187/0x1f0 [btrfs]
+ setup_items_for_insert+0x385/0x650 [btrfs]
+ __btrfs_drop_extents+0x129a/0x1870 [btrfs]
+...
+-----
+
+[Cause]
+Btrfs will call btrfs_check_leaf() in btrfs_mark_buffer_dirty() to check
+if the leaf is valid with CONFIG_BTRFS_FS_RUN_SANITY_TESTS=y.
+
+However quite some btrfs_mark_buffer_dirty() callers(*) don't really
+initialize its item data but only initialize its item pointers, leaving
+item data uninitialized.
+
+This makes tree-checker catch uninitialized data as error, causing
+such panic.
+
+*: These callers include but not limited to
+setup_items_for_insert()
+btrfs_split_item()
+btrfs_expand_item()
+
+[Fix]
+Add a new parameter @check_item_data to btrfs_check_leaf().
+With @check_item_data set to false, item data check will be skipped and
+fallback to old btrfs_check_leaf() behavior.
+
+So we can still get early warning if we screw up item pointers, and
+avoid false panic.
+
+Cc: Filipe Manana <fdmanana@gmail.com>
+Reported-by: Lakshmipathi.G <lakshmipathi.g@gmail.com>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Reviewed-by: Liu Bo <bo.li.liu@oracle.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/disk-io.c | 10 ++++++++--
+ fs/btrfs/tree-checker.c | 27 ++++++++++++++++++++++-----
+ fs/btrfs/tree-checker.h | 14 +++++++++++++-
+ 3 files changed, 43 insertions(+), 8 deletions(-)
+
+diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
+index 2df5e906db08..e42673477c25 100644
+--- a/fs/btrfs/disk-io.c
++++ b/fs/btrfs/disk-io.c
+@@ -610,7 +610,7 @@ static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
+ * that we don't try and read the other copies of this block, just
+ * return -EIO.
+ */
+- if (found_level == 0 && btrfs_check_leaf(root, eb)) {
++ if (found_level == 0 && btrfs_check_leaf_full(root, eb)) {
+ set_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags);
+ ret = -EIO;
+ }
+@@ -3870,7 +3870,13 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
+ buf->len,
+ fs_info->dirty_metadata_batch);
+ #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
+- if (btrfs_header_level(buf) == 0 && btrfs_check_leaf(root, buf)) {
++ /*
++ * Since btrfs_mark_buffer_dirty() can be called with item pointer set
++ * but item data not updated.
++ * So here we should only check item pointers, not item data.
++ */
++ if (btrfs_header_level(buf) == 0 &&
++ btrfs_check_leaf_relaxed(root, buf)) {
+ btrfs_print_leaf(buf);
+ ASSERT(0);
+ }
+diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
+index 5acdf3355a3f..ff4fa8f905d3 100644
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -195,7 +195,8 @@ static int check_leaf_item(struct btrfs_root *root,
+ return ret;
+ }
+
+-int btrfs_check_leaf(struct btrfs_root *root, struct extent_buffer *leaf)
++static int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf,
++ bool check_item_data)
+ {
+ struct btrfs_fs_info *fs_info = root->fs_info;
+ /* No valid key type is 0, so all key should be larger than this key */
+@@ -299,10 +300,15 @@ int btrfs_check_leaf(struct btrfs_root *root, struct extent_buffer *leaf)
+ return -EUCLEAN;
+ }
+
+- /* Check if the item size and content meet other criteria */
+- ret = check_leaf_item(root, leaf, &key, slot);
+- if (ret < 0)
+- return ret;
++ if (check_item_data) {
++ /*
++ * Check if the item size and content meet other
++ * criteria
++ */
++ ret = check_leaf_item(root, leaf, &key, slot);
++ if (ret < 0)
++ return ret;
++ }
+
+ prev_key.objectid = key.objectid;
+ prev_key.type = key.type;
+@@ -312,6 +318,17 @@ int btrfs_check_leaf(struct btrfs_root *root, struct extent_buffer *leaf)
+ return 0;
+ }
+
++int btrfs_check_leaf_full(struct btrfs_root *root, struct extent_buffer *leaf)
++{
++ return check_leaf(root, leaf, true);
++}
++
++int btrfs_check_leaf_relaxed(struct btrfs_root *root,
++ struct extent_buffer *leaf)
++{
++ return check_leaf(root, leaf, false);
++}
++
+ int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node)
+ {
+ unsigned long nr = btrfs_header_nritems(node);
+diff --git a/fs/btrfs/tree-checker.h b/fs/btrfs/tree-checker.h
+index 96c486e95d70..3d53e8d6fda0 100644
+--- a/fs/btrfs/tree-checker.h
++++ b/fs/btrfs/tree-checker.h
+@@ -20,7 +20,19 @@
+ #include "ctree.h"
+ #include "extent_io.h"
+
+-int btrfs_check_leaf(struct btrfs_root *root, struct extent_buffer *leaf);
++/*
++ * Comprehensive leaf checker.
++ * Will check not only the item pointers, but also every possible member
++ * in item data.
++ */
++int btrfs_check_leaf_full(struct btrfs_root *root, struct extent_buffer *leaf);
++
++/*
++ * Less strict leaf checker.
++ * Will only check item pointers, not reading item data.
++ */
++int btrfs_check_leaf_relaxed(struct btrfs_root *root,
++ struct extent_buffer *leaf);
+ int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node);
+
+ #endif
+--
+2.17.1
+
--- /dev/null
+From 2dfa491a5fca41357974482926c0ad6abe7cc360 Mon Sep 17 00:00:00 2001
+From: Shaokun Zhang <zhangshaokun@hisilicon.com>
+Date: Mon, 5 Nov 2018 18:49:09 +0800
+Subject: btrfs: tree-checker: Fix misleading group system information
+
+commit 761333f2f50ccc887aa9957ae829300262c0d15b upstream.
+
+block_group_err shows the group system as a decimal value with a '0x'
+prefix, which is somewhat misleading.
+
+Fix it to print hexadecimal, as was intended.
+
+Fixes: fce466eab7ac6 ("btrfs: tree-checker: Verify block_group_item")
+Reviewed-by: Nikolay Borisov <nborisov@suse.com>
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/tree-checker.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
+index fa8f64119e6f..f206aec1525d 100644
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -399,7 +399,7 @@ static int check_block_group_item(struct btrfs_fs_info *fs_info,
+ type != (BTRFS_BLOCK_GROUP_METADATA |
+ BTRFS_BLOCK_GROUP_DATA)) {
+ block_group_err(fs_info, leaf, slot,
+-"invalid type, have 0x%llx (%lu bits set) expect either 0x%llx, 0x%llx, 0x%llu or 0x%llx",
++"invalid type, have 0x%llx (%lu bits set) expect either 0x%llx, 0x%llx, 0x%llx or 0x%llx",
+ type, hweight64(type),
+ BTRFS_BLOCK_GROUP_DATA, BTRFS_BLOCK_GROUP_METADATA,
+ BTRFS_BLOCK_GROUP_SYSTEM,
+--
+2.17.1
+
--- /dev/null
+From faa30fcea2a773bc5a19c199e204d9c8ee40a0e2 Mon Sep 17 00:00:00 2001
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Wed, 6 Dec 2017 15:18:14 +0100
+Subject: btrfs: tree-checker: use %zu format string for size_t
+
+commit 7cfad65297bfe0aa2996cd72d21c898aa84436d9 upstream.
+
+The return value of sizeof() is of type size_t, so we must print it
+using the %z format modifier rather than %l to avoid this warning
+on some architectures:
+
+fs/btrfs/tree-checker.c: In function 'check_dir_item':
+fs/btrfs/tree-checker.c:273:50: error: format '%lu' expects argument of type 'long unsigned int', but argument 5 has type 'u32' {aka 'unsigned int'} [-Werror=format=]
+
+Fixes: 005887f2e3e0 ("btrfs: tree-checker: Add checker for dir item")
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/tree-checker.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
+index b32df86de9bf..9376739a4cc8 100644
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -223,7 +223,7 @@ static int check_dir_item(struct btrfs_root *root,
+ /* header itself should not cross item boundary */
+ if (cur + sizeof(*di) > item_size) {
+ dir_item_err(root, leaf, slot,
+- "dir item header crosses item boundary, have %lu boundary %u",
++ "dir item header crosses item boundary, have %zu boundary %u",
+ cur + sizeof(*di), item_size);
+ return -EUCLEAN;
+ }
+--
+2.17.1
+
--- /dev/null
+From eedbbc2fea1f26d5554fcba0eb3d19ce53a9b77c Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <wqu@suse.com>
+Date: Tue, 3 Jul 2018 17:10:05 +0800
+Subject: btrfs: tree-checker: Verify block_group_item
+
+commit fce466eab7ac6baa9d2dcd88abcf945be3d4a089 upstream.
+
+A crafted image with invalid block group items could make free space cache
+code to cause panic.
+
+We could detect such invalid block group item by checking:
+1) Item size
+ Known fixed value.
+2) Block group size (key.offset)
+ We have an upper limit on block group item (10G)
+3) Chunk objectid
+ Known fixed value.
+4) Type
+ Only 4 valid type values, DATA, METADATA, SYSTEM and DATA|METADATA.
+ No more than 1 bit set for profile type.
+5) Used space
+ No more than the block group size.
+
+This should allow btrfs to detect and refuse to mount the crafted image.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=199849
+Reported-by: Xu Wen <wen.xu@gatech.edu>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Reviewed-by: Gu Jinxiang <gujx@cn.fujitsu.com>
+Reviewed-by: Nikolay Borisov <nborisov@suse.com>
+Tested-by: Gu Jinxiang <gujx@cn.fujitsu.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+[bwh: Backported to 4.14:
+ - In check_leaf_item(), pass root->fs_info to check_block_group_item()
+ - Adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/tree-checker.c | 100 ++++++++++++++++++++++++++++++++++++++++
+ fs/btrfs/volumes.c | 2 +-
+ fs/btrfs/volumes.h | 2 +
+ 3 files changed, 103 insertions(+), 1 deletion(-)
+
+diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
+index f7e7a455b710..cf9b10a07134 100644
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -31,6 +31,7 @@
+ #include "disk-io.h"
+ #include "compression.h"
+ #include "hash.h"
++#include "volumes.h"
+
+ #define CORRUPT(reason, eb, root, slot) \
+ btrfs_crit(root->fs_info, \
+@@ -312,6 +313,102 @@ static int check_dir_item(struct btrfs_root *root,
+ return 0;
+ }
+
++__printf(4, 5)
++__cold
++static void block_group_err(const struct btrfs_fs_info *fs_info,
++ const struct extent_buffer *eb, int slot,
++ const char *fmt, ...)
++{
++ struct btrfs_key key;
++ struct va_format vaf;
++ va_list args;
++
++ btrfs_item_key_to_cpu(eb, &key, slot);
++ va_start(args, fmt);
++
++ vaf.fmt = fmt;
++ vaf.va = &args;
++
++ btrfs_crit(fs_info,
++ "corrupt %s: root=%llu block=%llu slot=%d bg_start=%llu bg_len=%llu, %pV",
++ btrfs_header_level(eb) == 0 ? "leaf" : "node",
++ btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot,
++ key.objectid, key.offset, &vaf);
++ va_end(args);
++}
++
++static int check_block_group_item(struct btrfs_fs_info *fs_info,
++ struct extent_buffer *leaf,
++ struct btrfs_key *key, int slot)
++{
++ struct btrfs_block_group_item bgi;
++ u32 item_size = btrfs_item_size_nr(leaf, slot);
++ u64 flags;
++ u64 type;
++
++ /*
++ * Here we don't really care about alignment since extent allocator can
++ * handle it. We care more about the size, as if one block group is
++ * larger than maximum size, it's must be some obvious corruption.
++ */
++ if (key->offset > BTRFS_MAX_DATA_CHUNK_SIZE || key->offset == 0) {
++ block_group_err(fs_info, leaf, slot,
++ "invalid block group size, have %llu expect (0, %llu]",
++ key->offset, BTRFS_MAX_DATA_CHUNK_SIZE);
++ return -EUCLEAN;
++ }
++
++ if (item_size != sizeof(bgi)) {
++ block_group_err(fs_info, leaf, slot,
++ "invalid item size, have %u expect %zu",
++ item_size, sizeof(bgi));
++ return -EUCLEAN;
++ }
++
++ read_extent_buffer(leaf, &bgi, btrfs_item_ptr_offset(leaf, slot),
++ sizeof(bgi));
++ if (btrfs_block_group_chunk_objectid(&bgi) !=
++ BTRFS_FIRST_CHUNK_TREE_OBJECTID) {
++ block_group_err(fs_info, leaf, slot,
++ "invalid block group chunk objectid, have %llu expect %llu",
++ btrfs_block_group_chunk_objectid(&bgi),
++ BTRFS_FIRST_CHUNK_TREE_OBJECTID);
++ return -EUCLEAN;
++ }
++
++ if (btrfs_block_group_used(&bgi) > key->offset) {
++ block_group_err(fs_info, leaf, slot,
++ "invalid block group used, have %llu expect [0, %llu)",
++ btrfs_block_group_used(&bgi), key->offset);
++ return -EUCLEAN;
++ }
++
++ flags = btrfs_block_group_flags(&bgi);
++ if (hweight64(flags & BTRFS_BLOCK_GROUP_PROFILE_MASK) > 1) {
++ block_group_err(fs_info, leaf, slot,
++"invalid profile flags, have 0x%llx (%lu bits set) expect no more than 1 bit set",
++ flags & BTRFS_BLOCK_GROUP_PROFILE_MASK,
++ hweight64(flags & BTRFS_BLOCK_GROUP_PROFILE_MASK));
++ return -EUCLEAN;
++ }
++
++ type = flags & BTRFS_BLOCK_GROUP_TYPE_MASK;
++ if (type != BTRFS_BLOCK_GROUP_DATA &&
++ type != BTRFS_BLOCK_GROUP_METADATA &&
++ type != BTRFS_BLOCK_GROUP_SYSTEM &&
++ type != (BTRFS_BLOCK_GROUP_METADATA |
++ BTRFS_BLOCK_GROUP_DATA)) {
++ block_group_err(fs_info, leaf, slot,
++"invalid type, have 0x%llx (%lu bits set) expect either 0x%llx, 0x%llx, 0x%llu or 0x%llx",
++ type, hweight64(type),
++ BTRFS_BLOCK_GROUP_DATA, BTRFS_BLOCK_GROUP_METADATA,
++ BTRFS_BLOCK_GROUP_SYSTEM,
++ BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA);
++ return -EUCLEAN;
++ }
++ return 0;
++}
++
+ /*
+ * Common point to switch the item-specific validation.
+ */
+@@ -333,6 +430,9 @@ static int check_leaf_item(struct btrfs_root *root,
+ case BTRFS_XATTR_ITEM_KEY:
+ ret = check_dir_item(root, leaf, key, slot);
+ break;
++ case BTRFS_BLOCK_GROUP_ITEM_KEY:
++ ret = check_block_group_item(root->fs_info, leaf, key, slot);
++ break;
+ }
+ return ret;
+ }
+diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
+index cfd5728e7519..9663b6aa2a56 100644
+--- a/fs/btrfs/volumes.c
++++ b/fs/btrfs/volumes.c
+@@ -4647,7 +4647,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
+
+ if (type & BTRFS_BLOCK_GROUP_DATA) {
+ max_stripe_size = SZ_1G;
+- max_chunk_size = 10 * max_stripe_size;
++ max_chunk_size = BTRFS_MAX_DATA_CHUNK_SIZE;
+ if (!devs_max)
+ devs_max = BTRFS_MAX_DEVS(info->chunk_root);
+ } else if (type & BTRFS_BLOCK_GROUP_METADATA) {
+diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
+index c5dd48eb7b3d..76fb6e84f201 100644
+--- a/fs/btrfs/volumes.h
++++ b/fs/btrfs/volumes.h
+@@ -24,6 +24,8 @@
+ #include <linux/btrfs.h>
+ #include "async-thread.h"
+
++#define BTRFS_MAX_DATA_CHUNK_SIZE (10ULL * SZ_1G)
++
+ extern struct mutex uuid_mutex;
+
+ #define BTRFS_STRIPE_LEN SZ_64K
+--
+2.17.1
+
--- /dev/null
+From 905aad8e5b31afab2b5c9840e6de4fce9b226995 Mon Sep 17 00:00:00 2001
+From: Gu Jinxiang <gujx@cn.fujitsu.com>
+Date: Wed, 4 Jul 2018 18:16:39 +0800
+Subject: btrfs: validate type when reading a chunk
+
+commit 315409b0098fb2651d86553f0436b70502b29bb2 upstream.
+
+Reported in https://bugzilla.kernel.org/show_bug.cgi?id=199839, with an
+image that has an invalid chunk type but does not return an error.
+
+Add chunk type check in btrfs_check_chunk_valid, to detect the wrong
+type combinations.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=199839
+Reported-by: Xu Wen <wen.xu@gatech.edu>
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: Gu Jinxiang <gujx@cn.fujitsu.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/volumes.c | 28 ++++++++++++++++++++++++++++
+ 1 file changed, 28 insertions(+)
+
+diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
+index a0947f4a3e87..cfd5728e7519 100644
+--- a/fs/btrfs/volumes.c
++++ b/fs/btrfs/volumes.c
+@@ -6353,6 +6353,8 @@ static int btrfs_check_chunk_valid(struct btrfs_fs_info *fs_info,
+ u16 num_stripes;
+ u16 sub_stripes;
+ u64 type;
++ u64 features;
++ bool mixed = false;
+
+ length = btrfs_chunk_length(leaf, chunk);
+ stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
+@@ -6391,6 +6393,32 @@ static int btrfs_check_chunk_valid(struct btrfs_fs_info *fs_info,
+ btrfs_chunk_type(leaf, chunk));
+ return -EIO;
+ }
++
++ if ((type & BTRFS_BLOCK_GROUP_TYPE_MASK) == 0) {
++ btrfs_err(fs_info, "missing chunk type flag: 0x%llx", type);
++ return -EIO;
++ }
++
++ if ((type & BTRFS_BLOCK_GROUP_SYSTEM) &&
++ (type & (BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA))) {
++ btrfs_err(fs_info,
++ "system chunk with data or metadata type: 0x%llx", type);
++ return -EIO;
++ }
++
++ features = btrfs_super_incompat_flags(fs_info->super_copy);
++ if (features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS)
++ mixed = true;
++
++ if (!mixed) {
++ if ((type & BTRFS_BLOCK_GROUP_METADATA) &&
++ (type & BTRFS_BLOCK_GROUP_DATA)) {
++ btrfs_err(fs_info,
++ "mixed chunk type in non-mixed mode: 0x%llx", type);
++ return -EIO;
++ }
++ }
++
+ if ((type & BTRFS_BLOCK_GROUP_RAID10 && sub_stripes != 2) ||
+ (type & BTRFS_BLOCK_GROUP_RAID1 && num_stripes < 1) ||
+ (type & BTRFS_BLOCK_GROUP_RAID5 && num_stripes < 2) ||
+--
+2.17.1
+
--- /dev/null
+From f642dd8fb8b207d53dce466b9442ee7553f39ce8 Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <wqu@suse.com>
+Date: Wed, 1 Aug 2018 10:37:17 +0800
+Subject: btrfs: Verify that every chunk has corresponding block group at mount
+ time
+
+commit 7ef49515fa6727cb4b6f2f5b0ffbc5fc20a9f8c6 upstream.
+
+If a crafted image has missing block group items, it could cause
+unexpected behavior and breaks the assumption of 1:1 chunk<->block group
+mapping.
+
+Although we have the block group -> chunk mapping check, we still need
+chunk -> block group mapping check.
+
+This patch will do extra check to ensure each chunk has its
+corresponding block group.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=199847
+Reported-by: Xu Wen <wen.xu@gatech.edu>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Reviewed-by: Gu Jinxiang <gujx@cn.fujitsu.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/extent-tree.c | 58 +++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 57 insertions(+), 1 deletion(-)
+
+diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
+index 2cb3569ac548..fdc42eddccc2 100644
+--- a/fs/btrfs/extent-tree.c
++++ b/fs/btrfs/extent-tree.c
+@@ -10092,6 +10092,62 @@ btrfs_create_block_group_cache(struct btrfs_fs_info *fs_info,
+ return cache;
+ }
+
++
++/*
++ * Iterate all chunks and verify that each of them has the corresponding block
++ * group
++ */
++static int check_chunk_block_group_mappings(struct btrfs_fs_info *fs_info)
++{
++ struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
++ struct extent_map *em;
++ struct btrfs_block_group_cache *bg;
++ u64 start = 0;
++ int ret = 0;
++
++ while (1) {
++ read_lock(&map_tree->map_tree.lock);
++ /*
++ * lookup_extent_mapping will return the first extent map
++ * intersecting the range, so setting @len to 1 is enough to
++ * get the first chunk.
++ */
++ em = lookup_extent_mapping(&map_tree->map_tree, start, 1);
++ read_unlock(&map_tree->map_tree.lock);
++ if (!em)
++ break;
++
++ bg = btrfs_lookup_block_group(fs_info, em->start);
++ if (!bg) {
++ btrfs_err(fs_info,
++ "chunk start=%llu len=%llu doesn't have corresponding block group",
++ em->start, em->len);
++ ret = -EUCLEAN;
++ free_extent_map(em);
++ break;
++ }
++ if (bg->key.objectid != em->start ||
++ bg->key.offset != em->len ||
++ (bg->flags & BTRFS_BLOCK_GROUP_TYPE_MASK) !=
++ (em->map_lookup->type & BTRFS_BLOCK_GROUP_TYPE_MASK)) {
++ btrfs_err(fs_info,
++"chunk start=%llu len=%llu flags=0x%llx doesn't match block group start=%llu len=%llu flags=0x%llx",
++ em->start, em->len,
++ em->map_lookup->type & BTRFS_BLOCK_GROUP_TYPE_MASK,
++ bg->key.objectid, bg->key.offset,
++ bg->flags & BTRFS_BLOCK_GROUP_TYPE_MASK);
++ ret = -EUCLEAN;
++ free_extent_map(em);
++ btrfs_put_block_group(bg);
++ break;
++ }
++ start = em->start + em->len;
++ free_extent_map(em);
++ btrfs_put_block_group(bg);
++ }
++ return ret;
++}
++
+ int btrfs_read_block_groups(struct btrfs_fs_info *info)
+ {
+ struct btrfs_path *path;
+@@ -10264,7 +10320,7 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info)
+ }
+
+ init_global_block_rsv(info);
+- ret = 0;
++ ret = check_chunk_block_group_mappings(info);
+ error:
+ btrfs_free_path(path);
+ return ret;
+--
+2.17.1
+
--- /dev/null
+From 1dc2b68b778c9974a278c8b3b0c7db03a125366b Mon Sep 17 00:00:00 2001
+From: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Date: Thu, 29 Nov 2018 19:17:34 +0000
+Subject: f2fs: Add sanity_check_inode() function
+
+This was done as part of commit 5d64600d4f33 "f2fs: avoid bug_on on
+corrupted inode" upstream, but the specific check that commit added is
+not applicable to 4.14.
+
+Cc: Jaegeuk Kim <jaegeuk@kernel.org>
+Cc: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/f2fs/inode.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
+index b1c0eb433841..917a6c3d5649 100644
+--- a/fs/f2fs/inode.c
++++ b/fs/f2fs/inode.c
+@@ -180,6 +180,13 @@ void f2fs_inode_chksum_set(struct f2fs_sb_info *sbi, struct page *page)
+ ri->i_inode_checksum = cpu_to_le32(f2fs_inode_chksum(sbi, page));
+ }
+
++static bool sanity_check_inode(struct inode *inode)
++{
++ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
++
++ return true;
++}
++
+ static int do_read_inode(struct inode *inode)
+ {
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+@@ -281,6 +288,10 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
+ ret = do_read_inode(inode);
+ if (ret)
+ goto bad_inode;
++ if (!sanity_check_inode(inode)) {
++ ret = -EINVAL;
++ goto bad_inode;
++ }
+ make_now:
+ if (ino == F2FS_NODE_INO(sbi)) {
+ inode->i_mapping->a_ops = &f2fs_node_aops;
+--
+2.17.1
+
--- /dev/null
+From d6f4d5a016326c1141f92ae931a66dab9d7c7d5e Mon Sep 17 00:00:00 2001
+From: Yunlei He <heyunlei@huawei.com>
+Date: Thu, 8 Mar 2018 16:29:13 +0800
+Subject: f2fs: check blkaddr more accuratly before issue a bio
+
+commit 0833721ec3658a4e9d5e58b6fa82cf9edc431e59 upstream.
+
+This patch check blkaddr more accuratly before issue a
+write or read bio.
+
+Signed-off-by: Yunlei He <heyunlei@huawei.com>
+Reviewed-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/f2fs/checkpoint.c | 2 ++
+ fs/f2fs/data.c | 5 +++--
+ fs/f2fs/f2fs.h | 1 +
+ fs/f2fs/segment.h | 25 +++++++++++++++++++------
+ 4 files changed, 25 insertions(+), 8 deletions(-)
+
+diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
+index 41fce930f44c..1bd4cd8c79c6 100644
+--- a/fs/f2fs/checkpoint.c
++++ b/fs/f2fs/checkpoint.c
+@@ -69,6 +69,7 @@ static struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index,
+ .old_blkaddr = index,
+ .new_blkaddr = index,
+ .encrypted_page = NULL,
++ .is_meta = is_meta,
+ };
+
+ if (unlikely(!is_meta))
+@@ -163,6 +164,7 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
+ .op_flags = sync ? (REQ_META | REQ_PRIO) : REQ_RAHEAD,
+ .encrypted_page = NULL,
+ .in_list = false,
++ .is_meta = (type != META_POR),
+ };
+ struct blk_plug plug;
+
+diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
+index 6fbb6d75318a..5913de3f661d 100644
+--- a/fs/f2fs/data.c
++++ b/fs/f2fs/data.c
+@@ -369,6 +369,7 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
+ struct page *page = fio->encrypted_page ?
+ fio->encrypted_page : fio->page;
+
++ verify_block_addr(fio, fio->new_blkaddr);
+ trace_f2fs_submit_page_bio(page, fio);
+ f2fs_trace_ios(fio, 0);
+
+@@ -413,8 +414,8 @@ next:
+ }
+
+ if (fio->old_blkaddr != NEW_ADDR)
+- verify_block_addr(sbi, fio->old_blkaddr);
+- verify_block_addr(sbi, fio->new_blkaddr);
++ verify_block_addr(fio, fio->old_blkaddr);
++ verify_block_addr(fio, fio->new_blkaddr);
+
+ bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page;
+
+diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
+index 54f8520ad7a2..aa7b033af1b0 100644
+--- a/fs/f2fs/f2fs.h
++++ b/fs/f2fs/f2fs.h
+@@ -910,6 +910,7 @@ struct f2fs_io_info {
+ bool submitted; /* indicate IO submission */
+ int need_lock; /* indicate we need to lock cp_rwsem */
+ bool in_list; /* indicate fio is in io_list */
++ bool is_meta; /* indicate borrow meta inode mapping or not */
+ enum iostat_type io_type; /* io type */
+ };
+
+diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
+index 4dfb5080098f..4b635e8c91b0 100644
+--- a/fs/f2fs/segment.h
++++ b/fs/f2fs/segment.h
+@@ -53,13 +53,19 @@
+ ((secno) == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno / \
+ (sbi)->segs_per_sec)) \
+
+-#define MAIN_BLKADDR(sbi) (SM_I(sbi)->main_blkaddr)
+-#define SEG0_BLKADDR(sbi) (SM_I(sbi)->seg0_blkaddr)
++#define MAIN_BLKADDR(sbi) \
++ (SM_I(sbi) ? SM_I(sbi)->main_blkaddr : \
++ le32_to_cpu(F2FS_RAW_SUPER(sbi)->main_blkaddr))
++#define SEG0_BLKADDR(sbi) \
++ (SM_I(sbi) ? SM_I(sbi)->seg0_blkaddr : \
++ le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment0_blkaddr))
+
+ #define MAIN_SEGS(sbi) (SM_I(sbi)->main_segments)
+ #define MAIN_SECS(sbi) ((sbi)->total_sections)
+
+-#define TOTAL_SEGS(sbi) (SM_I(sbi)->segment_count)
++#define TOTAL_SEGS(sbi) \
++ (SM_I(sbi) ? SM_I(sbi)->segment_count : \
++ le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment_count))
+ #define TOTAL_BLKS(sbi) (TOTAL_SEGS(sbi) << (sbi)->log_blocks_per_seg)
+
+ #define MAX_BLKADDR(sbi) (SEG0_BLKADDR(sbi) + TOTAL_BLKS(sbi))
+@@ -619,10 +625,17 @@ static inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno)
+ f2fs_bug_on(sbi, segno > TOTAL_SEGS(sbi) - 1);
+ }
+
+-static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr)
++static inline void verify_block_addr(struct f2fs_io_info *fio, block_t blk_addr)
+ {
+- BUG_ON(blk_addr < SEG0_BLKADDR(sbi)
+- || blk_addr >= MAX_BLKADDR(sbi));
++ struct f2fs_sb_info *sbi = fio->sbi;
++
++ if (PAGE_TYPE_OF_BIO(fio->type) == META &&
++ (!is_read_io(fio->op) || fio->is_meta))
++ BUG_ON(blk_addr < SEG0_BLKADDR(sbi) ||
++ blk_addr >= MAIN_BLKADDR(sbi));
++ else
++ BUG_ON(blk_addr < MAIN_BLKADDR(sbi) ||
++ blk_addr >= MAX_BLKADDR(sbi));
+ }
+
+ /*
+--
+2.17.1
+
--- /dev/null
+From 188bc3eea6c9e3b66cbcc504e4faf8047af815a1 Mon Sep 17 00:00:00 2001
+From: Chao Yu <yuchao0@huawei.com>
+Date: Wed, 23 May 2018 22:25:08 +0800
+Subject: f2fs: clean up with is_valid_blkaddr()
+
+commit 7b525dd01365c6764018e374d391c92466be1b7a upstream.
+
+- rename is_valid_blkaddr() to is_valid_meta_blkaddr() for readability.
+- introduce is_valid_blkaddr() for cleanup.
+
+No logic change in this patch.
+
+Signed-off-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/f2fs/checkpoint.c | 4 ++--
+ fs/f2fs/data.c | 18 +++++-------------
+ fs/f2fs/f2fs.h | 9 ++++++++-
+ fs/f2fs/file.c | 2 +-
+ fs/f2fs/inode.c | 2 +-
+ fs/f2fs/node.c | 5 ++---
+ fs/f2fs/recovery.c | 6 +++---
+ fs/f2fs/segment.c | 4 ++--
+ fs/f2fs/segment.h | 2 +-
+ 9 files changed, 25 insertions(+), 27 deletions(-)
+
+diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
+index 1bd4cd8c79c6..2b951046657e 100644
+--- a/fs/f2fs/checkpoint.c
++++ b/fs/f2fs/checkpoint.c
+@@ -118,7 +118,7 @@ struct page *get_tmp_page(struct f2fs_sb_info *sbi, pgoff_t index)
+ return __get_meta_page(sbi, index, false);
+ }
+
+-bool is_valid_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type)
++bool is_valid_meta_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type)
+ {
+ switch (type) {
+ case META_NAT:
+@@ -174,7 +174,7 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
+ blk_start_plug(&plug);
+ for (; nrpages-- > 0; blkno++) {
+
+- if (!is_valid_blkaddr(sbi, blkno, type))
++ if (!is_valid_meta_blkaddr(sbi, blkno, type))
+ goto out;
+
+ switch (type) {
+diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
+index 5913de3f661d..f7b2909e9c5f 100644
+--- a/fs/f2fs/data.c
++++ b/fs/f2fs/data.c
+@@ -413,7 +413,7 @@ next:
+ spin_unlock(&io->io_lock);
+ }
+
+- if (fio->old_blkaddr != NEW_ADDR)
++ if (is_valid_blkaddr(fio->old_blkaddr))
+ verify_block_addr(fio, fio->old_blkaddr);
+ verify_block_addr(fio, fio->new_blkaddr);
+
+@@ -946,7 +946,7 @@ next_dnode:
+ next_block:
+ blkaddr = datablock_addr(dn.inode, dn.node_page, dn.ofs_in_node);
+
+- if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR) {
++ if (!is_valid_blkaddr(blkaddr)) {
+ if (create) {
+ if (unlikely(f2fs_cp_error(sbi))) {
+ err = -EIO;
+@@ -1388,15 +1388,6 @@ static inline bool need_inplace_update(struct f2fs_io_info *fio)
+ return need_inplace_update_policy(inode, fio);
+ }
+
+-static inline bool valid_ipu_blkaddr(struct f2fs_io_info *fio)
+-{
+- if (fio->old_blkaddr == NEW_ADDR)
+- return false;
+- if (fio->old_blkaddr == NULL_ADDR)
+- return false;
+- return true;
+-}
+-
+ int do_write_data_page(struct f2fs_io_info *fio)
+ {
+ struct page *page = fio->page;
+@@ -1411,7 +1402,7 @@ int do_write_data_page(struct f2fs_io_info *fio)
+ f2fs_lookup_extent_cache(inode, page->index, &ei)) {
+ fio->old_blkaddr = ei.blk + page->index - ei.fofs;
+
+- if (valid_ipu_blkaddr(fio)) {
++ if (is_valid_blkaddr(fio->old_blkaddr)) {
+ ipu_force = true;
+ fio->need_lock = LOCK_DONE;
+ goto got_it;
+@@ -1438,7 +1429,8 @@ got_it:
+ * If current allocation needs SSR,
+ * it had better in-place writes for updated data.
+ */
+- if (ipu_force || (valid_ipu_blkaddr(fio) && need_inplace_update(fio))) {
++ if (ipu_force || (is_valid_blkaddr(fio->old_blkaddr) &&
++ need_inplace_update(fio))) {
+ err = encrypt_one_page(fio);
+ if (err)
+ goto out_writepage;
+diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
+index aa7b033af1b0..d74c77b51b71 100644
+--- a/fs/f2fs/f2fs.h
++++ b/fs/f2fs/f2fs.h
+@@ -2355,6 +2355,13 @@ static inline void f2fs_update_iostat(struct f2fs_sb_info *sbi,
+ spin_unlock(&sbi->iostat_lock);
+ }
+
++static inline bool is_valid_blkaddr(block_t blkaddr)
++{
++ if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR)
++ return false;
++ return true;
++}
++
+ /*
+ * file.c
+ */
+@@ -2565,7 +2572,7 @@ void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io);
+ struct page *grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index);
+ struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index);
+ struct page *get_tmp_page(struct f2fs_sb_info *sbi, pgoff_t index);
+-bool is_valid_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type);
++bool is_valid_meta_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type);
+ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
+ int type, bool sync);
+ void ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index);
+diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
+index 6f589730782d..d368eda462bb 100644
+--- a/fs/f2fs/file.c
++++ b/fs/f2fs/file.c
+@@ -334,7 +334,7 @@ static bool __found_offset(block_t blkaddr, pgoff_t dirty, pgoff_t pgofs,
+ switch (whence) {
+ case SEEK_DATA:
+ if ((blkaddr == NEW_ADDR && dirty == pgofs) ||
+- (blkaddr != NEW_ADDR && blkaddr != NULL_ADDR))
++ is_valid_blkaddr(blkaddr))
+ return true;
+ break;
+ case SEEK_HOLE:
+diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
+index 259b0aa283f0..2bcbbf566f0c 100644
+--- a/fs/f2fs/inode.c
++++ b/fs/f2fs/inode.c
+@@ -66,7 +66,7 @@ static bool __written_first_block(struct f2fs_inode *ri)
+ {
+ block_t addr = le32_to_cpu(ri->i_addr[offset_in_addr(ri)]);
+
+- if (addr != NEW_ADDR && addr != NULL_ADDR)
++ if (is_valid_blkaddr(addr))
+ return true;
+ return false;
+ }
+diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
+index 712505ec5de4..5f212fb2d62b 100644
+--- a/fs/f2fs/node.c
++++ b/fs/f2fs/node.c
+@@ -334,8 +334,7 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
+ new_blkaddr == NULL_ADDR);
+ f2fs_bug_on(sbi, nat_get_blkaddr(e) == NEW_ADDR &&
+ new_blkaddr == NEW_ADDR);
+- f2fs_bug_on(sbi, nat_get_blkaddr(e) != NEW_ADDR &&
+- nat_get_blkaddr(e) != NULL_ADDR &&
++ f2fs_bug_on(sbi, is_valid_blkaddr(nat_get_blkaddr(e)) &&
+ new_blkaddr == NEW_ADDR);
+
+ /* increment version no as node is removed */
+@@ -350,7 +349,7 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
+
+ /* change address */
+ nat_set_blkaddr(e, new_blkaddr);
+- if (new_blkaddr == NEW_ADDR || new_blkaddr == NULL_ADDR)
++ if (!is_valid_blkaddr(new_blkaddr))
+ set_nat_flag(e, IS_CHECKPOINTED, false);
+ __set_nat_cache_dirty(nm_i, e);
+
+diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
+index 765fadf954af..53f41ad4cbe1 100644
+--- a/fs/f2fs/recovery.c
++++ b/fs/f2fs/recovery.c
+@@ -236,7 +236,7 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head,
+ while (1) {
+ struct fsync_inode_entry *entry;
+
+- if (!is_valid_blkaddr(sbi, blkaddr, META_POR))
++ if (!is_valid_meta_blkaddr(sbi, blkaddr, META_POR))
+ return 0;
+
+ page = get_tmp_page(sbi, blkaddr);
+@@ -479,7 +479,7 @@ retry_dn:
+ }
+
+ /* dest is valid block, try to recover from src to dest */
+- if (is_valid_blkaddr(sbi, dest, META_POR)) {
++ if (is_valid_meta_blkaddr(sbi, dest, META_POR)) {
+
+ if (src == NULL_ADDR) {
+ err = reserve_new_block(&dn);
+@@ -540,7 +540,7 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
+ while (1) {
+ struct fsync_inode_entry *entry;
+
+- if (!is_valid_blkaddr(sbi, blkaddr, META_POR))
++ if (!is_valid_meta_blkaddr(sbi, blkaddr, META_POR))
+ break;
+
+ ra_meta_pages_cond(sbi, blkaddr);
+diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
+index 1104a6c80251..483d7a869679 100644
+--- a/fs/f2fs/segment.c
++++ b/fs/f2fs/segment.c
+@@ -1758,7 +1758,7 @@ bool is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr)
+ struct seg_entry *se;
+ bool is_cp = false;
+
+- if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR)
++ if (!is_valid_blkaddr(blkaddr))
+ return true;
+
+ mutex_lock(&sit_i->sentry_lock);
+@@ -2571,7 +2571,7 @@ void f2fs_wait_on_block_writeback(struct f2fs_sb_info *sbi, block_t blkaddr)
+ {
+ struct page *cpage;
+
+- if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR)
++ if (!is_valid_blkaddr(blkaddr))
+ return;
+
+ cpage = find_lock_page(META_MAPPING(sbi), blkaddr);
+diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
+index 4b635e8c91b0..f977774338c3 100644
+--- a/fs/f2fs/segment.h
++++ b/fs/f2fs/segment.h
+@@ -85,7 +85,7 @@
+ (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) & ((sbi)->blocks_per_seg - 1))
+
+ #define GET_SEGNO(sbi, blk_addr) \
+- ((((blk_addr) == NULL_ADDR) || ((blk_addr) == NEW_ADDR)) ? \
++ ((!is_valid_blkaddr(blk_addr)) ? \
+ NULL_SEGNO : GET_L2R_SEGNO(FREE_I(sbi), \
+ GET_SEGNO_FROM_SEG0(sbi, blk_addr)))
+ #define BLKS_PER_SEC(sbi) \
+--
+2.17.1
+
--- /dev/null
+From 5a15dbbc9f6d8abb1721458c97f040b72aab25e5 Mon Sep 17 00:00:00 2001
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+Date: Fri, 27 Apr 2018 19:03:22 -0700
+Subject: f2fs: enhance sanity_check_raw_super() to avoid potential overflow
+
+commit 0cfe75c5b011994651a4ca6d74f20aa997bfc69a upstream.
+
+In order to avoid the below overflow issue, we should have checked the
+boundaries in superblock before reaching out to allocation. As Linus suggested,
+the right place should be sanity_check_raw_super().
+
+Dr Silvio Cesare of InfoSect reported:
+
+There are integer overflows with using the cp_payload superblock field in the
+f2fs filesystem potentially leading to memory corruption.
+
+include/linux/f2fs_fs.h
+
+struct f2fs_super_block {
+...
+ __le32 cp_payload;
+
+fs/f2fs/f2fs.h
+
+typedef u32 block_t; /*
+ * should not change u32, since it is the on-disk block
+ * address format, __le32.
+ */
+...
+
+static inline block_t __cp_payload(struct f2fs_sb_info *sbi)
+{
+ return le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_payload);
+}
+
+fs/f2fs/checkpoint.c
+
+ block_t start_blk, orphan_blocks, i, j;
+...
+ start_blk = __start_cp_addr(sbi) + 1 + __cp_payload(sbi);
+ orphan_blocks = __start_sum_addr(sbi) - 1 - __cp_payload(sbi);
+
++++ integer overflows
+
+...
+ unsigned int cp_blks = 1 + __cp_payload(sbi);
+...
+ sbi->ckpt = kzalloc(cp_blks * blk_size, GFP_KERNEL);
+
++++ integer overflow leading to incorrect heap allocation.
+
+ int cp_payload_blks = __cp_payload(sbi);
+...
+ ckpt->cp_pack_start_sum = cpu_to_le32(1 + cp_payload_blks +
+ orphan_blocks);
+
++++ sign bug and integer overflow
+
+...
+ for (i = 1; i < 1 + cp_payload_blks; i++)
+
++++ integer overflow
+
+...
+
+ sbi->max_orphans = (sbi->blocks_per_seg - F2FS_CP_PACKS -
+ NR_CURSEG_TYPE - __cp_payload(sbi)) *
+ F2FS_ORPHANS_PER_BLOCK;
+
++++ integer overflow
+
+Reported-by: Greg KH <greg@kroah.com>
+Reported-by: Silvio Cesare <silvio.cesare@gmail.com>
+Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
+Reviewed-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Backported to 4.14: No hot file extension support]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/f2fs/super.c | 71 ++++++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 64 insertions(+), 7 deletions(-)
+
+diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
+index 7cda685296b2..c3e1090e7c0a 100644
+--- a/fs/f2fs/super.c
++++ b/fs/f2fs/super.c
+@@ -1807,6 +1807,8 @@ static inline bool sanity_check_area_boundary(struct f2fs_sb_info *sbi,
+ static int sanity_check_raw_super(struct f2fs_sb_info *sbi,
+ struct buffer_head *bh)
+ {
++ block_t segment_count, segs_per_sec, secs_per_zone;
++ block_t total_sections, blocks_per_seg;
+ struct f2fs_super_block *raw_super = (struct f2fs_super_block *)
+ (bh->b_data + F2FS_SUPER_OFFSET);
+ struct super_block *sb = sbi->sb;
+@@ -1863,6 +1865,68 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi,
+ return 1;
+ }
+
++ segment_count = le32_to_cpu(raw_super->segment_count);
++ segs_per_sec = le32_to_cpu(raw_super->segs_per_sec);
++ secs_per_zone = le32_to_cpu(raw_super->secs_per_zone);
++ total_sections = le32_to_cpu(raw_super->section_count);
++
++ /* blocks_per_seg should be 512, given the above check */
++ blocks_per_seg = 1 << le32_to_cpu(raw_super->log_blocks_per_seg);
++
++ if (segment_count > F2FS_MAX_SEGMENT ||
++ segment_count < F2FS_MIN_SEGMENTS) {
++ f2fs_msg(sb, KERN_INFO,
++ "Invalid segment count (%u)",
++ segment_count);
++ return 1;
++ }
++
++ if (total_sections > segment_count ||
++ total_sections < F2FS_MIN_SEGMENTS ||
++ segs_per_sec > segment_count || !segs_per_sec) {
++ f2fs_msg(sb, KERN_INFO,
++ "Invalid segment/section count (%u, %u x %u)",
++ segment_count, total_sections, segs_per_sec);
++ return 1;
++ }
++
++ if ((segment_count / segs_per_sec) < total_sections) {
++ f2fs_msg(sb, KERN_INFO,
++ "Small segment_count (%u < %u * %u)",
++ segment_count, segs_per_sec, total_sections);
++ return 1;
++ }
++
++ if (segment_count > (le32_to_cpu(raw_super->block_count) >> 9)) {
++ f2fs_msg(sb, KERN_INFO,
++ "Wrong segment_count / block_count (%u > %u)",
++ segment_count, le32_to_cpu(raw_super->block_count));
++ return 1;
++ }
++
++ if (secs_per_zone > total_sections) {
++ f2fs_msg(sb, KERN_INFO,
++ "Wrong secs_per_zone (%u > %u)",
++ secs_per_zone, total_sections);
++ return 1;
++ }
++ if (le32_to_cpu(raw_super->extension_count) > F2FS_MAX_EXTENSION) {
++ f2fs_msg(sb, KERN_INFO,
++ "Corrupted extension count (%u > %u)",
++ le32_to_cpu(raw_super->extension_count),
++ F2FS_MAX_EXTENSION);
++ return 1;
++ }
++
++ if (le32_to_cpu(raw_super->cp_payload) >
++ (blocks_per_seg - F2FS_CP_PACKS)) {
++ f2fs_msg(sb, KERN_INFO,
++ "Insane cp_payload (%u > %u)",
++ le32_to_cpu(raw_super->cp_payload),
++ blocks_per_seg - F2FS_CP_PACKS);
++ return 1;
++ }
++
+ /* check reserved ino info */
+ if (le32_to_cpu(raw_super->node_ino) != 1 ||
+ le32_to_cpu(raw_super->meta_ino) != 2 ||
+@@ -1875,13 +1939,6 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi,
+ return 1;
+ }
+
+- if (le32_to_cpu(raw_super->segment_count) > F2FS_MAX_SEGMENT) {
+- f2fs_msg(sb, KERN_INFO,
+- "Invalid segment count (%u)",
+- le32_to_cpu(raw_super->segment_count));
+- return 1;
+- }
+-
+ /* check CP/SIT/NAT/SSA/MAIN_AREA area boundary */
+ if (sanity_check_area_boundary(sbi, bh))
+ return 1;
+--
+2.17.1
+
--- /dev/null
+From c97fadd6a7ce75e4c0b37a9c6d8eca02abb9464c Mon Sep 17 00:00:00 2001
+From: Chao Yu <yuchao0@huawei.com>
+Date: Wed, 1 Aug 2018 19:13:44 +0800
+Subject: f2fs: fix to do sanity check with block address in main area
+
+commit c9b60788fc760d136211853f10ce73dc152d1f4a upstream.
+
+This patch add to do sanity check with below field:
+- cp_pack_total_block_count
+- blkaddr of data/node
+- extent info
+
+- Overview
+BUG() in verify_block_addr() when writing to a corrupted f2fs image
+
+- Reproduce (4.18 upstream kernel)
+
+- POC (poc.c)
+
+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, sizeof(buf));
+ fdatasync(fd);
+ close(fd);
+ }
+}
+
+int main(int argc, char *argv[]) {
+ activity(argv[1]);
+ return 0;
+}
+
+- Kernel message
+[ 689.349473] F2FS-fs (loop0): Mounted with checkpoint version = 3
+[ 699.728662] WARNING: CPU: 0 PID: 1309 at fs/f2fs/segment.c:2860 f2fs_inplace_write_data+0x232/0x240
+[ 699.728670] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd mac_hid i2c_piix4 soundcore ib_iser rdma_cm iw_cm ib_cm ib_core iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx raid1 raid0 multipath linear 8139too crct10dif_pclmul crc32_pclmul qxl drm_kms_helper syscopyarea aesni_intel sysfillrect sysimgblt fb_sys_fops ttm drm aes_x86_64 crypto_simd cryptd 8139cp glue_helper mii pata_acpi floppy
+[ 699.729056] CPU: 0 PID: 1309 Comm: a.out Not tainted 4.18.0-rc1+ #4
+[ 699.729064] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[ 699.729074] RIP: 0010:f2fs_inplace_write_data+0x232/0x240
+[ 699.729076] Code: ff e9 cf fe ff ff 49 8d 7d 10 e8 39 45 ad ff 4d 8b 7d 10 be 04 00 00 00 49 8d 7f 48 e8 07 49 ad ff 45 8b 7f 48 e9 fb fe ff ff <0f> 0b f0 41 80 4d 48 04 e9 65 fe ff ff 90 66 66 66 66 90 55 48 8d
+[ 699.729130] RSP: 0018:ffff8801f43af568 EFLAGS: 00010202
+[ 699.729139] RAX: 000000000000003f RBX: ffff8801f43af7b8 RCX: ffffffffb88c9113
+[ 699.729142] RDX: 0000000000000003 RSI: dffffc0000000000 RDI: ffff8802024e5540
+[ 699.729144] RBP: ffff8801f43af590 R08: 0000000000000009 R09: ffffffffffffffe8
+[ 699.729147] R10: 0000000000000001 R11: ffffed0039b0596a R12: ffff8802024e5540
+[ 699.729149] R13: ffff8801f0335500 R14: ffff8801e3e7a700 R15: ffff8801e1ee4450
+[ 699.729154] FS: 00007f9bf97f5700(0000) GS:ffff8801f6e00000(0000) knlGS:0000000000000000
+[ 699.729156] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[ 699.729159] CR2: 00007f9bf925d170 CR3: 00000001f0c34000 CR4: 00000000000006f0
+[ 699.729171] Call Trace:
+[ 699.729192] f2fs_do_write_data_page+0x2e2/0xe00
+[ 699.729203] ? f2fs_should_update_outplace+0xd0/0xd0
+[ 699.729238] ? memcg_drain_all_list_lrus+0x280/0x280
+[ 699.729269] ? __radix_tree_replace+0xa3/0x120
+[ 699.729276] __write_data_page+0x5c7/0xe30
+[ 699.729291] ? kasan_check_read+0x11/0x20
+[ 699.729310] ? page_mapped+0x8a/0x110
+[ 699.729321] ? page_mkclean+0xe9/0x160
+[ 699.729327] ? f2fs_do_write_data_page+0xe00/0xe00
+[ 699.729331] ? invalid_page_referenced_vma+0x130/0x130
+[ 699.729345] ? clear_page_dirty_for_io+0x332/0x450
+[ 699.729351] f2fs_write_cache_pages+0x4ca/0x860
+[ 699.729358] ? __write_data_page+0xe30/0xe30
+[ 699.729374] ? percpu_counter_add_batch+0x22/0xa0
+[ 699.729380] ? kasan_check_write+0x14/0x20
+[ 699.729391] ? _raw_spin_lock+0x17/0x40
+[ 699.729403] ? f2fs_mark_inode_dirty_sync.part.18+0x16/0x30
+[ 699.729413] ? iov_iter_advance+0x113/0x640
+[ 699.729418] ? f2fs_write_end+0x133/0x2e0
+[ 699.729423] ? balance_dirty_pages_ratelimited+0x239/0x640
+[ 699.729428] f2fs_write_data_pages+0x329/0x520
+[ 699.729433] ? generic_perform_write+0x250/0x320
+[ 699.729438] ? f2fs_write_cache_pages+0x860/0x860
+[ 699.729454] ? current_time+0x110/0x110
+[ 699.729459] ? f2fs_preallocate_blocks+0x1ef/0x370
+[ 699.729464] do_writepages+0x37/0xb0
+[ 699.729468] ? f2fs_write_cache_pages+0x860/0x860
+[ 699.729472] ? do_writepages+0x37/0xb0
+[ 699.729478] __filemap_fdatawrite_range+0x19a/0x1f0
+[ 699.729483] ? delete_from_page_cache_batch+0x4e0/0x4e0
+[ 699.729496] ? __vfs_write+0x2b2/0x410
+[ 699.729501] file_write_and_wait_range+0x66/0xb0
+[ 699.729506] f2fs_do_sync_file+0x1f9/0xd90
+[ 699.729511] ? truncate_partial_data_page+0x290/0x290
+[ 699.729521] ? __sb_end_write+0x30/0x50
+[ 699.729526] ? vfs_write+0x20f/0x260
+[ 699.729530] f2fs_sync_file+0x9a/0xb0
+[ 699.729534] ? f2fs_do_sync_file+0xd90/0xd90
+[ 699.729548] vfs_fsync_range+0x68/0x100
+[ 699.729554] ? __fget_light+0xc9/0xe0
+[ 699.729558] do_fsync+0x3d/0x70
+[ 699.729562] __x64_sys_fdatasync+0x24/0x30
+[ 699.729585] do_syscall_64+0x78/0x170
+[ 699.729595] entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[ 699.729613] RIP: 0033:0x7f9bf930d800
+[ 699.729615] 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 49 bf 2c 00 00 75 10 b8 4b 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 be 78 01 00 48 89 04 24
+[ 699.729668] RSP: 002b:00007ffee3606c68 EFLAGS: 00000246 ORIG_RAX: 000000000000004b
+[ 699.729673] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f9bf930d800
+[ 699.729675] RDX: 0000000000008000 RSI: 00000000006010a0 RDI: 0000000000000003
+[ 699.729678] RBP: 00007ffee3606ca0 R08: 0000000001503010 R09: 0000000000000000
+[ 699.729680] R10: 00000000000002e8 R11: 0000000000000246 R12: 0000000000400610
+[ 699.729683] R13: 00007ffee3606da0 R14: 0000000000000000 R15: 0000000000000000
+[ 699.729687] ---[ end trace 4ce02f25ff7d3df5 ]---
+[ 699.729782] ------------[ cut here ]------------
+[ 699.729785] kernel BUG at fs/f2fs/segment.h:654!
+[ 699.731055] invalid opcode: 0000 [#1] SMP KASAN PTI
+[ 699.732104] CPU: 0 PID: 1309 Comm: a.out Tainted: G W 4.18.0-rc1+ #4
+[ 699.733684] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[ 699.735611] RIP: 0010:f2fs_submit_page_bio+0x29b/0x730
+[ 699.736649] Code: 54 49 8d bd 18 04 00 00 e8 b2 59 af ff 41 8b 8d 18 04 00 00 8b 45 b8 41 d3 e6 44 01 f0 4c 8d 73 14 41 39 c7 0f 82 37 fe ff ff <0f> 0b 65 8b 05 2c 04 77 47 89 c0 48 0f a3 05 52 c1 d5 01 0f 92 c0
+[ 699.740524] RSP: 0018:ffff8801f43af508 EFLAGS: 00010283
+[ 699.741573] RAX: 0000000000000000 RBX: ffff8801f43af7b8 RCX: ffffffffb88a7cef
+[ 699.743006] RDX: 0000000000000007 RSI: dffffc0000000000 RDI: ffff8801e3e7a64c
+[ 699.744426] RBP: ffff8801f43af558 R08: ffffed003e066b55 R09: ffffed003e066b55
+[ 699.745833] R10: 0000000000000001 R11: ffffed003e066b54 R12: ffffea0007876940
+[ 699.747256] R13: ffff8801f0335500 R14: ffff8801e3e7a600 R15: 0000000000000001
+[ 699.748683] FS: 00007f9bf97f5700(0000) GS:ffff8801f6e00000(0000) knlGS:0000000000000000
+[ 699.750293] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[ 699.751462] CR2: 00007f9bf925d170 CR3: 00000001f0c34000 CR4: 00000000000006f0
+[ 699.752874] Call Trace:
+[ 699.753386] ? f2fs_inplace_write_data+0x93/0x240
+[ 699.754341] f2fs_inplace_write_data+0xd2/0x240
+[ 699.755271] f2fs_do_write_data_page+0x2e2/0xe00
+[ 699.756214] ? f2fs_should_update_outplace+0xd0/0xd0
+[ 699.757215] ? memcg_drain_all_list_lrus+0x280/0x280
+[ 699.758209] ? __radix_tree_replace+0xa3/0x120
+[ 699.759164] __write_data_page+0x5c7/0xe30
+[ 699.760002] ? kasan_check_read+0x11/0x20
+[ 699.760823] ? page_mapped+0x8a/0x110
+[ 699.761573] ? page_mkclean+0xe9/0x160
+[ 699.762345] ? f2fs_do_write_data_page+0xe00/0xe00
+[ 699.763332] ? invalid_page_referenced_vma+0x130/0x130
+[ 699.764374] ? clear_page_dirty_for_io+0x332/0x450
+[ 699.765347] f2fs_write_cache_pages+0x4ca/0x860
+[ 699.766276] ? __write_data_page+0xe30/0xe30
+[ 699.767161] ? percpu_counter_add_batch+0x22/0xa0
+[ 699.768112] ? kasan_check_write+0x14/0x20
+[ 699.768951] ? _raw_spin_lock+0x17/0x40
+[ 699.769739] ? f2fs_mark_inode_dirty_sync.part.18+0x16/0x30
+[ 699.770885] ? iov_iter_advance+0x113/0x640
+[ 699.771743] ? f2fs_write_end+0x133/0x2e0
+[ 699.772569] ? balance_dirty_pages_ratelimited+0x239/0x640
+[ 699.773680] f2fs_write_data_pages+0x329/0x520
+[ 699.774603] ? generic_perform_write+0x250/0x320
+[ 699.775544] ? f2fs_write_cache_pages+0x860/0x860
+[ 699.776510] ? current_time+0x110/0x110
+[ 699.777299] ? f2fs_preallocate_blocks+0x1ef/0x370
+[ 699.778279] do_writepages+0x37/0xb0
+[ 699.779026] ? f2fs_write_cache_pages+0x860/0x860
+[ 699.779978] ? do_writepages+0x37/0xb0
+[ 699.780755] __filemap_fdatawrite_range+0x19a/0x1f0
+[ 699.781746] ? delete_from_page_cache_batch+0x4e0/0x4e0
+[ 699.782820] ? __vfs_write+0x2b2/0x410
+[ 699.783597] file_write_and_wait_range+0x66/0xb0
+[ 699.784540] f2fs_do_sync_file+0x1f9/0xd90
+[ 699.785381] ? truncate_partial_data_page+0x290/0x290
+[ 699.786415] ? __sb_end_write+0x30/0x50
+[ 699.787204] ? vfs_write+0x20f/0x260
+[ 699.787941] f2fs_sync_file+0x9a/0xb0
+[ 699.788694] ? f2fs_do_sync_file+0xd90/0xd90
+[ 699.789572] vfs_fsync_range+0x68/0x100
+[ 699.790360] ? __fget_light+0xc9/0xe0
+[ 699.791128] do_fsync+0x3d/0x70
+[ 699.791779] __x64_sys_fdatasync+0x24/0x30
+[ 699.792614] do_syscall_64+0x78/0x170
+[ 699.793371] entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[ 699.794406] RIP: 0033:0x7f9bf930d800
+[ 699.795134] 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 49 bf 2c 00 00 75 10 b8 4b 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 be 78 01 00 48 89 04 24
+[ 699.798960] RSP: 002b:00007ffee3606c68 EFLAGS: 00000246 ORIG_RAX: 000000000000004b
+[ 699.800483] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f9bf930d800
+[ 699.801923] RDX: 0000000000008000 RSI: 00000000006010a0 RDI: 0000000000000003
+[ 699.803373] RBP: 00007ffee3606ca0 R08: 0000000001503010 R09: 0000000000000000
+[ 699.804798] R10: 00000000000002e8 R11: 0000000000000246 R12: 0000000000400610
+[ 699.806233] R13: 00007ffee3606da0 R14: 0000000000000000 R15: 0000000000000000
+[ 699.807667] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd mac_hid i2c_piix4 soundcore ib_iser rdma_cm iw_cm ib_cm ib_core iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx raid1 raid0 multipath linear 8139too crct10dif_pclmul crc32_pclmul qxl drm_kms_helper syscopyarea aesni_intel sysfillrect sysimgblt fb_sys_fops ttm drm aes_x86_64 crypto_simd cryptd 8139cp glue_helper mii pata_acpi floppy
+[ 699.817079] ---[ end trace 4ce02f25ff7d3df6 ]---
+[ 699.818068] RIP: 0010:f2fs_submit_page_bio+0x29b/0x730
+[ 699.819114] Code: 54 49 8d bd 18 04 00 00 e8 b2 59 af ff 41 8b 8d 18 04 00 00 8b 45 b8 41 d3 e6 44 01 f0 4c 8d 73 14 41 39 c7 0f 82 37 fe ff ff <0f> 0b 65 8b 05 2c 04 77 47 89 c0 48 0f a3 05 52 c1 d5 01 0f 92 c0
+[ 699.822919] RSP: 0018:ffff8801f43af508 EFLAGS: 00010283
+[ 699.823977] RAX: 0000000000000000 RBX: ffff8801f43af7b8 RCX: ffffffffb88a7cef
+[ 699.825436] RDX: 0000000000000007 RSI: dffffc0000000000 RDI: ffff8801e3e7a64c
+[ 699.826881] RBP: ffff8801f43af558 R08: ffffed003e066b55 R09: ffffed003e066b55
+[ 699.828292] R10: 0000000000000001 R11: ffffed003e066b54 R12: ffffea0007876940
+[ 699.829750] R13: ffff8801f0335500 R14: ffff8801e3e7a600 R15: 0000000000000001
+[ 699.831192] FS: 00007f9bf97f5700(0000) GS:ffff8801f6e00000(0000) knlGS:0000000000000000
+[ 699.832793] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[ 699.833981] CR2: 00007f9bf925d170 CR3: 00000001f0c34000 CR4: 00000000000006f0
+[ 699.835556] ==================================================================
+[ 699.837029] BUG: KASAN: stack-out-of-bounds in update_stack_state+0x38c/0x3e0
+[ 699.838462] Read of size 8 at addr ffff8801f43af970 by task a.out/1309
+
+[ 699.840086] CPU: 0 PID: 1309 Comm: a.out Tainted: G D W 4.18.0-rc1+ #4
+[ 699.841603] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[ 699.843475] Call Trace:
+[ 699.843982] dump_stack+0x7b/0xb5
+[ 699.844661] print_address_description+0x70/0x290
+[ 699.845607] kasan_report+0x291/0x390
+[ 699.846351] ? update_stack_state+0x38c/0x3e0
+[ 699.853831] __asan_load8+0x54/0x90
+[ 699.854569] update_stack_state+0x38c/0x3e0
+[ 699.855428] ? __read_once_size_nocheck.constprop.7+0x20/0x20
+[ 699.856601] ? __save_stack_trace+0x5e/0x100
+[ 699.857476] unwind_next_frame.part.5+0x18e/0x490
+[ 699.858448] ? unwind_dump+0x290/0x290
+[ 699.859217] ? clear_page_dirty_for_io+0x332/0x450
+[ 699.860185] __unwind_start+0x106/0x190
+[ 699.860974] __save_stack_trace+0x5e/0x100
+[ 699.861808] ? __save_stack_trace+0x5e/0x100
+[ 699.862691] ? unlink_anon_vmas+0xba/0x2c0
+[ 699.863525] save_stack_trace+0x1f/0x30
+[ 699.864312] save_stack+0x46/0xd0
+[ 699.864993] ? __alloc_pages_slowpath+0x1420/0x1420
+[ 699.865990] ? flush_tlb_mm_range+0x15e/0x220
+[ 699.866889] ? kasan_check_write+0x14/0x20
+[ 699.867724] ? __dec_node_state+0x92/0xb0
+[ 699.868543] ? lock_page_memcg+0x85/0xf0
+[ 699.869350] ? unlock_page_memcg+0x16/0x80
+[ 699.870185] ? page_remove_rmap+0x198/0x520
+[ 699.871048] ? mark_page_accessed+0x133/0x200
+[ 699.871930] ? _cond_resched+0x1a/0x50
+[ 699.872700] ? unmap_page_range+0xcd4/0xe50
+[ 699.873551] ? rb_next+0x58/0x80
+[ 699.874217] ? rb_next+0x58/0x80
+[ 699.874895] __kasan_slab_free+0x13c/0x1a0
+[ 699.875734] ? unlink_anon_vmas+0xba/0x2c0
+[ 699.876563] kasan_slab_free+0xe/0x10
+[ 699.877315] kmem_cache_free+0x89/0x1e0
+[ 699.878095] unlink_anon_vmas+0xba/0x2c0
+[ 699.878913] free_pgtables+0x101/0x1b0
+[ 699.879677] exit_mmap+0x146/0x2a0
+[ 699.880378] ? __ia32_sys_munmap+0x50/0x50
+[ 699.881214] ? kasan_check_read+0x11/0x20
+[ 699.882052] ? mm_update_next_owner+0x322/0x380
+[ 699.882985] mmput+0x8b/0x1d0
+[ 699.883602] do_exit+0x43a/0x1390
+[ 699.884288] ? mm_update_next_owner+0x380/0x380
+[ 699.885212] ? f2fs_sync_file+0x9a/0xb0
+[ 699.885995] ? f2fs_do_sync_file+0xd90/0xd90
+[ 699.886877] ? vfs_fsync_range+0x68/0x100
+[ 699.887694] ? __fget_light+0xc9/0xe0
+[ 699.888442] ? do_fsync+0x3d/0x70
+[ 699.889118] ? __x64_sys_fdatasync+0x24/0x30
+[ 699.889996] rewind_stack_do_exit+0x17/0x20
+[ 699.890860] RIP: 0033:0x7f9bf930d800
+[ 699.891585] Code: Bad RIP value.
+[ 699.892268] RSP: 002b:00007ffee3606c68 EFLAGS: 00000246 ORIG_RAX: 000000000000004b
+[ 699.893781] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f9bf930d800
+[ 699.895220] RDX: 0000000000008000 RSI: 00000000006010a0 RDI: 0000000000000003
+[ 699.896643] RBP: 00007ffee3606ca0 R08: 0000000001503010 R09: 0000000000000000
+[ 699.898069] R10: 00000000000002e8 R11: 0000000000000246 R12: 0000000000400610
+[ 699.899505] R13: 00007ffee3606da0 R14: 0000000000000000 R15: 0000000000000000
+
+[ 699.901241] The buggy address belongs to the page:
+[ 699.902215] page:ffffea0007d0ebc0 count:0 mapcount:0 mapping:0000000000000000 index:0x0
+[ 699.903811] flags: 0x2ffff0000000000()
+[ 699.904585] raw: 02ffff0000000000 0000000000000000 ffffffff07d00101 0000000000000000
+[ 699.906125] raw: 0000000000000000 0000000000240000 00000000ffffffff 0000000000000000
+[ 699.907673] page dumped because: kasan: bad access detected
+
+[ 699.909108] Memory state around the buggy address:
+[ 699.910077] ffff8801f43af800: 00 f1 f1 f1 f1 00 f4 f4 f4 f3 f3 f3 f3 00 00 00
+[ 699.911528] ffff8801f43af880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[ 699.912953] >ffff8801f43af900: 00 00 00 00 00 00 00 00 f1 01 f4 f4 f4 f2 f2 f2
+[ 699.914392] ^
+[ 699.915758] ffff8801f43af980: f2 00 f4 f4 00 00 00 00 f2 00 00 00 00 00 00 00
+[ 699.917193] ffff8801f43afa00: 00 00 00 00 00 00 00 00 00 f3 f3 f3 00 00 00 00
+[ 699.918634] ==================================================================
+
+- Location
+https://elixir.bootlin.com/linux/v4.18-rc1/source/fs/f2fs/segment.h#L644
+
+Reported-by Wen Xu <wen.xu@gatech.edu>
+Signed-off-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Backported to 4.14:
+ - Error label is different in validate_checkpoint() due to the earlier
+ backport of "f2fs: fix invalid memory access"
+ - Adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/f2fs/checkpoint.c | 22 +++++++++++++++++++---
+ fs/f2fs/data.c | 33 +++++++++++++++++++++++++++------
+ fs/f2fs/f2fs.h | 3 +++
+ fs/f2fs/file.c | 12 ++++++++++++
+ fs/f2fs/inode.c | 17 +++++++++++++++++
+ fs/f2fs/node.c | 4 ++++
+ fs/f2fs/segment.h | 3 +--
+ 7 files changed, 83 insertions(+), 11 deletions(-)
+
+diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
+index d7bd9745e883..c81cd5057b8e 100644
+--- a/fs/f2fs/checkpoint.c
++++ b/fs/f2fs/checkpoint.c
+@@ -86,8 +86,10 @@ repeat:
+ fio.page = page;
+
+ if (f2fs_submit_page_bio(&fio)) {
+- f2fs_put_page(page, 1);
+- goto repeat;
++ memset(page_address(page), 0, PAGE_SIZE);
++ f2fs_stop_checkpoint(sbi, false);
++ f2fs_bug_on(sbi, 1);
++ return page;
+ }
+
+ lock_page(page);
+@@ -141,8 +143,14 @@ bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
+ case META_POR:
+ case DATA_GENERIC:
+ if (unlikely(blkaddr >= MAX_BLKADDR(sbi) ||
+- blkaddr < MAIN_BLKADDR(sbi)))
++ blkaddr < MAIN_BLKADDR(sbi))) {
++ if (type == DATA_GENERIC) {
++ f2fs_msg(sbi->sb, KERN_WARNING,
++ "access invalid blkaddr:%u", blkaddr);
++ WARN_ON(1);
++ }
+ return false;
++ }
+ break;
+ case META_GENERIC:
+ if (unlikely(blkaddr < SEG0_BLKADDR(sbi) ||
+@@ -746,6 +754,14 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
+ &cp_page_1, version);
+ if (err)
+ return NULL;
++
++ if (le32_to_cpu(cp_block->cp_pack_total_block_count) >
++ sbi->blocks_per_seg) {
++ f2fs_msg(sbi->sb, KERN_WARNING,
++ "invalid cp_pack_total_block_count:%u",
++ le32_to_cpu(cp_block->cp_pack_total_block_count));
++ goto invalid_cp;
++ }
+ pre_version = *version;
+
+ cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1;
+diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
+index 615878806611..8f6e7c3a10f8 100644
+--- a/fs/f2fs/data.c
++++ b/fs/f2fs/data.c
+@@ -369,7 +369,10 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
+ struct page *page = fio->encrypted_page ?
+ fio->encrypted_page : fio->page;
+
+- verify_block_addr(fio, fio->new_blkaddr);
++ if (!f2fs_is_valid_blkaddr(fio->sbi, fio->new_blkaddr,
++ __is_meta_io(fio) ? META_GENERIC : DATA_GENERIC))
++ return -EFAULT;
++
+ trace_f2fs_submit_page_bio(page, fio);
+ f2fs_trace_ios(fio, 0);
+
+@@ -946,6 +949,12 @@ next_dnode:
+ next_block:
+ blkaddr = datablock_addr(dn.inode, dn.node_page, dn.ofs_in_node);
+
++ if (__is_valid_data_blkaddr(blkaddr) &&
++ !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC)) {
++ err = -EFAULT;
++ goto sync_out;
++ }
++
+ if (!is_valid_data_blkaddr(sbi, blkaddr)) {
+ if (create) {
+ if (unlikely(f2fs_cp_error(sbi))) {
+@@ -1264,6 +1273,10 @@ got_it:
+ SetPageUptodate(page);
+ goto confused;
+ }
++
++ if (!f2fs_is_valid_blkaddr(F2FS_I_SB(inode), block_nr,
++ DATA_GENERIC))
++ goto set_error_page;
+ } else {
+ zero_user_segment(page, 0, PAGE_SIZE);
+ if (!PageUptodate(page))
+@@ -1402,11 +1415,13 @@ int do_write_data_page(struct f2fs_io_info *fio)
+ f2fs_lookup_extent_cache(inode, page->index, &ei)) {
+ fio->old_blkaddr = ei.blk + page->index - ei.fofs;
+
+- if (is_valid_data_blkaddr(fio->sbi, fio->old_blkaddr)) {
+- ipu_force = true;
+- fio->need_lock = LOCK_DONE;
+- goto got_it;
+- }
++ if (!f2fs_is_valid_blkaddr(fio->sbi, fio->old_blkaddr,
++ DATA_GENERIC))
++ return -EFAULT;
++
++ ipu_force = true;
++ fio->need_lock = LOCK_DONE;
++ goto got_it;
+ }
+
+ /* Deadlock due to between page->lock and f2fs_lock_op */
+@@ -1425,6 +1440,12 @@ int do_write_data_page(struct f2fs_io_info *fio)
+ goto out_writepage;
+ }
+ got_it:
++ if (__is_valid_data_blkaddr(fio->old_blkaddr) &&
++ !f2fs_is_valid_blkaddr(fio->sbi, fio->old_blkaddr,
++ DATA_GENERIC)) {
++ err = -EFAULT;
++ goto out_writepage;
++ }
+ /*
+ * If current allocation needs SSR,
+ * it had better in-place writes for updated data.
+diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
+index d15d79457f5c..3f1a44696036 100644
+--- a/fs/f2fs/f2fs.h
++++ b/fs/f2fs/f2fs.h
+@@ -2357,6 +2357,9 @@ static inline void f2fs_update_iostat(struct f2fs_sb_info *sbi,
+ spin_unlock(&sbi->iostat_lock);
+ }
+
++#define __is_meta_io(fio) (PAGE_TYPE_OF_BIO(fio->type) == META && \
++ (!is_read_io(fio->op) || fio->is_meta))
++
+ bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
+ block_t blkaddr, int type);
+ void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...);
+diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
+index e9c575ef70b5..7d3189f1941c 100644
+--- a/fs/f2fs/file.c
++++ b/fs/f2fs/file.c
+@@ -397,6 +397,13 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
+ blkaddr = datablock_addr(dn.inode,
+ dn.node_page, dn.ofs_in_node);
+
++ if (__is_valid_data_blkaddr(blkaddr) &&
++ !f2fs_is_valid_blkaddr(F2FS_I_SB(inode),
++ blkaddr, DATA_GENERIC)) {
++ f2fs_put_dnode(&dn);
++ goto fail;
++ }
++
+ if (__found_offset(F2FS_I_SB(inode), blkaddr, dirty,
+ pgofs, whence)) {
+ f2fs_put_dnode(&dn);
+@@ -496,6 +503,11 @@ int truncate_data_blocks_range(struct dnode_of_data *dn, int count)
+
+ dn->data_blkaddr = NULL_ADDR;
+ set_data_blkaddr(dn);
++
++ if (__is_valid_data_blkaddr(blkaddr) &&
++ !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC))
++ continue;
++
+ invalidate_blocks(sbi, blkaddr);
+ if (dn->ofs_in_node == 0 && IS_INODE(dn->node_page))
+ clear_inode_flag(dn->inode, FI_FIRST_BLOCK_WRITTEN);
+diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
+index be7d9773d291..aeed9943836a 100644
+--- a/fs/f2fs/inode.c
++++ b/fs/f2fs/inode.c
+@@ -214,6 +214,23 @@ static bool sanity_check_inode(struct inode *inode, struct page *node_page)
+ __func__, inode->i_ino);
+ return false;
+ }
++
++ if (F2FS_I(inode)->extent_tree) {
++ struct extent_info *ei = &F2FS_I(inode)->extent_tree->largest;
++
++ if (ei->len &&
++ (!f2fs_is_valid_blkaddr(sbi, ei->blk, DATA_GENERIC) ||
++ !f2fs_is_valid_blkaddr(sbi, ei->blk + ei->len - 1,
++ DATA_GENERIC))) {
++ set_sbi_flag(sbi, SBI_NEED_FSCK);
++ f2fs_msg(sbi->sb, KERN_WARNING,
++ "%s: inode (ino=%lx) extent info [%u, %u, %u] "
++ "is incorrect, run fsck to fix",
++ __func__, inode->i_ino,
++ ei->blk, ei->fofs, ei->len);
++ return false;
++ }
++ }
+ return true;
+ }
+
+diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
+index 999814c8cbea..6adb6c60f017 100644
+--- a/fs/f2fs/node.c
++++ b/fs/f2fs/node.c
+@@ -1398,6 +1398,10 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted,
+ return 0;
+ }
+
++ if (__is_valid_data_blkaddr(ni.blk_addr) &&
++ !f2fs_is_valid_blkaddr(sbi, ni.blk_addr, DATA_GENERIC))
++ goto redirty_out;
++
+ if (atomic && !test_opt(sbi, NOBARRIER))
+ fio.op_flags |= REQ_PREFLUSH | REQ_FUA;
+
+diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
+index dd8f977fc273..47348d98165b 100644
+--- a/fs/f2fs/segment.h
++++ b/fs/f2fs/segment.h
+@@ -629,8 +629,7 @@ static inline void verify_block_addr(struct f2fs_io_info *fio, block_t blk_addr)
+ {
+ struct f2fs_sb_info *sbi = fio->sbi;
+
+- if (PAGE_TYPE_OF_BIO(fio->type) == META &&
+- (!is_read_io(fio->op) || fio->is_meta))
++ if (__is_meta_io(fio))
+ verify_blkaddr(sbi, blk_addr, META_GENERIC);
+ else
+ verify_blkaddr(sbi, blk_addr, DATA_GENERIC);
+--
+2.17.1
+
--- /dev/null
+From 06d37d52b3328742dc420dffd1ac72d71e12d846 Mon Sep 17 00:00:00 2001
+From: Chao Yu <yuchao0@huawei.com>
+Date: Wed, 1 Aug 2018 19:16:11 +0800
+Subject: f2fs: fix to do sanity check with cp_pack_start_sum
+
+commit e494c2f995d6181d6e29c4927d68e0f295ecf75b upstream.
+
+After fuzzing, cp_pack_start_sum could be corrupted, so current log's
+summary info should be wrong due to loading incorrect summary block.
+Then, if segment's type in current log is exceeded NR_CURSEG_TYPE, it
+can lead accessing invalid dirty_i->dirty_segmap bitmap finally.
+
+Add sanity check for cp_pack_start_sum to fix this issue.
+
+https://bugzilla.kernel.org/show_bug.cgi?id=200419
+
+- Reproduce
+
+- Kernel message (f2fs-dev w/ KASAN)
+[ 3117.578432] F2FS-fs (loop0): Invalid log blocks per segment (8)
+
+[ 3117.578445] F2FS-fs (loop0): Can't find valid F2FS filesystem in 2th superblock
+[ 3117.581364] F2FS-fs (loop0): invalid crc_offset: 30716
+[ 3117.583564] WARNING: CPU: 1 PID: 1225 at fs/f2fs/checkpoint.c:90 __get_meta_page+0x448/0x4b0
+[ 3117.583570] 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
+[ 3117.584014] CPU: 1 PID: 1225 Comm: mount Not tainted 4.17.0+ #1
+[ 3117.584017] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[ 3117.584022] RIP: 0010:__get_meta_page+0x448/0x4b0
+[ 3117.584023] Code: 00 49 8d bc 24 84 00 00 00 e8 74 54 da ff 41 83 8c 24 84 00 00 00 08 4c 89 f6 4c 89 ef e8 c0 d9 95 00 48 89 ef e8 18 e3 00 00 <0f> 0b f0 80 4d 48 04 e9 0f fe ff ff 0f 0b 48 89 c7 48 89 04 24 e8
+[ 3117.584072] RSP: 0018:ffff88018eb678c0 EFLAGS: 00010286
+[ 3117.584082] RAX: ffff88018f0a6a78 RBX: ffffea0007a46600 RCX: ffffffff9314d1b2
+[ 3117.584085] RDX: ffffffff00000001 RSI: 0000000000000000 RDI: ffff88018f0a6a98
+[ 3117.584087] RBP: ffff88018ebe9980 R08: 0000000000000002 R09: 0000000000000001
+[ 3117.584090] R10: 0000000000000001 R11: ffffed00326e4450 R12: ffff880193722200
+[ 3117.584092] R13: ffff88018ebe9afc R14: 0000000000000206 R15: ffff88018eb67900
+[ 3117.584096] FS: 00007f5694636840(0000) GS:ffff8801f3b00000(0000) knlGS:0000000000000000
+[ 3117.584098] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[ 3117.584101] CR2: 00000000016f21b8 CR3: 0000000191c22000 CR4: 00000000000006e0
+[ 3117.584112] Call Trace:
+[ 3117.584121] ? f2fs_set_meta_page_dirty+0x150/0x150
+[ 3117.584127] ? f2fs_build_segment_manager+0xbf9/0x3190
+[ 3117.584133] ? f2fs_npages_for_summary_flush+0x75/0x120
+[ 3117.584145] f2fs_build_segment_manager+0xda8/0x3190
+[ 3117.584151] ? f2fs_get_valid_checkpoint+0x298/0xa00
+[ 3117.584156] ? f2fs_flush_sit_entries+0x10e0/0x10e0
+[ 3117.584184] ? map_id_range_down+0x17c/0x1b0
+[ 3117.584188] ? __put_user_ns+0x30/0x30
+[ 3117.584206] ? find_next_bit+0x53/0x90
+[ 3117.584237] ? cpumask_next+0x16/0x20
+[ 3117.584249] f2fs_fill_super+0x1948/0x2b40
+[ 3117.584258] ? f2fs_commit_super+0x1a0/0x1a0
+[ 3117.584279] ? sget_userns+0x65e/0x690
+[ 3117.584296] ? set_blocksize+0x88/0x130
+[ 3117.584302] ? f2fs_commit_super+0x1a0/0x1a0
+[ 3117.584305] mount_bdev+0x1c0/0x200
+[ 3117.584310] mount_fs+0x5c/0x190
+[ 3117.584320] vfs_kern_mount+0x64/0x190
+[ 3117.584330] do_mount+0x2e4/0x1450
+[ 3117.584343] ? lockref_put_return+0x130/0x130
+[ 3117.584347] ? copy_mount_string+0x20/0x20
+[ 3117.584357] ? kasan_unpoison_shadow+0x31/0x40
+[ 3117.584362] ? kasan_kmalloc+0xa6/0xd0
+[ 3117.584373] ? memcg_kmem_put_cache+0x16/0x90
+[ 3117.584377] ? __kmalloc_track_caller+0x196/0x210
+[ 3117.584383] ? _copy_from_user+0x61/0x90
+[ 3117.584396] ? memdup_user+0x3e/0x60
+[ 3117.584401] ksys_mount+0x7e/0xd0
+[ 3117.584405] __x64_sys_mount+0x62/0x70
+[ 3117.584427] do_syscall_64+0x73/0x160
+[ 3117.584440] entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[ 3117.584455] RIP: 0033:0x7f5693f14b9a
+[ 3117.584456] 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
+[ 3117.584505] RSP: 002b:00007fff27346488 EFLAGS: 00000206 ORIG_RAX: 00000000000000a5
+[ 3117.584510] RAX: ffffffffffffffda RBX: 00000000016e2030 RCX: 00007f5693f14b9a
+[ 3117.584512] RDX: 00000000016e2210 RSI: 00000000016e3f30 RDI: 00000000016ee040
+[ 3117.584514] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000013
+[ 3117.584516] R10: 00000000c0ed0000 R11: 0000000000000206 R12: 00000000016ee040
+[ 3117.584519] R13: 00000000016e2210 R14: 0000000000000000 R15: 0000000000000003
+[ 3117.584523] ---[ end trace a8e0d899985faf31 ]---
+[ 3117.685663] F2FS-fs (loop0): f2fs_check_nid_range: out-of-range nid=2, run fsck to fix.
+[ 3117.685673] F2FS-fs (loop0): recover_data: ino = 2 (i_size: recover) recovered = 1, err = 0
+[ 3117.685707] ==================================================================
+[ 3117.685955] BUG: KASAN: slab-out-of-bounds in __remove_dirty_segment+0xdd/0x1e0
+[ 3117.686175] Read of size 8 at addr ffff88018f0a63d0 by task mount/1225
+
+[ 3117.686477] CPU: 0 PID: 1225 Comm: mount Tainted: G W 4.17.0+ #1
+[ 3117.686481] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[ 3117.686483] Call Trace:
+[ 3117.686494] dump_stack+0x71/0xab
+[ 3117.686512] print_address_description+0x6b/0x290
+[ 3117.686517] kasan_report+0x28e/0x390
+[ 3117.686522] ? __remove_dirty_segment+0xdd/0x1e0
+[ 3117.686527] __remove_dirty_segment+0xdd/0x1e0
+[ 3117.686532] locate_dirty_segment+0x189/0x190
+[ 3117.686538] f2fs_allocate_new_segments+0xa9/0xe0
+[ 3117.686543] recover_data+0x703/0x2c20
+[ 3117.686547] ? f2fs_recover_fsync_data+0x48f/0xd50
+[ 3117.686553] ? ksys_mount+0x7e/0xd0
+[ 3117.686564] ? policy_nodemask+0x1a/0x90
+[ 3117.686567] ? policy_node+0x56/0x70
+[ 3117.686571] ? add_fsync_inode+0xf0/0xf0
+[ 3117.686592] ? blk_finish_plug+0x44/0x60
+[ 3117.686597] ? f2fs_ra_meta_pages+0x38b/0x5e0
+[ 3117.686602] ? find_inode_fast+0xac/0xc0
+[ 3117.686606] ? f2fs_is_valid_blkaddr+0x320/0x320
+[ 3117.686618] ? __radix_tree_lookup+0x150/0x150
+[ 3117.686633] ? dqget+0x670/0x670
+[ 3117.686648] ? pagecache_get_page+0x29/0x410
+[ 3117.686656] ? kmem_cache_alloc+0x176/0x1e0
+[ 3117.686660] ? f2fs_is_valid_blkaddr+0x11d/0x320
+[ 3117.686664] f2fs_recover_fsync_data+0xc23/0xd50
+[ 3117.686670] ? f2fs_space_for_roll_forward+0x60/0x60
+[ 3117.686674] ? rb_insert_color+0x323/0x3d0
+[ 3117.686678] ? f2fs_recover_orphan_inodes+0xa5/0x700
+[ 3117.686683] ? proc_register+0x153/0x1d0
+[ 3117.686686] ? f2fs_remove_orphan_inode+0x10/0x10
+[ 3117.686695] ? f2fs_attr_store+0x50/0x50
+[ 3117.686700] ? proc_create_single_data+0x52/0x60
+[ 3117.686707] f2fs_fill_super+0x1d06/0x2b40
+[ 3117.686728] ? f2fs_commit_super+0x1a0/0x1a0
+[ 3117.686735] ? sget_userns+0x65e/0x690
+[ 3117.686740] ? set_blocksize+0x88/0x130
+[ 3117.686745] ? f2fs_commit_super+0x1a0/0x1a0
+[ 3117.686748] mount_bdev+0x1c0/0x200
+[ 3117.686753] mount_fs+0x5c/0x190
+[ 3117.686758] vfs_kern_mount+0x64/0x190
+[ 3117.686762] do_mount+0x2e4/0x1450
+[ 3117.686769] ? lockref_put_return+0x130/0x130
+[ 3117.686773] ? copy_mount_string+0x20/0x20
+[ 3117.686777] ? kasan_unpoison_shadow+0x31/0x40
+[ 3117.686780] ? kasan_kmalloc+0xa6/0xd0
+[ 3117.686786] ? memcg_kmem_put_cache+0x16/0x90
+[ 3117.686790] ? __kmalloc_track_caller+0x196/0x210
+[ 3117.686795] ? _copy_from_user+0x61/0x90
+[ 3117.686801] ? memdup_user+0x3e/0x60
+[ 3117.686804] ksys_mount+0x7e/0xd0
+[ 3117.686809] __x64_sys_mount+0x62/0x70
+[ 3117.686816] do_syscall_64+0x73/0x160
+[ 3117.686824] entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[ 3117.686829] RIP: 0033:0x7f5693f14b9a
+[ 3117.686830] 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
+[ 3117.686887] RSP: 002b:00007fff27346488 EFLAGS: 00000206 ORIG_RAX: 00000000000000a5
+[ 3117.686892] RAX: ffffffffffffffda RBX: 00000000016e2030 RCX: 00007f5693f14b9a
+[ 3117.686894] RDX: 00000000016e2210 RSI: 00000000016e3f30 RDI: 00000000016ee040
+[ 3117.686896] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000013
+[ 3117.686899] R10: 00000000c0ed0000 R11: 0000000000000206 R12: 00000000016ee040
+[ 3117.686901] R13: 00000000016e2210 R14: 0000000000000000 R15: 0000000000000003
+
+[ 3117.687005] Allocated by task 1225:
+[ 3117.687152] kasan_kmalloc+0xa6/0xd0
+[ 3117.687157] kmem_cache_alloc_trace+0xfd/0x200
+[ 3117.687161] f2fs_build_segment_manager+0x2d09/0x3190
+[ 3117.687165] f2fs_fill_super+0x1948/0x2b40
+[ 3117.687168] mount_bdev+0x1c0/0x200
+[ 3117.687171] mount_fs+0x5c/0x190
+[ 3117.687174] vfs_kern_mount+0x64/0x190
+[ 3117.687177] do_mount+0x2e4/0x1450
+[ 3117.687180] ksys_mount+0x7e/0xd0
+[ 3117.687182] __x64_sys_mount+0x62/0x70
+[ 3117.687186] do_syscall_64+0x73/0x160
+[ 3117.687190] entry_SYSCALL_64_after_hwframe+0x44/0xa9
+
+[ 3117.687285] Freed by task 19:
+[ 3117.687412] __kasan_slab_free+0x137/0x190
+[ 3117.687416] kfree+0x8b/0x1b0
+[ 3117.687460] ttm_bo_man_put_node+0x61/0x80 [ttm]
+[ 3117.687476] ttm_bo_cleanup_refs+0x15f/0x250 [ttm]
+[ 3117.687492] ttm_bo_delayed_delete+0x2f0/0x300 [ttm]
+[ 3117.687507] ttm_bo_delayed_workqueue+0x17/0x50 [ttm]
+[ 3117.687528] process_one_work+0x2f9/0x740
+[ 3117.687531] worker_thread+0x78/0x6b0
+[ 3117.687541] kthread+0x177/0x1c0
+[ 3117.687545] ret_from_fork+0x35/0x40
+
+[ 3117.687638] The buggy address belongs to the object at ffff88018f0a6300
+ which belongs to the cache kmalloc-192 of size 192
+[ 3117.688014] The buggy address is located 16 bytes to the right of
+ 192-byte region [ffff88018f0a6300, ffff88018f0a63c0)
+[ 3117.688382] The buggy address belongs to the page:
+[ 3117.688554] page:ffffea00063c2980 count:1 mapcount:0 mapping:ffff8801f3403180 index:0x0
+[ 3117.688788] flags: 0x17fff8000000100(slab)
+[ 3117.688944] raw: 017fff8000000100 ffffea00063c2840 0000000e0000000e ffff8801f3403180
+[ 3117.689166] raw: 0000000000000000 0000000080100010 00000001ffffffff 0000000000000000
+[ 3117.689386] page dumped because: kasan: bad access detected
+
+[ 3117.689653] Memory state around the buggy address:
+[ 3117.689816] ffff88018f0a6280: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
+[ 3117.690027] ffff88018f0a6300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[ 3117.690239] >ffff88018f0a6380: 00 00 fc fc fc fc fc fc fc fc fc fc fc fc fc fc
+[ 3117.690448] ^
+[ 3117.690644] ffff88018f0a6400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[ 3117.690868] ffff88018f0a6480: 00 00 fc fc fc fc fc fc fc fc fc fc fc fc fc fc
+[ 3117.691077] ==================================================================
+[ 3117.691290] Disabling lock debugging due to kernel taint
+[ 3117.693893] BUG: unable to handle kernel NULL pointer dereference at 0000000000000000
+[ 3117.694120] PGD 80000001f01bc067 P4D 80000001f01bc067 PUD 1d9638067 PMD 0
+[ 3117.694338] Oops: 0002 [#1] SMP KASAN PTI
+[ 3117.694490] CPU: 1 PID: 1225 Comm: mount Tainted: G B W 4.17.0+ #1
+[ 3117.694703] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[ 3117.695073] RIP: 0010:__remove_dirty_segment+0xe2/0x1e0
+[ 3117.695246] Code: c4 48 89 c7 e8 cf bb d7 ff 45 0f b6 24 24 41 83 e4 3f 44 88 64 24 07 41 83 e4 3f 4a 8d 7c e3 08 e8 b3 bc d7 ff 4a 8b 4c e3 08 <f0> 4c 0f b3 29 0f 82 94 00 00 00 48 8d bd 20 04 00 00 e8 97 bb d7
+[ 3117.695793] RSP: 0018:ffff88018eb67638 EFLAGS: 00010292
+[ 3117.695969] RAX: 0000000000000000 RBX: ffff88018f0a6300 RCX: 0000000000000000
+[ 3117.696182] RDX: 0000000000000000 RSI: 0000000000000297 RDI: 0000000000000297
+[ 3117.696391] RBP: ffff88018ebe9980 R08: ffffed003e743ebb R09: ffffed003e743ebb
+[ 3117.696604] R10: 0000000000000001 R11: ffffed003e743eba R12: 0000000000000019
+[ 3117.696813] R13: 0000000000000014 R14: 0000000000000320 R15: ffff88018ebe99e0
+[ 3117.697032] FS: 00007f5694636840(0000) GS:ffff8801f3b00000(0000) knlGS:0000000000000000
+[ 3117.697280] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[ 3117.702357] CR2: 00007fe89bb1a000 CR3: 0000000191c22000 CR4: 00000000000006e0
+[ 3117.707235] Call Trace:
+[ 3117.712077] locate_dirty_segment+0x189/0x190
+[ 3117.716891] f2fs_allocate_new_segments+0xa9/0xe0
+[ 3117.721617] recover_data+0x703/0x2c20
+[ 3117.726316] ? f2fs_recover_fsync_data+0x48f/0xd50
+[ 3117.730957] ? ksys_mount+0x7e/0xd0
+[ 3117.735573] ? policy_nodemask+0x1a/0x90
+[ 3117.740198] ? policy_node+0x56/0x70
+[ 3117.744829] ? add_fsync_inode+0xf0/0xf0
+[ 3117.749487] ? blk_finish_plug+0x44/0x60
+[ 3117.754152] ? f2fs_ra_meta_pages+0x38b/0x5e0
+[ 3117.758831] ? find_inode_fast+0xac/0xc0
+[ 3117.763448] ? f2fs_is_valid_blkaddr+0x320/0x320
+[ 3117.768046] ? __radix_tree_lookup+0x150/0x150
+[ 3117.772603] ? dqget+0x670/0x670
+[ 3117.777159] ? pagecache_get_page+0x29/0x410
+[ 3117.781648] ? kmem_cache_alloc+0x176/0x1e0
+[ 3117.786067] ? f2fs_is_valid_blkaddr+0x11d/0x320
+[ 3117.790476] f2fs_recover_fsync_data+0xc23/0xd50
+[ 3117.794790] ? f2fs_space_for_roll_forward+0x60/0x60
+[ 3117.799086] ? rb_insert_color+0x323/0x3d0
+[ 3117.803304] ? f2fs_recover_orphan_inodes+0xa5/0x700
+[ 3117.807563] ? proc_register+0x153/0x1d0
+[ 3117.811766] ? f2fs_remove_orphan_inode+0x10/0x10
+[ 3117.815947] ? f2fs_attr_store+0x50/0x50
+[ 3117.820087] ? proc_create_single_data+0x52/0x60
+[ 3117.824262] f2fs_fill_super+0x1d06/0x2b40
+[ 3117.828367] ? f2fs_commit_super+0x1a0/0x1a0
+[ 3117.832432] ? sget_userns+0x65e/0x690
+[ 3117.836500] ? set_blocksize+0x88/0x130
+[ 3117.840501] ? f2fs_commit_super+0x1a0/0x1a0
+[ 3117.844420] mount_bdev+0x1c0/0x200
+[ 3117.848275] mount_fs+0x5c/0x190
+[ 3117.852053] vfs_kern_mount+0x64/0x190
+[ 3117.855810] do_mount+0x2e4/0x1450
+[ 3117.859441] ? lockref_put_return+0x130/0x130
+[ 3117.862996] ? copy_mount_string+0x20/0x20
+[ 3117.866417] ? kasan_unpoison_shadow+0x31/0x40
+[ 3117.869719] ? kasan_kmalloc+0xa6/0xd0
+[ 3117.872948] ? memcg_kmem_put_cache+0x16/0x90
+[ 3117.876121] ? __kmalloc_track_caller+0x196/0x210
+[ 3117.879333] ? _copy_from_user+0x61/0x90
+[ 3117.882467] ? memdup_user+0x3e/0x60
+[ 3117.885604] ksys_mount+0x7e/0xd0
+[ 3117.888700] __x64_sys_mount+0x62/0x70
+[ 3117.891742] do_syscall_64+0x73/0x160
+[ 3117.894692] entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[ 3117.897669] RIP: 0033:0x7f5693f14b9a
+[ 3117.900563] 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
+[ 3117.906922] RSP: 002b:00007fff27346488 EFLAGS: 00000206 ORIG_RAX: 00000000000000a5
+[ 3117.910159] RAX: ffffffffffffffda RBX: 00000000016e2030 RCX: 00007f5693f14b9a
+[ 3117.913469] RDX: 00000000016e2210 RSI: 00000000016e3f30 RDI: 00000000016ee040
+[ 3117.916764] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000013
+[ 3117.920071] R10: 00000000c0ed0000 R11: 0000000000000206 R12: 00000000016ee040
+[ 3117.923393] R13: 00000000016e2210 R14: 0000000000000000 R15: 0000000000000003
+[ 3117.926680] 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
+[ 3117.949979] CR2: 0000000000000000
+[ 3117.954283] ---[ end trace a8e0d899985faf32 ]---
+[ 3117.958575] RIP: 0010:__remove_dirty_segment+0xe2/0x1e0
+[ 3117.962810] Code: c4 48 89 c7 e8 cf bb d7 ff 45 0f b6 24 24 41 83 e4 3f 44 88 64 24 07 41 83 e4 3f 4a 8d 7c e3 08 e8 b3 bc d7 ff 4a 8b 4c e3 08 <f0> 4c 0f b3 29 0f 82 94 00 00 00 48 8d bd 20 04 00 00 e8 97 bb d7
+[ 3117.971789] RSP: 0018:ffff88018eb67638 EFLAGS: 00010292
+[ 3117.976333] RAX: 0000000000000000 RBX: ffff88018f0a6300 RCX: 0000000000000000
+[ 3117.980926] RDX: 0000000000000000 RSI: 0000000000000297 RDI: 0000000000000297
+[ 3117.985497] RBP: ffff88018ebe9980 R08: ffffed003e743ebb R09: ffffed003e743ebb
+[ 3117.990098] R10: 0000000000000001 R11: ffffed003e743eba R12: 0000000000000019
+[ 3117.994761] R13: 0000000000000014 R14: 0000000000000320 R15: ffff88018ebe99e0
+[ 3117.999392] FS: 00007f5694636840(0000) GS:ffff8801f3b00000(0000) knlGS:0000000000000000
+[ 3118.004096] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[ 3118.008816] CR2: 00007fe89bb1a000 CR3: 0000000191c22000 CR4: 00000000000006e0
+
+- Location
+https://elixir.bootlin.com/linux/v4.18-rc3/source/fs/f2fs/segment.c#L775
+ if (test_and_clear_bit(segno, dirty_i->dirty_segmap[t]))
+ dirty_i->nr_dirty[t]--;
+Here dirty_i->dirty_segmap[t] can be NULL which leads to crash in test_and_clear_bit()
+
+Reported-by Wen Xu <wen.xu@gatech.edu>
+Signed-off-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Backported to 4.14: The function is called sanity_check_ckpt()]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/f2fs/checkpoint.c | 8 ++++----
+ fs/f2fs/super.c | 12 ++++++++++++
+ 2 files changed, 16 insertions(+), 4 deletions(-)
+
+diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
+index c81cd5057b8e..624817eeb25e 100644
+--- a/fs/f2fs/checkpoint.c
++++ b/fs/f2fs/checkpoint.c
+@@ -825,15 +825,15 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)
+ cp_block = (struct f2fs_checkpoint *)page_address(cur_page);
+ memcpy(sbi->ckpt, cp_block, blk_size);
+
+- /* Sanity checking of checkpoint */
+- if (sanity_check_ckpt(sbi))
+- goto free_fail_no_cp;
+-
+ if (cur_page == cp1)
+ sbi->cur_cp_pack = 1;
+ else
+ sbi->cur_cp_pack = 2;
+
++ /* Sanity checking of checkpoint */
++ if (sanity_check_ckpt(sbi))
++ goto free_fail_no_cp;
++
+ if (cp_blks <= 1)
+ goto done;
+
+diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
+index 9fafb1404f39..de4de4ebe64c 100644
+--- a/fs/f2fs/super.c
++++ b/fs/f2fs/super.c
+@@ -1957,6 +1957,7 @@ int sanity_check_ckpt(struct f2fs_sb_info *sbi)
+ unsigned int sit_bitmap_size, nat_bitmap_size;
+ unsigned int log_blocks_per_seg;
+ unsigned int segment_count_main;
++ unsigned int cp_pack_start_sum, cp_payload;
+ block_t user_block_count;
+ int i;
+
+@@ -2017,6 +2018,17 @@ int sanity_check_ckpt(struct f2fs_sb_info *sbi)
+ return 1;
+ }
+
++ cp_pack_start_sum = __start_sum_addr(sbi);
++ cp_payload = __cp_payload(sbi);
++ if (cp_pack_start_sum < cp_payload + 1 ||
++ cp_pack_start_sum > blocks_per_seg - 1 -
++ NR_CURSEG_TYPE) {
++ f2fs_msg(sbi->sb, KERN_ERR,
++ "Wrong cp_pack_start_sum: %u",
++ cp_pack_start_sum);
++ return 1;
++ }
++
+ if (unlikely(f2fs_cp_error(sbi))) {
+ f2fs_msg(sbi->sb, KERN_ERR, "A bug case: need to run fsck");
+ return 1;
+--
+2.17.1
+
--- /dev/null
+From a54a955bfc0c026d40d6550af736d7b6d57a8eea Mon Sep 17 00:00:00 2001
+From: Chao Yu <yuchao0@huawei.com>
+Date: Mon, 25 Jun 2018 23:29:49 +0800
+Subject: f2fs: fix to do sanity check with extra_attr feature
+
+commit 76d56d4ab4f2a9e4f085c7d77172194ddaccf7d2 upstream.
+
+If FI_EXTRA_ATTR is set in inode by fuzzing, inode.i_addr[0] will be
+parsed as inode.i_extra_isize, then in __recover_inline_status, inline
+data address will beyond boundary of page, result in accessing invalid
+memory.
+
+So in this condition, during reading inode page, let's do sanity check
+with EXTRA_ATTR feature of fs and extra_attr bit of inode, if they're
+inconsistent, deny to load this inode.
+
+- Overview
+Out-of-bound access in f2fs_iget() when mounting a corrupted f2fs image
+
+- Reproduce
+
+The following message will be got in KASAN build of 4.18 upstream kernel.
+[ 819.392227] ==================================================================
+[ 819.393901] BUG: KASAN: slab-out-of-bounds in f2fs_iget+0x736/0x1530
+[ 819.395329] Read of size 4 at addr ffff8801f099c968 by task mount/1292
+
+[ 819.397079] CPU: 1 PID: 1292 Comm: mount Not tainted 4.18.0-rc1+ #4
+[ 819.397082] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[ 819.397088] Call Trace:
+[ 819.397124] dump_stack+0x7b/0xb5
+[ 819.397154] print_address_description+0x70/0x290
+[ 819.397159] kasan_report+0x291/0x390
+[ 819.397163] ? f2fs_iget+0x736/0x1530
+[ 819.397176] check_memory_region+0x139/0x190
+[ 819.397182] __asan_loadN+0xf/0x20
+[ 819.397185] f2fs_iget+0x736/0x1530
+[ 819.397197] f2fs_fill_super+0x1b4f/0x2b40
+[ 819.397202] ? f2fs_fill_super+0x1b4f/0x2b40
+[ 819.397208] ? f2fs_commit_super+0x1b0/0x1b0
+[ 819.397227] ? set_blocksize+0x90/0x140
+[ 819.397241] mount_bdev+0x1c5/0x210
+[ 819.397245] ? f2fs_commit_super+0x1b0/0x1b0
+[ 819.397252] f2fs_mount+0x15/0x20
+[ 819.397256] mount_fs+0x60/0x1a0
+[ 819.397267] ? alloc_vfsmnt+0x309/0x360
+[ 819.397272] vfs_kern_mount+0x6b/0x1a0
+[ 819.397282] do_mount+0x34a/0x18c0
+[ 819.397300] ? lockref_put_or_lock+0xcf/0x160
+[ 819.397306] ? copy_mount_string+0x20/0x20
+[ 819.397318] ? memcg_kmem_put_cache+0x1b/0xa0
+[ 819.397324] ? kasan_check_write+0x14/0x20
+[ 819.397334] ? _copy_from_user+0x6a/0x90
+[ 819.397353] ? memdup_user+0x42/0x60
+[ 819.397359] ksys_mount+0x83/0xd0
+[ 819.397365] __x64_sys_mount+0x67/0x80
+[ 819.397388] do_syscall_64+0x78/0x170
+[ 819.397403] entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[ 819.397422] RIP: 0033:0x7f54c667cb9a
+[ 819.397424] 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
+[ 819.397483] RSP: 002b:00007ffd8f46cd08 EFLAGS: 00000202 ORIG_RAX: 00000000000000a5
+[ 819.397496] RAX: ffffffffffffffda RBX: 0000000000dfa030 RCX: 00007f54c667cb9a
+[ 819.397498] RDX: 0000000000dfa210 RSI: 0000000000dfbf30 RDI: 0000000000e02ec0
+[ 819.397501] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000013
+[ 819.397503] R10: 00000000c0ed0000 R11: 0000000000000202 R12: 0000000000e02ec0
+[ 819.397505] R13: 0000000000dfa210 R14: 0000000000000000 R15: 0000000000000003
+
+[ 819.397866] Allocated by task 139:
+[ 819.398702] save_stack+0x46/0xd0
+[ 819.398705] kasan_kmalloc+0xad/0xe0
+[ 819.398709] kasan_slab_alloc+0x11/0x20
+[ 819.398713] kmem_cache_alloc+0xd1/0x1e0
+[ 819.398717] dup_fd+0x50/0x4c0
+[ 819.398740] copy_process.part.37+0xbed/0x32e0
+[ 819.398744] _do_fork+0x16e/0x590
+[ 819.398748] __x64_sys_clone+0x69/0x80
+[ 819.398752] do_syscall_64+0x78/0x170
+[ 819.398756] entry_SYSCALL_64_after_hwframe+0x44/0xa9
+
+[ 819.399097] Freed by task 159:
+[ 819.399743] save_stack+0x46/0xd0
+[ 819.399747] __kasan_slab_free+0x13c/0x1a0
+[ 819.399750] kasan_slab_free+0xe/0x10
+[ 819.399754] kmem_cache_free+0x89/0x1e0
+[ 819.399757] put_files_struct+0x132/0x150
+[ 819.399761] exit_files+0x62/0x70
+[ 819.399766] do_exit+0x47b/0x1390
+[ 819.399770] do_group_exit+0x86/0x130
+[ 819.399774] __x64_sys_exit_group+0x2c/0x30
+[ 819.399778] do_syscall_64+0x78/0x170
+[ 819.399782] entry_SYSCALL_64_after_hwframe+0x44/0xa9
+
+[ 819.400115] The buggy address belongs to the object at ffff8801f099c680
+ which belongs to the cache files_cache of size 704
+[ 819.403234] The buggy address is located 40 bytes to the right of
+ 704-byte region [ffff8801f099c680, ffff8801f099c940)
+[ 819.405689] The buggy address belongs to the page:
+[ 819.406709] page:ffffea0007c26700 count:1 mapcount:0 mapping:ffff8801f69a3340 index:0xffff8801f099d380 compound_mapcount: 0
+[ 819.408984] flags: 0x2ffff0000008100(slab|head)
+[ 819.409932] raw: 02ffff0000008100 ffffea00077fb600 0000000200000002 ffff8801f69a3340
+[ 819.411514] raw: ffff8801f099d380 0000000080130000 00000001ffffffff 0000000000000000
+[ 819.413073] page dumped because: kasan: bad access detected
+
+[ 819.414539] Memory state around the buggy address:
+[ 819.415521] ffff8801f099c800: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
+[ 819.416981] ffff8801f099c880: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
+[ 819.418454] >ffff8801f099c900: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
+[ 819.419921] ^
+[ 819.421265] ffff8801f099c980: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb
+[ 819.422745] ffff8801f099ca00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
+[ 819.424206] ==================================================================
+[ 819.425668] Disabling lock debugging due to kernel taint
+[ 819.457463] F2FS-fs (loop0): Mounted with checkpoint version = 3
+
+The kernel still mounts the image. If you run the following program on the mounted folder mnt,
+
+(poc.c)
+
+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_RDONLY, 0);
+ if (fd >= 0) {
+ read(fd, (char *)buf, 11);
+ close(fd);
+ }
+}
+
+int main(int argc, char *argv[]) {
+ activity(argv[1]);
+ return 0;
+}
+
+You can get kernel crash:
+[ 819.457463] F2FS-fs (loop0): Mounted with checkpoint version = 3
+[ 918.028501] BUG: unable to handle kernel paging request at ffffed0048000d82
+[ 918.044020] PGD 23ffee067 P4D 23ffee067 PUD 23fbef067 PMD 0
+[ 918.045207] Oops: 0000 [#1] SMP KASAN PTI
+[ 918.046048] CPU: 0 PID: 1309 Comm: poc Tainted: G B 4.18.0-rc1+ #4
+[ 918.047573] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[ 918.049552] RIP: 0010:check_memory_region+0x5e/0x190
+[ 918.050565] Code: f8 49 c1 e8 03 49 89 db 49 c1 eb 03 4d 01 cb 4d 01 c1 4d 8d 63 01 4c 89 c8 4d 89 e2 4d 29 ca 49 83 fa 10 7f 3d 4d 85 d2 74 32 <41> 80 39 00 75 23 48 b8 01 00 00 00 00 fc ff df 4d 01 d1 49 01 c0
+[ 918.054322] RSP: 0018:ffff8801e3a1f258 EFLAGS: 00010202
+[ 918.055400] RAX: ffffed0048000d82 RBX: ffff880240006c11 RCX: ffffffffb8867d14
+[ 918.056832] RDX: 0000000000000000 RSI: 0000000000000002 RDI: ffff880240006c10
+[ 918.058253] RBP: ffff8801e3a1f268 R08: 1ffff10048000d82 R09: ffffed0048000d82
+[ 918.059717] R10: 0000000000000001 R11: ffffed0048000d82 R12: ffffed0048000d83
+[ 918.061159] R13: ffff8801e3a1f390 R14: 0000000000000000 R15: ffff880240006c08
+[ 918.062614] FS: 00007fac9732c700(0000) GS:ffff8801f6e00000(0000) knlGS:0000000000000000
+[ 918.064246] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[ 918.065412] CR2: ffffed0048000d82 CR3: 00000001df77a000 CR4: 00000000000006f0
+[ 918.066882] Call Trace:
+[ 918.067410] __asan_loadN+0xf/0x20
+[ 918.068149] f2fs_find_target_dentry+0xf4/0x270
+[ 918.069083] ? __get_node_page+0x331/0x5b0
+[ 918.069925] f2fs_find_in_inline_dir+0x24b/0x310
+[ 918.070881] ? f2fs_recover_inline_data+0x4c0/0x4c0
+[ 918.071905] ? unwind_next_frame.part.5+0x34f/0x490
+[ 918.072901] ? unwind_dump+0x290/0x290
+[ 918.073695] ? is_bpf_text_address+0xe/0x20
+[ 918.074566] __f2fs_find_entry+0x599/0x670
+[ 918.075408] ? kasan_unpoison_shadow+0x36/0x50
+[ 918.076315] ? kasan_kmalloc+0xad/0xe0
+[ 918.077100] ? memcg_kmem_put_cache+0x55/0xa0
+[ 918.077998] ? f2fs_find_target_dentry+0x270/0x270
+[ 918.079006] ? d_set_d_op+0x30/0x100
+[ 918.079749] ? __d_lookup_rcu+0x69/0x2e0
+[ 918.080556] ? __d_alloc+0x275/0x450
+[ 918.081297] ? kasan_check_write+0x14/0x20
+[ 918.082135] ? memset+0x31/0x40
+[ 918.082820] ? fscrypt_setup_filename+0x1ec/0x4c0
+[ 918.083782] ? d_alloc_parallel+0x5bb/0x8c0
+[ 918.084640] f2fs_find_entry+0xe9/0x110
+[ 918.085432] ? __f2fs_find_entry+0x670/0x670
+[ 918.086308] ? kasan_check_write+0x14/0x20
+[ 918.087163] f2fs_lookup+0x297/0x590
+[ 918.087902] ? f2fs_link+0x2b0/0x2b0
+[ 918.088646] ? legitimize_path.isra.29+0x61/0xa0
+[ 918.089589] __lookup_slow+0x12e/0x240
+[ 918.090371] ? may_delete+0x2b0/0x2b0
+[ 918.091123] ? __nd_alloc_stack+0xa0/0xa0
+[ 918.091944] lookup_slow+0x44/0x60
+[ 918.092642] walk_component+0x3ee/0xa40
+[ 918.093428] ? is_bpf_text_address+0xe/0x20
+[ 918.094283] ? pick_link+0x3e0/0x3e0
+[ 918.095047] ? in_group_p+0xa5/0xe0
+[ 918.095771] ? generic_permission+0x53/0x1e0
+[ 918.096666] ? security_inode_permission+0x1d/0x70
+[ 918.097646] ? inode_permission+0x7a/0x1f0
+[ 918.098497] link_path_walk+0x2a2/0x7b0
+[ 918.099298] ? apparmor_capget+0x3d0/0x3d0
+[ 918.100140] ? walk_component+0xa40/0xa40
+[ 918.100958] ? path_init+0x2e6/0x580
+[ 918.101695] path_openat+0x1bb/0x2160
+[ 918.102471] ? __save_stack_trace+0x92/0x100
+[ 918.103352] ? save_stack+0xb5/0xd0
+[ 918.104070] ? vfs_unlink+0x250/0x250
+[ 918.104822] ? save_stack+0x46/0xd0
+[ 918.105538] ? kasan_slab_alloc+0x11/0x20
+[ 918.106370] ? kmem_cache_alloc+0xd1/0x1e0
+[ 918.107213] ? getname_flags+0x76/0x2c0
+[ 918.107997] ? getname+0x12/0x20
+[ 918.108677] ? do_sys_open+0x14b/0x2c0
+[ 918.109450] ? __x64_sys_open+0x4c/0x60
+[ 918.110255] ? do_syscall_64+0x78/0x170
+[ 918.111083] ? entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[ 918.112148] ? entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[ 918.113204] ? f2fs_empty_inline_dir+0x1e0/0x1e0
+[ 918.114150] ? timespec64_trunc+0x5c/0x90
+[ 918.114993] ? wb_io_lists_depopulated+0x1a/0xc0
+[ 918.115937] ? inode_io_list_move_locked+0x102/0x110
+[ 918.116949] do_filp_open+0x12b/0x1d0
+[ 918.117709] ? may_open_dev+0x50/0x50
+[ 918.118475] ? kasan_kmalloc+0xad/0xe0
+[ 918.119246] do_sys_open+0x17c/0x2c0
+[ 918.119983] ? do_sys_open+0x17c/0x2c0
+[ 918.120751] ? filp_open+0x60/0x60
+[ 918.121463] ? task_work_run+0x4d/0xf0
+[ 918.122237] __x64_sys_open+0x4c/0x60
+[ 918.123001] do_syscall_64+0x78/0x170
+[ 918.123759] entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[ 918.124802] RIP: 0033:0x7fac96e3e040
+[ 918.125537] 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
+[ 918.129341] RSP: 002b:00007fff1b37f848 EFLAGS: 00000246 ORIG_RAX: 0000000000000002
+[ 918.130870] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fac96e3e040
+[ 918.132295] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 000000000122d080
+[ 918.133748] RBP: 00007fff1b37f9b0 R08: 00007fac9710bbd8 R09: 0000000000000001
+[ 918.135209] R10: 000000000000069d R11: 0000000000000246 R12: 0000000000400c20
+[ 918.136650] R13: 00007fff1b37fab0 R14: 0000000000000000 R15: 0000000000000000
+[ 918.138093] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd mac_hid i2c_piix4 soundcore ib_iser rdma_cm iw_cm ib_cm ib_core iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx raid1 raid0 multipath linear 8139too crct10dif_pclmul crc32_pclmul qxl drm_kms_helper syscopyarea aesni_intel sysfillrect sysimgblt fb_sys_fops ttm drm aes_x86_64 crypto_simd cryptd 8139cp glue_helper mii pata_acpi floppy
+[ 918.147924] CR2: ffffed0048000d82
+[ 918.148619] ---[ end trace 4ce02f25ff7d3df5 ]---
+[ 918.149563] RIP: 0010:check_memory_region+0x5e/0x190
+[ 918.150576] Code: f8 49 c1 e8 03 49 89 db 49 c1 eb 03 4d 01 cb 4d 01 c1 4d 8d 63 01 4c 89 c8 4d 89 e2 4d 29 ca 49 83 fa 10 7f 3d 4d 85 d2 74 32 <41> 80 39 00 75 23 48 b8 01 00 00 00 00 fc ff df 4d 01 d1 49 01 c0
+[ 918.154360] RSP: 0018:ffff8801e3a1f258 EFLAGS: 00010202
+[ 918.155411] RAX: ffffed0048000d82 RBX: ffff880240006c11 RCX: ffffffffb8867d14
+[ 918.156833] RDX: 0000000000000000 RSI: 0000000000000002 RDI: ffff880240006c10
+[ 918.158257] RBP: ffff8801e3a1f268 R08: 1ffff10048000d82 R09: ffffed0048000d82
+[ 918.159722] R10: 0000000000000001 R11: ffffed0048000d82 R12: ffffed0048000d83
+[ 918.161149] R13: ffff8801e3a1f390 R14: 0000000000000000 R15: ffff880240006c08
+[ 918.162587] FS: 00007fac9732c700(0000) GS:ffff8801f6e00000(0000) knlGS:0000000000000000
+[ 918.164203] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[ 918.165356] CR2: ffffed0048000d82 CR3: 00000001df77a000 CR4: 00000000000006f0
+
+Reported-by: Wen Xu <wen.xu@gatech.edu>
+Signed-off-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Backported to 4.14: adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/f2fs/inode.c | 18 ++++++++++++++----
+ 1 file changed, 14 insertions(+), 4 deletions(-)
+
+diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
+index 917a6c3d5649..428d502f23e8 100644
+--- a/fs/f2fs/inode.c
++++ b/fs/f2fs/inode.c
+@@ -184,6 +184,15 @@ static bool sanity_check_inode(struct inode *inode)
+ {
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+
++ if (f2fs_has_extra_attr(inode) &&
++ !f2fs_sb_has_extra_attr(sbi->sb)) {
++ set_sbi_flag(sbi, SBI_NEED_FSCK);
++ f2fs_msg(sbi->sb, KERN_WARNING,
++ "%s: inode (ino=%lx) is with extra_attr, "
++ "but extra_attr feature is off",
++ __func__, inode->i_ino);
++ return false;
++ }
+ return true;
+ }
+
+@@ -233,6 +242,11 @@ static int do_read_inode(struct inode *inode)
+
+ get_inline_info(inode, ri);
+
++ if (!sanity_check_inode(inode)) {
++ f2fs_put_page(node_page, 1);
++ return -EINVAL;
++ }
++
+ fi->i_extra_isize = f2fs_has_extra_attr(inode) ?
+ le16_to_cpu(ri->i_extra_isize) : 0;
+
+@@ -288,10 +302,6 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
+ ret = do_read_inode(inode);
+ if (ret)
+ goto bad_inode;
+- if (!sanity_check_inode(inode)) {
+- ret = -EINVAL;
+- goto bad_inode;
+- }
+ make_now:
+ if (ino == F2FS_NODE_INO(sbi)) {
+ inode->i_mapping->a_ops = &f2fs_node_aops;
+--
+2.17.1
+
--- /dev/null
+From 228d309db8003933868870058a16ef8d144e7074 Mon Sep 17 00:00:00 2001
+From: Chao Yu <yuchao0@huawei.com>
+Date: Sun, 8 Jul 2018 22:16:55 +0800
+Subject: f2fs: fix to do sanity check with i_extra_isize
+
+commit 18dd6470c2d14d10f5a2dd926925dc80dbd3abfd upstream.
+
+If inode.i_extra_isize was fuzzed to an abnormal value, when
+calculating inline data size, the result will overflow, result
+in accessing invalid memory area when operating inline data.
+
+Let's do sanity check with i_extra_isize during inode loading
+for fixing.
+
+https://bugzilla.kernel.org/show_bug.cgi?id=200421
+
+- Reproduce
+
+- 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;
+ char *foo_baz;
+ char *xattr;
+ int err;
+
+ err = asprintf(&foo_bar_baz, "%s/foo/bar/baz", mpoint);
+ err = asprintf(&foo_baz, "%s/foo/baz", mpoint);
+ err = asprintf(&xattr, "%s/foo/bar/xattr", mpoint);
+
+ rename(foo_bar_baz, foo_baz);
+
+ char buf2[113];
+ memset(buf2, 0, sizeof(buf2));
+ listxattr(xattr, buf2, sizeof(buf2));
+ removexattr(xattr, "user.mime_type");
+
+ }
+
+ int main(int argc, char *argv[]) {
+ activity(argv[1]);
+ return 0;
+ }
+
+- Kernel message
+Umount the image will leave the following message
+[ 2910.995489] F2FS-fs (loop0): Mounted with checkpoint version = 2
+[ 2918.416465] ==================================================================
+[ 2918.416807] BUG: KASAN: slab-out-of-bounds in f2fs_iget+0xcb9/0x1a80
+[ 2918.417009] Read of size 4 at addr ffff88018efc2068 by task a.out/1229
+
+[ 2918.417311] CPU: 1 PID: 1229 Comm: a.out Not tainted 4.17.0+ #1
+[ 2918.417314] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[ 2918.417323] Call Trace:
+[ 2918.417366] dump_stack+0x71/0xab
+[ 2918.417401] print_address_description+0x6b/0x290
+[ 2918.417407] kasan_report+0x28e/0x390
+[ 2918.417411] ? f2fs_iget+0xcb9/0x1a80
+[ 2918.417415] f2fs_iget+0xcb9/0x1a80
+[ 2918.417422] ? f2fs_lookup+0x2e7/0x580
+[ 2918.417425] f2fs_lookup+0x2e7/0x580
+[ 2918.417433] ? __recover_dot_dentries+0x400/0x400
+[ 2918.417447] ? legitimize_path.isra.29+0x5a/0xa0
+[ 2918.417453] __lookup_slow+0x11c/0x220
+[ 2918.417457] ? may_delete+0x2a0/0x2a0
+[ 2918.417475] ? deref_stack_reg+0xe0/0xe0
+[ 2918.417479] ? __lookup_hash+0xb0/0xb0
+[ 2918.417483] lookup_slow+0x3e/0x60
+[ 2918.417488] walk_component+0x3ac/0x990
+[ 2918.417492] ? generic_permission+0x51/0x1e0
+[ 2918.417495] ? inode_permission+0x51/0x1d0
+[ 2918.417499] ? pick_link+0x3e0/0x3e0
+[ 2918.417502] ? link_path_walk+0x4b1/0x770
+[ 2918.417513] ? _raw_spin_lock_irqsave+0x25/0x50
+[ 2918.417518] ? walk_component+0x990/0x990
+[ 2918.417522] ? path_init+0x2e6/0x580
+[ 2918.417526] path_lookupat+0x13f/0x430
+[ 2918.417531] ? trailing_symlink+0x3a0/0x3a0
+[ 2918.417534] ? do_renameat2+0x270/0x7b0
+[ 2918.417538] ? __kasan_slab_free+0x14c/0x190
+[ 2918.417541] ? do_renameat2+0x270/0x7b0
+[ 2918.417553] ? kmem_cache_free+0x85/0x1e0
+[ 2918.417558] ? do_renameat2+0x270/0x7b0
+[ 2918.417563] filename_lookup+0x13c/0x280
+[ 2918.417567] ? filename_parentat+0x2b0/0x2b0
+[ 2918.417572] ? kasan_unpoison_shadow+0x31/0x40
+[ 2918.417575] ? kasan_kmalloc+0xa6/0xd0
+[ 2918.417593] ? strncpy_from_user+0xaa/0x1c0
+[ 2918.417598] ? getname_flags+0x101/0x2b0
+[ 2918.417614] ? path_listxattr+0x87/0x110
+[ 2918.417619] path_listxattr+0x87/0x110
+[ 2918.417623] ? listxattr+0xc0/0xc0
+[ 2918.417637] ? mm_fault_error+0x1b0/0x1b0
+[ 2918.417654] do_syscall_64+0x73/0x160
+[ 2918.417660] entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[ 2918.417676] RIP: 0033:0x7f2f3a3480d7
+[ 2918.417677] Code: f0 ff ff 73 01 c3 48 8b 0d be dd 2b 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 b8 c2 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 91 dd 2b 00 f7 d8 64 89 01 48
+[ 2918.417732] RSP: 002b:00007fff4095b7d8 EFLAGS: 00000206 ORIG_RAX: 00000000000000c2
+[ 2918.417744] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f2f3a3480d7
+[ 2918.417746] RDX: 0000000000000071 RSI: 00007fff4095b810 RDI: 000000000126a0c0
+[ 2918.417749] RBP: 00007fff4095b890 R08: 000000000126a010 R09: 0000000000000000
+[ 2918.417751] R10: 00000000000001ab R11: 0000000000000206 R12: 00000000004005e0
+[ 2918.417753] R13: 00007fff4095b990 R14: 0000000000000000 R15: 0000000000000000
+
+[ 2918.417853] Allocated by task 329:
+[ 2918.418002] kasan_kmalloc+0xa6/0xd0
+[ 2918.418007] kmem_cache_alloc+0xc8/0x1e0
+[ 2918.418023] mempool_init_node+0x194/0x230
+[ 2918.418027] mempool_init+0x12/0x20
+[ 2918.418042] bioset_init+0x2bd/0x380
+[ 2918.418052] blk_alloc_queue_node+0xe9/0x540
+[ 2918.418075] dm_create+0x2c0/0x800
+[ 2918.418080] dev_create+0xd2/0x530
+[ 2918.418083] ctl_ioctl+0x2a3/0x5b0
+[ 2918.418087] dm_ctl_ioctl+0xa/0x10
+[ 2918.418092] do_vfs_ioctl+0x13e/0x8c0
+[ 2918.418095] ksys_ioctl+0x66/0x70
+[ 2918.418098] __x64_sys_ioctl+0x3d/0x50
+[ 2918.418102] do_syscall_64+0x73/0x160
+[ 2918.418106] entry_SYSCALL_64_after_hwframe+0x44/0xa9
+
+[ 2918.418204] Freed by task 0:
+[ 2918.418301] (stack is not available)
+
+[ 2918.418521] The buggy address belongs to the object at ffff88018efc0000
+ which belongs to the cache biovec-max of size 8192
+[ 2918.418894] The buggy address is located 104 bytes to the right of
+ 8192-byte region [ffff88018efc0000, ffff88018efc2000)
+[ 2918.419257] The buggy address belongs to the page:
+[ 2918.419431] page:ffffea00063bf000 count:1 mapcount:0 mapping:ffff8801f2242540 index:0x0 compound_mapcount: 0
+[ 2918.419702] flags: 0x17fff8000008100(slab|head)
+[ 2918.419879] raw: 017fff8000008100 dead000000000100 dead000000000200 ffff8801f2242540
+[ 2918.420101] raw: 0000000000000000 0000000000030003 00000001ffffffff 0000000000000000
+[ 2918.420322] page dumped because: kasan: bad access detected
+
+[ 2918.420599] Memory state around the buggy address:
+[ 2918.420764] ffff88018efc1f00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
+[ 2918.420975] ffff88018efc1f80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
+[ 2918.421194] >ffff88018efc2000: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
+[ 2918.421406] ^
+[ 2918.421627] ffff88018efc2080: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
+[ 2918.421838] ffff88018efc2100: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
+[ 2918.422046] ==================================================================
+[ 2918.422264] Disabling lock debugging due to kernel taint
+[ 2923.901641] BUG: unable to handle kernel paging request at ffff88018f0db000
+[ 2923.901884] PGD 22226a067 P4D 22226a067 PUD 222273067 PMD 18e642063 PTE 800000018f0db061
+[ 2923.902120] Oops: 0003 [#1] SMP KASAN PTI
+[ 2923.902274] CPU: 1 PID: 1231 Comm: umount Tainted: G B 4.17.0+ #1
+[ 2923.902490] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[ 2923.902761] RIP: 0010:__memset+0x24/0x30
+[ 2923.902906] Code: 90 90 90 90 90 90 66 66 90 66 90 49 89 f9 48 89 d1 83 e2 07 48 c1 e9 03 40 0f b6 f6 48 b8 01 01 01 01 01 01 01 01 48 0f af c6 <f3> 48 ab 89 d1 f3 aa 4c 89 c8 c3 90 49 89 f9 40 88 f0 48 89 d1 f3
+[ 2923.903446] RSP: 0018:ffff88018ddf7ae0 EFLAGS: 00010206
+[ 2923.903622] RAX: 0000000000000000 RBX: ffff8801d549d888 RCX: 1ffffffffffdaffb
+[ 2923.903833] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff88018f0daffc
+[ 2923.904062] RBP: ffff88018efc206c R08: 1ffff10031df840d R09: ffff88018efc206c
+[ 2923.904273] R10: ffffffffffffe1ee R11: ffffed0031df65fa R12: 0000000000000000
+[ 2923.904485] R13: ffff8801d549dc98 R14: 00000000ffffc3db R15: ffffea00063bec80
+[ 2923.904693] FS: 00007fa8b2f8a840(0000) GS:ffff8801f3b00000(0000) knlGS:0000000000000000
+[ 2923.904937] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[ 2923.910080] CR2: ffff88018f0db000 CR3: 000000018f892000 CR4: 00000000000006e0
+[ 2923.914930] Call Trace:
+[ 2923.919724] f2fs_truncate_inline_inode+0x114/0x170
+[ 2923.924487] f2fs_truncate_blocks+0x11b/0x7c0
+[ 2923.929178] ? f2fs_truncate_data_blocks+0x10/0x10
+[ 2923.933834] ? dqget+0x670/0x670
+[ 2923.938437] ? f2fs_destroy_extent_tree+0xd6/0x270
+[ 2923.943107] ? __radix_tree_lookup+0x2f/0x150
+[ 2923.947772] f2fs_truncate+0xd4/0x1a0
+[ 2923.952491] f2fs_evict_inode+0x5ab/0x610
+[ 2923.957204] evict+0x15f/0x280
+[ 2923.961898] __dentry_kill+0x161/0x250
+[ 2923.966634] shrink_dentry_list+0xf3/0x250
+[ 2923.971897] shrink_dcache_parent+0xa9/0x100
+[ 2923.976561] ? shrink_dcache_sb+0x1f0/0x1f0
+[ 2923.981177] ? wait_for_completion+0x8a/0x210
+[ 2923.985781] ? migrate_swap_stop+0x2d0/0x2d0
+[ 2923.990332] do_one_tree+0xe/0x40
+[ 2923.994735] shrink_dcache_for_umount+0x3a/0xa0
+[ 2923.999077] generic_shutdown_super+0x3e/0x1c0
+[ 2924.003350] kill_block_super+0x4b/0x70
+[ 2924.007619] deactivate_locked_super+0x65/0x90
+[ 2924.011812] cleanup_mnt+0x5c/0xa0
+[ 2924.015995] task_work_run+0xce/0xf0
+[ 2924.020174] exit_to_usermode_loop+0x115/0x120
+[ 2924.024293] do_syscall_64+0x12f/0x160
+[ 2924.028479] entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[ 2924.032709] RIP: 0033:0x7fa8b2868487
+[ 2924.036888] 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 e1 c9 2b 00 f7 d8 64 89 01 48
+[ 2924.045750] RSP: 002b:00007ffc39824d58 EFLAGS: 00000246 ORIG_RAX: 00000000000000a6
+[ 2924.050190] RAX: 0000000000000000 RBX: 00000000008ea030 RCX: 00007fa8b2868487
+[ 2924.054604] RDX: 0000000000000001 RSI: 0000000000000000 RDI: 00000000008f4360
+[ 2924.058940] RBP: 00000000008f4360 R08: 0000000000000000 R09: 0000000000000014
+[ 2924.063186] R10: 00000000000006b2 R11: 0000000000000246 R12: 00007fa8b2d7183c
+[ 2924.067418] R13: 0000000000000000 R14: 00000000008ea210 R15: 00007ffc39824fe0
+[ 2924.071534] 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
+[ 2924.098044] CR2: ffff88018f0db000
+[ 2924.102520] ---[ end trace a8e0d899985faf31 ]---
+[ 2924.107012] RIP: 0010:__memset+0x24/0x30
+[ 2924.111448] Code: 90 90 90 90 90 90 66 66 90 66 90 49 89 f9 48 89 d1 83 e2 07 48 c1 e9 03 40 0f b6 f6 48 b8 01 01 01 01 01 01 01 01 48 0f af c6 <f3> 48 ab 89 d1 f3 aa 4c 89 c8 c3 90 49 89 f9 40 88 f0 48 89 d1 f3
+[ 2924.120724] RSP: 0018:ffff88018ddf7ae0 EFLAGS: 00010206
+[ 2924.125312] RAX: 0000000000000000 RBX: ffff8801d549d888 RCX: 1ffffffffffdaffb
+[ 2924.129931] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff88018f0daffc
+[ 2924.134537] RBP: ffff88018efc206c R08: 1ffff10031df840d R09: ffff88018efc206c
+[ 2924.139175] R10: ffffffffffffe1ee R11: ffffed0031df65fa R12: 0000000000000000
+[ 2924.143825] R13: ffff8801d549dc98 R14: 00000000ffffc3db R15: ffffea00063bec80
+[ 2924.148500] FS: 00007fa8b2f8a840(0000) GS:ffff8801f3b00000(0000) knlGS:0000000000000000
+[ 2924.153247] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[ 2924.158003] CR2: ffff88018f0db000 CR3: 000000018f892000 CR4: 00000000000006e0
+[ 2924.164641] BUG: Bad rss-counter state mm:00000000fa04621e idx:0 val:4
+[ 2924.170007] BUG: Bad rss-counter
+tate mm:00000000fa04621e idx:1 val:2
+
+- Location
+https://elixir.bootlin.com/linux/v4.18-rc3/source/fs/f2fs/inline.c#L78
+ memset(addr + from, 0, MAX_INLINE_DATA(inode) - from);
+Here the length can be negative.
+
+Reported-by Wen Xu <wen.xu@gatech.edu>
+Signed-off-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Backported to 4.14: adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/f2fs/inode.c | 18 +++++++++++++++---
+ 1 file changed, 15 insertions(+), 3 deletions(-)
+
+diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
+index aeed9943836a..9a40724dbaa6 100644
+--- a/fs/f2fs/inode.c
++++ b/fs/f2fs/inode.c
+@@ -183,6 +183,7 @@ void f2fs_inode_chksum_set(struct f2fs_sb_info *sbi, struct page *page)
+ static bool sanity_check_inode(struct inode *inode, struct page *node_page)
+ {
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
++ struct f2fs_inode_info *fi = F2FS_I(inode);
+ unsigned long long iblocks;
+
+ iblocks = le64_to_cpu(F2FS_INODE(node_page)->i_blocks);
+@@ -215,6 +216,17 @@ static bool sanity_check_inode(struct inode *inode, struct page *node_page)
+ return false;
+ }
+
++ if (fi->i_extra_isize > F2FS_TOTAL_EXTRA_ATTR_SIZE ||
++ fi->i_extra_isize % sizeof(__le32)) {
++ set_sbi_flag(sbi, SBI_NEED_FSCK);
++ f2fs_msg(sbi->sb, KERN_WARNING,
++ "%s: inode (ino=%lx) has corrupted i_extra_isize: %d, "
++ "max: %zu",
++ __func__, inode->i_ino, fi->i_extra_isize,
++ F2FS_TOTAL_EXTRA_ATTR_SIZE);
++ return false;
++ }
++
+ if (F2FS_I(inode)->extent_tree) {
+ struct extent_info *ei = &F2FS_I(inode)->extent_tree->largest;
+
+@@ -280,14 +292,14 @@ static int do_read_inode(struct inode *inode)
+
+ get_inline_info(inode, ri);
+
++ fi->i_extra_isize = f2fs_has_extra_attr(inode) ?
++ le16_to_cpu(ri->i_extra_isize) : 0;
++
+ if (!sanity_check_inode(inode, node_page)) {
+ f2fs_put_page(node_page, 1);
+ return -EINVAL;
+ }
+
+- fi->i_extra_isize = f2fs_has_extra_attr(inode) ?
+- le16_to_cpu(ri->i_extra_isize) : 0;
+-
+ /* check data exist */
+ if (f2fs_has_inline_data(inode) && !f2fs_exist_data(inode))
+ __recover_inline_status(inode, node_page);
+--
+2.17.1
+
--- /dev/null
+From e823b46ea58cc739c4ae39d35e2d2f6022fbab5b Mon Sep 17 00:00:00 2001
+From: Chao Yu <yuchao0@huawei.com>
+Date: Fri, 29 Jun 2018 13:55:22 +0800
+Subject: f2fs: fix to do sanity check with node footer and iblocks
+
+commit e34438c903b653daca2b2a7de95aed46226f8ed3 upstream.
+
+This patch adds to do sanity check with below fields of inode to
+avoid reported panic.
+- node footer
+- iblocks
+
+https://bugzilla.kernel.org/show_bug.cgi?id=200223
+
+- Overview
+BUG() triggered in f2fs_truncate_inode_blocks() when un-mounting a mounted f2fs image after writing to it
+
+- Reproduce
+
+- POC (poc.c)
+
+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);
+
+ // open / write / read
+ 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));
+ close(fd);
+ }
+
+}
+
+int main(int argc, char *argv[]) {
+ activity(argv[1]);
+ return 0;
+}
+
+- Kernel meesage
+[ 552.479723] F2FS-fs (loop0): Mounted with checkpoint version = 2
+[ 556.451891] ------------[ cut here ]------------
+[ 556.451899] kernel BUG at fs/f2fs/node.c:987!
+[ 556.452920] invalid opcode: 0000 [#1] SMP KASAN PTI
+[ 556.453936] CPU: 1 PID: 1310 Comm: umount Not tainted 4.18.0-rc1+ #4
+[ 556.455213] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[ 556.457140] RIP: 0010:f2fs_truncate_inode_blocks+0x4a7/0x6f0
+[ 556.458280] Code: e8 ae ea ff ff 41 89 c7 c1 e8 1f 84 c0 74 0a 41 83 ff fe 0f 85 35 ff ff ff 81 85 b0 fe ff ff fb 03 00 00 e9 f7 fd ff ff 0f 0b <0f> 0b e8 62 b7 9a 00 48 8b bd a0 fe ff ff e8 56 54 ae ff 48 8b b5
+[ 556.462015] RSP: 0018:ffff8801f292f808 EFLAGS: 00010286
+[ 556.463068] RAX: ffffed003e73242d RBX: ffff8801f292f958 RCX: ffffffffb88b81bc
+[ 556.464479] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffff8801f3992164
+[ 556.465901] RBP: ffff8801f292f980 R08: ffffed003e73242d R09: ffffed003e73242d
+[ 556.467311] R10: 0000000000000001 R11: ffffed003e73242c R12: 00000000fffffc64
+[ 556.468706] R13: ffff8801f3992000 R14: 0000000000000058 R15: 00000000ffff8801
+[ 556.470117] FS: 00007f8029297840(0000) GS:ffff8801f6f00000(0000) knlGS:0000000000000000
+[ 556.471702] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[ 556.472838] CR2: 000055f5f57305d8 CR3: 00000001f18b0000 CR4: 00000000000006e0
+[ 556.474265] Call Trace:
+[ 556.474782] ? f2fs_alloc_nid_failed+0xf0/0xf0
+[ 556.475686] ? truncate_nodes+0x980/0x980
+[ 556.476516] ? pagecache_get_page+0x21f/0x2f0
+[ 556.477412] ? __asan_loadN+0xf/0x20
+[ 556.478153] ? __get_node_page+0x331/0x5b0
+[ 556.478992] ? reweight_entity+0x1e6/0x3b0
+[ 556.479826] f2fs_truncate_blocks+0x55e/0x740
+[ 556.480709] ? f2fs_truncate_data_blocks+0x20/0x20
+[ 556.481689] ? __radix_tree_lookup+0x34/0x160
+[ 556.482630] ? radix_tree_lookup+0xd/0x10
+[ 556.483445] f2fs_truncate+0xd4/0x1a0
+[ 556.484206] f2fs_evict_inode+0x5ce/0x630
+[ 556.485032] evict+0x16f/0x290
+[ 556.485664] iput+0x280/0x300
+[ 556.486300] dentry_unlink_inode+0x165/0x1e0
+[ 556.487169] __dentry_kill+0x16a/0x260
+[ 556.487936] dentry_kill+0x70/0x250
+[ 556.488651] shrink_dentry_list+0x125/0x260
+[ 556.489504] shrink_dcache_parent+0xc1/0x110
+[ 556.490379] ? shrink_dcache_sb+0x200/0x200
+[ 556.491231] ? bit_wait_timeout+0xc0/0xc0
+[ 556.492047] do_one_tree+0x12/0x40
+[ 556.492743] shrink_dcache_for_umount+0x3f/0xa0
+[ 556.493656] generic_shutdown_super+0x43/0x1c0
+[ 556.494561] kill_block_super+0x52/0x80
+[ 556.495341] kill_f2fs_super+0x62/0x70
+[ 556.496105] deactivate_locked_super+0x6f/0xa0
+[ 556.497004] deactivate_super+0x5e/0x80
+[ 556.497785] cleanup_mnt+0x61/0xa0
+[ 556.498492] __cleanup_mnt+0x12/0x20
+[ 556.499218] task_work_run+0xc8/0xf0
+[ 556.499949] exit_to_usermode_loop+0x125/0x130
+[ 556.500846] do_syscall_64+0x138/0x170
+[ 556.501609] entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[ 556.502659] RIP: 0033:0x7f8028b77487
+[ 556.503384] 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 e1 c9 2b 00 f7 d8 64 89 01 48
+[ 556.507137] RSP: 002b:00007fff9f2e3598 EFLAGS: 00000246 ORIG_RAX: 00000000000000a6
+[ 556.508637] RAX: 0000000000000000 RBX: 0000000000ebd030 RCX: 00007f8028b77487
+[ 556.510069] RDX: 0000000000000001 RSI: 0000000000000000 RDI: 0000000000ec41e0
+[ 556.511481] RBP: 0000000000ec41e0 R08: 0000000000000000 R09: 0000000000000014
+[ 556.512892] R10: 00000000000006b2 R11: 0000000000000246 R12: 00007f802908083c
+[ 556.514320] R13: 0000000000000000 R14: 0000000000ebd210 R15: 00007fff9f2e3820
+[ 556.515745] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd mac_hid i2c_piix4 soundcore ib_iser rdma_cm iw_cm ib_cm ib_core iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx raid1 raid0 multipath linear 8139too crct10dif_pclmul crc32_pclmul qxl drm_kms_helper syscopyarea aesni_intel sysfillrect sysimgblt fb_sys_fops ttm drm aes_x86_64 crypto_simd cryptd 8139cp glue_helper mii pata_acpi floppy
+[ 556.529276] ---[ end trace 4ce02f25ff7d3df5 ]---
+[ 556.530340] RIP: 0010:f2fs_truncate_inode_blocks+0x4a7/0x6f0
+[ 556.531513] Code: e8 ae ea ff ff 41 89 c7 c1 e8 1f 84 c0 74 0a 41 83 ff fe 0f 85 35 ff ff ff 81 85 b0 fe ff ff fb 03 00 00 e9 f7 fd ff ff 0f 0b <0f> 0b e8 62 b7 9a 00 48 8b bd a0 fe ff ff e8 56 54 ae ff 48 8b b5
+[ 556.535330] RSP: 0018:ffff8801f292f808 EFLAGS: 00010286
+[ 556.536395] RAX: ffffed003e73242d RBX: ffff8801f292f958 RCX: ffffffffb88b81bc
+[ 556.537824] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffff8801f3992164
+[ 556.539290] RBP: ffff8801f292f980 R08: ffffed003e73242d R09: ffffed003e73242d
+[ 556.540709] R10: 0000000000000001 R11: ffffed003e73242c R12: 00000000fffffc64
+[ 556.542131] R13: ffff8801f3992000 R14: 0000000000000058 R15: 00000000ffff8801
+[ 556.543579] FS: 00007f8029297840(0000) GS:ffff8801f6f00000(0000) knlGS:0000000000000000
+[ 556.545180] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[ 556.546338] CR2: 000055f5f57305d8 CR3: 00000001f18b0000 CR4: 00000000000006e0
+[ 556.547809] ==================================================================
+[ 556.549248] BUG: KASAN: stack-out-of-bounds in arch_tlb_gather_mmu+0x52/0x170
+[ 556.550672] Write of size 8 at addr ffff8801f292fd10 by task umount/1310
+
+[ 556.552338] CPU: 1 PID: 1310 Comm: umount Tainted: G D 4.18.0-rc1+ #4
+[ 556.553886] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[ 556.555756] Call Trace:
+[ 556.556264] dump_stack+0x7b/0xb5
+[ 556.556944] print_address_description+0x70/0x290
+[ 556.557903] kasan_report+0x291/0x390
+[ 556.558649] ? arch_tlb_gather_mmu+0x52/0x170
+[ 556.559537] __asan_store8+0x57/0x90
+[ 556.560268] arch_tlb_gather_mmu+0x52/0x170
+[ 556.561110] tlb_gather_mmu+0x12/0x40
+[ 556.561862] exit_mmap+0x123/0x2a0
+[ 556.562555] ? __ia32_sys_munmap+0x50/0x50
+[ 556.563384] ? exit_aio+0x98/0x230
+[ 556.564079] ? __x32_compat_sys_io_submit+0x260/0x260
+[ 556.565099] ? taskstats_exit+0x1f4/0x640
+[ 556.565925] ? kasan_check_read+0x11/0x20
+[ 556.566739] ? mm_update_next_owner+0x322/0x380
+[ 556.567652] mmput+0x8b/0x1d0
+[ 556.568260] do_exit+0x43a/0x1390
+[ 556.568937] ? mm_update_next_owner+0x380/0x380
+[ 556.569855] ? deactivate_super+0x5e/0x80
+[ 556.570668] ? cleanup_mnt+0x61/0xa0
+[ 556.571395] ? __cleanup_mnt+0x12/0x20
+[ 556.572156] ? task_work_run+0xc8/0xf0
+[ 556.572917] ? exit_to_usermode_loop+0x125/0x130
+[ 556.573861] rewind_stack_do_exit+0x17/0x20
+[ 556.574707] RIP: 0033:0x7f8028b77487
+[ 556.575428] Code: Bad RIP value.
+[ 556.576106] RSP: 002b:00007fff9f2e3598 EFLAGS: 00000246 ORIG_RAX: 00000000000000a6
+[ 556.577599] RAX: 0000000000000000 RBX: 0000000000ebd030 RCX: 00007f8028b77487
+[ 556.579020] RDX: 0000000000000001 RSI: 0000000000000000 RDI: 0000000000ec41e0
+[ 556.580422] RBP: 0000000000ec41e0 R08: 0000000000000000 R09: 0000000000000014
+[ 556.581833] R10: 00000000000006b2 R11: 0000000000000246 R12: 00007f802908083c
+[ 556.583252] R13: 0000000000000000 R14: 0000000000ebd210 R15: 00007fff9f2e3820
+
+[ 556.584983] The buggy address belongs to the page:
+[ 556.585961] page:ffffea0007ca4bc0 count:0 mapcount:0 mapping:0000000000000000 index:0x0
+[ 556.587540] flags: 0x2ffff0000000000()
+[ 556.588296] raw: 02ffff0000000000 0000000000000000 dead000000000200 0000000000000000
+[ 556.589822] raw: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000000
+[ 556.591359] page dumped because: kasan: bad access detected
+
+[ 556.592786] Memory state around the buggy address:
+[ 556.593753] ffff8801f292fc00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[ 556.595191] ffff8801f292fc80: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 00 00 00 00
+[ 556.596613] >ffff8801f292fd00: 00 00 f3 00 00 00 00 f3 f3 00 00 00 00 f4 f4 f4
+[ 556.598044] ^
+[ 556.598797] ffff8801f292fd80: f3 f3 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
+[ 556.600225] ffff8801f292fe00: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 00 f4 f4 f4
+[ 556.601647] ==================================================================
+
+- Location
+https://elixir.bootlin.com/linux/v4.18-rc1/source/fs/f2fs/node.c#L987
+ case NODE_DIND_BLOCK:
+ err = truncate_nodes(&dn, nofs, offset[1], 3);
+ cont = 0;
+ break;
+
+ default:
+ BUG(); <---
+ }
+
+Reported-by Wen Xu <wen.xu@gatech.edu>
+Signed-off-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/f2fs/inode.c | 25 +++++++++++++++++++++++--
+ 1 file changed, 23 insertions(+), 2 deletions(-)
+
+diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
+index 428d502f23e8..be7d9773d291 100644
+--- a/fs/f2fs/inode.c
++++ b/fs/f2fs/inode.c
+@@ -180,9 +180,30 @@ void f2fs_inode_chksum_set(struct f2fs_sb_info *sbi, struct page *page)
+ ri->i_inode_checksum = cpu_to_le32(f2fs_inode_chksum(sbi, page));
+ }
+
+-static bool sanity_check_inode(struct inode *inode)
++static bool sanity_check_inode(struct inode *inode, struct page *node_page)
+ {
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
++ unsigned long long iblocks;
++
++ iblocks = le64_to_cpu(F2FS_INODE(node_page)->i_blocks);
++ if (!iblocks) {
++ set_sbi_flag(sbi, SBI_NEED_FSCK);
++ f2fs_msg(sbi->sb, KERN_WARNING,
++ "%s: corrupted inode i_blocks i_ino=%lx iblocks=%llu, "
++ "run fsck to fix.",
++ __func__, inode->i_ino, iblocks);
++ return false;
++ }
++
++ if (ino_of_node(node_page) != nid_of_node(node_page)) {
++ set_sbi_flag(sbi, SBI_NEED_FSCK);
++ f2fs_msg(sbi->sb, KERN_WARNING,
++ "%s: corrupted inode footer i_ino=%lx, ino,nid: "
++ "[%u, %u] run fsck to fix.",
++ __func__, inode->i_ino,
++ ino_of_node(node_page), nid_of_node(node_page));
++ return false;
++ }
+
+ if (f2fs_has_extra_attr(inode) &&
+ !f2fs_sb_has_extra_attr(sbi->sb)) {
+@@ -242,7 +263,7 @@ static int do_read_inode(struct inode *inode)
+
+ get_inline_info(inode, ri);
+
+- if (!sanity_check_inode(inode)) {
++ if (!sanity_check_inode(inode, node_page)) {
+ f2fs_put_page(node_page, 1);
+ return -EINVAL;
+ }
+--
+2.17.1
+
--- /dev/null
+From 2d3a5dc812c7a6bc3a74431dafc1bd8e0bf721a0 Mon Sep 17 00:00:00 2001
+From: Chao Yu <yuchao0@huawei.com>
+Date: Sat, 23 Jun 2018 00:12:36 +0800
+Subject: f2fs: fix to do sanity check with secs_per_zone
+
+commit 42bf546c1fe3f3654bdf914e977acbc2b80a5be5 upstream.
+
+As Wen Xu reported in below link:
+
+https://bugzilla.kernel.org/show_bug.cgi?id=200183
+
+- Overview
+Divide zero in reset_curseg() when mounting a crafted f2fs image
+
+- Reproduce
+
+- Kernel message
+[ 588.281510] divide error: 0000 [#1] SMP KASAN PTI
+[ 588.282701] CPU: 0 PID: 1293 Comm: mount Not tainted 4.18.0-rc1+ #4
+[ 588.284000] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[ 588.286178] RIP: 0010:reset_curseg+0x94/0x1a0
+[ 588.298166] RSP: 0018:ffff8801e88d7940 EFLAGS: 00010246
+[ 588.299360] RAX: 0000000000000014 RBX: ffff8801e1d46d00 RCX: ffffffffb88bf60b
+[ 588.300809] RDX: 0000000000000000 RSI: dffffc0000000000 RDI: ffff8801e1d46d64
+[ 588.305272] R13: 0000000000000000 R14: 0000000000000014 R15: 0000000000000000
+[ 588.306822] FS: 00007fad85008840(0000) GS:ffff8801f6e00000(0000) knlGS:0000000000000000
+[ 588.308456] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[ 588.309623] CR2: 0000000001705078 CR3: 00000001f30f8000 CR4: 00000000000006f0
+[ 588.311085] Call Trace:
+[ 588.311637] f2fs_build_segment_manager+0x103f/0x3410
+[ 588.316136] ? f2fs_commit_super+0x1b0/0x1b0
+[ 588.317031] ? set_blocksize+0x90/0x140
+[ 588.319473] f2fs_mount+0x15/0x20
+[ 588.320166] mount_fs+0x60/0x1a0
+[ 588.320847] ? alloc_vfsmnt+0x309/0x360
+[ 588.321647] vfs_kern_mount+0x6b/0x1a0
+[ 588.322432] do_mount+0x34a/0x18c0
+[ 588.323175] ? strndup_user+0x46/0x70
+[ 588.323937] ? copy_mount_string+0x20/0x20
+[ 588.324793] ? memcg_kmem_put_cache+0x1b/0xa0
+[ 588.325702] ? kasan_check_write+0x14/0x20
+[ 588.326562] ? _copy_from_user+0x6a/0x90
+[ 588.327375] ? memdup_user+0x42/0x60
+[ 588.328118] ksys_mount+0x83/0xd0
+[ 588.328808] __x64_sys_mount+0x67/0x80
+[ 588.329607] do_syscall_64+0x78/0x170
+[ 588.330400] entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[ 588.331461] RIP: 0033:0x7fad848e8b9a
+[ 588.336022] RSP: 002b:00007ffd7c5b6be8 EFLAGS: 00000206 ORIG_RAX: 00000000000000a5
+[ 588.337547] RAX: ffffffffffffffda RBX: 00000000016f8030 RCX: 00007fad848e8b9a
+[ 588.338999] RDX: 00000000016f8210 RSI: 00000000016f9f30 RDI: 0000000001700ec0
+[ 588.340442] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000013
+[ 588.341887] R10: 00000000c0ed0000 R11: 0000000000000206 R12: 0000000001700ec0
+[ 588.343341] R13: 00000000016f8210 R14: 0000000000000000 R15: 0000000000000003
+[ 588.354891] ---[ end trace 4ce02f25ff7d3df5 ]---
+[ 588.355862] RIP: 0010:reset_curseg+0x94/0x1a0
+[ 588.360742] RSP: 0018:ffff8801e88d7940 EFLAGS: 00010246
+[ 588.361812] RAX: 0000000000000014 RBX: ffff8801e1d46d00 RCX: ffffffffb88bf60b
+[ 588.363485] RDX: 0000000000000000 RSI: dffffc0000000000 RDI: ffff8801e1d46d64
+[ 588.365213] RBP: ffff8801e88d7968 R08: ffffed003c32266f R09: ffffed003c32266f
+[ 588.366661] R10: 0000000000000001 R11: ffffed003c32266e R12: ffff8801f0337700
+[ 588.368110] R13: 0000000000000000 R14: 0000000000000014 R15: 0000000000000000
+[ 588.370057] FS: 00007fad85008840(0000) GS:ffff8801f6e00000(0000) knlGS:0000000000000000
+[ 588.372099] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[ 588.373291] CR2: 0000000001705078 CR3: 00000001f30f8000 CR4: 00000000000006f0
+
+- Location
+https://elixir.bootlin.com/linux/latest/source/fs/f2fs/segment.c#L2147
+ curseg->zone = GET_ZONE_FROM_SEG(sbi, curseg->segno);
+
+If secs_per_zone is corrupted due to fuzzing test, it will cause divide
+zero operation when using GET_ZONE_FROM_SEG macro, so we should do more
+sanity check with secs_per_zone during mount to avoid this issue.
+
+Signed-off-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/f2fs/super.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
+index c3e1090e7c0a..084ff9c82a37 100644
+--- a/fs/f2fs/super.c
++++ b/fs/f2fs/super.c
+@@ -1904,9 +1904,9 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi,
+ return 1;
+ }
+
+- if (secs_per_zone > total_sections) {
++ if (secs_per_zone > total_sections || !secs_per_zone) {
+ f2fs_msg(sb, KERN_INFO,
+- "Wrong secs_per_zone (%u > %u)",
++ "Wrong secs_per_zone / total_sections (%u, %u)",
+ secs_per_zone, total_sections);
+ return 1;
+ }
+--
+2.17.1
+
--- /dev/null
+From 541ea5aaed0979a635b3552db12a4f724cd62a73 Mon Sep 17 00:00:00 2001
+From: Chao Yu <yuchao0@huawei.com>
+Date: Wed, 27 Jun 2018 18:05:54 +0800
+Subject: f2fs: fix to do sanity check with user_block_count
+
+commit 9dc956b2c8523aed39d1e6508438be9fea28c8fc upstream.
+
+This patch fixs to do sanity check with user_block_count.
+
+- Overview
+Divide zero in utilization when mount() a corrupted f2fs image
+
+- Reproduce (4.18 upstream kernel)
+
+- Kernel message
+[ 564.099503] F2FS-fs (loop0): invalid crc value
+[ 564.101991] divide error: 0000 [#1] SMP KASAN PTI
+[ 564.103103] CPU: 1 PID: 1298 Comm: f2fs_discard-7: Not tainted 4.18.0-rc1+ #4
+[ 564.104584] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[ 564.106624] RIP: 0010:issue_discard_thread+0x248/0x5c0
+[ 564.107692] Code: ff ff 48 8b bd e8 fe ff ff 41 8b 9d 4c 04 00 00 e8 cd b8 ad ff 41 8b 85 50 04 00 00 31 d2 48 8d 04 80 48 8d 04 80 48 c1 e0 02 <48> f7 f3 83 f8 50 7e 16 41 c7 86 7c ff ff ff 01 00 00 00 41 c7 86
+[ 564.111686] RSP: 0018:ffff8801f3117dc0 EFLAGS: 00010206
+[ 564.112775] RAX: 0000000000000384 RBX: 0000000000000000 RCX: ffffffffb88c1e03
+[ 564.114250] RDX: 0000000000000000 RSI: dffffc0000000000 RDI: ffff8801e3aa4850
+[ 564.115706] RBP: ffff8801f3117f00 R08: 1ffffffff751a1d0 R09: fffffbfff751a1d0
+[ 564.117177] R10: 0000000000000001 R11: fffffbfff751a1d0 R12: 00000000fffffffc
+[ 564.118634] R13: ffff8801e3aa4400 R14: ffff8801f3117ed8 R15: ffff8801e2050000
+[ 564.120094] FS: 0000000000000000(0000) GS:ffff8801f6f00000(0000) knlGS:0000000000000000
+[ 564.121748] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[ 564.122923] CR2: 000000000202b078 CR3: 00000001f11ac000 CR4: 00000000000006e0
+[ 564.124383] Call Trace:
+[ 564.124924] ? __issue_discard_cmd+0x480/0x480
+[ 564.125882] ? __sched_text_start+0x8/0x8
+[ 564.126756] ? __kthread_parkme+0xcb/0x100
+[ 564.127620] ? kthread_blkcg+0x70/0x70
+[ 564.128412] kthread+0x180/0x1d0
+[ 564.129105] ? __issue_discard_cmd+0x480/0x480
+[ 564.130029] ? kthread_associate_blkcg+0x150/0x150
+[ 564.131033] ret_from_fork+0x35/0x40
+[ 564.131794] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd mac_hid i2c_piix4 soundcore ib_iser rdma_cm iw_cm ib_cm ib_core iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx raid1 raid0 multipath linear 8139too crct10dif_pclmul crc32_pclmul qxl drm_kms_helper syscopyarea aesni_intel sysfillrect sysimgblt fb_sys_fops ttm drm aes_x86_64 crypto_simd cryptd 8139cp glue_helper mii pata_acpi floppy
+[ 564.141798] ---[ end trace 4ce02f25ff7d3df5 ]---
+[ 564.142773] RIP: 0010:issue_discard_thread+0x248/0x5c0
+[ 564.143885] Code: ff ff 48 8b bd e8 fe ff ff 41 8b 9d 4c 04 00 00 e8 cd b8 ad ff 41 8b 85 50 04 00 00 31 d2 48 8d 04 80 48 8d 04 80 48 c1 e0 02 <48> f7 f3 83 f8 50 7e 16 41 c7 86 7c ff ff ff 01 00 00 00 41 c7 86
+[ 564.147776] RSP: 0018:ffff8801f3117dc0 EFLAGS: 00010206
+[ 564.148856] RAX: 0000000000000384 RBX: 0000000000000000 RCX: ffffffffb88c1e03
+[ 564.150424] RDX: 0000000000000000 RSI: dffffc0000000000 RDI: ffff8801e3aa4850
+[ 564.151906] RBP: ffff8801f3117f00 R08: 1ffffffff751a1d0 R09: fffffbfff751a1d0
+[ 564.153463] R10: 0000000000000001 R11: fffffbfff751a1d0 R12: 00000000fffffffc
+[ 564.154915] R13: ffff8801e3aa4400 R14: ffff8801f3117ed8 R15: ffff8801e2050000
+[ 564.156405] FS: 0000000000000000(0000) GS:ffff8801f6f00000(0000) knlGS:0000000000000000
+[ 564.158070] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[ 564.159279] CR2: 000000000202b078 CR3: 00000001f11ac000 CR4: 00000000000006e0
+[ 564.161043] ==================================================================
+[ 564.162587] BUG: KASAN: stack-out-of-bounds in from_kuid_munged+0x1d/0x50
+[ 564.163994] Read of size 4 at addr ffff8801f3117c84 by task f2fs_discard-7:/1298
+
+[ 564.165852] CPU: 1 PID: 1298 Comm: f2fs_discard-7: Tainted: G D 4.18.0-rc1+ #4
+[ 564.167593] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[ 564.169522] Call Trace:
+[ 564.170057] dump_stack+0x7b/0xb5
+[ 564.170778] print_address_description+0x70/0x290
+[ 564.171765] kasan_report+0x291/0x390
+[ 564.172540] ? from_kuid_munged+0x1d/0x50
+[ 564.173408] __asan_load4+0x78/0x80
+[ 564.174148] from_kuid_munged+0x1d/0x50
+[ 564.174962] do_notify_parent+0x1f5/0x4f0
+[ 564.175808] ? send_sigqueue+0x390/0x390
+[ 564.176639] ? css_set_move_task+0x152/0x340
+[ 564.184197] do_exit+0x1290/0x1390
+[ 564.184950] ? __issue_discard_cmd+0x480/0x480
+[ 564.185884] ? mm_update_next_owner+0x380/0x380
+[ 564.186829] ? __sched_text_start+0x8/0x8
+[ 564.187672] ? __kthread_parkme+0xcb/0x100
+[ 564.188528] ? kthread_blkcg+0x70/0x70
+[ 564.189333] ? kthread+0x180/0x1d0
+[ 564.190052] ? __issue_discard_cmd+0x480/0x480
+[ 564.190983] rewind_stack_do_exit+0x17/0x20
+
+[ 564.192190] The buggy address belongs to the page:
+[ 564.193213] page:ffffea0007cc45c0 count:0 mapcount:0 mapping:0000000000000000 index:0x0
+[ 564.194856] flags: 0x2ffff0000000000()
+[ 564.195644] raw: 02ffff0000000000 0000000000000000 dead000000000200 0000000000000000
+[ 564.197247] raw: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000000
+[ 564.198826] page dumped because: kasan: bad access detected
+
+[ 564.200299] Memory state around the buggy address:
+[ 564.201306] ffff8801f3117b80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[ 564.202779] ffff8801f3117c00: 00 00 00 00 00 00 00 00 00 00 00 f3 f3 f3 f3 f3
+[ 564.204252] >ffff8801f3117c80: f3 f3 f3 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1
+[ 564.205742] ^
+[ 564.206424] ffff8801f3117d00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[ 564.207908] ffff8801f3117d80: f3 f3 f3 f3 f3 f3 f3 f3 00 00 00 00 00 00 00 00
+[ 564.209389] ==================================================================
+[ 564.231795] F2FS-fs (loop0): Mounted with checkpoint version = 2
+
+- Location
+https://elixir.bootlin.com/linux/v4.18-rc1/source/fs/f2fs/segment.h#L586
+ return div_u64((u64)valid_user_blocks(sbi) * 100,
+ sbi->user_block_count);
+Missing checks on sbi->user_block_count.
+
+Reported-by: Wen Xu <wen.xu@gatech.edu>
+Signed-off-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/f2fs/super.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
+index 084ff9c82a37..9fafb1404f39 100644
+--- a/fs/f2fs/super.c
++++ b/fs/f2fs/super.c
+@@ -1956,6 +1956,8 @@ int sanity_check_ckpt(struct f2fs_sb_info *sbi)
+ unsigned int sit_segs, nat_segs;
+ unsigned int sit_bitmap_size, nat_bitmap_size;
+ unsigned int log_blocks_per_seg;
++ unsigned int segment_count_main;
++ block_t user_block_count;
+ int i;
+
+ total = le32_to_cpu(raw_super->segment_count);
+@@ -1980,6 +1982,16 @@ int sanity_check_ckpt(struct f2fs_sb_info *sbi)
+ return 1;
+ }
+
++ user_block_count = le64_to_cpu(ckpt->user_block_count);
++ segment_count_main = le32_to_cpu(raw_super->segment_count_main);
++ log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg);
++ if (!user_block_count || user_block_count >=
++ segment_count_main << log_blocks_per_seg) {
++ f2fs_msg(sbi->sb, KERN_ERR,
++ "Wrong user_block_count: %u", user_block_count);
++ return 1;
++ }
++
+ main_segs = le32_to_cpu(raw_super->segment_count_main);
+ blocks_per_seg = sbi->blocks_per_seg;
+
+@@ -1996,7 +2008,6 @@ int sanity_check_ckpt(struct f2fs_sb_info *sbi)
+
+ sit_bitmap_size = le32_to_cpu(ckpt->sit_ver_bitmap_bytesize);
+ nat_bitmap_size = le32_to_cpu(ckpt->nat_ver_bitmap_bytesize);
+- log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg);
+
+ if (sit_bitmap_size != ((sit_segs / 2) << log_blocks_per_seg) / 8 ||
+ nat_bitmap_size != ((nat_segs / 2) << log_blocks_per_seg) / 8) {
+--
+2.17.1
+
--- /dev/null
+From ab3a3eca9f4d090652c5575a0631642dffb8b367 Mon Sep 17 00:00:00 2001
+From: Chao Yu <yuchao0@huawei.com>
+Date: Tue, 5 Jun 2018 17:44:11 +0800
+Subject: f2fs: introduce and spread verify_blkaddr
+
+commit e1da7872f6eda977bd812346bf588c35e4495a1e upstream.
+
+This patch introduces verify_blkaddr to check meta/data block address
+with valid range to detect bug earlier.
+
+In addition, once we encounter an invalid blkaddr, notice user to run
+fsck to fix, and let the kernel panic.
+
+Signed-off-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Backported to 4.14: I skipped an earlier renaming of
+ is_valid_meta_blkaddr() to f2fs_is_valid_meta_blkaddr()]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/f2fs/checkpoint.c | 11 +++++++++--
+ fs/f2fs/data.c | 8 ++++----
+ fs/f2fs/f2fs.h | 32 +++++++++++++++++++++++++++++---
+ fs/f2fs/file.c | 9 +++++----
+ fs/f2fs/inode.c | 7 ++++---
+ fs/f2fs/node.c | 4 ++--
+ fs/f2fs/recovery.c | 6 +++---
+ fs/f2fs/segment.c | 4 ++--
+ fs/f2fs/segment.h | 8 +++-----
+ 9 files changed, 61 insertions(+), 28 deletions(-)
+
+diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
+index 2b951046657e..d7bd9745e883 100644
+--- a/fs/f2fs/checkpoint.c
++++ b/fs/f2fs/checkpoint.c
+@@ -118,7 +118,8 @@ struct page *get_tmp_page(struct f2fs_sb_info *sbi, pgoff_t index)
+ return __get_meta_page(sbi, index, false);
+ }
+
+-bool is_valid_meta_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type)
++bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
++ block_t blkaddr, int type)
+ {
+ switch (type) {
+ case META_NAT:
+@@ -138,10 +139,16 @@ bool is_valid_meta_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type)
+ return false;
+ break;
+ case META_POR:
++ case DATA_GENERIC:
+ if (unlikely(blkaddr >= MAX_BLKADDR(sbi) ||
+ blkaddr < MAIN_BLKADDR(sbi)))
+ return false;
+ break;
++ case META_GENERIC:
++ if (unlikely(blkaddr < SEG0_BLKADDR(sbi) ||
++ blkaddr >= MAIN_BLKADDR(sbi)))
++ return false;
++ break;
+ default:
+ BUG();
+ }
+@@ -174,7 +181,7 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
+ blk_start_plug(&plug);
+ for (; nrpages-- > 0; blkno++) {
+
+- if (!is_valid_meta_blkaddr(sbi, blkno, type))
++ if (!f2fs_is_valid_blkaddr(sbi, blkno, type))
+ goto out;
+
+ switch (type) {
+diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
+index f7b2909e9c5f..615878806611 100644
+--- a/fs/f2fs/data.c
++++ b/fs/f2fs/data.c
+@@ -413,7 +413,7 @@ next:
+ spin_unlock(&io->io_lock);
+ }
+
+- if (is_valid_blkaddr(fio->old_blkaddr))
++ if (__is_valid_data_blkaddr(fio->old_blkaddr))
+ verify_block_addr(fio, fio->old_blkaddr);
+ verify_block_addr(fio, fio->new_blkaddr);
+
+@@ -946,7 +946,7 @@ next_dnode:
+ next_block:
+ blkaddr = datablock_addr(dn.inode, dn.node_page, dn.ofs_in_node);
+
+- if (!is_valid_blkaddr(blkaddr)) {
++ if (!is_valid_data_blkaddr(sbi, blkaddr)) {
+ if (create) {
+ if (unlikely(f2fs_cp_error(sbi))) {
+ err = -EIO;
+@@ -1402,7 +1402,7 @@ int do_write_data_page(struct f2fs_io_info *fio)
+ f2fs_lookup_extent_cache(inode, page->index, &ei)) {
+ fio->old_blkaddr = ei.blk + page->index - ei.fofs;
+
+- if (is_valid_blkaddr(fio->old_blkaddr)) {
++ if (is_valid_data_blkaddr(fio->sbi, fio->old_blkaddr)) {
+ ipu_force = true;
+ fio->need_lock = LOCK_DONE;
+ goto got_it;
+@@ -1429,7 +1429,7 @@ got_it:
+ * If current allocation needs SSR,
+ * it had better in-place writes for updated data.
+ */
+- if (ipu_force || (is_valid_blkaddr(fio->old_blkaddr) &&
++ if (ipu_force || (is_valid_data_blkaddr(fio->sbi, fio->old_blkaddr) &&
+ need_inplace_update(fio))) {
+ err = encrypt_one_page(fio);
+ if (err)
+diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
+index d74c77b51b71..d15d79457f5c 100644
+--- a/fs/f2fs/f2fs.h
++++ b/fs/f2fs/f2fs.h
+@@ -162,7 +162,7 @@ struct cp_control {
+ };
+
+ /*
+- * For CP/NAT/SIT/SSA readahead
++ * indicate meta/data type
+ */
+ enum {
+ META_CP,
+@@ -170,6 +170,8 @@ enum {
+ META_SIT,
+ META_SSA,
+ META_POR,
++ DATA_GENERIC,
++ META_GENERIC,
+ };
+
+ /* for the list of ino */
+@@ -2355,13 +2357,36 @@ static inline void f2fs_update_iostat(struct f2fs_sb_info *sbi,
+ spin_unlock(&sbi->iostat_lock);
+ }
+
+-static inline bool is_valid_blkaddr(block_t blkaddr)
++bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
++ block_t blkaddr, int type);
++void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...);
++static inline void verify_blkaddr(struct f2fs_sb_info *sbi,
++ block_t blkaddr, int type)
++{
++ if (!f2fs_is_valid_blkaddr(sbi, blkaddr, type)) {
++ f2fs_msg(sbi->sb, KERN_ERR,
++ "invalid blkaddr: %u, type: %d, run fsck to fix.",
++ blkaddr, type);
++ f2fs_bug_on(sbi, 1);
++ }
++}
++
++static inline bool __is_valid_data_blkaddr(block_t blkaddr)
+ {
+ if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR)
+ return false;
+ return true;
+ }
+
++static inline bool is_valid_data_blkaddr(struct f2fs_sb_info *sbi,
++ block_t blkaddr)
++{
++ if (!__is_valid_data_blkaddr(blkaddr))
++ return false;
++ verify_blkaddr(sbi, blkaddr, DATA_GENERIC);
++ return true;
++}
++
+ /*
+ * file.c
+ */
+@@ -2572,7 +2597,8 @@ void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io);
+ struct page *grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index);
+ struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index);
+ struct page *get_tmp_page(struct f2fs_sb_info *sbi, pgoff_t index);
+-bool is_valid_meta_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type);
++bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
++ block_t blkaddr, int type);
+ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
+ int type, bool sync);
+ void ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index);
+diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
+index d368eda462bb..e9c575ef70b5 100644
+--- a/fs/f2fs/file.c
++++ b/fs/f2fs/file.c
+@@ -328,13 +328,13 @@ static pgoff_t __get_first_dirty_index(struct address_space *mapping,
+ return pgofs;
+ }
+
+-static bool __found_offset(block_t blkaddr, pgoff_t dirty, pgoff_t pgofs,
+- int whence)
++static bool __found_offset(struct f2fs_sb_info *sbi, block_t blkaddr,
++ pgoff_t dirty, pgoff_t pgofs, int whence)
+ {
+ switch (whence) {
+ case SEEK_DATA:
+ if ((blkaddr == NEW_ADDR && dirty == pgofs) ||
+- is_valid_blkaddr(blkaddr))
++ is_valid_data_blkaddr(sbi, blkaddr))
+ return true;
+ break;
+ case SEEK_HOLE:
+@@ -397,7 +397,8 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
+ blkaddr = datablock_addr(dn.inode,
+ dn.node_page, dn.ofs_in_node);
+
+- if (__found_offset(blkaddr, dirty, pgofs, whence)) {
++ if (__found_offset(F2FS_I_SB(inode), blkaddr, dirty,
++ pgofs, whence)) {
+ f2fs_put_dnode(&dn);
+ goto found;
+ }
+diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
+index 2bcbbf566f0c..b1c0eb433841 100644
+--- a/fs/f2fs/inode.c
++++ b/fs/f2fs/inode.c
+@@ -62,11 +62,12 @@ static void __get_inode_rdev(struct inode *inode, struct f2fs_inode *ri)
+ }
+ }
+
+-static bool __written_first_block(struct f2fs_inode *ri)
++static bool __written_first_block(struct f2fs_sb_info *sbi,
++ struct f2fs_inode *ri)
+ {
+ block_t addr = le32_to_cpu(ri->i_addr[offset_in_addr(ri)]);
+
+- if (is_valid_blkaddr(addr))
++ if (is_valid_data_blkaddr(sbi, addr))
+ return true;
+ return false;
+ }
+@@ -235,7 +236,7 @@ static int do_read_inode(struct inode *inode)
+ /* get rdev by using inline_info */
+ __get_inode_rdev(inode, ri);
+
+- if (__written_first_block(ri))
++ if (__written_first_block(sbi, ri))
+ set_inode_flag(inode, FI_FIRST_BLOCK_WRITTEN);
+
+ if (!need_inode_block_update(sbi, inode->i_ino))
+diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
+index 5f212fb2d62b..999814c8cbea 100644
+--- a/fs/f2fs/node.c
++++ b/fs/f2fs/node.c
+@@ -334,7 +334,7 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
+ new_blkaddr == NULL_ADDR);
+ f2fs_bug_on(sbi, nat_get_blkaddr(e) == NEW_ADDR &&
+ new_blkaddr == NEW_ADDR);
+- f2fs_bug_on(sbi, is_valid_blkaddr(nat_get_blkaddr(e)) &&
++ f2fs_bug_on(sbi, is_valid_data_blkaddr(sbi, nat_get_blkaddr(e)) &&
+ new_blkaddr == NEW_ADDR);
+
+ /* increment version no as node is removed */
+@@ -349,7 +349,7 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
+
+ /* change address */
+ nat_set_blkaddr(e, new_blkaddr);
+- if (!is_valid_blkaddr(new_blkaddr))
++ if (!is_valid_data_blkaddr(sbi, new_blkaddr))
+ set_nat_flag(e, IS_CHECKPOINTED, false);
+ __set_nat_cache_dirty(nm_i, e);
+
+diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
+index 53f41ad4cbe1..6ea445377767 100644
+--- a/fs/f2fs/recovery.c
++++ b/fs/f2fs/recovery.c
+@@ -236,7 +236,7 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head,
+ while (1) {
+ struct fsync_inode_entry *entry;
+
+- if (!is_valid_meta_blkaddr(sbi, blkaddr, META_POR))
++ if (!f2fs_is_valid_blkaddr(sbi, blkaddr, META_POR))
+ return 0;
+
+ page = get_tmp_page(sbi, blkaddr);
+@@ -479,7 +479,7 @@ retry_dn:
+ }
+
+ /* dest is valid block, try to recover from src to dest */
+- if (is_valid_meta_blkaddr(sbi, dest, META_POR)) {
++ if (f2fs_is_valid_blkaddr(sbi, dest, META_POR)) {
+
+ if (src == NULL_ADDR) {
+ err = reserve_new_block(&dn);
+@@ -540,7 +540,7 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
+ while (1) {
+ struct fsync_inode_entry *entry;
+
+- if (!is_valid_meta_blkaddr(sbi, blkaddr, META_POR))
++ if (!f2fs_is_valid_blkaddr(sbi, blkaddr, META_POR))
+ break;
+
+ ra_meta_pages_cond(sbi, blkaddr);
+diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
+index 483d7a869679..5c698757e116 100644
+--- a/fs/f2fs/segment.c
++++ b/fs/f2fs/segment.c
+@@ -1758,7 +1758,7 @@ bool is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr)
+ struct seg_entry *se;
+ bool is_cp = false;
+
+- if (!is_valid_blkaddr(blkaddr))
++ if (!is_valid_data_blkaddr(sbi, blkaddr))
+ return true;
+
+ mutex_lock(&sit_i->sentry_lock);
+@@ -2571,7 +2571,7 @@ void f2fs_wait_on_block_writeback(struct f2fs_sb_info *sbi, block_t blkaddr)
+ {
+ struct page *cpage;
+
+- if (!is_valid_blkaddr(blkaddr))
++ if (!is_valid_data_blkaddr(sbi, blkaddr))
+ return;
+
+ cpage = find_lock_page(META_MAPPING(sbi), blkaddr);
+diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
+index f977774338c3..dd8f977fc273 100644
+--- a/fs/f2fs/segment.h
++++ b/fs/f2fs/segment.h
+@@ -85,7 +85,7 @@
+ (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) & ((sbi)->blocks_per_seg - 1))
+
+ #define GET_SEGNO(sbi, blk_addr) \
+- ((!is_valid_blkaddr(blk_addr)) ? \
++ ((!is_valid_data_blkaddr(sbi, blk_addr)) ? \
+ NULL_SEGNO : GET_L2R_SEGNO(FREE_I(sbi), \
+ GET_SEGNO_FROM_SEG0(sbi, blk_addr)))
+ #define BLKS_PER_SEC(sbi) \
+@@ -631,11 +631,9 @@ static inline void verify_block_addr(struct f2fs_io_info *fio, block_t blk_addr)
+
+ if (PAGE_TYPE_OF_BIO(fio->type) == META &&
+ (!is_read_io(fio->op) || fio->is_meta))
+- BUG_ON(blk_addr < SEG0_BLKADDR(sbi) ||
+- blk_addr >= MAIN_BLKADDR(sbi));
++ verify_blkaddr(sbi, blk_addr, META_GENERIC);
+ else
+- BUG_ON(blk_addr < MAIN_BLKADDR(sbi) ||
+- blk_addr >= MAX_BLKADDR(sbi));
++ verify_blkaddr(sbi, blk_addr, DATA_GENERIC);
+ }
+
+ /*
+--
+2.17.1
+
--- /dev/null
+From d4c155202fe9130693f1fb4584ba4bfe5394d0cb Mon Sep 17 00:00:00 2001
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+Date: Tue, 24 Apr 2018 15:44:16 -0600
+Subject: f2fs: sanity check on sit entry
+
+commit b2ca374f33bd33fd822eb871876e4888cf79dc97 upstream.
+
+syzbot hit the following crash on upstream commit
+87ef12027b9b1dd0e0b12cf311fbcb19f9d92539 (Wed Apr 18 19:48:17 2018 +0000)
+Merge tag 'ceph-for-4.17-rc2' of git://github.com/ceph/ceph-client
+syzbot dashboard link: https://syzkaller.appspot.com/bug?extid=83699adeb2d13579c31e
+
+C reproducer: https://syzkaller.appspot.com/x/repro.c?id=5805208181407744
+syzkaller reproducer: https://syzkaller.appspot.com/x/repro.syz?id=6005073343676416
+Raw console output: https://syzkaller.appspot.com/x/log.txt?id=6555047731134464
+Kernel config: https://syzkaller.appspot.com/x/.config?id=1808800213120130118
+compiler: gcc (GCC) 8.0.1 20180413 (experimental)
+
+IMPORTANT: if you fix the bug, please add the following tag to the commit:
+Reported-by: syzbot+83699adeb2d13579c31e@syzkaller.appspotmail.com
+It will help syzbot understand when the bug is fixed. See footer for details.
+If you forward the report, please keep this part and the footer.
+
+F2FS-fs (loop0): Magic Mismatch, valid(0xf2f52010) - read(0x0)
+F2FS-fs (loop0): Can't find valid F2FS filesystem in 1th superblock
+F2FS-fs (loop0): invalid crc value
+BUG: unable to handle kernel paging request at ffffed006b2a50c0
+PGD 21ffee067 P4D 21ffee067 PUD 21fbeb067 PMD 0
+Oops: 0000 [#1] SMP KASAN
+Dumping ftrace buffer:
+ (ftrace buffer empty)
+Modules linked in:
+CPU: 0 PID: 4514 Comm: syzkaller989480 Not tainted 4.17.0-rc1+ #8
+Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
+RIP: 0010:build_sit_entries fs/f2fs/segment.c:3653 [inline]
+RIP: 0010:build_segment_manager+0x7ef7/0xbf70 fs/f2fs/segment.c:3852
+RSP: 0018:ffff8801b102e5b0 EFLAGS: 00010a06
+RAX: 1ffff1006b2a50c0 RBX: 0000000000000004 RCX: 0000000000000001
+RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff8801ac74243e
+RBP: ffff8801b102f410 R08: ffff8801acbd46c0 R09: fffffbfff14d9af8
+R10: fffffbfff14d9af8 R11: ffff8801acbd46c0 R12: ffff8801ac742a80
+R13: ffff8801d9519100 R14: dffffc0000000000 R15: ffff880359528600
+FS: 0000000001e04880(0000) GS:ffff8801dae00000(0000) knlGS:0000000000000000
+CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+CR2: ffffed006b2a50c0 CR3: 00000001ac6ac000 CR4: 00000000001406f0
+DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
+DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
+Call Trace:
+ f2fs_fill_super+0x4095/0x7bf0 fs/f2fs/super.c:2803
+ mount_bdev+0x30c/0x3e0 fs/super.c:1165
+ f2fs_mount+0x34/0x40 fs/f2fs/super.c:3020
+ mount_fs+0xae/0x328 fs/super.c:1268
+ vfs_kern_mount.part.34+0xd4/0x4d0 fs/namespace.c:1037
+ vfs_kern_mount fs/namespace.c:1027 [inline]
+ do_new_mount fs/namespace.c:2517 [inline]
+ do_mount+0x564/0x3070 fs/namespace.c:2847
+ ksys_mount+0x12d/0x140 fs/namespace.c:3063
+ __do_sys_mount fs/namespace.c:3077 [inline]
+ __se_sys_mount fs/namespace.c:3074 [inline]
+ __x64_sys_mount+0xbe/0x150 fs/namespace.c:3074
+ do_syscall_64+0x1b1/0x800 arch/x86/entry/common.c:287
+ entry_SYSCALL_64_after_hwframe+0x49/0xbe
+RIP: 0033:0x443d6a
+RSP: 002b:00007ffd312813c8 EFLAGS: 00000297 ORIG_RAX: 00000000000000a5
+RAX: ffffffffffffffda RBX: 0000000020000c00 RCX: 0000000000443d6a
+RDX: 0000000020000000 RSI: 0000000020000100 RDI: 00007ffd312813d0
+RBP: 0000000000000003 R08: 0000000020016a00 R09: 000000000000000a
+R10: 0000000000000000 R11: 0000000000000297 R12: 0000000000000004
+R13: 0000000000402c60 R14: 0000000000000000 R15: 0000000000000000
+RIP: build_sit_entries fs/f2fs/segment.c:3653 [inline] RSP: ffff8801b102e5b0
+RIP: build_segment_manager+0x7ef7/0xbf70 fs/f2fs/segment.c:3852 RSP: ffff8801b102e5b0
+CR2: ffffed006b2a50c0
+---[ end trace a2034989e196ff17 ]---
+
+Reported-and-tested-by: syzbot+83699adeb2d13579c31e@syzkaller.appspotmail.com
+Reviewed-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/f2fs/segment.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
+index 3c7bbbae0afa..1104a6c80251 100644
+--- a/fs/f2fs/segment.c
++++ b/fs/f2fs/segment.c
+@@ -3304,6 +3304,15 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
+ unsigned int old_valid_blocks;
+
+ start = le32_to_cpu(segno_in_journal(journal, i));
++ if (start >= MAIN_SEGS(sbi)) {
++ f2fs_msg(sbi->sb, KERN_ERR,
++ "Wrong journal entry on segno %u",
++ start);
++ set_sbi_flag(sbi, SBI_NEED_FSCK);
++ err = -EINVAL;
++ break;
++ }
++
+ se = &sit_i->sentries[start];
+ sit = sit_in_journal(journal, i);
+
+--
+2.17.1
+
--- /dev/null
+From fc90ac4eb1eefac7eecd005a524e49b630012fc1 Mon Sep 17 00:00:00 2001
+From: Ilya Dryomov <idryomov@gmail.com>
+Date: Fri, 27 Jul 2018 19:18:34 +0200
+Subject: libceph: add authorizer challenge
+
+commit 6daca13d2e72bedaaacfc08f873114c9307d5aea upstream.
+
+When a client authenticates with a service, an authorizer is sent with
+a nonce to the service (ceph_x_authorize_[ab]) and the service responds
+with a mutation of that nonce (ceph_x_authorize_reply). This lets the
+client verify the service is who it says it is but it doesn't protect
+against a replay: someone can trivially capture the exchange and reuse
+the same authorizer to authenticate themselves.
+
+Allow the service to reject an initial authorizer with a random
+challenge (ceph_x_authorize_challenge). The client then has to respond
+with an updated authorizer proving they are able to decrypt the
+service's challenge and that the new authorizer was produced for this
+specific connection instance.
+
+The accepting side requires this challenge and response unconditionally
+if the client side advertises they have CEPHX_V2 feature bit.
+
+This addresses CVE-2018-1128.
+
+Link: http://tracker.ceph.com/issues/24836
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+Reviewed-by: Sage Weil <sage@redhat.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ceph/mds_client.c | 11 ++++++
+ include/linux/ceph/auth.h | 8 ++++
+ include/linux/ceph/messenger.h | 3 ++
+ include/linux/ceph/msgr.h | 2 +-
+ net/ceph/auth.c | 16 ++++++++
+ net/ceph/auth_x.c | 72 +++++++++++++++++++++++++++++++---
+ net/ceph/auth_x_protocol.h | 7 ++++
+ net/ceph/messenger.c | 17 +++++++-
+ net/ceph/osd_client.c | 11 ++++++
+ 9 files changed, 140 insertions(+), 7 deletions(-)
+
+diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
+index bf378ddca4db..a48984dd6426 100644
+--- a/fs/ceph/mds_client.c
++++ b/fs/ceph/mds_client.c
+@@ -4079,6 +4079,16 @@ static struct ceph_auth_handshake *get_authorizer(struct ceph_connection *con,
+ return auth;
+ }
+
++static int add_authorizer_challenge(struct ceph_connection *con,
++ void *challenge_buf, int challenge_buf_len)
++{
++ struct ceph_mds_session *s = con->private;
++ struct ceph_mds_client *mdsc = s->s_mdsc;
++ struct ceph_auth_client *ac = mdsc->fsc->client->monc.auth;
++
++ return ceph_auth_add_authorizer_challenge(ac, s->s_auth.authorizer,
++ challenge_buf, challenge_buf_len);
++}
+
+ static int verify_authorizer_reply(struct ceph_connection *con)
+ {
+@@ -4142,6 +4152,7 @@ static const struct ceph_connection_operations mds_con_ops = {
+ .put = con_put,
+ .dispatch = dispatch,
+ .get_authorizer = get_authorizer,
++ .add_authorizer_challenge = add_authorizer_challenge,
+ .verify_authorizer_reply = verify_authorizer_reply,
+ .invalidate_authorizer = invalidate_authorizer,
+ .peer_reset = peer_reset,
+diff --git a/include/linux/ceph/auth.h b/include/linux/ceph/auth.h
+index e931da8424a4..6728c2ee0205 100644
+--- a/include/linux/ceph/auth.h
++++ b/include/linux/ceph/auth.h
+@@ -64,6 +64,10 @@ struct ceph_auth_client_ops {
+ /* ensure that an existing authorizer is up to date */
+ int (*update_authorizer)(struct ceph_auth_client *ac, int peer_type,
+ struct ceph_auth_handshake *auth);
++ int (*add_authorizer_challenge)(struct ceph_auth_client *ac,
++ struct ceph_authorizer *a,
++ void *challenge_buf,
++ int challenge_buf_len);
+ int (*verify_authorizer_reply)(struct ceph_auth_client *ac,
+ struct ceph_authorizer *a);
+ void (*invalidate_authorizer)(struct ceph_auth_client *ac,
+@@ -118,6 +122,10 @@ void ceph_auth_destroy_authorizer(struct ceph_authorizer *a);
+ extern int ceph_auth_update_authorizer(struct ceph_auth_client *ac,
+ int peer_type,
+ struct ceph_auth_handshake *a);
++int ceph_auth_add_authorizer_challenge(struct ceph_auth_client *ac,
++ struct ceph_authorizer *a,
++ void *challenge_buf,
++ int challenge_buf_len);
+ extern int ceph_auth_verify_authorizer_reply(struct ceph_auth_client *ac,
+ struct ceph_authorizer *a);
+ extern void ceph_auth_invalidate_authorizer(struct ceph_auth_client *ac,
+diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h
+index 9056077c023f..18fbe910ed55 100644
+--- a/include/linux/ceph/messenger.h
++++ b/include/linux/ceph/messenger.h
+@@ -31,6 +31,9 @@ struct ceph_connection_operations {
+ struct ceph_auth_handshake *(*get_authorizer) (
+ struct ceph_connection *con,
+ int *proto, int force_new);
++ int (*add_authorizer_challenge)(struct ceph_connection *con,
++ void *challenge_buf,
++ int challenge_buf_len);
+ int (*verify_authorizer_reply) (struct ceph_connection *con);
+ int (*invalidate_authorizer)(struct ceph_connection *con);
+
+diff --git a/include/linux/ceph/msgr.h b/include/linux/ceph/msgr.h
+index 73ae2a926548..9e50aede46c8 100644
+--- a/include/linux/ceph/msgr.h
++++ b/include/linux/ceph/msgr.h
+@@ -91,7 +91,7 @@ struct ceph_entity_inst {
+ #define CEPH_MSGR_TAG_SEQ 13 /* 64-bit int follows with seen seq number */
+ #define CEPH_MSGR_TAG_KEEPALIVE2 14 /* keepalive2 byte + ceph_timespec */
+ #define CEPH_MSGR_TAG_KEEPALIVE2_ACK 15 /* keepalive2 reply */
+-
++#define CEPH_MSGR_TAG_CHALLENGE_AUTHORIZER 16 /* cephx v2 doing server challenge */
+
+ /*
+ * connection negotiation
+diff --git a/net/ceph/auth.c b/net/ceph/auth.c
+index dbde2b3c3c15..fbeee068ea14 100644
+--- a/net/ceph/auth.c
++++ b/net/ceph/auth.c
+@@ -315,6 +315,22 @@ int ceph_auth_update_authorizer(struct ceph_auth_client *ac,
+ }
+ EXPORT_SYMBOL(ceph_auth_update_authorizer);
+
++int ceph_auth_add_authorizer_challenge(struct ceph_auth_client *ac,
++ struct ceph_authorizer *a,
++ void *challenge_buf,
++ int challenge_buf_len)
++{
++ int ret = 0;
++
++ mutex_lock(&ac->mutex);
++ if (ac->ops && ac->ops->add_authorizer_challenge)
++ ret = ac->ops->add_authorizer_challenge(ac, a, challenge_buf,
++ challenge_buf_len);
++ mutex_unlock(&ac->mutex);
++ return ret;
++}
++EXPORT_SYMBOL(ceph_auth_add_authorizer_challenge);
++
+ int ceph_auth_verify_authorizer_reply(struct ceph_auth_client *ac,
+ struct ceph_authorizer *a)
+ {
+diff --git a/net/ceph/auth_x.c b/net/ceph/auth_x.c
+index 722791f45b2a..ce28bb07d8fd 100644
+--- a/net/ceph/auth_x.c
++++ b/net/ceph/auth_x.c
+@@ -295,7 +295,8 @@ bad:
+ * authorizer. The first part (ceph_x_authorize_a) should already be
+ * encoded.
+ */
+-static int encrypt_authorizer(struct ceph_x_authorizer *au)
++static int encrypt_authorizer(struct ceph_x_authorizer *au,
++ u64 *server_challenge)
+ {
+ struct ceph_x_authorize_a *msg_a;
+ struct ceph_x_authorize_b *msg_b;
+@@ -308,16 +309,28 @@ static int encrypt_authorizer(struct ceph_x_authorizer *au)
+ end = au->buf->vec.iov_base + au->buf->vec.iov_len;
+
+ msg_b = p + ceph_x_encrypt_offset();
+- msg_b->struct_v = 1;
++ msg_b->struct_v = 2;
+ msg_b->nonce = cpu_to_le64(au->nonce);
++ if (server_challenge) {
++ msg_b->have_challenge = 1;
++ msg_b->server_challenge_plus_one =
++ cpu_to_le64(*server_challenge + 1);
++ } else {
++ msg_b->have_challenge = 0;
++ msg_b->server_challenge_plus_one = 0;
++ }
+
+ ret = ceph_x_encrypt(&au->session_key, p, end - p, sizeof(*msg_b));
+ if (ret < 0)
+ return ret;
+
+ p += ret;
+- WARN_ON(p > end);
+- au->buf->vec.iov_len = p - au->buf->vec.iov_base;
++ if (server_challenge) {
++ WARN_ON(p != end);
++ } else {
++ WARN_ON(p > end);
++ au->buf->vec.iov_len = p - au->buf->vec.iov_base;
++ }
+
+ return 0;
+ }
+@@ -382,7 +395,7 @@ static int ceph_x_build_authorizer(struct ceph_auth_client *ac,
+ le64_to_cpu(msg_a->ticket_blob.secret_id));
+
+ get_random_bytes(&au->nonce, sizeof(au->nonce));
+- ret = encrypt_authorizer(au);
++ ret = encrypt_authorizer(au, NULL);
+ if (ret) {
+ pr_err("failed to encrypt authorizer: %d", ret);
+ goto out_au;
+@@ -664,6 +677,54 @@ static int ceph_x_update_authorizer(
+ return 0;
+ }
+
++static int decrypt_authorize_challenge(struct ceph_x_authorizer *au,
++ void *challenge_buf,
++ int challenge_buf_len,
++ u64 *server_challenge)
++{
++ struct ceph_x_authorize_challenge *ch =
++ challenge_buf + sizeof(struct ceph_x_encrypt_header);
++ int ret;
++
++ /* no leading len */
++ ret = __ceph_x_decrypt(&au->session_key, challenge_buf,
++ challenge_buf_len);
++ if (ret < 0)
++ return ret;
++ if (ret < sizeof(*ch)) {
++ pr_err("bad size %d for ceph_x_authorize_challenge\n", ret);
++ return -EINVAL;
++ }
++
++ *server_challenge = le64_to_cpu(ch->server_challenge);
++ return 0;
++}
++
++static int ceph_x_add_authorizer_challenge(struct ceph_auth_client *ac,
++ struct ceph_authorizer *a,
++ void *challenge_buf,
++ int challenge_buf_len)
++{
++ struct ceph_x_authorizer *au = (void *)a;
++ u64 server_challenge;
++ int ret;
++
++ ret = decrypt_authorize_challenge(au, challenge_buf, challenge_buf_len,
++ &server_challenge);
++ if (ret) {
++ pr_err("failed to decrypt authorize challenge: %d", ret);
++ return ret;
++ }
++
++ ret = encrypt_authorizer(au, &server_challenge);
++ if (ret) {
++ pr_err("failed to encrypt authorizer w/ challenge: %d", ret);
++ return ret;
++ }
++
++ return 0;
++}
++
+ static int ceph_x_verify_authorizer_reply(struct ceph_auth_client *ac,
+ struct ceph_authorizer *a)
+ {
+@@ -816,6 +877,7 @@ static const struct ceph_auth_client_ops ceph_x_ops = {
+ .handle_reply = ceph_x_handle_reply,
+ .create_authorizer = ceph_x_create_authorizer,
+ .update_authorizer = ceph_x_update_authorizer,
++ .add_authorizer_challenge = ceph_x_add_authorizer_challenge,
+ .verify_authorizer_reply = ceph_x_verify_authorizer_reply,
+ .invalidate_authorizer = ceph_x_invalidate_authorizer,
+ .reset = ceph_x_reset,
+diff --git a/net/ceph/auth_x_protocol.h b/net/ceph/auth_x_protocol.h
+index 32c13d763b9a..24b0b74564d0 100644
+--- a/net/ceph/auth_x_protocol.h
++++ b/net/ceph/auth_x_protocol.h
+@@ -70,6 +70,13 @@ struct ceph_x_authorize_a {
+ struct ceph_x_authorize_b {
+ __u8 struct_v;
+ __le64 nonce;
++ __u8 have_challenge;
++ __le64 server_challenge_plus_one;
++} __attribute__ ((packed));
++
++struct ceph_x_authorize_challenge {
++ __u8 struct_v;
++ __le64 server_challenge;
+ } __attribute__ ((packed));
+
+ struct ceph_x_authorize_reply {
+diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
+index 0b121327d32f..ad33baa2008d 100644
+--- a/net/ceph/messenger.c
++++ b/net/ceph/messenger.c
+@@ -2052,9 +2052,24 @@ static int process_connect(struct ceph_connection *con)
+ if (con->auth) {
+ /*
+ * Any connection that defines ->get_authorizer()
+- * should also define ->verify_authorizer_reply().
++ * should also define ->add_authorizer_challenge() and
++ * ->verify_authorizer_reply().
++ *
+ * See get_connect_authorizer().
+ */
++ if (con->in_reply.tag == CEPH_MSGR_TAG_CHALLENGE_AUTHORIZER) {
++ ret = con->ops->add_authorizer_challenge(
++ con, con->auth->authorizer_reply_buf,
++ le32_to_cpu(con->in_reply.authorizer_len));
++ if (ret < 0)
++ return ret;
++
++ con_out_kvec_reset(con);
++ __prepare_write_connect(con);
++ prepare_read_connect(con);
++ return 0;
++ }
++
+ ret = con->ops->verify_authorizer_reply(con);
+ if (ret < 0) {
+ con->error_msg = "bad authorize reply";
+diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c
+index 2814dba5902d..53ea2d48896c 100644
+--- a/net/ceph/osd_client.c
++++ b/net/ceph/osd_client.c
+@@ -5292,6 +5292,16 @@ static struct ceph_auth_handshake *get_authorizer(struct ceph_connection *con,
+ return auth;
+ }
+
++static int add_authorizer_challenge(struct ceph_connection *con,
++ void *challenge_buf, int challenge_buf_len)
++{
++ struct ceph_osd *o = con->private;
++ struct ceph_osd_client *osdc = o->o_osdc;
++ struct ceph_auth_client *ac = osdc->client->monc.auth;
++
++ return ceph_auth_add_authorizer_challenge(ac, o->o_auth.authorizer,
++ challenge_buf, challenge_buf_len);
++}
+
+ static int verify_authorizer_reply(struct ceph_connection *con)
+ {
+@@ -5341,6 +5351,7 @@ static const struct ceph_connection_operations osd_con_ops = {
+ .put = put_osd_con,
+ .dispatch = dispatch,
+ .get_authorizer = get_authorizer,
++ .add_authorizer_challenge = add_authorizer_challenge,
+ .verify_authorizer_reply = verify_authorizer_reply,
+ .invalidate_authorizer = invalidate_authorizer,
+ .alloc_msg = alloc_msg,
+--
+2.17.1
+
--- /dev/null
+From 5bb530635eb6229ab4a63cc561974fdcda3d0616 Mon Sep 17 00:00:00 2001
+From: Ilya Dryomov <idryomov@gmail.com>
+Date: Thu, 26 Jul 2018 18:05:43 +0200
+Subject: libceph: factor out __ceph_x_decrypt()
+
+commit c571fe24d243bfe7017f0e67fe800b3cc2a1d1f7 upstream.
+
+Will be used for decrypting the server challenge which is only preceded
+by ceph_x_encrypt_header.
+
+Drop struct_v check to allow for extending ceph_x_encrypt_header in the
+future.
+
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+Reviewed-by: Sage Weil <sage@redhat.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ceph/auth_x.c | 33 ++++++++++++++++++++++++---------
+ 1 file changed, 24 insertions(+), 9 deletions(-)
+
+diff --git a/net/ceph/auth_x.c b/net/ceph/auth_x.c
+index 2f4a1baf5f52..9cac05239346 100644
+--- a/net/ceph/auth_x.c
++++ b/net/ceph/auth_x.c
+@@ -70,25 +70,40 @@ static int ceph_x_encrypt(struct ceph_crypto_key *secret, void *buf,
+ return sizeof(u32) + ciphertext_len;
+ }
+
++static int __ceph_x_decrypt(struct ceph_crypto_key *secret, void *p,
++ int ciphertext_len)
++{
++ struct ceph_x_encrypt_header *hdr = p;
++ int plaintext_len;
++ int ret;
++
++ ret = ceph_crypt(secret, false, p, ciphertext_len, ciphertext_len,
++ &plaintext_len);
++ if (ret)
++ return ret;
++
++ if (le64_to_cpu(hdr->magic) != CEPHX_ENC_MAGIC) {
++ pr_err("%s bad magic\n", __func__);
++ return -EINVAL;
++ }
++
++ return plaintext_len - sizeof(*hdr);
++}
++
+ static int ceph_x_decrypt(struct ceph_crypto_key *secret, void **p, void *end)
+ {
+- struct ceph_x_encrypt_header *hdr = *p + sizeof(u32);
+- int ciphertext_len, plaintext_len;
++ int ciphertext_len;
+ int ret;
+
+ ceph_decode_32_safe(p, end, ciphertext_len, e_inval);
+ ceph_decode_need(p, end, ciphertext_len, e_inval);
+
+- ret = ceph_crypt(secret, false, *p, end - *p, ciphertext_len,
+- &plaintext_len);
+- if (ret)
++ ret = __ceph_x_decrypt(secret, *p, ciphertext_len);
++ if (ret < 0)
+ return ret;
+
+- if (hdr->struct_v != 1 || le64_to_cpu(hdr->magic) != CEPHX_ENC_MAGIC)
+- return -EPERM;
+-
+ *p += ciphertext_len;
+- return plaintext_len - sizeof(struct ceph_x_encrypt_header);
++ return ret;
+
+ e_inval:
+ return -EINVAL;
+--
+2.17.1
+
--- /dev/null
+From 55b4028d703b5184ee8cb15af858eba1da52277e Mon Sep 17 00:00:00 2001
+From: Ilya Dryomov <idryomov@gmail.com>
+Date: Thu, 26 Jul 2018 17:43:47 +0200
+Subject: libceph: factor out __prepare_write_connect()
+
+commit c0f56b483aa09c99bfe97409a43ad786f33b8a5a upstream.
+
+Will be used for sending ceph_msg_connect with an updated authorizer,
+after the server challenges the initial authorizer.
+
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+Reviewed-by: Sage Weil <sage@redhat.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ceph/messenger.c | 21 ++++++++++++---------
+ 1 file changed, 12 insertions(+), 9 deletions(-)
+
+diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
+index 3a82e6d2864b..0b121327d32f 100644
+--- a/net/ceph/messenger.c
++++ b/net/ceph/messenger.c
+@@ -1446,6 +1446,17 @@ static void prepare_write_banner(struct ceph_connection *con)
+ con_flag_set(con, CON_FLAG_WRITE_PENDING);
+ }
+
++static void __prepare_write_connect(struct ceph_connection *con)
++{
++ con_out_kvec_add(con, sizeof(con->out_connect), &con->out_connect);
++ if (con->auth)
++ con_out_kvec_add(con, con->auth->authorizer_buf_len,
++ con->auth->authorizer_buf);
++
++ con->out_more = 0;
++ con_flag_set(con, CON_FLAG_WRITE_PENDING);
++}
++
+ static int prepare_write_connect(struct ceph_connection *con)
+ {
+ unsigned int global_seq = get_global_seq(con->msgr, 0);
+@@ -1481,15 +1492,7 @@ static int prepare_write_connect(struct ceph_connection *con)
+ if (ret)
+ return ret;
+
+- con_out_kvec_add(con, sizeof (con->out_connect),
+- &con->out_connect);
+- if (con->auth)
+- con_out_kvec_add(con, con->auth->authorizer_buf_len,
+- con->auth->authorizer_buf);
+-
+- con->out_more = 0;
+- con_flag_set(con, CON_FLAG_WRITE_PENDING);
+-
++ __prepare_write_connect(con);
+ return 0;
+ }
+
+--
+2.17.1
+
--- /dev/null
+From 007883236b05988d113f8aa20efd4a50b1ad7e91 Mon Sep 17 00:00:00 2001
+From: Ilya Dryomov <idryomov@gmail.com>
+Date: Fri, 27 Jul 2018 16:37:54 +0200
+Subject: libceph: factor out encrypt_authorizer()
+
+commit 149cac4a50b0b4081b38b2f38de6ef71c27eaa85 upstream.
+
+Will be used for encrypting both the initial and updated authorizers.
+
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+Reviewed-by: Sage Weil <sage@redhat.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ceph/auth_x.c | 49 ++++++++++++++++++++++++++++++++++-------------
+ 1 file changed, 36 insertions(+), 13 deletions(-)
+
+diff --git a/net/ceph/auth_x.c b/net/ceph/auth_x.c
+index 9cac05239346..722791f45b2a 100644
+--- a/net/ceph/auth_x.c
++++ b/net/ceph/auth_x.c
+@@ -290,6 +290,38 @@ bad:
+ return -EINVAL;
+ }
+
++/*
++ * Encode and encrypt the second part (ceph_x_authorize_b) of the
++ * authorizer. The first part (ceph_x_authorize_a) should already be
++ * encoded.
++ */
++static int encrypt_authorizer(struct ceph_x_authorizer *au)
++{
++ struct ceph_x_authorize_a *msg_a;
++ struct ceph_x_authorize_b *msg_b;
++ void *p, *end;
++ int ret;
++
++ msg_a = au->buf->vec.iov_base;
++ WARN_ON(msg_a->ticket_blob.secret_id != cpu_to_le64(au->secret_id));
++ p = (void *)(msg_a + 1) + le32_to_cpu(msg_a->ticket_blob.blob_len);
++ end = au->buf->vec.iov_base + au->buf->vec.iov_len;
++
++ msg_b = p + ceph_x_encrypt_offset();
++ msg_b->struct_v = 1;
++ msg_b->nonce = cpu_to_le64(au->nonce);
++
++ ret = ceph_x_encrypt(&au->session_key, p, end - p, sizeof(*msg_b));
++ if (ret < 0)
++ return ret;
++
++ p += ret;
++ WARN_ON(p > end);
++ au->buf->vec.iov_len = p - au->buf->vec.iov_base;
++
++ return 0;
++}
++
+ static void ceph_x_authorizer_cleanup(struct ceph_x_authorizer *au)
+ {
+ ceph_crypto_key_destroy(&au->session_key);
+@@ -306,7 +338,6 @@ static int ceph_x_build_authorizer(struct ceph_auth_client *ac,
+ int maxlen;
+ struct ceph_x_authorize_a *msg_a;
+ struct ceph_x_authorize_b *msg_b;
+- void *p, *end;
+ int ret;
+ int ticket_blob_len =
+ (th->ticket_blob ? th->ticket_blob->vec.iov_len : 0);
+@@ -350,21 +381,13 @@ static int ceph_x_build_authorizer(struct ceph_auth_client *ac,
+ dout(" th %p secret_id %lld %lld\n", th, th->secret_id,
+ le64_to_cpu(msg_a->ticket_blob.secret_id));
+
+- p = msg_a + 1;
+- p += ticket_blob_len;
+- end = au->buf->vec.iov_base + au->buf->vec.iov_len;
+-
+- msg_b = p + ceph_x_encrypt_offset();
+- msg_b->struct_v = 1;
+ get_random_bytes(&au->nonce, sizeof(au->nonce));
+- msg_b->nonce = cpu_to_le64(au->nonce);
+- ret = ceph_x_encrypt(&au->session_key, p, end - p, sizeof(*msg_b));
+- if (ret < 0)
++ ret = encrypt_authorizer(au);
++ if (ret) {
++ pr_err("failed to encrypt authorizer: %d", ret);
+ goto out_au;
++ }
+
+- p += ret;
+- WARN_ON(p > end);
+- au->buf->vec.iov_len = p - au->buf->vec.iov_base;
+ dout(" built authorizer nonce %llx len %d\n", au->nonce,
+ (int)au->buf->vec.iov_len);
+ return 0;
+--
+2.17.1
+
--- /dev/null
+From 14735e0afb6ed378becd0dedf37d1e5ddfa12084 Mon Sep 17 00:00:00 2001
+From: Ilya Dryomov <idryomov@gmail.com>
+Date: Fri, 27 Jul 2018 19:25:32 +0200
+Subject: libceph: implement CEPHX_V2 calculation mode
+
+commit cc255c76c70f7a87d97939621eae04b600d9f4a1 upstream.
+
+Derive the signature from the entire buffer (both AES cipher blocks)
+instead of using just the first half of the first block, leaving out
+data_crc entirely.
+
+This addresses CVE-2018-1129.
+
+Link: http://tracker.ceph.com/issues/24837
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+Reviewed-by: Sage Weil <sage@redhat.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/ceph/ceph_features.h | 7 +--
+ net/ceph/auth_x.c | 73 +++++++++++++++++++++++-------
+ 2 files changed, 60 insertions(+), 20 deletions(-)
+
+diff --git a/include/linux/ceph/ceph_features.h b/include/linux/ceph/ceph_features.h
+index 59042d5ac520..70f42eef813b 100644
+--- a/include/linux/ceph/ceph_features.h
++++ b/include/linux/ceph/ceph_features.h
+@@ -165,9 +165,9 @@ DEFINE_CEPH_FEATURE(58, 1, FS_FILE_LAYOUT_V2) // overlap
+ DEFINE_CEPH_FEATURE(59, 1, FS_BTIME)
+ DEFINE_CEPH_FEATURE(59, 1, FS_CHANGE_ATTR) // overlap
+ DEFINE_CEPH_FEATURE(59, 1, MSG_ADDR2) // overlap
+-DEFINE_CEPH_FEATURE(60, 1, BLKIN_TRACING) // *do not share this bit*
++DEFINE_CEPH_FEATURE(60, 1, OSD_RECOVERY_DELETES) // *do not share this bit*
++DEFINE_CEPH_FEATURE(61, 1, CEPHX_V2) // *do not share this bit*
+
+-DEFINE_CEPH_FEATURE(61, 1, RESERVED2) // unused, but slow down!
+ DEFINE_CEPH_FEATURE(62, 1, RESERVED) // do not use; used as a sentinal
+ DEFINE_CEPH_FEATURE_DEPRECATED(63, 1, RESERVED_BROKEN, LUMINOUS) // client-facing
+
+@@ -209,7 +209,8 @@ DEFINE_CEPH_FEATURE_DEPRECATED(63, 1, RESERVED_BROKEN, LUMINOUS) // client-facin
+ CEPH_FEATURE_SERVER_JEWEL | \
+ CEPH_FEATURE_MON_STATEFUL_SUB | \
+ CEPH_FEATURE_CRUSH_TUNABLES5 | \
+- CEPH_FEATURE_NEW_OSDOPREPLY_ENCODING)
++ CEPH_FEATURE_NEW_OSDOPREPLY_ENCODING | \
++ CEPH_FEATURE_CEPHX_V2)
+
+ #define CEPH_FEATURES_REQUIRED_DEFAULT \
+ (CEPH_FEATURE_NOSRCADDR | \
+diff --git a/net/ceph/auth_x.c b/net/ceph/auth_x.c
+index ce28bb07d8fd..10eb759bbcb4 100644
+--- a/net/ceph/auth_x.c
++++ b/net/ceph/auth_x.c
+@@ -9,6 +9,7 @@
+
+ #include <linux/ceph/decode.h>
+ #include <linux/ceph/auth.h>
++#include <linux/ceph/ceph_features.h>
+ #include <linux/ceph/libceph.h>
+ #include <linux/ceph/messenger.h>
+
+@@ -803,26 +804,64 @@ static int calc_signature(struct ceph_x_authorizer *au, struct ceph_msg *msg,
+ __le64 *psig)
+ {
+ void *enc_buf = au->enc_buf;
+- struct {
+- __le32 len;
+- __le32 header_crc;
+- __le32 front_crc;
+- __le32 middle_crc;
+- __le32 data_crc;
+- } __packed *sigblock = enc_buf + ceph_x_encrypt_offset();
+ int ret;
+
+- sigblock->len = cpu_to_le32(4*sizeof(u32));
+- sigblock->header_crc = msg->hdr.crc;
+- sigblock->front_crc = msg->footer.front_crc;
+- sigblock->middle_crc = msg->footer.middle_crc;
+- sigblock->data_crc = msg->footer.data_crc;
+- ret = ceph_x_encrypt(&au->session_key, enc_buf, CEPHX_AU_ENC_BUF_LEN,
+- sizeof(*sigblock));
+- if (ret < 0)
+- return ret;
++ if (!CEPH_HAVE_FEATURE(msg->con->peer_features, CEPHX_V2)) {
++ struct {
++ __le32 len;
++ __le32 header_crc;
++ __le32 front_crc;
++ __le32 middle_crc;
++ __le32 data_crc;
++ } __packed *sigblock = enc_buf + ceph_x_encrypt_offset();
++
++ sigblock->len = cpu_to_le32(4*sizeof(u32));
++ sigblock->header_crc = msg->hdr.crc;
++ sigblock->front_crc = msg->footer.front_crc;
++ sigblock->middle_crc = msg->footer.middle_crc;
++ sigblock->data_crc = msg->footer.data_crc;
++
++ ret = ceph_x_encrypt(&au->session_key, enc_buf,
++ CEPHX_AU_ENC_BUF_LEN, sizeof(*sigblock));
++ if (ret < 0)
++ return ret;
++
++ *psig = *(__le64 *)(enc_buf + sizeof(u32));
++ } else {
++ struct {
++ __le32 header_crc;
++ __le32 front_crc;
++ __le32 front_len;
++ __le32 middle_crc;
++ __le32 middle_len;
++ __le32 data_crc;
++ __le32 data_len;
++ __le32 seq_lower_word;
++ } __packed *sigblock = enc_buf;
++ struct {
++ __le64 a, b, c, d;
++ } __packed *penc = enc_buf;
++ int ciphertext_len;
++
++ sigblock->header_crc = msg->hdr.crc;
++ sigblock->front_crc = msg->footer.front_crc;
++ sigblock->front_len = msg->hdr.front_len;
++ sigblock->middle_crc = msg->footer.middle_crc;
++ sigblock->middle_len = msg->hdr.middle_len;
++ sigblock->data_crc = msg->footer.data_crc;
++ sigblock->data_len = msg->hdr.data_len;
++ sigblock->seq_lower_word = *(__le32 *)&msg->hdr.seq;
++
++ /* no leading len, no ceph_x_encrypt_header */
++ ret = ceph_crypt(&au->session_key, true, enc_buf,
++ CEPHX_AU_ENC_BUF_LEN, sizeof(*sigblock),
++ &ciphertext_len);
++ if (ret)
++ return ret;
++
++ *psig = penc->a ^ penc->b ^ penc->c ^ penc->d;
++ }
+
+- *psig = *(__le64 *)(enc_buf + sizeof(u32));
+ return 0;
+ }
+
+--
+2.17.1
+
--- /dev/null
+From c30cbc400acba029b39ee6098a7907f9194b149d Mon Sep 17 00:00:00 2001
+From: Ilya Dryomov <idryomov@gmail.com>
+Date: Thu, 26 Jul 2018 15:17:46 +0200
+Subject: libceph: store ceph_auth_handshake pointer in ceph_connection
+
+commit 262614c4294d33b1f19e0d18c0091d9c329b544a upstream.
+
+We already copy authorizer_reply_buf and authorizer_reply_buf_len into
+ceph_connection. Factoring out __prepare_write_connect() requires two
+more: authorizer_buf and authorizer_buf_len. Store the pointer to the
+handshake in con->auth rather than piling on.
+
+Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
+Reviewed-by: Sage Weil <sage@redhat.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/ceph/messenger.h | 3 +-
+ net/ceph/messenger.c | 54 ++++++++++++++++------------------
+ 2 files changed, 27 insertions(+), 30 deletions(-)
+
+diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h
+index ead9d85f1c11..9056077c023f 100644
+--- a/include/linux/ceph/messenger.h
++++ b/include/linux/ceph/messenger.h
+@@ -203,9 +203,8 @@ struct ceph_connection {
+ attempt for this connection, client */
+ u32 peer_global_seq; /* peer's global seq for this connection */
+
++ struct ceph_auth_handshake *auth;
+ int auth_retry; /* true if we need a newer authorizer */
+- void *auth_reply_buf; /* where to put the authorizer reply */
+- int auth_reply_buf_len;
+
+ struct mutex mutex;
+
+diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
+index 5281da82371a..3a82e6d2864b 100644
+--- a/net/ceph/messenger.c
++++ b/net/ceph/messenger.c
+@@ -1411,24 +1411,26 @@ static void prepare_write_keepalive(struct ceph_connection *con)
+ * Connection negotiation.
+ */
+
+-static struct ceph_auth_handshake *get_connect_authorizer(struct ceph_connection *con,
+- int *auth_proto)
++static int get_connect_authorizer(struct ceph_connection *con)
+ {
+ struct ceph_auth_handshake *auth;
++ int auth_proto;
+
+ if (!con->ops->get_authorizer) {
++ con->auth = NULL;
+ con->out_connect.authorizer_protocol = CEPH_AUTH_UNKNOWN;
+ con->out_connect.authorizer_len = 0;
+- return NULL;
++ return 0;
+ }
+
+- auth = con->ops->get_authorizer(con, auth_proto, con->auth_retry);
++ auth = con->ops->get_authorizer(con, &auth_proto, con->auth_retry);
+ if (IS_ERR(auth))
+- return auth;
++ return PTR_ERR(auth);
+
+- con->auth_reply_buf = auth->authorizer_reply_buf;
+- con->auth_reply_buf_len = auth->authorizer_reply_buf_len;
+- return auth;
++ con->auth = auth;
++ con->out_connect.authorizer_protocol = cpu_to_le32(auth_proto);
++ con->out_connect.authorizer_len = cpu_to_le32(auth->authorizer_buf_len);
++ return 0;
+ }
+
+ /*
+@@ -1448,8 +1450,7 @@ static int prepare_write_connect(struct ceph_connection *con)
+ {
+ unsigned int global_seq = get_global_seq(con->msgr, 0);
+ int proto;
+- int auth_proto;
+- struct ceph_auth_handshake *auth;
++ int ret;
+
+ switch (con->peer_name.type) {
+ case CEPH_ENTITY_TYPE_MON:
+@@ -1476,20 +1477,15 @@ static int prepare_write_connect(struct ceph_connection *con)
+ con->out_connect.protocol_version = cpu_to_le32(proto);
+ con->out_connect.flags = 0;
+
+- auth_proto = CEPH_AUTH_UNKNOWN;
+- auth = get_connect_authorizer(con, &auth_proto);
+- if (IS_ERR(auth))
+- return PTR_ERR(auth);
+-
+- con->out_connect.authorizer_protocol = cpu_to_le32(auth_proto);
+- con->out_connect.authorizer_len = auth ?
+- cpu_to_le32(auth->authorizer_buf_len) : 0;
++ ret = get_connect_authorizer(con);
++ if (ret)
++ return ret;
+
+ con_out_kvec_add(con, sizeof (con->out_connect),
+ &con->out_connect);
+- if (auth && auth->authorizer_buf_len)
+- con_out_kvec_add(con, auth->authorizer_buf_len,
+- auth->authorizer_buf);
++ if (con->auth)
++ con_out_kvec_add(con, con->auth->authorizer_buf_len,
++ con->auth->authorizer_buf);
+
+ con->out_more = 0;
+ con_flag_set(con, CON_FLAG_WRITE_PENDING);
+@@ -1753,11 +1749,14 @@ static int read_partial_connect(struct ceph_connection *con)
+ if (ret <= 0)
+ goto out;
+
+- size = le32_to_cpu(con->in_reply.authorizer_len);
+- end += size;
+- ret = read_partial(con, end, size, con->auth_reply_buf);
+- if (ret <= 0)
+- goto out;
++ if (con->auth) {
++ size = le32_to_cpu(con->in_reply.authorizer_len);
++ end += size;
++ ret = read_partial(con, end, size,
++ con->auth->authorizer_reply_buf);
++ if (ret <= 0)
++ goto out;
++ }
+
+ dout("read_partial_connect %p tag %d, con_seq = %u, g_seq = %u\n",
+ con, (int)con->in_reply.tag,
+@@ -1765,7 +1764,6 @@ static int read_partial_connect(struct ceph_connection *con)
+ le32_to_cpu(con->in_reply.global_seq));
+ out:
+ return ret;
+-
+ }
+
+ /*
+@@ -2048,7 +2046,7 @@ static int process_connect(struct ceph_connection *con)
+
+ dout("process_connect on %p tag %d\n", con, (int)con->in_tag);
+
+- if (con->auth_reply_buf) {
++ if (con->auth) {
+ /*
+ * Any connection that defines ->get_authorizer()
+ * should also define ->verify_authorizer_reply().
+--
+2.17.1
+
--- /dev/null
+From 3e5d52f97edee1e861bfc579bb1924c7b5e655f8 Mon Sep 17 00:00:00 2001
+From: Matthias Schwarzott <zzam@gentoo.org>
+Date: Mon, 30 Oct 2017 06:07:29 -0400
+Subject: media: em28xx: Fix use-after-free when disconnecting
+
+[ Upstream commit 910b0797fa9e8af09c44a3fa36cb310ba7a7218d ]
+
+Fix bug by moving the i2c_unregister_device calls after deregistration
+of dvb frontend.
+
+The new style i2c drivers already destroys the frontend object at
+i2c_unregister_device time.
+When the dvb frontend is unregistered afterwards it leads to this oops:
+
+ [ 6058.866459] BUG: unable to handle kernel NULL pointer dereference at 00000000000001f8
+ [ 6058.866578] IP: dvb_frontend_stop+0x30/0xd0 [dvb_core]
+ [ 6058.866644] PGD 0
+ [ 6058.866646] P4D 0
+
+ [ 6058.866726] Oops: 0000 [#1] SMP
+ [ 6058.866768] Modules linked in: rc_pinnacle_pctv_hd(O) em28xx_rc(O) si2157(O) si2168(O) em28xx_dvb(O) em28xx(O) si2165(O) a8293(O) tda10071(O) tea5767(O) tuner(O) cx23885(O) tda18271(O) videobuf2_dvb(O) videobuf2_dma_sg(O) m88ds3103(O) tveeprom(O) cx2341x(O) v4l2_common(O) dvb_core(O) rc_core(O) videobuf2_memops(O) videobuf2_v4l2(O) videobuf2_core(O) videodev(O) media(O) bluetooth ecdh_generic ums_realtek uas rtl8192cu rtl_usb rtl8192c_common rtlwifi usb_storage snd_hda_codec_realtek snd_hda_codec_hdmi snd_hda_codec_generic i2c_mux snd_hda_intel snd_hda_codec snd_hwdep x86_pkg_temp_thermal snd_hda_core kvm_intel kvm irqbypass [last unloaded: videobuf2_memops]
+ [ 6058.867497] CPU: 2 PID: 7349 Comm: kworker/2:0 Tainted: G W O 4.13.9-gentoo #1
+ [ 6058.867595] Hardware name: MEDION E2050 2391/H81H3-EM2, BIOS H81EM2W08.308 08/25/2014
+ [ 6058.867692] Workqueue: usb_hub_wq hub_event
+ [ 6058.867746] task: ffff88011a15e040 task.stack: ffffc90003074000
+ [ 6058.867825] RIP: 0010:dvb_frontend_stop+0x30/0xd0 [dvb_core]
+ [ 6058.867896] RSP: 0018:ffffc90003077b58 EFLAGS: 00010293
+ [ 6058.867964] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 000000010040001f
+ [ 6058.868056] RDX: ffff88011a15e040 RSI: ffffea000464e400 RDI: ffff88001cbe3028
+ [ 6058.868150] RBP: ffffc90003077b68 R08: ffff880119390380 R09: 000000010040001f
+ [ 6058.868241] R10: ffffc90003077b18 R11: 000000000001e200 R12: ffff88001cbe3028
+ [ 6058.868330] R13: ffff88001cbe68d0 R14: ffff8800cf734000 R15: ffff8800cf734098
+ [ 6058.868419] FS: 0000000000000000(0000) GS:ffff88011fb00000(0000) knlGS:0000000000000000
+ [ 6058.868511] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+ [ 6058.868578] CR2: 00000000000001f8 CR3: 00000001113c5000 CR4: 00000000001406e0
+ [ 6058.868662] Call Trace:
+ [ 6058.868705] dvb_unregister_frontend+0x2a/0x80 [dvb_core]
+ [ 6058.868774] em28xx_dvb_fini+0x132/0x220 [em28xx_dvb]
+ [ 6058.868840] em28xx_close_extension+0x34/0x90 [em28xx]
+ [ 6058.868902] em28xx_usb_disconnect+0x4e/0x70 [em28xx]
+ [ 6058.868968] usb_unbind_interface+0x6d/0x260
+ [ 6058.869025] device_release_driver_internal+0x150/0x210
+ [ 6058.869094] device_release_driver+0xd/0x10
+ [ 6058.869150] bus_remove_device+0xe4/0x160
+ [ 6058.869204] device_del+0x1ce/0x2f0
+ [ 6058.869253] usb_disable_device+0x99/0x270
+ [ 6058.869306] usb_disconnect+0x8d/0x260
+ [ 6058.869359] hub_event+0x93d/0x1520
+ [ 6058.869408] ? dequeue_task_fair+0xae5/0xd20
+ [ 6058.869467] process_one_work+0x1d9/0x3e0
+ [ 6058.869522] worker_thread+0x43/0x3e0
+ [ 6058.869576] kthread+0x104/0x140
+ [ 6058.869602] ? trace_event_raw_event_workqueue_work+0x80/0x80
+ [ 6058.869640] ? kthread_create_on_node+0x40/0x40
+ [ 6058.869673] ret_from_fork+0x22/0x30
+ [ 6058.869698] Code: 54 49 89 fc 53 48 8b 9f 18 03 00 00 0f 1f 44 00 00 41 83 bc 24 04 05 00 00 02 74 0c 41 c7 84 24 04 05 00 00 01 00 00 00 0f ae f0 <48> 8b bb f8 01 00 00 48 85 ff 74 5c e8 df 40 f0 e0 48 8b 93 f8
+ [ 6058.869850] RIP: dvb_frontend_stop+0x30/0xd0 [dvb_core] RSP: ffffc90003077b58
+ [ 6058.869894] CR2: 00000000000001f8
+ [ 6058.875880] ---[ end trace 717eecf7193b3fc6 ]---
+
+Signed-off-by: Matthias Schwarzott <zzam@gentoo.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/usb/em28xx/em28xx-dvb.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
+index 4a7db623fe29..29cdaaf1ed90 100644
+--- a/drivers/media/usb/em28xx/em28xx-dvb.c
++++ b/drivers/media/usb/em28xx/em28xx-dvb.c
+@@ -2105,6 +2105,8 @@ static int em28xx_dvb_fini(struct em28xx *dev)
+ }
+ }
+
++ em28xx_unregister_dvb(dvb);
++
+ /* remove I2C SEC */
+ client = dvb->i2c_client_sec;
+ if (client) {
+@@ -2126,7 +2128,6 @@ static int em28xx_dvb_fini(struct em28xx *dev)
+ i2c_unregister_device(client);
+ }
+
+- em28xx_unregister_dvb(dvb);
+ kfree(dvb);
+ dev->dvb = NULL;
+ kref_put(&dev->ref, em28xx_free_device);
+--
+2.17.1
+
--- /dev/null
+From 4f3a265cee9e47bdd279ed75dd9aa112a4eb7aa7 Mon Sep 17 00:00:00 2001
+From: Vakul Garg <vakul.garg@nxp.com>
+Date: Mon, 10 Sep 2018 22:53:46 +0530
+Subject: net/tls: Fixed return value when tls_complete_pending_work() fails
+
+commit 150085791afb8054e11d2e080d4b9cd755dd7f69 upstream.
+
+In tls_sw_sendmsg() and tls_sw_sendpage(), the variable 'ret' has
+been set to return value of tls_complete_pending_work(). This allows
+return of proper error code if tls_complete_pending_work() fails.
+
+Fixes: 3c4d7559159b ("tls: kernel TLS support")
+Signed-off-by: Vakul Garg <vakul.garg@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+[bwh: Backported to 4.14: adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/tls/tls_sw.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
+index 5996fb5756e1..d18d4a478e4f 100644
+--- a/net/tls/tls_sw.c
++++ b/net/tls/tls_sw.c
+@@ -388,7 +388,7 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
+ {
+ struct tls_context *tls_ctx = tls_get_ctx(sk);
+ struct tls_sw_context *ctx = tls_sw_ctx(tls_ctx);
+- int ret = 0;
++ int ret;
+ int required_size;
+ long timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
+ bool eor = !(msg->msg_flags & MSG_MORE);
+@@ -403,7 +403,8 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
+
+ lock_sock(sk);
+
+- if (tls_complete_pending_work(sk, tls_ctx, msg->msg_flags, &timeo))
++ ret = tls_complete_pending_work(sk, tls_ctx, msg->msg_flags, &timeo);
++ if (ret)
+ goto send_end;
+
+ if (unlikely(msg->msg_controllen)) {
+@@ -539,7 +540,7 @@ int tls_sw_sendpage(struct sock *sk, struct page *page,
+ {
+ struct tls_context *tls_ctx = tls_get_ctx(sk);
+ struct tls_sw_context *ctx = tls_sw_ctx(tls_ctx);
+- int ret = 0;
++ int ret;
+ long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
+ bool eor;
+ size_t orig_size = size;
+@@ -559,7 +560,8 @@ int tls_sw_sendpage(struct sock *sk, struct page *page,
+
+ sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
+
+- if (tls_complete_pending_work(sk, tls_ctx, flags, &timeo))
++ ret = tls_complete_pending_work(sk, tls_ctx, flags, &timeo);
++ if (ret)
+ goto sendpage_end;
+
+ /* Call the sk_stream functions to manage the sndbuf mem. */
+--
+2.17.1
+
--- /dev/null
+From c7056af71383df8c55db643227f7012d0ce49536 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 2 Dec 2018 10:03:24 -0500
+Subject: Revert "wlcore: Add missing PM call for
+ wlcore_cmd_wait_for_event_or_timeout()"
+
+This reverts commit e87efc44dd36ba3db59847c418354711ebad779b which was
+upstream commit 4ec7cece87b3ed21ffcd407c62fb2f151a366bc1.
+
+From Dietmar May's report on the stable mailing list
+(https://www.spinics.net/lists/stable/msg272201.html):
+
+> I've run into some problems which appear due to (a) recent patch(es) on
+> the wlcore wifi driver.
+>
+> 4.4.160 - commit 3fdd34643ffc378b5924941fad40352c04610294
+> 4.9.131 - commit afeeecc764436f31d4447575bb9007732333818c
+>
+> Earlier versions (4.9.130 and 4.4.159 - tested back to 4.4.49) do not
+> exhibit this problem. It is still present in 4.9.141.
+>
+> master as of 4.20.0-rc4 does not exhibit this problem.
+>
+> Basically, during client association when in AP mode (running hostapd),
+> handshake may or may not complete following a noticeable delay. If
+> successful, then the driver fails consistently in warn_slowpath_null
+> during disassociation. If unsuccessful, the wifi client attempts multiple
+> times, sometimes failing repeatedly. I've had clients unable to connect
+> for 3-5 minutes during testing, with the syslog filled with dozens of
+> backtraces. syslog details are below.
+>
+> I'm working on an embedded device with a TI 3352 ARM processor and a
+> murata wl1271 module in sdio mode. We're running a fully patched ubuntu
+> 18.04 ARM build, with a kernel built from kernel.org's stable/linux repo <https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=linux-4.9.y&id=afeeecc764436f31d4447575bb9007732333818c>.
+> Relevant parts of the kernel config are included below.
+>
+> The commit message states:
+>
+> > /I've only seen this few times with the runtime PM patches enabled so
+> > this one is probably not needed before that. This seems to work
+> > currently based on the current PM implementation timer. Let's apply
+> > this separately though in case others are hitting this issue./
+> We're not doing anything explicit with power management. The device is an
+> IoT edge gateway with battery backup, normally running on wall power. The
+> battery is currently used solely to shut down the system cleanly to avoid
+> filesystem corruption.
+>
+> The device tree is configured to keep power in suspend; but the device
+> should never suspend, so in our case, there is no need to call
+> wl1271_ps_elp_wakeup() or wl1271_ps_elp_sleep(), as occurs in the patch.
+
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ti/wlcore/cmd.c | 6 ------
+ 1 file changed, 6 deletions(-)
+
+diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c
+index f48c3f62966d..761cf8573a80 100644
+--- a/drivers/net/wireless/ti/wlcore/cmd.c
++++ b/drivers/net/wireless/ti/wlcore/cmd.c
+@@ -35,7 +35,6 @@
+ #include "wl12xx_80211.h"
+ #include "cmd.h"
+ #include "event.h"
+-#include "ps.h"
+ #include "tx.h"
+ #include "hw_ops.h"
+
+@@ -192,10 +191,6 @@ int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl,
+
+ timeout_time = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
+
+- ret = wl1271_ps_elp_wakeup(wl);
+- if (ret < 0)
+- return ret;
+-
+ do {
+ if (time_after(jiffies, timeout_time)) {
+ wl1271_debug(DEBUG_CMD, "timeout waiting for event %d",
+@@ -227,7 +222,6 @@ int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl,
+ } while (!event);
+
+ out:
+- wl1271_ps_elp_sleep(wl);
+ kfree(events_vector);
+ return ret;
+ }
+--
+2.17.1
+
mm-khugepaged-minor-reorderings-in-collapse_shmem.patch
mm-khugepaged-collapse_shmem-without-freezing-new_pa.patch
mm-khugepaged-collapse_shmem-do-not-crash-on-compoun.patch
+media-em28xx-fix-use-after-free-when-disconnecting.patch
+ubi-initialize-fastmap-checkmapping-correctly.patch
+libceph-store-ceph_auth_handshake-pointer-in-ceph_co.patch
+libceph-factor-out-__prepare_write_connect.patch
+libceph-factor-out-__ceph_x_decrypt.patch
+libceph-factor-out-encrypt_authorizer.patch
+libceph-add-authorizer-challenge.patch
+libceph-implement-cephx_v2-calculation-mode.patch
+bpf-prevent-memory-disambiguation-attack.patch
+tls-add-function-to-update-the-tls-socket-configurat.patch
+tls-fix-tls-ulp-context-leak-when-tls_tx-setsockopt-.patch
+tls-avoid-copying-crypto_info-again-after-cipher_typ.patch
+tls-don-t-override-sk_write_space-if-tls_set_sw_offl.patch
+tls-use-correct-sk-sk_prot-for-ipv6.patch
+net-tls-fixed-return-value-when-tls_complete_pending.patch
+wil6210-missing-length-check-in-wmi_set_ie.patch
+btrfs-validate-type-when-reading-a-chunk.patch
+btrfs-verify-that-every-chunk-has-corresponding-bloc.patch
+btrfs-refactor-check_leaf-function-for-later-expansi.patch
+btrfs-check-if-item-pointer-overlaps-with-the-item-i.patch
+btrfs-add-sanity-check-for-extent_data-when-reading-.patch
+btrfs-add-checker-for-extent_csum.patch
+btrfs-move-leaf-and-node-validation-checker-to-tree-.patch
+btrfs-tree-checker-enhance-btrfs_check_node-output.patch
+btrfs-tree-checker-fix-false-panic-for-sanity-test.patch
+btrfs-tree-checker-add-checker-for-dir-item.patch
+btrfs-tree-checker-use-zu-format-string-for-size_t.patch
+btrfs-tree-check-reduce-stack-consumption-in-check_d.patch
+btrfs-tree-checker-verify-block_group_item.patch
+btrfs-tree-checker-detect-invalid-and-empty-essentia.patch
+btrfs-check-that-each-block-group-has-corresponding-.patch
+btrfs-tree-checker-check-level-for-leaves-and-nodes.patch
+btrfs-tree-checker-fix-misleading-group-system-infor.patch
+f2fs-check-blkaddr-more-accuratly-before-issue-a-bio.patch
+f2fs-sanity-check-on-sit-entry.patch
+f2fs-enhance-sanity_check_raw_super-to-avoid-potenti.patch
+f2fs-clean-up-with-is_valid_blkaddr.patch
+f2fs-introduce-and-spread-verify_blkaddr.patch
+f2fs-fix-to-do-sanity-check-with-secs_per_zone.patch
+f2fs-add-sanity_check_inode-function.patch
+f2fs-fix-to-do-sanity-check-with-extra_attr-feature.patch
+f2fs-fix-to-do-sanity-check-with-user_block_count.patch
+f2fs-fix-to-do-sanity-check-with-node-footer-and-ibl.patch
+f2fs-fix-to-do-sanity-check-with-block-address-in-ma.patch
+f2fs-fix-to-do-sanity-check-with-i_extra_isize.patch
+f2fs-fix-to-do-sanity-check-with-cp_pack_start_sum.patch
+xfs-don-t-fail-when-converting-shortform-attr-to-lon.patch
+revert-wlcore-add-missing-pm-call-for-wlcore_cmd_wai.patch
--- /dev/null
+From 75c0c62057604caac55e70d89af87317db0a7169 Mon Sep 17 00:00:00 2001
+From: Ilya Lesokhin <ilyal@mellanox.com>
+Date: Mon, 13 Nov 2017 10:22:45 +0200
+Subject: tls: Add function to update the TLS socket configuration
+
+commit 6d88207fcfddc002afe3e2e4a455e5201089d5d9 upstream.
+
+The tx configuration is now stored in ctx->tx_conf.
+And sk->sk_prot is updated trough a function
+This will simplify things when we add rx
+and support for different possible
+tx and rx cross configurations.
+
+Signed-off-by: Ilya Lesokhin <ilyal@mellanox.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/tls.h | 2 ++
+ net/tls/tls_main.c | 46 ++++++++++++++++++++++++++++++++--------------
+ 2 files changed, 34 insertions(+), 14 deletions(-)
+
+diff --git a/include/net/tls.h b/include/net/tls.h
+index 86ed3dd80fe7..0c3ab2af74d3 100644
+--- a/include/net/tls.h
++++ b/include/net/tls.h
+@@ -89,6 +89,8 @@ struct tls_context {
+
+ void *priv_ctx;
+
++ u8 tx_conf:2;
++
+ u16 prepend_size;
+ u16 tag_size;
+ u16 overhead_size;
+diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
+index 4f2971f528db..191a8adee3ea 100644
+--- a/net/tls/tls_main.c
++++ b/net/tls/tls_main.c
+@@ -46,8 +46,18 @@ MODULE_DESCRIPTION("Transport Layer Security Support");
+ MODULE_LICENSE("Dual BSD/GPL");
+ MODULE_ALIAS_TCP_ULP("tls");
+
+-static struct proto tls_base_prot;
+-static struct proto tls_sw_prot;
++enum {
++ TLS_BASE_TX,
++ TLS_SW_TX,
++ TLS_NUM_CONFIG,
++};
++
++static struct proto tls_prots[TLS_NUM_CONFIG];
++
++static inline void update_sk_prot(struct sock *sk, struct tls_context *ctx)
++{
++ sk->sk_prot = &tls_prots[ctx->tx_conf];
++}
+
+ int wait_on_pending_writer(struct sock *sk, long *timeo)
+ {
+@@ -364,8 +374,8 @@ static int do_tls_setsockopt_tx(struct sock *sk, char __user *optval,
+ {
+ struct tls_crypto_info *crypto_info, tmp_crypto_info;
+ struct tls_context *ctx = tls_get_ctx(sk);
+- struct proto *prot = NULL;
+ int rc = 0;
++ int tx_conf;
+
+ if (!optval || (optlen < sizeof(*crypto_info))) {
+ rc = -EINVAL;
+@@ -422,11 +432,12 @@ static int do_tls_setsockopt_tx(struct sock *sk, char __user *optval,
+
+ /* currently SW is default, we will have ethtool in future */
+ rc = tls_set_sw_offload(sk, ctx);
+- prot = &tls_sw_prot;
++ tx_conf = TLS_SW_TX;
+ if (rc)
+ goto err_crypto_info;
+
+- sk->sk_prot = prot;
++ ctx->tx_conf = tx_conf;
++ update_sk_prot(sk, ctx);
+ goto out;
+
+ err_crypto_info:
+@@ -488,7 +499,9 @@ static int tls_init(struct sock *sk)
+ icsk->icsk_ulp_data = ctx;
+ ctx->setsockopt = sk->sk_prot->setsockopt;
+ ctx->getsockopt = sk->sk_prot->getsockopt;
+- sk->sk_prot = &tls_base_prot;
++
++ ctx->tx_conf = TLS_BASE_TX;
++ update_sk_prot(sk, ctx);
+ out:
+ return rc;
+ }
+@@ -499,16 +512,21 @@ static struct tcp_ulp_ops tcp_tls_ulp_ops __read_mostly = {
+ .init = tls_init,
+ };
+
++static void build_protos(struct proto *prot, struct proto *base)
++{
++ prot[TLS_BASE_TX] = *base;
++ prot[TLS_BASE_TX].setsockopt = tls_setsockopt;
++ prot[TLS_BASE_TX].getsockopt = tls_getsockopt;
++
++ prot[TLS_SW_TX] = prot[TLS_BASE_TX];
++ prot[TLS_SW_TX].close = tls_sk_proto_close;
++ prot[TLS_SW_TX].sendmsg = tls_sw_sendmsg;
++ prot[TLS_SW_TX].sendpage = tls_sw_sendpage;
++}
++
+ static int __init tls_register(void)
+ {
+- tls_base_prot = tcp_prot;
+- tls_base_prot.setsockopt = tls_setsockopt;
+- tls_base_prot.getsockopt = tls_getsockopt;
+-
+- tls_sw_prot = tls_base_prot;
+- tls_sw_prot.sendmsg = tls_sw_sendmsg;
+- tls_sw_prot.sendpage = tls_sw_sendpage;
+- tls_sw_prot.close = tls_sk_proto_close;
++ build_protos(tls_prots, &tcp_prot);
+
+ tcp_register_ulp(&tcp_tls_ulp_ops);
+
+--
+2.17.1
+
--- /dev/null
+From 83006446cf9037a89bafe41e8c93ae3c67a91ed4 Mon Sep 17 00:00:00 2001
+From: Ilya Lesokhin <ilyal@mellanox.com>
+Date: Mon, 13 Nov 2017 10:22:48 +0200
+Subject: tls: Avoid copying crypto_info again after cipher_type check.
+
+commit 196c31b4b54474b31dee3c30352c45c2a93e9226 upstream.
+
+Avoid copying crypto_info again after cipher_type check
+to avoid a TOCTOU exploits.
+The temporary array on the stack is removed as we don't really need it
+
+Fixes: 3c4d7559159b ('tls: kernel TLS support')
+Signed-off-by: Ilya Lesokhin <ilyal@mellanox.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+[bwh: Backported to 4.14: Preserve changes made by earlier backports of
+ "tls: return -EBUSY if crypto_info is already set" and "tls: zero the
+ crypto information from tls_context before freeing"]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/tls/tls_main.c | 33 ++++++++++++++-------------------
+ 1 file changed, 14 insertions(+), 19 deletions(-)
+
+diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
+index b5f9c578bcf0..f88df514ad5f 100644
+--- a/net/tls/tls_main.c
++++ b/net/tls/tls_main.c
+@@ -381,7 +381,7 @@ static int tls_getsockopt(struct sock *sk, int level, int optname,
+ static int do_tls_setsockopt_tx(struct sock *sk, char __user *optval,
+ unsigned int optlen)
+ {
+- struct tls_crypto_info *crypto_info, tmp_crypto_info;
++ struct tls_crypto_info *crypto_info;
+ struct tls_context *ctx = tls_get_ctx(sk);
+ int rc = 0;
+ int tx_conf;
+@@ -391,38 +391,33 @@ static int do_tls_setsockopt_tx(struct sock *sk, char __user *optval,
+ goto out;
+ }
+
+- rc = copy_from_user(&tmp_crypto_info, optval, sizeof(*crypto_info));
++ crypto_info = &ctx->crypto_send.info;
++ /* Currently we don't support set crypto info more than one time */
++ if (TLS_CRYPTO_INFO_READY(crypto_info)) {
++ rc = -EBUSY;
++ goto out;
++ }
++
++ rc = copy_from_user(crypto_info, optval, sizeof(*crypto_info));
+ if (rc) {
+ rc = -EFAULT;
+ goto out;
+ }
+
+ /* check version */
+- if (tmp_crypto_info.version != TLS_1_2_VERSION) {
++ if (crypto_info->version != TLS_1_2_VERSION) {
+ rc = -ENOTSUPP;
+- goto out;
+- }
+-
+- /* get user crypto info */
+- crypto_info = &ctx->crypto_send.info;
+-
+- /* Currently we don't support set crypto info more than one time */
+- if (TLS_CRYPTO_INFO_READY(crypto_info)) {
+- rc = -EBUSY;
+- goto out;
++ goto err_crypto_info;
+ }
+
+- switch (tmp_crypto_info.cipher_type) {
++ switch (crypto_info->cipher_type) {
+ case TLS_CIPHER_AES_GCM_128: {
+ if (optlen != sizeof(struct tls12_crypto_info_aes_gcm_128)) {
+ rc = -EINVAL;
+ goto err_crypto_info;
+ }
+- rc = copy_from_user(
+- crypto_info,
+- optval,
+- sizeof(struct tls12_crypto_info_aes_gcm_128));
+-
++ rc = copy_from_user(crypto_info + 1, optval + sizeof(*crypto_info),
++ optlen - sizeof(*crypto_info));
+ if (rc) {
+ rc = -EFAULT;
+ goto err_crypto_info;
+--
+2.17.1
+
--- /dev/null
+From 65db835b5099a4be67c4b22efadf6372a6246d88 Mon Sep 17 00:00:00 2001
+From: Ilya Lesokhin <ilyal@mellanox.com>
+Date: Mon, 13 Nov 2017 10:22:49 +0200
+Subject: tls: don't override sk_write_space if tls_set_sw_offload fails.
+
+commit ee181e5201e640a4b92b217e9eab2531dab57d2c upstream.
+
+If we fail to enable tls in the kernel we shouldn't override
+the sk_write_space callback
+
+Fixes: 3c4d7559159b ('tls: kernel TLS support')
+Signed-off-by: Ilya Lesokhin <ilyal@mellanox.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/tls/tls_main.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
+index f88df514ad5f..33187e34599b 100644
+--- a/net/tls/tls_main.c
++++ b/net/tls/tls_main.c
+@@ -429,9 +429,6 @@ static int do_tls_setsockopt_tx(struct sock *sk, char __user *optval,
+ goto err_crypto_info;
+ }
+
+- ctx->sk_write_space = sk->sk_write_space;
+- sk->sk_write_space = tls_write_space;
+-
+ /* currently SW is default, we will have ethtool in future */
+ rc = tls_set_sw_offload(sk, ctx);
+ tx_conf = TLS_SW_TX;
+@@ -440,6 +437,8 @@ static int do_tls_setsockopt_tx(struct sock *sk, char __user *optval,
+
+ ctx->tx_conf = tx_conf;
+ update_sk_prot(sk, ctx);
++ ctx->sk_write_space = sk->sk_write_space;
++ sk->sk_write_space = tls_write_space;
+ goto out;
+
+ err_crypto_info:
+--
+2.17.1
+
--- /dev/null
+From 3f5057d9b9f89eefcd10e9aceea9e3c3b251c3e4 Mon Sep 17 00:00:00 2001
+From: Ilya Lesokhin <ilyal@mellanox.com>
+Date: Mon, 13 Nov 2017 10:22:46 +0200
+Subject: tls: Fix TLS ulp context leak, when TLS_TX setsockopt is not used.
+
+commit ff45d820a2df163957ad8ab459b6eb6976144c18 upstream.
+
+Previously the TLS ulp context would leak if we attached a TLS ulp
+to a socket but did not use the TLS_TX setsockopt,
+or did use it but it failed.
+This patch solves the issue by overriding prot[TLS_BASE_TX].close
+and fixing tls_sk_proto_close to work properly
+when its called with ctx->tx_conf == TLS_BASE_TX.
+This patch also removes ctx->free_resources as we can use ctx->tx_conf
+to obtain the relevant information.
+
+Fixes: 3c4d7559159b ('tls: kernel TLS support')
+Signed-off-by: Ilya Lesokhin <ilyal@mellanox.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+[bwh: Backported to 4.14: Keep using tls_ctx_free() as introduced by
+ the earlier backport of "tls: zero the crypto information from
+ tls_context before freeing"]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/tls.h | 2 +-
+ net/tls/tls_main.c | 24 ++++++++++++++++--------
+ net/tls/tls_sw.c | 3 +--
+ 3 files changed, 18 insertions(+), 11 deletions(-)
+
+diff --git a/include/net/tls.h b/include/net/tls.h
+index 0c3ab2af74d3..604fd982da19 100644
+--- a/include/net/tls.h
++++ b/include/net/tls.h
+@@ -106,7 +106,6 @@ struct tls_context {
+
+ u16 pending_open_record_frags;
+ int (*push_pending_record)(struct sock *sk, int flags);
+- void (*free_resources)(struct sock *sk);
+
+ void (*sk_write_space)(struct sock *sk);
+ void (*sk_proto_close)(struct sock *sk, long timeout);
+@@ -131,6 +130,7 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size);
+ int tls_sw_sendpage(struct sock *sk, struct page *page,
+ int offset, size_t size, int flags);
+ void tls_sw_close(struct sock *sk, long timeout);
++void tls_sw_free_tx_resources(struct sock *sk);
+
+ void tls_sk_destruct(struct sock *sk, struct tls_context *ctx);
+ void tls_icsk_clean_acked(struct sock *sk);
+diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
+index 191a8adee3ea..b5f9c578bcf0 100644
+--- a/net/tls/tls_main.c
++++ b/net/tls/tls_main.c
+@@ -249,6 +249,12 @@ static void tls_sk_proto_close(struct sock *sk, long timeout)
+ void (*sk_proto_close)(struct sock *sk, long timeout);
+
+ lock_sock(sk);
++ sk_proto_close = ctx->sk_proto_close;
++
++ if (ctx->tx_conf == TLS_BASE_TX) {
++ tls_ctx_free(ctx);
++ goto skip_tx_cleanup;
++ }
+
+ if (!tls_complete_pending_work(sk, ctx, 0, &timeo))
+ tls_handle_open_record(sk, 0);
+@@ -265,13 +271,16 @@ static void tls_sk_proto_close(struct sock *sk, long timeout)
+ sg++;
+ }
+ }
+- ctx->free_resources(sk);
++
+ kfree(ctx->rec_seq);
+ kfree(ctx->iv);
+
+- sk_proto_close = ctx->sk_proto_close;
+- tls_ctx_free(ctx);
++ if (ctx->tx_conf == TLS_SW_TX) {
++ tls_sw_free_tx_resources(sk);
++ tls_ctx_free(ctx);
++ }
+
++skip_tx_cleanup:
+ release_sock(sk);
+ sk_proto_close(sk, timeout);
+ }
+@@ -428,8 +437,6 @@ static int do_tls_setsockopt_tx(struct sock *sk, char __user *optval,
+ ctx->sk_write_space = sk->sk_write_space;
+ sk->sk_write_space = tls_write_space;
+
+- ctx->sk_proto_close = sk->sk_prot->close;
+-
+ /* currently SW is default, we will have ethtool in future */
+ rc = tls_set_sw_offload(sk, ctx);
+ tx_conf = TLS_SW_TX;
+@@ -499,6 +506,7 @@ static int tls_init(struct sock *sk)
+ icsk->icsk_ulp_data = ctx;
+ ctx->setsockopt = sk->sk_prot->setsockopt;
+ ctx->getsockopt = sk->sk_prot->getsockopt;
++ ctx->sk_proto_close = sk->sk_prot->close;
+
+ ctx->tx_conf = TLS_BASE_TX;
+ update_sk_prot(sk, ctx);
+@@ -515,11 +523,11 @@ static struct tcp_ulp_ops tcp_tls_ulp_ops __read_mostly = {
+ static void build_protos(struct proto *prot, struct proto *base)
+ {
+ prot[TLS_BASE_TX] = *base;
+- prot[TLS_BASE_TX].setsockopt = tls_setsockopt;
+- prot[TLS_BASE_TX].getsockopt = tls_getsockopt;
++ prot[TLS_BASE_TX].setsockopt = tls_setsockopt;
++ prot[TLS_BASE_TX].getsockopt = tls_getsockopt;
++ prot[TLS_BASE_TX].close = tls_sk_proto_close;
+
+ prot[TLS_SW_TX] = prot[TLS_BASE_TX];
+- prot[TLS_SW_TX].close = tls_sk_proto_close;
+ prot[TLS_SW_TX].sendmsg = tls_sw_sendmsg;
+ prot[TLS_SW_TX].sendpage = tls_sw_sendpage;
+ }
+diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
+index 6ae9ca567d6c..5996fb5756e1 100644
+--- a/net/tls/tls_sw.c
++++ b/net/tls/tls_sw.c
+@@ -646,7 +646,7 @@ sendpage_end:
+ return ret;
+ }
+
+-static void tls_sw_free_resources(struct sock *sk)
++void tls_sw_free_tx_resources(struct sock *sk)
+ {
+ struct tls_context *tls_ctx = tls_get_ctx(sk);
+ struct tls_sw_context *ctx = tls_sw_ctx(tls_ctx);
+@@ -685,7 +685,6 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx)
+ }
+
+ ctx->priv_ctx = (struct tls_offload_context *)sw_ctx;
+- ctx->free_resources = tls_sw_free_resources;
+
+ crypto_info = &ctx->crypto_send.info;
+ switch (crypto_info->cipher_type) {
+--
+2.17.1
+
--- /dev/null
+From 6c45b3bbf47c28c6d290e5afd18d1df4cdbec36b Mon Sep 17 00:00:00 2001
+From: Boris Pismenny <borisp@mellanox.com>
+Date: Tue, 27 Feb 2018 14:18:39 +0200
+Subject: tls: Use correct sk->sk_prot for IPV6
+
+commit c113187d38ff85dc302a1bb55864b203ebb2ba10 upstream.
+
+The tls ulp overrides sk->prot with a new tls specific proto structs.
+The tls specific structs were previously based on the ipv4 specific
+tcp_prot sturct.
+As a result, attaching the tls ulp to an ipv6 tcp socket replaced
+some ipv6 callback with the ipv4 equivalents.
+
+This patch adds ipv6 tls proto structs and uses them when
+attached to ipv6 sockets.
+
+Fixes: 3c4d7559159b ('tls: kernel TLS support')
+Signed-off-by: Boris Pismenny <borisp@mellanox.com>
+Signed-off-by: Ilya Lesokhin <ilyal@mellanox.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/tls/tls_main.c | 52 +++++++++++++++++++++++++++++++++-------------
+ 1 file changed, 37 insertions(+), 15 deletions(-)
+
+diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
+index 33187e34599b..e903bdd39b9f 100644
+--- a/net/tls/tls_main.c
++++ b/net/tls/tls_main.c
+@@ -46,17 +46,27 @@ MODULE_DESCRIPTION("Transport Layer Security Support");
+ MODULE_LICENSE("Dual BSD/GPL");
+ MODULE_ALIAS_TCP_ULP("tls");
+
++enum {
++ TLSV4,
++ TLSV6,
++ TLS_NUM_PROTS,
++};
++
+ enum {
+ TLS_BASE_TX,
+ TLS_SW_TX,
+ TLS_NUM_CONFIG,
+ };
+
+-static struct proto tls_prots[TLS_NUM_CONFIG];
++static struct proto *saved_tcpv6_prot;
++static DEFINE_MUTEX(tcpv6_prot_mutex);
++static struct proto tls_prots[TLS_NUM_PROTS][TLS_NUM_CONFIG];
+
+ static inline void update_sk_prot(struct sock *sk, struct tls_context *ctx)
+ {
+- sk->sk_prot = &tls_prots[ctx->tx_conf];
++ int ip_ver = sk->sk_family == AF_INET6 ? TLSV6 : TLSV4;
++
++ sk->sk_prot = &tls_prots[ip_ver][ctx->tx_conf];
+ }
+
+ int wait_on_pending_writer(struct sock *sk, long *timeo)
+@@ -476,8 +486,21 @@ static int tls_setsockopt(struct sock *sk, int level, int optname,
+ return do_tls_setsockopt(sk, optname, optval, optlen);
+ }
+
++static void build_protos(struct proto *prot, struct proto *base)
++{
++ prot[TLS_BASE_TX] = *base;
++ prot[TLS_BASE_TX].setsockopt = tls_setsockopt;
++ prot[TLS_BASE_TX].getsockopt = tls_getsockopt;
++ prot[TLS_BASE_TX].close = tls_sk_proto_close;
++
++ prot[TLS_SW_TX] = prot[TLS_BASE_TX];
++ prot[TLS_SW_TX].sendmsg = tls_sw_sendmsg;
++ prot[TLS_SW_TX].sendpage = tls_sw_sendpage;
++}
++
+ static int tls_init(struct sock *sk)
+ {
++ int ip_ver = sk->sk_family == AF_INET6 ? TLSV6 : TLSV4;
+ struct inet_connection_sock *icsk = inet_csk(sk);
+ struct tls_context *ctx;
+ int rc = 0;
+@@ -502,6 +525,17 @@ static int tls_init(struct sock *sk)
+ ctx->getsockopt = sk->sk_prot->getsockopt;
+ ctx->sk_proto_close = sk->sk_prot->close;
+
++ /* Build IPv6 TLS whenever the address of tcpv6_prot changes */
++ if (ip_ver == TLSV6 &&
++ unlikely(sk->sk_prot != smp_load_acquire(&saved_tcpv6_prot))) {
++ mutex_lock(&tcpv6_prot_mutex);
++ if (likely(sk->sk_prot != saved_tcpv6_prot)) {
++ build_protos(tls_prots[TLSV6], sk->sk_prot);
++ smp_store_release(&saved_tcpv6_prot, sk->sk_prot);
++ }
++ mutex_unlock(&tcpv6_prot_mutex);
++ }
++
+ ctx->tx_conf = TLS_BASE_TX;
+ update_sk_prot(sk, ctx);
+ out:
+@@ -514,21 +548,9 @@ static struct tcp_ulp_ops tcp_tls_ulp_ops __read_mostly = {
+ .init = tls_init,
+ };
+
+-static void build_protos(struct proto *prot, struct proto *base)
+-{
+- prot[TLS_BASE_TX] = *base;
+- prot[TLS_BASE_TX].setsockopt = tls_setsockopt;
+- prot[TLS_BASE_TX].getsockopt = tls_getsockopt;
+- prot[TLS_BASE_TX].close = tls_sk_proto_close;
+-
+- prot[TLS_SW_TX] = prot[TLS_BASE_TX];
+- prot[TLS_SW_TX].sendmsg = tls_sw_sendmsg;
+- prot[TLS_SW_TX].sendpage = tls_sw_sendpage;
+-}
+-
+ static int __init tls_register(void)
+ {
+- build_protos(tls_prots, &tcp_prot);
++ build_protos(tls_prots[TLSV4], &tcp_prot);
+
+ tcp_register_ulp(&tcp_tls_ulp_ops);
+
+--
+2.17.1
+
--- /dev/null
+From 6c2f1c1731c9c25b48882f64f5762d4e981cd306 Mon Sep 17 00:00:00 2001
+From: Richard Weinberger <richard@nod.at>
+Date: Tue, 12 Jun 2018 09:33:16 +0200
+Subject: ubi: Initialize Fastmap checkmapping correctly
+
+commit 25677478474a91fa1b46f19a4a591a9848bca6fb upstream
+
+We cannot do it last, otherwithse it will be skipped for dynamic
+volumes.
+
+Reported-by: Lachmann, Juergen <juergen.lachmann@harman.com>
+Fixes: 34653fd8c46e ("ubi: fastmap: Check each mapping only once")
+Signed-off-by: Richard Weinberger <richard@nod.at>
+Signed-off-by: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mtd/ubi/vtbl.c | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
+index 94d7a865b135..7504f430c011 100644
+--- a/drivers/mtd/ubi/vtbl.c
++++ b/drivers/mtd/ubi/vtbl.c
+@@ -578,6 +578,16 @@ static int init_volumes(struct ubi_device *ubi,
+ vol->ubi = ubi;
+ reserved_pebs += vol->reserved_pebs;
+
++ /*
++ * We use ubi->peb_count and not vol->reserved_pebs because
++ * we want to keep the code simple. Otherwise we'd have to
++ * resize/check the bitmap upon volume resize too.
++ * Allocating a few bytes more does not hurt.
++ */
++ err = ubi_fastmap_init_checkmap(vol, ubi->peb_count);
++ if (err)
++ return err;
++
+ /*
+ * In case of dynamic volume UBI knows nothing about how many
+ * data is stored there. So assume the whole volume is used.
+@@ -620,16 +630,6 @@ static int init_volumes(struct ubi_device *ubi,
+ (long long)(vol->used_ebs - 1) * vol->usable_leb_size;
+ vol->used_bytes += av->last_data_size;
+ vol->last_eb_bytes = av->last_data_size;
+-
+- /*
+- * We use ubi->peb_count and not vol->reserved_pebs because
+- * we want to keep the code simple. Otherwise we'd have to
+- * resize/check the bitmap upon volume resize too.
+- * Allocating a few bytes more does not hurt.
+- */
+- err = ubi_fastmap_init_checkmap(vol, ubi->peb_count);
+- if (err)
+- return err;
+ }
+
+ /* And add the layout volume */
+--
+2.17.1
+
--- /dev/null
+From 78e34acd58faa8ea15c5e282676e5f188f2432ac Mon Sep 17 00:00:00 2001
+From: Lior David <qca_liord@qca.qualcomm.com>
+Date: Tue, 14 Nov 2017 15:25:39 +0200
+Subject: wil6210: missing length check in wmi_set_ie
+
+commit b5a8ffcae4103a9d823ea3aa3a761f65779fbe2a upstream.
+
+Add a length check in wmi_set_ie to detect unsigned integer
+overflow.
+
+Signed-off-by: Lior David <qca_liord@qca.qualcomm.com>
+Signed-off-by: Maya Erez <qca_merez@qca.qualcomm.com>
+Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/wil6210/wmi.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
+index ffdd2fa401b1..d63d7c326801 100644
+--- a/drivers/net/wireless/ath/wil6210/wmi.c
++++ b/drivers/net/wireless/ath/wil6210/wmi.c
+@@ -1380,8 +1380,14 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
+ };
+ int rc;
+ u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len;
+- struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL);
++ struct wmi_set_appie_cmd *cmd;
+
++ if (len < ie_len) {
++ rc = -EINVAL;
++ goto out;
++ }
++
++ cmd = kzalloc(len, GFP_KERNEL);
+ if (!cmd) {
+ rc = -ENOMEM;
+ goto out;
+--
+2.17.1
+
--- /dev/null
+From e51c18bdd2550bd3456a374755ceb5879cfb025c Mon Sep 17 00:00:00 2001
+From: "Darrick J. Wong" <darrick.wong@oracle.com>
+Date: Tue, 17 Apr 2018 19:10:15 -0700
+Subject: xfs: don't fail when converting shortform attr to long form during
+ ATTR_REPLACE
+
+commit 7b38460dc8e4eafba06c78f8e37099d3b34d473c upstream.
+
+Kanda Motohiro reported that expanding a tiny xattr into a large xattr
+fails on XFS because we remove the tiny xattr from a shortform fork and
+then try to re-add it after converting the fork to extents format having
+not removed the ATTR_REPLACE flag. This fails because the attr is no
+longer present, causing a fs shutdown.
+
+This is derived from the patch in his bug report, but we really
+shouldn't ignore a nonzero retval from the remove call.
+
+Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=199119
+Reported-by: kanda.motohiro@gmail.com
+Reviewed-by: Dave Chinner <dchinner@redhat.com>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/xfs/libxfs/xfs_attr.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
+index 6249c92671de..ea66f04f46f7 100644
+--- a/fs/xfs/libxfs/xfs_attr.c
++++ b/fs/xfs/libxfs/xfs_attr.c
+@@ -501,7 +501,14 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
+ if (args->flags & ATTR_CREATE)
+ return retval;
+ retval = xfs_attr_shortform_remove(args);
+- ASSERT(retval == 0);
++ if (retval)
++ return retval;
++ /*
++ * Since we have removed the old attr, clear ATTR_REPLACE so
++ * that the leaf format add routine won't trip over the attr
++ * not being around.
++ */
++ args->flags &= ~ATTR_REPLACE;
+ }
+
+ if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX ||
+--
+2.17.1
+