Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp3427518imu; Sun, 11 Nov 2018 14:52:04 -0800 (PST) X-Google-Smtp-Source: AJdET5dPi/yu0PfElfvpjtv7QpoKhdNrydb/EsQ1Dg4G0g/6SJy9AbRz5crhHSBvIHWv5vZvVlcx X-Received: by 2002:a17:902:1006:: with SMTP id b6-v6mr17076565pla.252.1541976723987; Sun, 11 Nov 2018 14:52:03 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1541976723; cv=none; d=google.com; s=arc-20160816; b=Fr0eLifpU+gZLE0P6+zOxnUyBVoOKjauOM3enVSiy4ntHZfdQ8jNehWAIJEzttgB6H vS4rkLrCz8+sz3LlVirA4wAN5tB8JJsf7J53VFxw5ZI0KxIMeZQWsOSYk11oDwwgvfFa JRKGC6iIYK3Nd1dmXsoowHNgfeAFMHPLnGwo9uB0XJ2t/saQynjprr6awkf4Gw2i08YW QeN4ndqGyDFMCExsfRyLnO6hEOeyWdNH9obanoxrBlRQuqKeDmvZ8wL7QvVCvgPnZys/ C5iN6WzM+leTEY/nAmVMZUXaz2lCo4U0xRypuwiIrDe6P/0SzSDE2EtRhfJlsisQi2cd t4/w== 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=GNY5gUGOpJlKAmJ1UuhNWpUqBBzgH/jFjaqBcg0GSsI=; b=M5T9Jvi2u225FMTFt+e3hDVLK8wSaIh4JRc/ucCX3+TpbmoNaM1VHsbHefBY6+Hiti 7jpvI91g+bNpqeqzx1XoJ++2GRef1Jg/MP8ZUvHS/1T/I7t2N9+w4XCe4ivFB3NCjWxQ MNpipbqOQFX2RKjTLn2Nv5NboTmvW7zq7snQ0mEOvYb7DGJhjV0ymDlq3cSzfvfw4rTe JrtYQ9ekE40JhnBMeoHGTcAUZGbrfQmPKK9KET8dfrsVVAaGFd3tMAClv+mQ60AZOOW6 yunPGo3ajNzVCpVVZmwUcR4bWCY/aMJLCr/L/6iR4YX0zvpHsw9v99O4f+55Ymq7D+Ln bM8A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=L+LZMWgC; 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 188-v6si16043926pfd.19.2018.11.11.14.51.48; Sun, 11 Nov 2018 14:52:03 -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=L+LZMWgC; 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 S2390979AbeKLIld (ORCPT + 99 others); Mon, 12 Nov 2018 03:41:33 -0500 Received: from mail.kernel.org ([198.145.29.99]:54772 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2404155AbeKLIXG (ORCPT ); Mon, 12 Nov 2018 03:23:06 -0500 Received: from localhost (unknown [206.108.79.134]) (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 389012154B; Sun, 11 Nov 2018 22:33:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1541975589; bh=JwIiKnLRpEx4aGZGAR5RlAekbppAhgbr+9rG0Ui5cFU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=L+LZMWgCJ3w5qxTi2pZGdIAk/Bno7QvQ7QSowjqh32ABiSc0BelkOxXvTr6Z0Li42 /Qw5t9/9SeMOpgZLtHbjNgfb574W92H5rCCVJsxN/2SDaiX43qsZFtlm8ULMtM6/r8 Idtq5CoinrInve80AtANxIPdvLoLTg+ux46ecRTQ= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Xu Wen , Qu Wenruo , David Sterba Subject: [PATCH 4.14 198/222] btrfs: locking: Add extra check in btrfs_init_new_buffer() to avoid deadlock Date: Sun, 11 Nov 2018 14:24:55 -0800 Message-Id: <20181111221704.495904534@linuxfoundation.org> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181111221647.665769131@linuxfoundation.org> References: <20181111221647.665769131@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review 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. ------------------ From: Qu Wenruo commit b72c3aba09a53fc7c1824250d71180ca154517a7 upstream. [BUG] For certain crafted image, whose csum root leaf has missing backref, if we try to trigger write with data csum, it could cause deadlock with the following kernel WARN_ON(): WARNING: CPU: 1 PID: 41 at fs/btrfs/locking.c:230 btrfs_tree_lock+0x3e2/0x400 CPU: 1 PID: 41 Comm: kworker/u4:1 Not tainted 4.18.0-rc1+ #8 Workqueue: btrfs-endio-write btrfs_endio_write_helper RIP: 0010:btrfs_tree_lock+0x3e2/0x400 Call Trace: btrfs_alloc_tree_block+0x39f/0x770 __btrfs_cow_block+0x285/0x9e0 btrfs_cow_block+0x191/0x2e0 btrfs_search_slot+0x492/0x1160 btrfs_lookup_csum+0xec/0x280 btrfs_csum_file_blocks+0x2be/0xa60 add_pending_csums+0xaf/0xf0 btrfs_finish_ordered_io+0x74b/0xc90 finish_ordered_fn+0x15/0x20 normal_work_helper+0xf6/0x500 btrfs_endio_write_helper+0x12/0x20 process_one_work+0x302/0x770 worker_thread+0x81/0x6d0 kthread+0x180/0x1d0 ret_from_fork+0x35/0x40 [CAUSE] That crafted image has missing backref for csum tree root leaf. And when we try to allocate new tree block, since there is no EXTENT/METADATA_ITEM for csum tree root, btrfs consider it's free slot and use it. The extent tree of the image looks like: Normal image | This fuzzed image ----------------------------------+-------------------------------- BG 29360128 | BG 29360128 One empty slot | One empty slot 29364224: backref to UUID tree | 29364224: backref to UUID tree Two empty slots | Two empty slots 29376512: backref to CSUM tree | One empty slot (bad type) <<< 29380608: backref to D_RELOC tree | 29380608: backref to D_RELOC tree ... | ... Since bytenr 29376512 has no METADATA/EXTENT_ITEM, when btrfs try to alloc tree block, it's an valid slot for btrfs. And for finish_ordered_write, when we need to insert csum, we try to CoW csum tree root. By accident, empty slots at bytenr BG_OFFSET, BG_OFFSET + 8K, BG_OFFSET + 12K is already used by tree block COW for other trees, the next empty slot is BG_OFFSET + 16K, which should be the backref for CSUM tree. But due to the bad type, btrfs can recognize it and still consider it as an empty slot, and will try to use it for csum tree CoW. Then in the following call trace, we will try to lock the new tree block, which turns out to be the old csum tree root which is already locked: btrfs_search_slot() called on csum tree root, which is at 29376512 |- btrfs_cow_block() |- btrfs_set_lock_block() | |- Now locks tree block 29376512 (old csum tree root) |- __btrfs_cow_block() |- btrfs_alloc_tree_block() |- btrfs_reserve_extent() | Now it returns tree block 29376512, which extent tree | shows its empty slot, but it's already hold by csum tree |- btrfs_init_new_buffer() |- btrfs_tree_lock() | Triggers WARN_ON(eb->lock_owner == current->pid) |- wait_event() Wait lock owner to release the lock, but it's locked by ourself, so it will deadlock [FIX] This patch will do the lock_owner and current->pid check at btrfs_init_new_buffer(). So above deadlock can be avoided. Since such problem can only happen in crafted image, we will still trigger kernel warning for later aborted transaction, but with a little more meaningful warning message. Link: https://bugzilla.kernel.org/show_bug.cgi?id=200405 Reported-by: Xu Wen CC: stable@vger.kernel.org # 4.4+ Signed-off-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/extent-tree.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -8398,6 +8398,19 @@ btrfs_init_new_buffer(struct btrfs_trans if (IS_ERR(buf)) return buf; + /* + * Extra safety check in case the extent tree is corrupted and extent + * allocator chooses to use a tree block which is already used and + * locked. + */ + if (buf->lock_owner == current->pid) { + btrfs_err_rl(fs_info, +"tree block %llu owner %llu already locked by pid=%d, extent tree corruption detected", + buf->start, btrfs_header_owner(buf), current->pid); + free_extent_buffer(buf); + return ERR_PTR(-EUCLEAN); + } + btrfs_set_header_generation(buf, trans->transid); btrfs_set_buffer_lockdep_class(root->root_key.objectid, buf, level); btrfs_tree_lock(buf);