mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/2] btrfs: tree-checker: reject simple quota metadata without SIMPLE_QUOTA
@ 2026-11-03  3:49 Siddharth Mishra
  2026-11-03  3:49 ` [PATCH 1/2] btrfs: tree-checker: validate qgroup status item Siddharth Mishra
  2026-11-03  3:49 ` [PATCH 2/2] btrfs: tree-checker: reject extent owner ref without simple quota Siddharth Mishra
  0 siblings, 2 replies; 6+ messages in thread
From: Siddharth Mishra @ 2026-11-03  3:49 UTC (permalink / raw)
  To: David Sterba
  Cc: Qu Wenruo, Boris Burkov, Chris Mason, linux-btrfs, linux-kernel,
	Siddharth Mishra

Simple quotas put two types of metadata on the disk : the status item
with SIMPLE_MODE, and the owner ref in an extent item.  These two types
are correct only when the super block has the SIMPLE_QUOTA bit.  Several
functions ASSERT() this rule.  The tree-checker does not enforce it :

- The tree-checker does not examine the status item.  A status item
  with SIMPLE_MODE and no SIMPLE_QUOTA bit causes a BUG at mount, in
  qgroup_read_enable_gen().  Patch 1 adds a check.

- For an owner ref without the SIMPLE_QUOTA bit, check_extent_item()
  gives a WARN_ON() and accepts the leaf.  When btrfs frees the extent,
  btrfs_get_extent_inline_ref_type() causes a BUG.  Patch 2 rejects the
  leaf.  syzbot found both symptoms in 2024, without a reproducer.

Two sources can put these states on a disk : a damaged or crafted
image, and a power failure just after simple quotas were enabled on a
kernel without commit f2363e6fcc79 ("btrfs: fix transaction atomicity
bug when enabling simple quotas").

I reproduced both problems with crafted images on for-next.  With the
patches, the tree-checker rejects the bad leaf.  With patch 1, btrfs
then mounts the filesystem without quotas.  With patch 2, the mount
fails.  A clean simple quota filesystem still mounts, writes data, frees
extents and mounts again.

Siddharth Mishra (2):
  btrfs: tree-checker: validate qgroup status item
  btrfs: tree-checker: reject extent owner ref without simple quota

 fs/btrfs/tree-checker.c | 41 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 40 insertions(+), 1 deletion(-)


base-commit: d6f76ca0a70d0c814731394a625ff0dc1feb390e
-- 
2.54.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/2] btrfs: tree-checker: validate qgroup status item
  2026-11-03  3:49 [PATCH 0/2] btrfs: tree-checker: reject simple quota metadata without SIMPLE_QUOTA Siddharth Mishra
