Received: by 2002:ac0:a594:0:0:0:0:0 with SMTP id m20-v6csp800455imm; Mon, 21 May 2018 14:43:32 -0700 (PDT) X-Google-Smtp-Source: AB8JxZrWK7FsHV59tGxp8JxD+xAXdFW9rdMqkDFjJySw6mtIwFyA5QBFoQA2IctVmPHRrbrN/sWn X-Received: by 2002:a63:710b:: with SMTP id m11-v6mr16970397pgc.326.1526939012055; Mon, 21 May 2018 14:43:32 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1526939012; cv=none; d=google.com; s=arc-20160816; b=xwaXqKN3evIKsi31TUcsJCV7DGh5GnxIt1PPTrYS/r+IuCntJZi3lzQgJssE7JSrS9 CKVGi+Sddp1z+PFh+1e9ivYH85D5CWFVLazZ7e8yCTbLRmznzZnYrxtDj5BXmJOAyiT4 Rq9VeMTPBMvkhFBr/NERbde5J4mG82orT70VFn0jHqVx0YB+hC/xqh/ALTwrIR0E9h/A zdDk1rV/QHnRJlyIUXjxQud+tEIiJQgt5nd5uoXnXHhmVyJP6f7rjDWhB6RcQhmW9L1O FgiXUYmpK1UZO6IYE2K0ouioSEZY8sA1BE1bBpWXdhhohzsWMkSAgQNkxEH3qchr+qC+ 2BBw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:user-agent:references :in-reply-to:message-id:date:subject:cc:to:from:dkim-signature :arc-authentication-results; bh=n9On6LrFy1ZIuIoNH+fJ/BUvCS9e7ghsgOjQlWjA3r8=; b=T6GzSdAQPqe8KUtTq78KOc/itKws3Ly3Z44OFRNWz64IVcd/FlsVQ91WytLhQO+F24 gBm9NPlx/v1zGR0BVnaRmtck1r/03V9V0bA/VBrVNrhXdtO4WNJgr4myj0fvKdmGOe36 MEpSWjEIRHvKO6jzNrtmoRI4vUg69Osts4NufzAEJFzf+vUwJrxx93ZvKgmwsKBeUhF2 qzni/YUhfPKQttah2AC3nEEdJn19JL0CEJk/kAiLjieqpOuybzU6gNDQXqWAqTILs6zx YGGpBjU79k8AOHkx6ZjDGB4QIl5s6wrFAdL5iYTIaKSOQFkoi7OZpQIisKwCIOUI1m3O 9d3g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=PyaNyuvs; 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 v16-v6si14302165pfm.151.2018.05.21.14.43.17; Mon, 21 May 2018 14:43:32 -0700 (PDT) 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=PyaNyuvs; 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 S932322AbeEUVmB (ORCPT + 99 others); Mon, 21 May 2018 17:42:01 -0400 Received: from mail.kernel.org ([198.145.29.99]:39440 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751304AbeEUVYc (ORCPT ); Mon, 21 May 2018 17:24:32 -0400 Received: from localhost (LFbn-1-12247-202.w90-92.abo.wanadoo.fr [90.92.61.202]) (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 C561F20853; Mon, 21 May 2018 21:24:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1526937872; bh=/ytAgZpZyG48/QqPd6TxqDDiKmq6/YICM4jGifcLcKM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=PyaNyuvsjelggBSvPA9OUectkWa4LVy/FccInYmLGqtMXvezwl8wNomxkYj3T9CzU 3s4y1F+0dhxuCRdkBjoHycmAAZ6VljNsDibHOIO1JT9vGcg6jqB7a/YAHTREBeqEFm IK4r1WGIM0xj+LIQPkRvVweAIBbVfQQRS7NCCkHw= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Robbie Ko , Filipe Manana , David Sterba Subject: [PATCH 4.16 056/110] Btrfs: send, fix invalid access to commit roots due to concurrent snapshotting Date: Mon, 21 May 2018 23:11:53 +0200 Message-Id: <20180521210510.588122736@linuxfoundation.org> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180521210503.823249477@linuxfoundation.org> References: <20180521210503.823249477@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 4.16-stable review patch. If anyone has any objections, please let me know. ------------------ From: Robbie Ko commit 6f2f0b394b54e2b159ef969a0b5274e9bbf82ff2 upstream. [BUG] btrfs incremental send BUG happens when creating a snapshot of snapshot that is being used by send. [REASON] The problem can happen if while we are doing a send one of the snapshots used (parent or send) is snapshotted, because snapshoting implies COWing the root of the source subvolume/snapshot. 1. When doing an incremental send, the send process will get the commit roots from the parent and send snapshots, and add references to them through extent_buffer_get(). 2. When a snapshot/subvolume is snapshotted, its root node is COWed (transaction.c:create_pending_snapshot()). 3. COWing releases the space used by the node immediately, through: __btrfs_cow_block() --btrfs_free_tree_block() ----btrfs_add_free_space(bytenr of node) 4. Because send doesn't hold a transaction open, it's possible that the transaction used to create the snapshot commits, switches the commit root and the old space used by the previous root node gets assigned to some other node allocation. Allocation of a new node will use the existing extent buffer found in memory, which we previously got a reference through extent_buffer_get(), and allow the extent buffer's content (pages) to be modified: btrfs_alloc_tree_block --btrfs_reserve_extent ----find_free_extent (get bytenr of old node) --btrfs_init_new_buffer (use bytenr of old node) ----btrfs_find_create_tree_block ------alloc_extent_buffer --------find_extent_buffer (get old node) 5. So send can access invalid memory content and have unpredictable behaviour. [FIX] So we fix the problem by copying the commit roots of the send and parent snapshots and use those copies. CallTrace looks like this: ------------[ cut here ]------------ kernel BUG at fs/btrfs/ctree.c:1861! invalid opcode: 0000 [#1] SMP CPU: 6 PID: 24235 Comm: btrfs Tainted: P O 3.10.105 #23721 ffff88046652d680 ti: ffff88041b720000 task.ti: ffff88041b720000 RIP: 0010:[] read_node_slot+0x108/0x110 [btrfs] RSP: 0018:ffff88041b723b68 EFLAGS: 00010246 RAX: ffff88043ca6b000 RBX: ffff88041b723c50 RCX: ffff880000000000 RDX: 000000000000004c RSI: ffff880314b133f8 RDI: ffff880458b24000 RBP: 0000000000000000 R08: 0000000000000001 R09: ffff88041b723c66 R10: 0000000000000001 R11: 0000000000001000 R12: ffff8803f3e48890 R13: ffff8803f3e48880 R14: ffff880466351800 R15: 0000000000000001 FS: 00007f8c321dc8c0(0000) GS:ffff88047fcc0000(0000) CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 R2: 00007efd1006d000 CR3: 0000000213a24000 CR4: 00000000003407e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Stack: ffff88041b723c50 ffff8803f3e48880 ffff8803f3e48890 ffff8803f3e48880 ffff880466351800 0000000000000001 ffffffffa08dd9d7 ffff88041b723c50 ffff8803f3e48880 ffff88041b723c66 ffffffffa08dde85 a9ff88042d2c4400 Call Trace: [] ? tree_move_down.isra.33+0x27/0x50 [btrfs] [] ? tree_advance+0xb5/0xc0 [btrfs] [] ? btrfs_compare_trees+0x2d4/0x760 [btrfs] [] ? finish_inode_if_needed+0x870/0x870 [btrfs] [] ? btrfs_ioctl_send+0xeda/0x1050 [btrfs] [] ? btrfs_ioctl+0x1e3d/0x33f0 [btrfs] [] ? handle_pte_fault+0x373/0x990 [] ? atomic_notifier_call_chain+0x16/0x20 [] ? set_task_cpu+0xb6/0x1d0 [] ? handle_mm_fault+0x143/0x2a0 [] ? __do_page_fault+0x1d0/0x500 [] ? check_preempt_curr+0x57/0x90 [] ? do_vfs_ioctl+0x4aa/0x990 [] ? do_fork+0x113/0x3b0 [] ? trace_hardirqs_off_thunk+0x3a/0x6c [] ? SyS_ioctl+0x88/0xa0 [] ? system_call_fastpath+0x16/0x1b ---[ end trace 29576629ee80b2e1 ]--- Fixes: 7069830a9e38 ("Btrfs: add btrfs_compare_trees function") CC: stable@vger.kernel.org # 3.6+ Signed-off-by: Robbie Ko Reviewed-by: Filipe Manana Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/ctree.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -5460,12 +5460,24 @@ int btrfs_compare_trees(struct btrfs_roo down_read(&fs_info->commit_root_sem); left_level = btrfs_header_level(left_root->commit_root); left_root_level = left_level; - left_path->nodes[left_level] = left_root->commit_root; + left_path->nodes[left_level] = + btrfs_clone_extent_buffer(left_root->commit_root); + if (!left_path->nodes[left_level]) { + up_read(&fs_info->commit_root_sem); + ret = -ENOMEM; + goto out; + } extent_buffer_get(left_path->nodes[left_level]); right_level = btrfs_header_level(right_root->commit_root); right_root_level = right_level; - right_path->nodes[right_level] = right_root->commit_root; + right_path->nodes[right_level] = + btrfs_clone_extent_buffer(right_root->commit_root); + if (!right_path->nodes[right_level]) { + up_read(&fs_info->commit_root_sem); + ret = -ENOMEM; + goto out; + } extent_buffer_get(right_path->nodes[right_level]); up_read(&fs_info->commit_root_sem);