Skip to main content

Linux Kernel CVE-2026-31519

| EUVDEUVD-2026-24903 MEDIUM
NULL Pointer Dereference (CWE-476)
2026-04-22 416baaa9-dc9f-4396-8d5f-8c081fb06d67 GHSA-p3jm-9f4h-xp4f
5.5
CVSS 3.1 · NVD
Share

Severity by source

NVD PRIMARY
5.5 MEDIUM
AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H
SUSE
MEDIUM
qualitative
Red Hat
5.5 MEDIUM
qualitative

Primary rating from NVD.

CVSS VectorNVD

CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H
Attack Vector
Local
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
None
Availability
High

Lifecycle Timeline

7
Analysis Generated
Apr 28, 2026 - 19:07 vuln.today
CVSS changed
Apr 28, 2026 - 19:07 NVD
5.5 (MEDIUM)
Patch released
Apr 28, 2026 - 18:54 nvd
Patch available
Patch available
Apr 22, 2026 - 16:33 EUVD
EUVD ID Assigned
Apr 22, 2026 - 14:22 euvd
EUVD-2026-24903
Analysis Generated
Apr 22, 2026 - 14:22 vuln.today
CVE Published
Apr 22, 2026 - 14:16 nvd
MEDIUM 5.5

DescriptionCVE.org

In the Linux kernel, the following vulnerability has been resolved:

btrfs: set BTRFS_ROOT_ORPHAN_CLEANUP during subvol create

We have recently observed a number of subvolumes with broken dentries. ls-ing the parent dir looks like:

drwxrwxrwt 1 root root 16 Jan 23 16:49 . drwxr-xr-x 1 root root 24 Jan 23 16:48 .. d????????? ? ? ? ? ? broken_subvol

and similarly stat-ing the file fails.

In this state, deleting the subvol fails with ENOENT, but attempting to create a new file or subvol over it errors out with EEXIST and even aborts the fs. Which leaves us a bit stuck.

dmesg contains a single notable error message reading: "could not do orphan cleanup -2"

2 is ENOENT and the error comes from the failure handling path of btrfs_orphan_cleanup(), with the stack leading back up to btrfs_lookup().

btrfs_lookup btrfs_lookup_dentry btrfs_orphan_cleanup // prints that message and returns -ENOENT

After some detailed inspection of the internal state, it became clear that:

  • there are no orphan items for the subvol
  • the subvol is otherwise healthy looking, it is not half-deleted or

anything, there is no drop progress, etc.

  • the subvol was created a while ago and does the meaningful first

btrfs_orphan_cleanup() call that sets BTRFS_ROOT_ORPHAN_CLEANUP much later.

  • after btrfs_orphan_cleanup() fails, btrfs_lookup_dentry() returns -ENOENT,

which results in a negative dentry for the subvolume via d_splice_alias(NULL, dentry), leading to the observed behavior. The bug can be mitigated by dropping the dentry cache, at which point we can successfully delete the subvolume if we want.

i.e., btrfs_lookup() btrfs_lookup_dentry() if (!sb_rdonly(inode->vfs_inode)->vfs_inode) btrfs_orphan_cleanup(sub_root) test_and_set_bit(BTRFS_ROOT_ORPHAN_CLEANUP) btrfs_search_slot() // finds orphan item for inode N ... prints "could not do orphan cleanup -2" if (inode == ERR_PTR(-ENOENT)) inode = NULL; return d_splice_alias(NULL, dentry) // NEGATIVE DENTRY for valid subvolume

btrfs_orphan_cleanup() does test_and_set_bit(BTRFS_ROOT_ORPHAN_CLEANUP) on the root when it runs, so it cannot run more than once on a given root, so something else must run concurrently. However, the obvious routes to deleting an orphan when nlinks goes to 0 should not be able to run without first doing a lookup into the subvolume, which should run btrfs_orphan_cleanup() and set the bit.

The final important observation is that create_subvol() calls d_instantiate_new() but does not set BTRFS_ROOT_ORPHAN_CLEANUP, so if the dentry cache gets dropped, the next lookup into the subvolume will make a real call into btrfs_orphan_cleanup() for the first time. This opens up the possibility of concurrently deleting the inode/orphan items but most typical evict() paths will be holding a reference on the parent dentry (child dentry holds parent->d_lockref.count via dget in d_alloc(), released in __dentry_kill()) and prevent the parent from being removed from the dentry cache.