@ 2026-11-03  3:49 ` Siddharth Mishra
  2026-11-03  4:36   ` Qu Wenruo
  2026-11-03  3:49 ` [PATCH 2/2] btrfs: tree-checker: reject extent owner ref without simple quota Siddharth Mishra
  1 sibling, 1 reply; 6+ messages in thread
From: Siddharth Mishra @ 2026-11-03  3:49 UTC (permalink / raw)
  To: David Sterba
  Cc: Qu Wenruo, Boris Burkov, Chris Mason, linux-btrfs, linux-kernel,
	Siddharth Mishra, stable

[BUG]
An image can have a status item with SIMPLE_MODE and a super block
without the SIMPLE_QUOTA bit.  On a kernel with CONFIG_BTRFS_ASSERT=y,
the mount of this image causes a BUG :

  assertion failed: btrfs_fs_incompat(fs_info, SIMPLE_QUOTA),
  in fs/btrfs/qgroup.c:411
  kernel BUG at fs/btrfs/qgroup.c:411!
  Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI
  RIP: 0010:btrfs_read_qgroup_config.cold (fs/btrfs/qgroup.c:411)
  Call Trace:
   open_ctree (fs/btrfs/disk-io.c:3789)
   btrfs_get_tree.cold (fs/btrfs/super.c:2133)
   vfs_get_tree (fs/super.c:1943)
   fc_mount (fs/namespace.c:1282)
   path_mount (fs/namespace.c:4337)
   __x64_sys_mount (fs/namespace.c:4542)

Without CONFIG_BTRFS_ASSERT, the mount is successful in simple quota
mode.  The first data write then adds an owner ref.  The write-time
tree-checker sees the owner ref without the SIMPLE_QUOTA bit and gives
a WARN_ON() (tree-checker.c:1782).

[CAUSE]
The tree-checker does not examine the status item.
btrfs_read_qgroup_config() reads the flags of the status item.  For
SIMPLE_MODE, it calls qgroup_read_enable_gen().  This function ASSERT()s
that the SIMPLE_QUOTA bit is set and that the item contains enable_gen.
Since commit f2363e6fcc79, the kernel does not write SIMPLE_MODE without
the SIMPLE_QUOTA bit.  Thus only a damaged or crafted image has this
state.

[FIX]
Add a tree-checker rule for the status item :
- The item must contain the four members of all versions : version,
  generation, flags and rescan.
- With SIMPLE_MODE, the super block must have the SIMPLE_QUOTA bit, and
  the item must also contain enable_gen.
If a rule fails, the tree-checker rejects the leaf with -EUCLEAN.  Then
btrfs_read_roots() cannot read the quota root.  It ignores the error, as
before, and btrfs mounts the filesystem without quotas.

Fuzzing found this bug. An AI tool helped to analyse the cause and to
write the fix. I tested on btrfs for-next (d6f76ca0a70d), with and
without KASAN and CONFIG_BTRFS_ASSERT=y. Without the patch, the kernel
gives the BUG above, or the WARN_ON() at the first write. With the
patch, the tree-checker rejects the leaf ("qgroup status item has
SIMPLE_MODE but SIMPLE_QUOTA incompat bit unset"). The mount is
successful without quotas. There is no BUG and no WARN_ON(). A clean
simple quota filesystem still mounts, writes data, frees extents and
mounts again. Its status item passes the check at each commit. The
fstests group qgroup has no new failure (34 passed, 3 not run here). A
crafted image and a C reproducer are available on request.

Fixes: 182940f4f4db ("btrfs: qgroup: add new quota mode for simple quotas")
Cc: stable@vger.kernel.org # 6.7+
Signed-off-by: Siddharth Mishra <smish149@asu.edu>
---
 fs/btrfs/tree-checker.c | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
index 61ea8f42c..0d75cb537 100644
--- a/fs/btrfs/tree-checker.c
+++ b/fs/btrfs/tree-checker.c
@@ -2083,6 +2083,38 @@ static int check_raid_stripe_extent(const struct extent_buffer *leaf,
 	return 0;
 }
 
+static int check_qgroup_status_item(const struct extent_buffer *leaf, int slot)
+{
+	const u32 item_size = btrfs_item_size(leaf, slot);
+	const u32 min_size = offsetof(struct btrfs_qgroup_status_item, enable_gen);
+	struct btrfs_qgroup_status_item *ptr;
+
+	/* version, generation, flags and rescan are always present. */
+	if (unlikely(item_size < min_size)) {
+		generic_err(leaf, slot,
+		"invalid qgroup status item size, have %u expect at least %u",
+			    item_size, min_size);
+		return -EUCLEAN;
+	}
+	ptr = btrfs_item_ptr(leaf, slot, struct btrfs_qgroup_status_item);
+	if (!(btrfs_qgroup_status_flags(leaf, ptr) & BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE))
+		return 0;
+
+	/* Simple quotas need the incompat bit and the enable_gen member. */
+	if (unlikely(!btrfs_fs_incompat(leaf->fs_info, SIMPLE_QUOTA))) {
+		generic_err(leaf, slot,
+	"qgroup status item has SIMPLE_MODE but SIMPLE_QUOTA incompat bit unset");
+		return -EUCLEAN;
+	}
+	if (unlikely(item_size < sizeof(*ptr))) {
+		generic_err(leaf, slot,
+	"invalid qgroup status item size for simple quota, have %u expect at least %zu",
+			    item_size, sizeof(*ptr));
+		return -EUCLEAN;
+	}
+	return 0;
+}
+
 static int check_remap_key(const struct extent_buffer *leaf,
 			   const struct btrfs_key *key, int slot)
 {
@@ -2475,6 +2507,9 @@ static enum btrfs_tree_block_status check_leaf_item(struct extent_buffer *leaf,
 	case BTRFS_FREE_SPACE_BITMAP_KEY:
 		ret = check_free_space_bitmap(leaf, key, slot, prev_key);
 		break;
+	case BTRFS_QGROUP_STATUS_KEY:
+		ret = check_qgroup_status_item(leaf, slot);
+		break;
 	case BTRFS_IDENTITY_REMAP_KEY:
 	case BTRFS_REMAP_KEY:
 	case BTRFS_REMAP_BACKREF_KEY:
-- 
2.54.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 2/2] btrfs: tree-checker: reject extent owner ref without simple quota
  2026-11-03  3:49 [PATCH 0/2] btrfs: tree-checker: reject simple quota metadata without SIMPLE_QUOTA Siddharth Mishra
  2026-11-03  3:49 ` [PATCH 1/2] btrfs: tree-checker: validate qgroup status item Siddharth Mishra
