Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp10788642imu; Thu, 6 Dec 2018 06:51:13 -0800 (PST) X-Google-Smtp-Source: AFSGD/WwPeXedi3HaLrZRm5TfQUlFOSquYatDXqGauCPH3xEvV2cJK74IP+3UzA7BZ3YyIrnxH7C X-Received: by 2002:a63:e84c:: with SMTP id a12mr24107508pgk.241.1544107873216; Thu, 06 Dec 2018 06:51:13 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1544107873; cv=none; d=google.com; s=arc-20160816; b=ZyNKB0c8stsjXNa6EvKTH+7frPqhVG82twH0vTxxRyPi4Mc4rJ+ITCeP569tW/ON85 +filPGJacibg7dL0Ll/39FPvJNL2UD8ONnBcSWpCtphAbf2LjUCDdgTD+AB4/fERmILj VQVHsLrmiEHt8m5J8igFB9529IRgoe9VdlUfYe4uBND5bwAbuYNKXj6GgmEUCjSIHka0 m7V2aYJLXS+/P01eMypWw1kzXd1M9rX6Li1SBvTVILY9kf1uqo00YEyMQ5OZypNJEcDg eMe244zifHw92Qp/MPsai6Rsi7uR+Y+KLJH6WQjrP20H5XONzRI9KXUl6VTtfvjlzwsW dh2w== 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=WXkCj7GAvjFzY9cp/kx8TdqunF/hxfjW8+56bLspWUU=; b=Od7fV6bneVYjX4eG+vj6+ykgx4481Rk7jNZ30DoIzVRci4lkDgMi0i5I8WD1GQ4GdD oiHP8NsSRL7dTLJfq+NJDXd/HMDNPK27wvvCO17YoRqFsJtugsaxI99PiDJbeWMIHESP W34PCfyjdegJpeKy7nN1oT5fafqScignms+LHFVLkryySarsQ/ycBieMbOcmv8hxkHRR RQfwEjXyjbKLFiiV6fMVXMODca0tQ3m4+6LrR5bq3b1IbCL4RamaGO/Qf1ZEIc71fqmS g9A92nj2jOYtSmUJZgL7XbdtuNUqYyRu9Ulmx0ecKvjiCaYnnVoSve5C76oRdP5w5Kg7 Z4bQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=xqqc5qOU; 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 e13si395347pgh.251.2018.12.06.06.50.57; Thu, 06 Dec 2018 06:51:13 -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=xqqc5qOU; 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 S1731495AbeLFOrt (ORCPT + 99 others); Thu, 6 Dec 2018 09:47:49 -0500 Received: from mail.kernel.org ([198.145.29.99]:52846 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730276AbeLFOrp (ORCPT ); Thu, 6 Dec 2018 09:47:45 -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 94C9E2146D; Thu, 6 Dec 2018 14:47:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1544107665; bh=WPYW+iIEPFHUYDdvdiMkxBGc6FNXqlcK+mWzIYty9Nw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=xqqc5qOU5/H3LIdG25cYXJOaf0IP2CyUyRCaIibH9eW/il8rR5mRxsBeDDm2s//Cn 7fUMMiLGQm5jibXc6k4S2VE9dSg0jwX6JmId37JUNKv+Ob0iIg5ZOf8H5yYZ30nz8n U1VijJQHCBB29oKObglFhdb3LlpSmYOx0TKaHefY= 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 Subject: [PATCH 4.9 075/101] btrfs: tree-checker: Add checker for dir item Date: Thu, 6 Dec 2018 15:39:14 +0100 Message-Id: <20181206143016.411314214@linuxfoundation.org> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181206143011.174892052@linuxfoundation.org> References: <20181206143011.174892052@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.9-stable review patch. If anyone has any objections, please let me know. ------------------ From: Qu Wenruo 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 [bwh: Backported to 4.9: BTRFS_MAX_XATTR_SIZE() takes a root not an fs_info] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/tree-checker.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) --- 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, \ @@ -176,6 +177,141 @@ static int check_csum_item(struct btrfs_ } /* + * 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)) { + 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)); + 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. */ static int check_leaf_item(struct btrfs_root *root, @@ -191,6 +327,11 @@ static int check_leaf_item(struct btrfs_ 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; }