From patchwork Tue Aug 22 07:37:17 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Qu Wenruo X-Patchwork-Id: 9914345 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 55D62608A6 for ; Tue, 22 Aug 2017 07:38:04 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 46220287C8 for ; Tue, 22 Aug 2017 07:38:04 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3B5F328809; Tue, 22 Aug 2017 07:38:04 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,FREEMAIL_FROM, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9F3562880B for ; Tue, 22 Aug 2017 07:38:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754727AbdHVHhk (ORCPT ); Tue, 22 Aug 2017 03:37:40 -0400 Received: from mout.gmx.net ([212.227.15.19]:60946 "EHLO mout.gmx.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754712AbdHVHh3 (ORCPT ); Tue, 22 Aug 2017 03:37:29 -0400 Received: from localhost.localdomain ([45.32.39.184]) by mail.gmx.com (mrgmx001 [212.227.17.184]) with ESMTPSA (Nemesis) id 0MJByE-1dhIb93NiU-002nKS; Tue, 22 Aug 2017 09:37:26 +0200 From: Qu Wenruo To: linux-btrfs@vger.kernel.org Cc: dsterba@suse.cz Subject: [PATCH 3/3] btrfs: Add sanity check for EXTENT_DATA when reading out leaf Date: Tue, 22 Aug 2017 16:37:17 +0900 Message-Id: <20170822073717.13081-4-quwenruo.btrfs@gmx.com> X-Mailer: git-send-email 2.13.3 In-Reply-To: <20170822073717.13081-1-quwenruo.btrfs@gmx.com> References: <20170822073717.13081-1-quwenruo.btrfs@gmx.com> X-Provags-ID: V03:K0:U0XIEEyyE189rntCvJtlG13HezUw2NgYEjFU5ZlvrV0m7v8oaVo oZifXC+gZt/a/SY3UM1x4tKxq+wAQmN1RVGkCOzJ9Q4IcQ3tUqmCKmHjyVH3nd5kKgmIpxq HP59PzHcr9BRbgjTFcjQ80cHZmgU/BR4cWU0+zMT9HwQTmfNe564Mug2cPBAh/UoFfl8UEo ZbdULtN2K248qa3kWP7hw== X-UI-Out-Filterresults: notjunk:1; V01:K0:hWZr1XH/goA=:sX5ILDfdVIgbtX1NeV9H7E iglxkcEmdtwbLKEy73yExOAutQTODRjrBk7Tr6DBU2hvcn+h4HLSoNSGluAzblb8ZS50Ipnz0 K9hiu57I2Yj9ToxHM0X24W0Vm+FSHkLNh3WRxOTrK2Dm1UGacfP/MjJrMCeup0X7Q9dOR0CqQ yM2ny5zhanzHPTV7q7qXRUenge/uaN9s4SD6w/pIbLkMWdY6O8kGHRBv1b+m3Ut8qJs6jPLnO jVzaEz2bu027HApTvdYeR+RF9WYVw0IPxacSap0CCk4cGIXpgXQU4PeYCjyLHjOHSfIT8zX/r nxAsyAyMaPpC32Y3ZCKUUrn570rEiqeLYdoiLlrBM3n691LS4F7v5zrwxD4lC6th+NQr5OUFC R9HCnTrIHpdPNSrwZJwS93qlV0nXnqvrtUnX9dCWPdf7Xz/zi/15Ozo6PzCYzxaJX4KbY1JD/ E1apc6ceMBp5NVqbP66Gjg0rKnbwJolkup8SBxeCMb1GAqJ0gZ91iZqqTO7WvobzGWWV2E8VR QanwUiHl/cyLk4X4c+/cJOl9n1SE006pF6yoCislkrrOfHugkmRoGivjBnSulAe2zoqQkVAB3 bCl2jkVLSi+4qDB4P8Bh+iVbBzOBgl4hVrmZ8lS2wI0/hAtVEoe21G39JDOQtu+UmmbrLErnF zcgjXnvfjhO8v/s1aIljiLQzS273+irLWy8d7mS9N0k0vYCFNRA+wLpSIFn5e+a5hDUGouePm 1toORmTs2hRc1vI8bw+PieCvyGAN+Qp+7vHoaHhdx26Qd3igcoV88hrTSheQE5DX/y0gPpWfY 2QLXn0UhKziL1jsRfQOkmy0QxcZAg== Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add extra checker for item with EXTENT_DATA type. This checks the following thing: 1) Item size Plain text inline file extent size must match item size. (compressed inline file extent has no info 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 restrict check in the context of btrfs_item for EXTENT_DATA. Signed-off-by: Qu Wenruo --- fs/btrfs/disk-io.c | 88 +++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/btrfs_tree.h | 1 + 2 files changed, 89 insertions(+) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 59ee7b959bf0..557f9a520e2a 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -549,6 +549,83 @@ 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, int slot) +{ + struct btrfs_file_extent_item *fi; + u32 sectorsize = root->fs_info->sectorsize; + u32 item_size = btrfs_item_size_nr(leaf, slot); + + fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); + + if (btrfs_file_extent_type(leaf, fi) >= BTRFS_FILE_EXTENT_LAST_TYPE) { + CORRUPT("invalid file extent type", leaf, root, slot); + return -EIO; + } + if (btrfs_file_extent_compression(leaf, fi) >= BTRFS_COMPRESS_LAST) { + CORRUPT("invalid file extent compression", leaf, root, slot); + return -EIO; + } + if (btrfs_file_extent_encryption(leaf, fi)) { + CORRUPT("invalid file extent encryption", leaf, root, slot); + return -EIO; + } + if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) { + if (btrfs_file_extent_compression(leaf, fi) != + BTRFS_COMPRESS_NONE) + return 0; + /* Plaintext 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 -EIO; + } + 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 -EIO; + } + 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 -EIO; + } + + return 0; +} + +static int check_leaf_item(struct btrfs_root *root, + struct extent_buffer *leaf, int slot) +{ + struct btrfs_key key; + int ret = 0; + + btrfs_item_key_to_cpu(leaf, &key, slot); + /* + * Considering how overcrowded the code will be inside the switch, + * complex verification is better to moved its own function. + */ + switch (key.type) { + case BTRFS_EXTENT_DATA_KEY: + ret = check_extent_data_item(root, leaf, slot); + break; + } + return ret; +} + static noinline int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf) { @@ -605,9 +682,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 check 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); @@ -650,6 +731,13 @@ static noinline int check_leaf(struct btrfs_root *root, return -EIO; } + /* + * Check if the item size and content meets other limitation + */ + ret = check_leaf_item(root, leaf, 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 10689e1fdf11..3aadbb74a024 100644 --- a/include/uapi/linux/btrfs_tree.h +++ b/include/uapi/linux/btrfs_tree.h @@ -732,6 +732,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_LAST_TYPE 3 struct btrfs_file_extent_item { /*