Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp3469568imu; Sun, 11 Nov 2018 15:49:54 -0800 (PST) X-Google-Smtp-Source: AJdET5cKIKV/iRVIB7z+nsmxlthONGiReDPXA1En9xQ6s1mpmRH38Io43bn7lVg/h9JtFY5DNc/B X-Received: by 2002:a17:902:aa08:: with SMTP id be8-v6mr6552699plb.294.1541980194072; Sun, 11 Nov 2018 15:49:54 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1541980194; cv=none; d=google.com; s=arc-20160816; b=qZW7Xsv1sj1vNJlgfISziqL+lOCMckSxouOq+upj4E9Z/U/k2tLOcHrvOHuiI2rvSH QSnkWUlyzklYYuZi4Kq3E9ArDg9abO8qkIbWXX4jBCO1eOgiQAaa2uzbQ82HEVY5DStm hMJMvOycQIiuF4ElrWLeYASxlTjLXLQ8lIobxh6bh0MBw4iOxBabWg97p367YJ51QAxI 9jSTsaDisQJxZernWoEoedw9/zq09+orAv4dCk2q9FVzZeJ7A4+bq99i9tKvQFFzs1eP uDOkxyy3QI/sH3oTBtg5R7lssLhQC2IvhflFIq6WJBzf7Rnd0AbZiJ8afXgxjeUrgh+C nJHA== 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=UZjshJZOj/EhZP+316xnbQcL0rYWD1240bY68fPTmS8=; b=ccYAAcfpOqcI7hGli7AmMrDZsvFrzg8MEpgO6els/fheqR8M4VkSfOElyFYHpsDqnh /FwlJKfFxECWj69MtWHWY62xvk6HK6BMqG3eAicvjzL2Vyg1HB++nspPW40ERgwzG+z6 JBXnA6t8nL/VvjvbzGZuQZTsOQHz3CJQ3Q0b9ThywF5y3PuSQ93z/NMshWc5myxHmuKe tGUoHL4uqx87zefZTF59bzBcvB2eMzUzyydzRqie6kSU7xK8WXxzcdTzjfeKbtj9F+f3 Hf4iWhA5TVNVFS741DV5wp6bdpzwJQ0zZf0xApwy8Ep4Jy2Yrl1Nii5xLF/3sPfUN4W9 cBsQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=cCtycK2M; 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 37-v6si16259583ple.389.2018.11.11.15.49.38; Sun, 11 Nov 2018 15:49:54 -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=cCtycK2M; 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 S1733064AbeKLISl (ORCPT + 99 others); Mon, 12 Nov 2018 03:18:41 -0500 Received: from mail.kernel.org ([198.145.29.99]:38730 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1733025AbeKLISk (ORCPT ); Mon, 12 Nov 2018 03:18:40 -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 1D3CD2241B; Sun, 11 Nov 2018 22:28:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1541975324; bh=IUZgjDT3n+JyAg7YLAG/pYidiVe2/f9dsTW2w9ufLAg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=cCtycK2MCoYGjxbiBnZYpOpA7gmLkJaeK0n2vTga7fWKODBK7u3F+xNZVGtohnB3u bYXYfpQJHsFIfWUUKHCL7MTsIe2zB1jU08uISRX9SUTrVz9UCx5c/YeEZjBMx+XjER /LHgTDc5DHt8VQ2uWKF08+tnGgqJuyo0xliLJOlY= 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.19 328/361] btrfs: locking: Add extra check in btrfs_init_new_buffer() to avoid deadlock Date: Sun, 11 Nov 2018 14:21:15 -0800 Message-Id: <20181111221659.624922237@linuxfoundation.org> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181111221619.915519183@linuxfoundation.org> References: <20181111221619.915519183@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.19-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 @@ -8119,6 +8119,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_buffer_lockdep_class(root->root_key.objectid, buf, level); btrfs_tree_lock(buf); clean_tree_block(fs_info, buf);