@ 2026-11-03  3:49 ` Siddharth Mishra
  2026-11-03  4:40   ` Qu Wenruo
  1 sibling, 1 reply; 6+ messages in thread
From: Siddharth Mishra @ 2026-11-03  3:49 UTC (permalink / raw)
  To: David Sterba
  Cc: Qu Wenruo, Boris Burkov, Chris Mason, linux-btrfs, linux-kernel,
	Siddharth Mishra, stable

[BUG]
An extent item can contain an owner ref.  The owner ref is correct only
when the super block has the SIMPLE_QUOTA bit.  If the bit is not set,
check_extent_item() gives a WARN_ON() and then accepts the leaf :

	case BTRFS_EXTENT_OWNER_REF_KEY:
		WARN_ON(!btrfs_fs_incompat(fs_info, SIMPLE_QUOTA));
		break;

For all other incorrect inline refs, check_extent_item() returns
-EUCLEAN.  After the tree-checker accepts the leaf, a free of the extent
calls btrfs_get_extent_inline_ref_type().  This function ASSERT()s the
SIMPLE_QUOTA bit.

I made a crafted image : an owner ref, no SIMPLE_QUOTA bit, and no quota
tree.  On a kernel with CONFIG_BTRFS_ASSERT=y, I removed the file of the
extent.  At the next commit, btrfs frees the extent and gives :

  WARNING: fs/btrfs/tree-checker.c:1782 at __btrfs_check_leaf
  assertion failed: btrfs_fs_incompat(fs_info, SIMPLE_QUOTA),
  in fs/btrfs/extent-tree.c:354
  kernel BUG at fs/btrfs/extent-tree.c:354!
  Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI
  RIP: 0010:btrfs_get_extent_inline_ref_type.cold
  (fs/btrfs/extent-tree.c:354)
  Call Trace:
   lookup_inline_extent_backref (fs/btrfs/extent-tree.c:919)
   lookup_extent_backref (fs/btrfs/extent-tree.c:1100)
   __btrfs_free_extent.isra.0 (fs/btrfs/extent-tree.c:3319)
   __btrfs_run_delayed_refs (fs/btrfs/extent-tree.c:2134)
   btrfs_run_delayed_refs (fs/btrfs/extent-tree.c:2246)
   btrfs_commit_transaction (fs/btrfs/transaction.c:2278)
   ksys_sync (fs/sync.c:104)

Without CONFIG_BTRFS_ASSERT, the kernel gives only the WARN_ON().  Then
btrfs continues to use the owner ref.

[CAUSE]
For an owner ref without the SIMPLE_QUOTA bit, the tree-checker gives a
WARN_ON() and keeps the leaf.  For all other inline ref types, it
rejects the leaf.  Two sources can put owner refs without the
SIMPLE_QUOTA bit on a disk : a damaged or crafted image, and a kernel
without commit f2363e6fcc79 ("btrfs: fix transaction atomicity bug when
enabling simple quotas").

[FIX]
Reject the leaf with -EUCLEAN, as for all other incorrect inline refs.
Then btrfs finds the problem when it reads the leaf, and the ASSERT() is
not reached.

syzbot reported the WARN_ON() and the ASSERT() in 2024 without a
reproducer.  Both reports were closed for inactivity.  At that time, the
WARN_ON() was noted as something that "should be handled in a better
way".  I found the cause during the analysis of a fuzzing report.  An AI
tool helped.  I tested with a crafted image on btrfs for-next
(d6f76ca0a70d).  Without the patch, the kernel gives the WARN_ON(), and
the BUG above with CONFIG_BTRFS_ASSERT=y.  With the patch, the
tree-checker rejects the leaf ("extent owner ref without simple quota")
and the mount fails with -EIO.  There is no WARN_ON() and no BUG.  A
clean simple quota filesystem still writes data, frees extents and
mounts again without errors.  The fstests group qgroup has no new
failure (34 passed, 3 not run here).  The crafted image and the commands
are available on request.

Link: https://syzkaller.appspot.com/bug?extid=d7d1fc7e21835ca19219
Link: https://syzkaller.appspot.com/bug?extid=4983e68a6d77180bfe33
Fixes: d9a620f77e33 ("btrfs: new inline ref storing owning subvol of data extents")
Cc: stable@vger.kernel.org # 6.7+
Signed-off-by: Siddharth Mishra <smish149@asu.edu>
---
 fs/btrfs/tree-checker.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
index 0d75cb537..5c44bed99 100644
--- a/fs/btrfs/tree-checker.c
+++ b/fs/btrfs/tree-checker.c
@@ -1779,7 +1779,11 @@ static int check_extent_item(struct extent_buffer *leaf,
 			inline_refs += btrfs_shared_data_ref_count(leaf, sref);
 			break;
 		case BTRFS_EXTENT_OWNER_REF_KEY:
-			WARN_ON(!btrfs_fs_incompat(fs_info, SIMPLE_QUOTA));
+			if (unlikely(!btrfs_fs_incompat(fs_info, SIMPLE_QUOTA))) {
+				extent_err(leaf, slot,
+					   "extent owner ref without simple quota");
+				return -EUCLEAN;
+			}
 			break;
 		default:
 			extent_err(leaf, slot, "unknown inline ref type: %u",
-- 
2.54.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] btrfs: tree-checker: validate qgroup status item
  2026-11-03  3:49 ` [PATCH 1/2] btrfs: tree-checker: validate qgroup status item Siddharth Mishra
@ 2026-11-03  4:36   ` Qu Wenruo
  0 siblings, 0 replies; 6+ messages in thread
From: Qu Wenruo @ 2026-11-03  4:36 UTC (permalink / raw)
  To: Siddharth Mishra, David Sterba
  Cc: Boris Burkov, Chris Mason, linux-btrfs, linux-kernel, stable



在 2026/11/3 14:19, Siddharth Mishra 写道:
> [BUG]
> An image can have a status item with SIMPLE_MODE and a super block
> without the SIMPLE_QUOTA bit.  On a kernel with CONFIG_BTRFS_ASSERT=y,
> the mount of this image causes a BUG :
> 
>    assertion failed: btrfs_fs_incompat(fs_info, SIMPLE_QUOTA),
>    in fs/btrfs/qgroup.c:411
>    kernel BUG at fs/btrfs/qgroup.c:411!
>    Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI
>    RIP: 0010:btrfs_read_qgroup_config.cold (fs/btrfs/qgroup.c:411)
>    Call Trace:
>     open_ctree (fs/btrfs/disk-io.c:3789)
>     btrfs_get_tree.cold (fs/btrfs/super.c:2133)
>     vfs_get_tree (fs/super.c:1943)
>     fc_mount (fs/namespace.c:1282)
>     path_mount (fs/namespace.c:4337)
>     __x64_sys_mount (fs/namespace.c:4542)
> 
> Without CONFIG_BTRFS_ASSERT, the mount is successful in simple quota
> mode.  The first data write then adds an owner ref.  The write-time
> tree-checker sees the owner ref without the SIMPLE_QUOTA bit and gives
> a WARN_ON() (tree-checker.c:1782).
> 
> [CAUSE]
> The tree-checker does not examine the status item.
> btrfs_read_qgroup_config() reads the flags of the status item.  For
> SIMPLE_MODE, it calls qgroup_read_enable_gen().  This function ASSERT()s
> that the SIMPLE_QUOTA bit is set and that the item contains enable_gen.
> Since commit f2363e6fcc79, the kernel does not write SIMPLE_MODE without
> the SIMPLE_QUOTA bit.  Thus only a damaged or crafted image has this
> state.

The easiest way to show the cause is to provide a tree dump of the 
offending leaf, and highlight the offending tree blocks.

> 
> [FIX]
> Add a tree-checker rule for the status item :
> - The item must contain the four members of all versions : version,
>    generation, flags and rescan.
> - With SIMPLE_MODE, the super block must have the SIMPLE_QUOTA bit, and
>    the item must also contain enable_gen.
> If a rule fails, the tree-checker rejects the leaf with -EUCLEAN.  Then
> btrfs_read_roots() cannot read the quota root.  It ignores the error, as
> before, and btrfs mounts the filesystem without quotas.
> 
> Fuzzing found this bug. An AI tool helped to analyse the cause and to
> write the fix. I tested on btrfs for-next (d6f76ca0a70d), with and
> without KASAN and CONFIG_BTRFS_ASSERT=y. Without the patch, the kernel
> gives the BUG above, or the WARN_ON() at the first write. With the
> patch, the tree-checker rejects the leaf ("qgroup status item has
> SIMPLE_MODE but SIMPLE_QUOTA incompat bit unset"). The mount is
> successful without quotas. There is no BUG and no WARN_ON(). A clean
> simple quota filesystem still mounts, writes data, frees extents and
> mounts again. Its status item passes the check at each commit. The
> fstests group qgroup has no new failure (34 passed, 3 not run here). A
> crafted image and a C reproducer are available on request.

Drop the whole paragraph starting with "Fuzzing found".

It makes no sense. And tell your agent to write this rule into its 
memory file.

This looks very chatgpt, and so far I have no good experience with 
patches generated by that.

> 
> Fixes: 182940f4f4db ("btrfs: qgroup: add new quota mode for simple quotas")

I don't think this should count as a fix.

> Cc: stable@vger.kernel.org # 6.7+
> Signed-off-by: Siddharth Mishra <smish149@asu.edu>
> ---
>   fs/btrfs/tree-checker.c | 35 +++++++++++++++++++++++++++++++++++
>   1 file changed, 35 insertions(+)
> 
> diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
> index 61ea8f42c..0d75cb537 100644
> --- a/fs/btrfs/tree-checker.c
> +++ b/fs/btrfs/tree-checker.c
> @@ -2083,6 +2083,38 @@ static int check_raid_stripe_extent(const struct extent_buffer *leaf,
>   	return 0;
>   }
>   
> +static int check_qgroup_status_item(const struct extent_buffer *leaf, int slot)
> +{
> +	const u32 item_size = btrfs_item_size(leaf, slot);
> +	const u32 min_size = offsetof(struct btrfs_qgroup_status_item, enable_gen);
> +	struct btrfs_qgroup_status_item *ptr;
> +
> +	/* version, generation, flags and rescan are always present. */

I don't think the comment adds much value.

Tell your agent to keep comments at minimal.

> +	if (unlikely(item_size < min_size)) {
> +		generic_err(leaf, slot,
> +		"invalid qgroup status item size, have %u expect at least %u",
> +			    item_size, min_size);
> +		return -EUCLEAN;
> +	}
> +	ptr = btrfs_item_ptr(leaf, slot, struct btrfs_qgroup_status_item);
> +	if (!(btrfs_qgroup_status_flags(leaf, ptr) & BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE))
> +		return 0;
> +
> +	/* Simple quotas need the incompat bit and the enable_gen member. */
> +	if (unlikely(!btrfs_fs_incompat(leaf->fs_info, SIMPLE_QUOTA))) {
> +		generic_err(leaf, slot,
> +	"qgroup status item has SIMPLE_MODE but SIMPLE_QUOTA incompat bit unset");
> +		return -EUCLEAN;
> +	}
> +	if (unlikely(item_size < sizeof(*ptr))) {
> +		generic_err(leaf, slot,
> +	"invalid qgroup status item size for simple quota, have %u expect at least %zu",
> +			    item_size, sizeof(*ptr));
> +		return -EUCLEAN;
> +	}
> +	return 0;
> +}
> +
>   static int check_remap_key(const struct extent_buffer *leaf,
>   			   const struct btrfs_key *key, int slot)
>   {
> @@ -2475,6 +2507,9 @@ static enum btrfs_tree_block_status check_leaf_item(struct extent_buffer *leaf,
>   	case BTRFS_FREE_SPACE_BITMAP_KEY:
>   		ret = check_free_space_bitmap(leaf, key, slot, prev_key);
>   		break;
> +	case BTRFS_QGROUP_STATUS_KEY:
> +		ret = check_qgroup_status_item(leaf, slot);
> +		break;
>   	case BTRFS_IDENTITY_REMAP_KEY:
>   	case BTRFS_REMAP_KEY:
>   	case BTRFS_REMAP_BACKREF_KEY:


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/2] btrfs: tree-checker: reject extent owner ref without simple quota
  2026-11-03  3:49 ` [PATCH 2/2] btrfs: tree-checker: reject extent owner ref without simple quota Siddharth Mishra
@ 2026-11-03  4:40   ` Qu Wenruo
  2026-11-03  5:15     ` Siddharth Mishra
  0 siblings, 1 reply; 6+ messages in thread
From: Qu Wenruo @ 2026-11-03  4:40 UTC (permalink / raw)
  To: Siddharth Mishra, David Sterba
  Cc: Boris Burkov, Chris Mason, linux-btrfs, linux-kernel, stable



在 2026/11/3 14:19, Siddharth Mishra 写道:
> [BUG]
> An extent item can contain an owner ref.  The owner ref is correct only
> when the super block has the SIMPLE_QUOTA bit.  If the bit is not set,
> check_extent_item() gives a WARN_ON() and then accepts the leaf :
> 
> 	case BTRFS_EXTENT_OWNER_REF_KEY:
> 		WARN_ON(!btrfs_fs_incompat(fs_info, SIMPLE_QUOTA));
> 		break;
> 
> For all other incorrect inline refs, check_extent_item() returns
> -EUCLEAN.  After the tree-checker accepts the leaf, a free of the extent
> calls btrfs_get_extent_inline_ref_type().  This function ASSERT()s the
> SIMPLE_QUOTA bit.
> 
> I made a crafted image : an owner ref, no SIMPLE_QUOTA bit, and no quota
> tree.  On a kernel with CONFIG_BTRFS_ASSERT=y, I removed the file of the
> extent.  At the next commit, btrfs frees the extent and gives :

I don't think this should go into BUG section, but CAUSE.

> 
>    WARNING: fs/btrfs/tree-checker.c:1782 at __btrfs_check_leaf
>    assertion failed: btrfs_fs_incompat(fs_info, SIMPLE_QUOTA),
>    in fs/btrfs/extent-tree.c:354
>    kernel BUG at fs/btrfs/extent-tree.c:354!
>    Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI
>    RIP: 0010:btrfs_get_extent_inline_ref_type.cold
>    (fs/btrfs/extent-tree.c:354)
>    Call Trace:
>     lookup_inline_extent_backref (fs/btrfs/extent-tree.c:919)
>     lookup_extent_backref (fs/btrfs/extent-tree.c:1100)
>     __btrfs_free_extent.isra.0 (fs/btrfs/extent-tree.c:3319)
>     __btrfs_run_delayed_refs (fs/btrfs/extent-tree.c:2134)
>     btrfs_run_delayed_refs (fs/btrfs/extent-tree.c:2246)
>     btrfs_commit_transaction (fs/btrfs/transaction.c:2278)
>     ksys_sync (fs/sync.c:104)
> 
> Without CONFIG_BTRFS_ASSERT, the kernel gives only the WARN_ON().  Then
> btrfs continues to use the owner ref.
> 
> [CAUSE]
> For an owner ref without the SIMPLE_QUOTA bit, the tree-checker gives a
> WARN_ON() and keeps the leaf.  For all other inline ref types, it
> rejects the leaf.  Two sources can put owner refs without the
> SIMPLE_QUOTA bit on a disk : a damaged or crafted image, and a kernel
> without commit f2363e6fcc79 ("btrfs: fix transaction atomicity bug when
> enabling simple quotas").
> 
> [FIX]
> Reject the leaf with -EUCLEAN, as for all other incorrect inline refs.
> Then btrfs finds the problem when it reads the leaf, and the ASSERT() is
> not reached.
> 
> syzbot reported the WARN_ON() and the ASSERT() in 2024 without a
> reproducer.  Both reports were closed for inactivity.  At that time, the
> WARN_ON() was noted as something that "should be handled in a better
> way".  I found the cause during the analysis of a fuzzing report.  An AI
> tool helped.  I tested with a crafted image on btrfs for-next
> (d6f76ca0a70d).  Without the patch, the kernel gives the WARN_ON(), and
> the BUG above with CONFIG_BTRFS_ASSERT=y.  With the patch, the
> tree-checker rejects the leaf ("extent owner ref without simple quota")
> and the mount fails with -EIO.  There is no WARN_ON() and no BUG.  A
> clean simple quota filesystem still writes data, frees extents and
> mounts again without errors.  The fstests group qgroup has no new
> failure (34 passed, 3 not run here).  The crafted image and the commands
> are available on request.

Again, remove the last paragraph.

> 
> Link: https://syzkaller.appspot.com/bug?extid=d7d1fc7e21835ca19219
> Link: https://syzkaller.appspot.com/bug?extid=4983e68a6d77180bfe33
> Fixes: d9a620f77e33 ("btrfs: new inline ref storing owning subvol of data extents")

Again, I don't think this really counts as a fixes.

Or all hardening would be considered as a fix, which makes no sense.

> Cc: stable@vger.kernel.org # 6.7+
> Signed-off-by: Siddharth Mishra <smish149@asu.edu>
> ---
>   fs/btrfs/tree-checker.c | 6 +++++-
>   1 file changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
> index 0d75cb537..5c44bed99 100644
> --- a/fs/btrfs/tree-checker.c
> +++ b/fs/btrfs/tree-checker.c
> @@ -1779,7 +1779,11 @@ static int check_extent_item(struct extent_buffer *leaf,
>   			inline_refs += btrfs_shared_data_ref_count(leaf, sref);
>   			break;
>   		case BTRFS_EXTENT_OWNER_REF_KEY:
> -			WARN_ON(!btrfs_fs_incompat(fs_info, SIMPLE_QUOTA));
> +			if (unlikely(!btrfs_fs_incompat(fs_info, SIMPLE_QUOTA))) {
> +				extent_err(leaf, slot,
> +					   "extent owner ref without simple quota");
> +				return -EUCLEAN;
> +			}
>   			break;
>   		default:
>   			extent_err(leaf, slot, "unknown inline ref type: %u",


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/2] btrfs: tree-checker: reject extent owner ref without simple quota
  2026-11-03  4:40   ` Qu Wenruo
@ 2026-11-03  5:15     ` Siddharth Mishra
  0 siblings, 0 replies; 6+ messages in thread
From: Siddharth Mishra @ 2026-11-03  5:15 UTC (permalink / raw)
  To: Qu Wenruo
  Cc: David Sterba, Boris Burkov, Chris Mason, linux-btrfs,
	linux-kernel, stable

On Mon, Nov 2, 2026 at 9:41 PM Qu Wenruo <wqu@suse.com> wrote:
>
> I don't think this should go into BUG section, but CAUSE.
>
> Again, remove the last paragraph.
>
> Again, I don't think this really counts as a fixes.
>
> Or all hardening would be considered as a fix, which makes no sense.
>

Thanks for the review. I'll send v2 with your reviews addressed.
v2 will drop the last paragraph and the fixes tag from both patches,
add the tree dumps you asked for, remove the comments, and move the
reproduction of the second patch into the [CAUSE] section.

Thanks,
Siddharth

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-11-03  5:16 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-03  3:49 [PATCH 0/2] btrfs: tree-checker: reject simple quota metadata without SIMPLE_QUOTA Siddharth Mishra
2026-11-03  3:49 ` [PATCH 1/2] btrfs: tree-checker: validate qgroup status item Siddharth Mishra
2026-11-03  4:36   ` Qu Wenruo
2026-11-03  3:49 ` [PATCH 2/2] btrfs: tree-checker: reject extent owner ref without simple quota Siddharth Mishra
2026-11-03  4:40   ` Qu Wenruo
2026-11-03  5:15     ` Siddharth Mishra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®