From patchwork Thu May 14 03:06:24 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Qu Wenruo X-Patchwork-Id: 6402551 Return-Path: X-Original-To: patchwork-linux-btrfs@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 33A89BEEE1 for ; Thu, 14 May 2015 03:08:40 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 42D5620435 for ; Thu, 14 May 2015 03:08:39 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 3A61C2042B for ; Thu, 14 May 2015 03:08:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S934620AbbENDI3 (ORCPT ); Wed, 13 May 2015 23:08:29 -0400 Received: from cn.fujitsu.com ([59.151.112.132]:7072 "EHLO heian.cn.fujitsu.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S933286AbbENDI2 (ORCPT ); Wed, 13 May 2015 23:08:28 -0400 X-IronPort-AV: E=Sophos;i="5.04,848,1406563200"; d="scan'208";a="92133777" Received: from localhost (HELO edo.cn.fujitsu.com) ([10.167.33.5]) by heian.cn.fujitsu.com with ESMTP; 14 May 2015 11:04:30 +0800 Received: from G08CNEXCHPEKD02.g08.fujitsu.local (localhost.localdomain [127.0.0.1]) by edo.cn.fujitsu.com (8.14.3/8.13.1) with ESMTP id t4E3746P032109; Thu, 14 May 2015 11:07:04 +0800 Received: from localhost.localdomain (10.167.226.33) by G08CNEXCHPEKD02.g08.fujitsu.local (10.167.33.89) with Microsoft SMTP Server (TLS) id 14.3.181.6; Thu, 14 May 2015 11:08:25 +0800 From: Qu Wenruo To: CC: Subject: [PATCH] btrfs-progs: Enhance read_tree_block to avoid memory corruption. Date: Thu, 14 May 2015 11:06:24 +0800 Message-ID: <1431572784-32124-1-git-send-email-quwenruo@cn.fujitsu.com> X-Mailer: git-send-email 2.4.0 MIME-Version: 1.0 X-Originating-IP: [10.167.226.33] Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add the following tree_block check to avoid memory corruption or hostile image: 1) Check level. Level >= BTRFS_MAX_LEVEL won't be read out. 2) Nritems. For nritems == 0 or nr_items > max_nritems, the tree_block won't be read out. Max nritems is calculated in a easy method. For node, it's straightforward, just (nodesize - header size) / (btrfs_key_ptr) For leaf, (nodesize - header size) / (btrfs_item), assume btrfs support item size == 0; This fixes 3 kernel bugs: BZ#97171, BZ#97191, BZ#97271. Reported-by: Lukas Lueg Signed-off-by: Qu Wenruo --- disk-io.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/disk-io.c b/disk-io.c index bf796c6..356150a 100644 --- a/disk-io.c +++ b/disk-io.c @@ -37,8 +37,22 @@ /* specified errno for check_tree_block */ #define BTRFS_BAD_BYTENR (-1) #define BTRFS_BAD_FSID (-2) +#define BTRFS_BAD_LEVEL (-3) +#define BTRFS_BAD_NRITEMS (-4) #define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) + +/* Calculate max possible nritems for a leaf/node */ +static u32 max_nritems(u8 level, u32 nodesize) +{ + + if (level == 0) + return ((nodesize - sizeof(struct btrfs_header)) / + sizeof(struct btrfs_item)); + return ((nodesize - sizeof(struct btrfs_header)) / + sizeof(struct btrfs_key_ptr)); +} + static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf) { @@ -47,6 +61,12 @@ static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf) if (buf->start != btrfs_header_bytenr(buf)) return BTRFS_BAD_BYTENR; + if (btrfs_header_level(buf) >= BTRFS_MAX_LEVEL) + return BTRFS_BAD_LEVEL; + if (btrfs_header_nritems(buf) == 0 || + btrfs_header_nritems(buf) > max_nritems(btrfs_header_level(buf), + root->nodesize)) + return BTRFS_BAD_NRITEMS; fs_devices = root->fs_info->fs_devices; while (fs_devices) { @@ -82,6 +102,14 @@ static void print_tree_block_error(struct btrfs_root *root, fprintf(stderr, "bytenr mismatch, want=%llu, have=%llu\n", eb->start, btrfs_header_bytenr(eb)); break; + case BTRFS_BAD_LEVEL: + fprintf(stderr, "bad level, %u > %u\n", + btrfs_header_level(eb), BTRFS_MAX_LEVEL); + break; + case BTRFS_BAD_NRITEMS: + fprintf(stderr, "invalid nr_items: %u\n", + btrfs_header_nritems(eb)); + break; } }