Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp8122279imu; Tue, 4 Dec 2018 03:23:11 -0800 (PST) X-Google-Smtp-Source: AFSGD/UlQBs7pnf1xgF4C9IIInAp0KltS7gTVlRazw2HMUHwK5XvxVkBmLyNoWAFPPrkU5EtmUCi X-Received: by 2002:a65:6215:: with SMTP id d21mr16398418pgv.289.1543922591467; Tue, 04 Dec 2018 03:23:11 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1543922591; cv=none; d=google.com; s=arc-20160816; b=YhegrH26VDeZ8VT44ckVCfI5Eu63VSsxJrHfkpyKe2DOT2PiODpF0ntlYsmHINuDm+ vdi/XFuloqBfxdolW6uEVOoliKH+2Fz4XROnqqTLJj/dW4xf/mlhbTgf8x3+P3dhyMfk MMxUtrhrne5yD4NJYwRj5S6dyuHDGECY3cZKGvqZqgbJQ4omBUtnseU+p3KeOFfwS1Wx cYOvL+G4F3yDLJa1owXHpeKWtdpQsKxv/ZYRZOEVmprrMAkJqelTNXeu8IlbOBpMTJpU /bdge4/R10s5bWzJV3b/giBHTCyuIyqEglltml2F4hH+c763NFesB3yVVz5Mg9NChHJY IvLQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=w+JuM7ZVNpZp8oYa1qCNyAYkcIHtZXPqj58IXi7HWB4=; b=z9PfzYYLh1XENS0XAMD4xVqrtco/eavfeyvQI3oMnknfcHsmV4/bQY3zQUmpKPuW4F yqLBgSBGuX5CXFTjDAAJpjdDp7Sv1LoujMlkG83cP2fv4732hKVO3NlYL7rENliWQtWf F0HfFheTqblbKrwYka/kIsmsV5eQFvCs8lkJbL487nAF5/dkkSPnqnU3UHJvFfirhTNQ LijK0naL7aT0LeBBUhRtX5HWvB/YPSTsqyLUDkgm9ZnwfGwK/38L7SD849WB8SgRZRA/ +N1JKswe5uN/SNE2g8P+AwxjTh9cKTDr2UBvs1fQf0QN3pnnc8tUMiviUK22kXkONgOd nxfg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b="z/YbYYzn"; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 20si17518110pft.177.2018.12.04.03.22.56; Tue, 04 Dec 2018 03:23:11 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b="z/YbYYzn"; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727564AbeLDLWW (ORCPT + 99 others); Tue, 4 Dec 2018 06:22:22 -0500 Received: from mail.kernel.org ([198.145.29.99]:48446 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727063AbeLDLC1 (ORCPT ); Tue, 4 Dec 2018 06:02:27 -0500 Received: from localhost (5356596B.cm-6-7b.dynamic.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 72627214DB; Tue, 4 Dec 2018 11:02:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1543921346; bh=V9JU1Bbi/BI5jHyyLlxqLYwirfGF0S6rh9mj/ueSPWE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=z/YbYYznQrAKX8SsgcPE57YwAcOSOQhDZyYqZ+aT7VEeuo5vfOztV9mZrPcHccOUl 8CdWm++f74Kz9aeP4GvXkYgUmzXDqgB1rhY52u1AoMgFrkGHNcjE7ugox5Kbt5o5H4 tXU6gYoufmkaqbMoI4p6zHPEVY7NjqIa03VJTI3g= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Qu Wenruo , Nikolay Borisov , Su Yue , David Sterba , Ben Hutchings , Sasha Levin Subject: [PATCH 4.14 036/146] btrfs: tree-checker: Add checker for dir item Date: Tue, 4 Dec 2018 11:48:42 +0100 Message-Id: <20181204103728.310308634@linuxfoundation.org> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181204103726.750894136@linuxfoundation.org> References: <20181204103726.750894136@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review X-Patchwork-Hint: ignore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 4.14-stable review patch. If anyone has any objections, please let me know. ------------------ 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 Reviewed-by: Nikolay Borisov Reviewed-by: Su Yue Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Ben Hutchings Signed-off-by: Sasha Levin --- 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