From nobody Fri Apr 3 04:38:35 2026 Received: from mail-pl1-f174.google.com (mail-pl1-f174.google.com [209.85.214.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F32C6222585 for ; Wed, 25 Mar 2026 00:44:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774399449; cv=none; b=WES+rbM0YEOjhBlrcn/FD+dDdeap8vqsJ72I9QqECpYDBK5KzHBUh+WdSiwdo8htrgLOJZokgFteqqt9FSNBSmeeI7ng/UL1XFRrgGdOcxxkj7YjBs1DXIKZQFkiVygpktwGLhf52McowUx0pOhwHNrVjWjqqh0xILNtqKP7q1c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774399449; c=relaxed/simple; bh=pJxBZfkEpVbsRmIxx3V5vwBM1L3AVHZCKc/i40H0bn0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=PnQ65PT9HYQHe9Y+m/7N5WyuuVisZHqbAIsN4WUqfXehhpsuJSvxNs25IP9KNAktaU+/y2VOpyq+lipjdPRE4oWPUgy2K/NrtbskwfNNft5hk3Nvf6Jchr15QrwTNomFRunYCYp28xDQ8lDnTSbAOjLcy59b35zZ1WeXl38Elak= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=jzUylgCM; arc=none smtp.client-ip=209.85.214.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="jzUylgCM" Received: by mail-pl1-f174.google.com with SMTP id d9443c01a7336-2ad21f437eeso2934865ad.0 for ; Tue, 24 Mar 2026 17:44:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1774399447; x=1775004247; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=fUxVMW0Q6ViE/Zxq8+fERJmXmaxdxo0no4qCgJ6CNic=; b=jzUylgCMt2r/tBZvY9JHE8aVkhdiYXwiaTl+HpocxqxYP/09K21OuwSK0UTlSuRnHI rad3SI33jEq2SyJHyLfK/HUTDIQp6ekbETd7r19FzdKIh0RJrQD/zHy6i/Zs28SrnQ7U dbd67piv5jNI3eDshMf1Hl0URaWswGlLaPQg9/kT9ujU4WIiDWxBDgi04ZyQuBTcE8e8 WX1Zfcu6leaIOZ4u6/W25RyPiY7VRSg7iKhqahOIJ3iExRGnx8abQ/8xPjfFz1YHUkmF yVKzQu4CHzHgdzPh0tHyfJJ4Zkpo+Mm4o1Ujsj83C+gk+ztgITshUcLmfw5uEI7qtlnw vrTQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774399447; x=1775004247; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=fUxVMW0Q6ViE/Zxq8+fERJmXmaxdxo0no4qCgJ6CNic=; b=DVWK6pIFStmM7lV3445ASivaa6J1iomtMdYncadfWYsm6TJn+qKbkLowK6mUb8pPBB P658gP/3I1Fd34XykGnXyQE5F6l6heIiVeiWANXIysUtxiuksV3BIW6SkKuPSO4r1OXs pWWKtX3JqQvnXrRZNAXLPuIDBFksw2+cWFk00E3m399Mzu8sO74TArZsgiKHps1U9MMu phPiYVcXKyzniZK+NCpQPKvbzwivHF0rh0npsedIi16orI+YNMvT8OzcWSZplcxOmpUm tJaD1pk25HyPiBwAEMeVKUMCIgZyA707ZoSMwsWjSuN7ckesN5FhJTt4xHqsAQMVrqfN N3Lg== X-Forwarded-Encrypted: i=1; AJvYcCWsgF0YNxMozaouXRuVSsNJjub2wy4ujzCr67TmljStpaQfhGcc0Py+MSmm7zsSlMDCWa4xxGCbUdIbEEQ=@vger.kernel.org X-Gm-Message-State: AOJu0YxoctruEd1R3WrpAVq1IMXpISnxtIhzMP+ecjGweiMh8rFU2O6V 8LyjI0T+0RsUPKGPwA5v2d2RN2EmTC8UzasE1x2L/b+S3Ainu/1dABJu X-Gm-Gg: ATEYQzxHwX0vX0OJ6eQZ8Z3cC8U4eQr4SlQK4OHEsd+67CBYGH/WfJD5sPdKNiyS4Kg VTxgLX/twRFwHCM7H6oxYbctcZ9qH7yq+jtQzqIWJdKr6iqMMeSotQ5zNBmE5JBLRXstF+a14Wh g/nYqaPuGu/xg7o5hvnFJS0gm+KoiKaDi0eQnu7oMcU3/GntjF2ys3OlybtvHw8oAV4oQRrcZcu 6Al82x3dxer3aZH+ZaM+0VQnbNr4WRyLK06J6ivbPUWbMlVSZC+LdjRh+dXhilgIDmvmvPcOYg5 qQ8hLAGOQQQKaHc4GJw6VWqQPJFh7g/xao9UiJKJmVfIlZz/PWa6LnWLXvuBtsFn7LuXN3wiaBE 59CvtPnvK7HkHHuhKKuA0wYh5THgcDH1jay4hmi8joSCOYVj5RbA5gpUeXMImeHiIWwktQ3XOiA i9727lFA6Sxk8MbuIZtNPn1jT8DPxPQVZYWG4aggEaXYvkdQad5uzgyo60RFUEkYFf8pkO0Rr75 mJnpz6JEQ== X-Received: by 2002:a17:903:37c5:b0:2ae:be67:722f with SMTP id d9443c01a7336-2b0b07f9bd5mr16343605ad.22.1774399447341; Tue, 24 Mar 2026 17:44:07 -0700 (PDT) Received: from kernel-fuzz.. ([103.172.182.26]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2b0836554acsm207457015ad.51.2026.03.24.17.44.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 24 Mar 2026 17:44:06 -0700 (PDT) From: ZhengYuan Huang To: dsterba@suse.com, clm@fb.com, idryomov@gmail.com Cc: linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, baijiaju1990@gmail.com, r33s3n6@gmail.com, zzzccc427@gmail.com, ZhengYuan Huang Subject: [PATCH v3 4/4] btrfs: fix check_chunk_block_group_mappings() to iterate all chunk maps Date: Wed, 25 Mar 2026 08:43:39 +0800 Message-ID: <20260325004339.2323838-5-gality369@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260325004339.2323838-1-gality369@gmail.com> References: <20260325004339.2323838-1-gality369@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" [BUG] A corrupted image with a chunk present in the chunk tree but whose corresponding block group item is missing from the extent tree can be mounted successfully, even though check_chunk_block_group_mappings() is supposed to catch exactly this corruption at mount time. Once mounted, running btrfs balance with a usage filter (-dusage=3DN or -dusage=3Dmin..max) triggers a null-ptr-deref: KASAN: null-ptr-deref in range [0x0000000000000070-0x0000000000000077] RIP: 0010:chunk_usage_filter fs/btrfs/volumes.c:3874 [inline] RIP: 0010:should_balance_chunk fs/btrfs/volumes.c:4018 [inline] RIP: 0010:__btrfs_balance fs/btrfs/volumes.c:4172 [inline] RIP: 0010:btrfs_balance+0x2024/0x42b0 fs/btrfs/volumes.c:4604 [CAUSE] The crash occurs because __btrfs_balance() iterates the on-disk chunk tree, finds the orphaned chunk, calls chunk_usage_filter() (or chunk_usage_range_filter()), which queries the in-memory block group cache via btrfs_lookup_block_group(). Since no block group was ever inserted for this chunk, the lookup returns NULL, and the subsequent dereference of cache->used crashes. check_chunk_block_group_mappings() uses btrfs_find_chunk_map() to iterate the in-memory chunk map (fs_info->mapping_tree): map =3D btrfs_find_chunk_map(fs_info, start, 1); With @start =3D 0 and @length =3D 1, btrfs_find_chunk_map() looks for a chunk map that *contains* the logical address 0. If no chunk contains logical address 0, btrfs_find_chunk_map(fs_info, 0, 1) returns NULL immediately and the loop breaks after the very first iteration, having checked zero chunks. The entire verification function is therefore a no-op, and the corrupted image passes the mount-time check undetected. [FIX] Replace the btrfs_find_chunk_map() based loop with a direct in-order walk of fs_info->mapping_tree using rb_first_cached() + rb_next(). This guarantees that every chunk map in the tree is visited regardless of the logical addresses involved. No lock is taken around the traversal. This function is called during mount from btrfs_read_block_groups(), which is invoked from open_ctree() before any background threads (cleaner, transaction kthread, etc.) are started. There are therefore no concurrent writers that could modify mapping_tree at this point. An analogous lockless direct traversal of mapping_tree already exists in fill_dummy_bgs() in the same file. Since we walk the RB-tree directly via rb_entry() without going through btrfs_find_chunk_map(), no reference is taken on each map entry, so the btrfs_free_chunk_map() calls are also removed. Signed-off-by: ZhengYuan Huang --- fs/btrfs/block-group.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c index 5322ef2ae015..d1e075a8905a 100644 --- a/fs/btrfs/block-group.c +++ b/fs/btrfs/block-group.c @@ -2319,29 +2319,26 @@ static struct btrfs_block_group *btrfs_create_block= _group_cache( */ static int check_chunk_block_group_mappings(struct btrfs_fs_info *fs_info) { - u64 start =3D 0; + struct rb_node *node; int ret =3D 0; =20 - while (1) { + /* + * This is called during mount from btrfs_read_block_groups(), before + * any background threads are started, so no concurrent writers can + * modify the mapping_tree. No lock is needed here. + */ + for (node =3D rb_first_cached(&fs_info->mapping_tree); node; + node =3D rb_next(node)) { struct btrfs_chunk_map *map; struct btrfs_block_group *bg; =20 - /* - * btrfs_find_chunk_map() will return the first chunk map - * intersecting the range, so setting @length to 1 is enough to - * get the first chunk. - */ - map =3D btrfs_find_chunk_map(fs_info, start, 1); - if (!map) - break; - + map =3D rb_entry(node, struct btrfs_chunk_map, rb_node); bg =3D btrfs_lookup_block_group(fs_info, map->start); if (unlikely(!bg)) { btrfs_err(fs_info, "chunk start=3D%llu len=3D%llu doesn't have corresponding block group", map->start, map->chunk_len); ret =3D -EUCLEAN; - btrfs_free_chunk_map(map); break; } if (unlikely(bg->start !=3D map->start || bg->length !=3D map->chunk_len= || @@ -2354,12 +2351,9 @@ static int check_chunk_block_group_mappings(struct b= trfs_fs_info *fs_info) bg->start, bg->length, bg->flags & BTRFS_BLOCK_GROUP_TYPE_MASK); ret =3D -EUCLEAN; - btrfs_free_chunk_map(map); btrfs_put_block_group(bg); break; } - start =3D map->start + map->chunk_len; - btrfs_free_chunk_map(map); btrfs_put_block_group(bg); } return ret; --=20 2.43.0