Look up another CVE · open CVE-2025-40303 in the interactive tracker
CVE-2025-40303
btrfs: ensure no dirty metadata is written back for an fs with errors
Published 2025-12-08 (10 months ago) by the Linux kernel CNA. Subsystem fs/btrfs. Debian urgency: not yet assigned.
What to do, per Debian release
Debian's own status for CVE-2025-40303 in every release this site tracks, and what each one means in practice. Every status below is the one the Debian Security Team publishes for this CVE. source
| Release | Status | Version | What this means |
|---|---|---|---|
| Debian 12bookworm | vulnerable | 6.1.190-1 | No fix published anywhere yet, neither in Debian nor upstream for the series bookworm tracks. Watch the Debian tracker page for this CVE. Advisories for bookworm have historically landed a median of 23 days after publication. |
| Debian 13trixie | fixed | 6.12.63-1 | Update the kernel and reboot. Fixed in 6.12.63-1. A running kernel keeps the old code until the machine restarts. |
| Debian 14forky | fixed | 6.17.8-1 | Update the kernel and reboot. Fixed in 6.17.8-1. A running kernel keeps the old code until the machine restarts. |
| Debian unstablesid | fixed | 6.17.8-1 | Update the kernel and reboot. Fixed in 6.17.8-1. A running kernel keeps the old code until the machine restarts. |
The vulnerability
What the bug is
[BUG] During development of a minor feature (make sure all btrfs_bio::end_io() is called in task context), I noticed a crash in generic/388, where metadata writes triggered new works after btrfs_stop_all_workers(). It turns out that it can even happen without any code modification, just using RAID5 for metadata and the same workload from generic/388 is going to trigger the use-after-free. [CAUSE] If btrfs hits an error, the fs is marked as error, no new transaction is allowed thus metadata is in a frozen state. But there are some metadata modifications before that error, and they are still in the btree inode page cache. Since there will be no real transaction commit, all those dirty folios are just kept as is in the page cache, and they can not be invalidated by invalidate_inode_pages2() call inside close_ctree(), because they are dirty. And finally after btrfs_stop_all_workers(), we call iput() on btree inode, which triggers writeback of those dirty metadata. And if the fs is using RAID56 metadata, this will trigger RMW and queue new works into rmw_workers, which is already stopped, causing warning from queue_work() and use-after-free. [FIX] Add a special handling for write_one_eb(), that if the fs is already in an error state, immediately mark the bbio as failure, instead of really submitting them. Then during close_ctree(), iput() will just discard all those dirty tree blocks without really writing them back, thus no more new jobs for already stopped-and-freed workqueues. The extra discard in write_one_eb() also acts as an extra safenet. E.g. the transaction abort is triggered by some extent/free space tree corruptions, and since extent/free space tree is already corrupted some tree blocks may be allocated where they shouldn't be (overwriting existing tree blocks). In that case writing them back will further corrupting the fs.
Where it lives
The fix touches these files. If the subsystem is one you do not use, the practical exposure is lower, though the package is still the vulnerable one.
fs/btrfs/extent_io.c
- What this is
- BTRFS FILE SYSTEMMAINTAINERS section matched on fs/btrfs/ · linux-btrfs@vger.kernel.org · Maintained
- Kernel module
- btrfs
Check it on the machine
grep -w CONFIG_BTRFS_FS /boot/config-$(uname -r)Reads the booted kernel's own configuration, on the machine and nowhere else. =y is built in, =m is a module, and an is not set line means the code is not there.
lsmod | grep -w btrfsPrints a line if that module is loaded right now, and nothing if it is not. One that is not loaded can still be loaded later by anything that needs it.
Show whether Debian builds this, per release
Debian builds this as a loadable module. Every release below compiles it as a module on every flavour, so whether the code is in the running kernel depends on whether that module is loaded.
- bookworm, trixie, forky, sidm
- m
- a loadable module on every flavour - check lsmod, can be blacklisted
- Build switch
- CONFIG_BTRFS_FS
From the configuration Debian publishes for every kernel flavour it builds. It covers only the architectures Debian ships a linux-config package for, and nothing about a kernel you built yourself. Debian's own status above stays authoritative about the source package.MAINTAINERS kbuild Makefiles Debian linux-config packages
Signals
- Published
- 2025-12-08 (10 months ago)source
- CVSS
- 7.8 high
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:Hsource recompute it - Attack vector
- local (AV:L)source
- EPSS
- 0.14%, higher than 2.9% of all CVEssource
- CISA KEV
- not listedthe KEV catalogue
- Debian urgency
- not yet assignedsource
- Subsystem
- fs/btrfs
Upstream fixes
The versions the CNA records as introducing and fixing this, and the commit for each. source
| Introduced | Fixed in | Commit |
|---|---|---|
| 3.10 | 6.6.117 | 066ee13f05fb |
| 3.10 | 6.12.58 | e2b3859067bf |
| 3.10 | 6.17.8 | 54a5b5a15588 |
| 3.10 | 6.18 | 2618849f31e7 |
Why the CNA scored it this way
Quoted from the kernel CNA's own scoring file, word for word. A highlighted metric carries the most severe value CVSS v3.1 defines for it, which is what pushes the score up. source
- AV:LAttack vector, local
- btrfs is a local filesystem; the bug is reached through ordinary local filesystem activity that dirties btree metadata plus the unmount path (`close_ctree()`), with no network-facing component.
- AC:LAttack complexity, low
- The sequence (fs error state with pending dirty metadata → unmount → writeback into the already-destroyed rmw_workers workqueue) is deterministic rather than a race, and the author reproduced it with an unmodified kernel using the stock generic/388 workload on RAID5 metadata, a profile an attacker supplying the image chooses freely.
- PR:LPrivileges required, low
- An unprivileged local user with write access to a btrfs mount generates the dirty metadata and can drive the workload; on desktop/kiosk systems udisks2 auto-mounts and unmounts attacker-supplied removable media without any root credential, so real root in the initial namespace is not required.
- UI:NUser interaction, none
- No separate victim action is needed — the attacker's own workload dirties the metadata and the unmount/eject that triggers the freed-workqueue use is performed by the attacker or occurs automatically during normal system operation.
- S:UScope, unchanged
- The corruption stays within kernel memory and the filesystem managed by the same kernel; no VM, IOMMU, or sandbox boundary is crossed.
- C:HConfidentiality impact, high
- queue_work() dereferences the freed workqueue_struct and its per-CPU pwq/pool, reading freed slab memory that an attacker can reclaim with sprayed objects, yielding an information-disclosure primitive on kernel memory.
- I:HIntegrity impact, high
- The use-after-free performs list insertions into the freed workqueue/pool structures, giving a write primitive into attacker-groomed memory, and the commit additionally documents that submitting these tree blocks can overwrite live metadata and further corrupt the on-disk filesystem.
- A:HAvailability impact, high
- The bug produces a queue_work() WARN and a use-after-free during unmount, crashing the kernel on a code path that runs after the workqueues have been torn down.