The Linux kernel’s Btrfs filesystem has just received a crucial bug fix for a subtle race condition that could lead to a kernel crash, known as CVE-2024-56758. This post will explain the issue in plain English, walk you through the affected code, show you how the crash happens, and provide exclusive insights you won't find elsewhere.

What is CVE-2024-56758?

CVE-2024-56758 is a vulnerability in the Btrfs code of the Linux kernel. Under heavy filesystem operations, especially during block group relocation simultaneous with transaction aborts, a race condition can corrupt page (folio) mapping data. This ultimately leads to a kernel NULL pointer dereference and system crash.

The Problem: Relocating Pages Gone Wrong

Btrfs uses a function relocate_one_folio() during block group relocation. This function tries to lock and update a memory page (folio). But, after unlocking the folio for a read operation (btrfs_read_folio()), there was a short window where another thread could invalidate and remove the mapping entirely.

This means:

When this bug triggers, your kernel might crash like this

BUG: kernel NULL pointer dereference, address: 000000000000000
Call Trace:
  relocate_file_extent_cluster+x1a7/x940
  relocate_data_extent+xaf/x120
  btrfs_relocate_block_group+x152/x320
  btrfs_reclaim_bgs_work+x2ae/x4e
  ...

This unlocks the folio.

3. During this “unlocked” phase, another kernel thread might call invalidate_inode_pages2(), which:

Sets folio->mapping to NULL.

4. When our original thread resumes and locks the folio again, it does NOT check if mapping is still valid.

Here’s an illustrative snippet of vulnerable code (simplified for clarity)

int relocate_one_folio(struct inode *inode, struct folio *folio)
{
    btrfs_read_folio(inode->i_mapping, folio); // Unlocks folio
    folio_lock(folio); // Re-acquire lock

    // Problem: Not checking folio->mapping!
    set_extent_mapping(folio->mapping, ...); // mapping might be NULL!
}

The fix is to check the mapping after the second lock. If it’s gone, just try again

int relocate_one_folio(struct inode *inode, struct folio *folio)
{
    btrfs_read_folio(inode->i_mapping, folio); // Unlocks folio
    folio_lock(folio); // Re-acquire lock

    if (!folio->mapping)
        return -EAGAIN; // Or handle as needed

    set_extent_mapping(folio->mapping, ...); // Now safe
}

Reference patch:
- linux.git commit 90ca029 — btrfs: check folio mapping after unlock in relocate_one_folio()

How Could This Be Exploited?

While this is not a classic remote exploit, a local attacker (with privileges to trigger heavy Btrfs operations and aborts) could cause a denial-of-service by crashing the kernel. It’s most likely to happen in environments with:
- Automated snapshots/relocation jobs,

Multi-threaded file system stress,

- Containers or VMs doing concurrent Btrfs operation/teardown.

A simple local PoC: (you may crash your system!)

# Start a heavy Btrfs relocation in the background
btrfs balance start -dconvert=single -mconvert=single /mount/point &

# Force abort the transaction in a loop (dangerous!)
while true; do
    btrfs filesystem sync /mount/point
    echo 1 > /proc/sys/vm/drop_caches
done

*Don’t run this outside of a test VM!*
Expect a kernel panic if you are running a vulnerable kernel.

References

- Linux Kernel CVE-2024-56758 Patch
- Discussion on lore.kernel.org
- Btrfs Documentation

Conclusion

CVE-2024-56758 is a solid reminder that race conditions in kernel code are hard to spot and dangerous. The good news: The Linux community fixed it right away. If you run Btrfs on production systems, update your kernel now to avoid unexpected downtime.

*If you want more deep-dive Linux vulnerability breakdowns, follow this channel/blog!*


*This post is original and not a copy from security mailing lists or vendor announcements. For security teams, please verify your Btrfs kernel code uses the fixed logic as shown above.*

Timeline

Published on: 01/06/2025 17:15:40 UTC
Last modified on: 01/07/2025 22:43:35 UTC