The one exception is delayed iputs. Ordered extent creation calls igrab() on the inode. If the file is unlinked and closed while those refs are held, iput() in __dentry_kill() decrements i_count but does not trigger eviction (i_count > 0). The child dentry is freed and the subvol dentry's d_lockref.count drops to 0, making it evictable while the inode is still alive.

Since there are two races (the race between writeback and unlink and the race between lookup and delayed iputs), and there are too many moving parts, the following three diagrams show the complete picture. (Only the second and third are races)

Phase 1: Create Subvol in dentry cache without BTRFS_ROOT_ORPHAN_CLEANUP set

btrfs_mksubvol() lookup_one_len() __lookup_slow() d_alloc_parallel() __d_alloc() // d_lockref.count = 1 create_subvol(dentry) // doesn't touch the bit.. d_instantiate_new(dentry, inode) // dentry in cache with d_lockref.c ---truncated---

AnalysisAI

A denial-of-service vulnerability in the Linux kernel's Btrfs filesystem implementation allows local authenticated attackers to cause filesystem corruption and crashes through a race condition during subvolume creation and lookup. When a newly created Btrfs subvolume's dentry cache is dropped before the BTRFS_ROOT_ORPHAN_CLEANUP flag is set, concurrent orphan cleanup operations can fail with ENOENT, creating negative dentries that prevent subvolume deletion and cause filesystem aborts. EPSS score of 0.02% indicates this is a low-probability exploitation scenario requiring specific timing and configuration conditions, though the impact is severe for affected systems. No public exploit code is identified at time of analysis.

Technical ContextAI

The vulnerability resides in the Btrfs subvolume creation and directory lookup logic within the Linux kernel. When a subvolume is created via create_subvol(), the function calls d_instantiate_new() to add the dentry to the cache but fails to set the BTRFS_ROOT_ORPHAN_CLEANUP flag on the root inode. This flag is normally set during the first btrfs_orphan_cleanup() call, which occurs on subsequent lookups via btrfs_lookup_dentry(). The root cause (CWE-476: Null Pointer Dereference) manifests as a race condition: if the dentry cache is dropped between subvolume creation and the first lookup, a concurrent orphan cleanup attempt can fail with ENOENT when btrfs_search_slot() encounters missing orphan items. This causes btrfs_lookup_dentry() to return ERR_PTR(-ENOENT), which is then converted to a NULL pointer passed to d_splice_alias(), creating a negative dentry for a valid subvolume. The race is enabled by delayed iput operations that allow child dentries to be freed while parent dentries remain cached, or by concurrent unlink/writeback operations. The CPE indicates all Linux kernel versions are potentially affected, with patched versions available for 6.1.168, 6.6.131, 6.12.80, 6.18.21, 6.19.11, and 7.0 stable branches.

RemediationAI

Vendor-released patches are available for stable Linux kernel branches: apply kernel update to version 6.1.168 or later for the 6.1 branch, 6.6.131 or later for the 6.6 branch, 6.12.80 or later for the 6.12 branch, 6.18.21 or later for the 6.18 branch, 6.19.11 or later for the 6.19 branch, or 7.0 or later for the 7.0 branch. The fix sets BTRFS_ROOT_ORPHAN_CLEANUP during subvolume creation, preventing the race condition. Interim workarounds for unpatched systems include: (1) restrict Btrfs subvolume creation permissions to root only (via file capabilities or access controls), eliminating the requirement for PR:L authentication; (2) disable Btrfs as the primary filesystem for multi-tenant environments where local users have shell access; (3) monitor Btrfs filesystem health via btrfs filesystem show and immediately investigate any subvolumes with permission display anomalies (d????????? entries), manually clearing the dentry cache with echo 3 > /proc/sys/vm/drop_caches and attempting subvolume deletion/recreation. Note that drop_caches may degrade performance on heavily loaded systems due to cache rebuild overhead. The most robust mitigation is immediate kernel patching, as the workarounds require operational overhead and do not fully prevent exploitation by determined local attackers with appropriate access levels.

Vendor StatusVendor

SUSE

Severity: Medium
Product Status
SUSE Linux Enterprise Desktop 15 SP7 Fixed
SUSE Linux Enterprise Desktop 15 SP7 Fixed
SUSE Linux Enterprise High Availability Extension 15 SP7 Fixed
SUSE Linux Enterprise High Availability Extension 15 SP7 Fixed
SUSE Linux Enterprise High Performance Computing 15 SP7 Fixed

Share

CVE-2026-31519 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy