From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5DD5D2D8378; Mon, 6 Oct 2025 18:19:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759774755; cv=none; b=QMzO5GMQm0LKt02h6iE4lvFN/snbTZoRfUvgs+mxx5uuoVQRor662uE9a4sNJzTkhvIcmiL/GxWSFz8DQy3fKYIGMxMABoqc1EAECRgZwSt9DeXu2D56nN0NX9v62g8UhSXHahlPvJzL0m4hbJIW4CmxKxNr917mKbV8RUwud6A= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759774755; c=relaxed/simple; bh=1pyLy00NZb1vphlK8GJSm3aNFmpULaWgJg31wAuOlI0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=B66ZQfkhu2grRLenfJoxXqFvjeCSyBQQFu+qzCWm03Fm6oJGj/mrkZ1n5Hic4CvvQUH/b/dNozy+cHB/W02k8AbuNskL7QMi1FiLoR5G5MgWcwdNgO6Mm1FXeq9ssZgX0uas+wSLxx9aTIviGmfKPkNwQnnkIQD2aZ3XX9dOy/E= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=k/zp3/mu; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="k/zp3/mu" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 54AD0C4CEF5; Mon, 6 Oct 2025 18:19:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1759774755; bh=1pyLy00NZb1vphlK8GJSm3aNFmpULaWgJg31wAuOlI0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=k/zp3/muoAXAxAPlK2aDg9f72jCgwUmwgfirjdaPYdchj1vWDnNrd6kn2E/xmc59B i2MbVKg54mE40iOga14t0HoLTbjfdJWldf5a3GJtU6LaeV2G6CCr8er5qmT5C29nbm CdDvYAFXiaDruEdCBtdpcbOXH1CRuYtZGA+YPu1zg26G02tZJL08O9+OwWMTpdHi78 K2KBktshQJWs7K0sRlDmwLVLzc+pG/mXKdbWBHEpjIpzgbEnDAYg6uDjC0ccJnQFO1 /GDGc6LfNJt0GdCuMXVtqSLOkQ5WAspaC+qoe6WDihsZId/uZ65yQzekluU/qp+VOz 7uKe9F1FNLH6Q== From: Sasha Levin To: patches@lists.linux.dev, stable@vger.kernel.org Cc: Johannes Thumshirn , Damien Le Moal , David Sterba , Sasha Levin , clm@fb.com, linux-btrfs@vger.kernel.org Subject: [PATCH AUTOSEL 6.17-6.6] btrfs: zoned: return error from btrfs_zone_finish_endio() Date: Mon, 6 Oct 2025 14:17:44 -0400 Message-ID: <20251006181835.1919496-12-sashal@kernel.org> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20251006181835.1919496-1-sashal@kernel.org> References: <20251006181835.1919496-1-sashal@kernel.org> Precedence: bulk X-Mailing-List: patches@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-stable: review X-Patchwork-Hint: Ignore X-stable-base: Linux 6.17.1 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Johannes Thumshirn [ Upstream commit 3c44cd3c79fcb38a86836dea6ff8fec322a9e68c ] Now that btrfs_zone_finish_endio_workfn() is directly calling do_zone_finish() the only caller of btrfs_zone_finish_endio() is btrfs_finish_one_ordered(). btrfs_finish_one_ordered() already has error handling in-place so btrfs_zone_finish_endio() can return an error if the block group lookup fails. Also as btrfs_zone_finish_endio() already checks for zoned filesystems and returns early, there's no need to do this in the caller. Reviewed-by: Damien Le Moal Signed-off-by: Johannes Thumshirn Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- LLM Generated explanations, may be completely bogus: ## Backport Recommendation: **YES** This commit should definitely be backported to stable kernel trees (and indeed has already been backported to this 6.17 stable tree). --- ## Detailed Analysis ### **1. Bug Being Fixed** The commit fixes a critical NULL pointer dereference vulnerability in the btrfs zoned device feature. The problematic code at **fs/btrfs/zoned.c:2476** uses: ```c block_group = btrfs_lookup_block_group(fs_info, logical); ASSERT(block_group); ``` **Problems with this approach:** - `ASSERT()` can be compiled out in production kernels, leaving no runtime check - If `btrfs_lookup_block_group()` returns NULL, the code continues and dereferences the NULL pointer at line 2479 (`if (block_group->flags & BTRFS_BLOCK_GROUP_DATA)`) - This leads to a kernel crash or undefined behavior ### **2. Evidence of Real-World Impact** My investigation found commit **d3cfa44164688** (from August 2023) which documents an actual crash from this exact issue: ``` KASAN: null-ptr-deref in range [0x0000000000000088-0x000000000000008f] RIP: 0010:btrfs_zone_finish_endio.part.0+0x34/0x160 [btrfs] ``` The crash report states: > "btrfs_lookup_block_group() in btrfs_zone_finish_endio() failed to find a block group and will hit an assert or a null pointer dereference" This occurred during data relocation when `ordered_extent->logical` was set to an invalid value, demonstrating that block group lookups **can and do fail** in production scenarios. ### **3. The Fix - Code Changes Analysis** **In fs/btrfs/zoned.c (btrfs_zone_finish_endio function):** - **Line 2467**: Changed function signature from `void` to `int` to return error codes - **Line 2473**: Early return now returns `0` (success) instead of void - **Lines 2475-2477**: Replaced `ASSERT(block_group)` with: ```c if (WARN_ON_ONCE(!block_group)) return -ENOENT; ``` - `WARN_ON_ONCE()` cannot be compiled out - provides runtime detection - Returns `-ENOENT` error to caller instead of crashing - Uses `_ONCE` variant to avoid log spam if issue repeats - **Line 2493**: Added `return 0` at normal exit path **In fs/btrfs/inode.c (btrfs_finish_one_ordered function):** - **Lines 3110-3112** (before): Called `btrfs_zone_finish_endio()` only if zoned, as void function - **Lines 3110-3113** (after): - Unconditionally calls `btrfs_zone_finish_endio()` (the zoned check moved inside) - Captures return value in `ret` - Checks for error and jumps to `out` label for proper cleanup - The `out` label at line 3228 already has comprehensive error handling that calls `btrfs_mark_ordered_extent_error()` to properly handle the failure **In fs/btrfs/zoned.h:** - **Line 66**: Updated function declaration from `void` to `int` - **Lines 217-221**: Updated the non-zoned stub to return `int` with value `0` ### **4. Why This is a Good Backport Candidate** **Severity:** - Fixes a NULL pointer dereference that crashes the kernel - Affects users of btrfs zoned device feature - Has been confirmed to occur in real-world usage (reproducible with btrfs/028 test) **Code Quality:** - Small, focused change (15 insertions, 9 deletions across 3 files) - Follows kernel best practices (WARN_ON instead of ASSERT) - Adds proper error handling rather than silently ignoring issues - Leverages existing error handling infrastructure **Dependencies:** - Depends on preceding commit **3d16abf6c88ae** ("directly call do_zone_finish() from btrfs_zone_finish_endio_workfn()") - Both commits work together as a series and have been backported together - The preceding commit removes one caller, simplifying the code before adding error handling **Risk Assessment:** - **Low regression risk**: The change is defensive - adds error handling where none existed - The caller (`btrfs_finish_one_ordered`) already had error handling infrastructure ready (the `out:` label and error path) - No subsequent fixes or reverts found - Reviewed-by tag from Damien Le Moal indicates peer review - No architectural changes - just improved error handling ### **5. Stable Tree Rules Compliance** This commit follows all stable kernel tree rules: - ✅ Fixes an important bug (kernel crash) - ✅ Small and obviously correct - ✅ Minimal risk of regression - ✅ Confined to btrfs subsystem (specifically zoned device code) - ✅ Does not introduce new features - ✅ No major architectural changes ### **6. Backport Status** **Already backported**: This commit has been backported to the 6.17 stable tree as commit **d7ca28dca807e** by stable tree maintainer Sasha Levin on October 1, 2025, confirming that kernel maintainers have already determined this is appropriate for stable backporting. --- ## Conclusion **YES** - This commit is an excellent candidate for stable backporting. It fixes a confirmed kernel crash bug in btrfs zoned devices with minimal code changes and low regression risk. The fix follows best practices by replacing a potentially-compiled-out ASSERT with proper runtime error detection and handling. The commit has already been successfully backported to this stable tree, demonstrating maintainer confidence in its suitability. fs/btrfs/inode.c | 7 ++++--- fs/btrfs/zoned.c | 8 +++++--- fs/btrfs/zoned.h | 9 ++++++--- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 18db1053cdf08..4a745f43c895c 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3107,9 +3107,10 @@ int btrfs_finish_one_ordered(struct btrfs_ordered_extent *ordered_extent) goto out; } - if (btrfs_is_zoned(fs_info)) - btrfs_zone_finish_endio(fs_info, ordered_extent->disk_bytenr, - ordered_extent->disk_num_bytes); + ret = btrfs_zone_finish_endio(fs_info, ordered_extent->disk_bytenr, + ordered_extent->disk_num_bytes); + if (ret) + goto out; if (test_bit(BTRFS_ORDERED_TRUNCATED, &ordered_extent->flags)) { truncated = true; diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c index f426276e2b6bf..6641b8e9c15c2 100644 --- a/fs/btrfs/zoned.c +++ b/fs/btrfs/zoned.c @@ -2464,16 +2464,17 @@ bool btrfs_can_activate_zone(struct btrfs_fs_devices *fs_devices, u64 flags) return ret; } -void btrfs_zone_finish_endio(struct btrfs_fs_info *fs_info, u64 logical, u64 length) +int btrfs_zone_finish_endio(struct btrfs_fs_info *fs_info, u64 logical, u64 length) { struct btrfs_block_group *block_group; u64 min_alloc_bytes; if (!btrfs_is_zoned(fs_info)) - return; + return 0; block_group = btrfs_lookup_block_group(fs_info, logical); - ASSERT(block_group); + if (WARN_ON_ONCE(!block_group)) + return -ENOENT; /* No MIXED_BG on zoned btrfs. */ if (block_group->flags & BTRFS_BLOCK_GROUP_DATA) @@ -2490,6 +2491,7 @@ void btrfs_zone_finish_endio(struct btrfs_fs_info *fs_info, u64 logical, u64 len out: btrfs_put_block_group(block_group); + return 0; } static void btrfs_zone_finish_endio_workfn(struct work_struct *work) diff --git a/fs/btrfs/zoned.h b/fs/btrfs/zoned.h index 6e11533b8e14c..17c5656580dd9 100644 --- a/fs/btrfs/zoned.h +++ b/fs/btrfs/zoned.h @@ -83,7 +83,7 @@ int btrfs_sync_zone_write_pointer(struct btrfs_device *tgt_dev, u64 logical, bool btrfs_zone_activate(struct btrfs_block_group *block_group); int btrfs_zone_finish(struct btrfs_block_group *block_group); bool btrfs_can_activate_zone(struct btrfs_fs_devices *fs_devices, u64 flags); -void btrfs_zone_finish_endio(struct btrfs_fs_info *fs_info, u64 logical, +int btrfs_zone_finish_endio(struct btrfs_fs_info *fs_info, u64 logical, u64 length); void btrfs_schedule_zone_finish_bg(struct btrfs_block_group *bg, struct extent_buffer *eb); @@ -234,8 +234,11 @@ static inline bool btrfs_can_activate_zone(struct btrfs_fs_devices *fs_devices, return true; } -static inline void btrfs_zone_finish_endio(struct btrfs_fs_info *fs_info, - u64 logical, u64 length) { } +static inline int btrfs_zone_finish_endio(struct btrfs_fs_info *fs_info, + u64 logical, u64 length) +{ + return 0; +} static inline void btrfs_schedule_zone_finish_bg(struct btrfs_block_group *bg, struct extent_buffer *eb) { } -- 2.51.0