--- /dev/null
+From 8f77ba4ef3fe576ee26236469647056d88874af5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Sep 2018 07:59:34 +0800
+Subject: btrfs: tree-checker: Check level for leaves and nodes
+
+From: Qu Wenruo <wqu@suse.com>
+
+[ Upstream commit f556faa46eb4e96d0d0772e74ecf66781e132f72 ]
+
+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>
+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 235c2970b944..d98ec885b72a 100644
+--- a/fs/btrfs/tree-checker.c
++++ b/fs/btrfs/tree-checker.c
+@@ -485,6 +485,13 @@ static int check_leaf(struct btrfs_fs_info *fs_info, struct extent_buffer *leaf,
+ u32 nritems = btrfs_header_nritems(leaf);
+ int slot;
+
++ if (btrfs_header_level(leaf) != 0) {
++ generic_err(fs_info, 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
+@@ -649,9 +656,16 @@ int btrfs_check_node(struct btrfs_fs_info *fs_info, 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(fs_info, 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(fs_info)) {
+ btrfs_crit(fs_info,
+ "corrupt node: root=%llu block=%llu, nritems too %s, have %lu expect range [1,%u]",
+--
+2.25.1
+