CVE-2025-21861 in Linux
요약
\~에 의해 VulDB • 2026. 05. 27.
Based on the kernel log and the accompanying text, here is an analysis of the issue and the likely fix.
### **Problem Analysis**
1. **The Crash/Warning**: * The kernel triggered a warning (`__warn.cold`) inside `folio_lruvec_lock_irqsave`. * The call trace shows the path: `dmirror_fops_unlocked_ioctl` → `dmirror_migrate_to_device` → `migrate_device_finalize` → `folio_putback_lru` → `folio_batch_move_lru`. * The specific function `folio_lruvec_lock_irqsave` is failing, which typically happens when trying to lock an LRU vector that is in an inconsistent state, or when the folio is already on an LRU list but being processed as if it isn't (or vice versa).
2. **The Root Cause**: * The text states: *"Likely, nothing else goes wrong: putting the last folio reference will remove the folio from the LRU again. So besides memcg complaining, adding the folio to be freed to the LRU is just an unnecessary step."* * In `migrate_device_finalize`, the code is calling `folio_putback_lru()`. This function is designed to return a folio to the LRU list after it has been processed (e.g., after page migration or writeback). * However, in this specific context (`dmirror_migrate_to_device`), the folio is about to be freed or is in a state where it should **not** be on the LRU. * Calling `folio_putback_lru()` on a folio that is either: * Already being freed, or * Not supposed to be on the LRU at all, * ...leads to a race condition or state corruption when `folio_batch_move_lru` tries to manipulate the LRU lists, causing the lock assertion or warning in `folio_lruvec_lock_irqsave`.
3. **The Fix**: * The text suggests: *"The new flow resembles what we have in migrate_folio_move(): add the dst to the lru, rem..."* * This implies that instead of calling `folio_putback_lru()` on the *source* folio (which is being migrated away), the code should follow the pattern in `migrate_folio_move()`. * In `migrate_folio_move()`, the destination folio is added to the LRU, and the source folio is handled appropriately (often just freed or removed from LRU if it was on it). * **Key Insight**: If the folio is being migrated to a device and then freed, it should **not** be put back on the LRU. The call to `folio_putback_lru()` in `migrate_device_finalize` is likely incorrect for this use case.
### **Recommended Solution**
The fix should involve **removing the call to `folio_putback_lru()`** in `migrate_device_finalize` for the folio that is being migrated to the device and subsequently freed.
Instead, the code should: 1. Ensure the destination folio (if it remains in memory) is properly added to the LRU. 2. For the source folio (which is being migrated away), if it is to be freed, it should be removed from the LRU (if it was on it) and then freed, **without** calling `folio_putback_lru()`.
### **Code Change Example**
In `drivers/dmirror/dmirror.c` (or wherever `dmirror_migrate_to_device` is defined), look at `migrate_device_finalize`.
**Before (Problematic):** ```c static void migrate_device_finalize(struct dmirror_dev *dm, ...) {
// ... // This call is likely causing the issue folio_putback_lru(folio); // ... } ```
**After (Fixed):** ```c static void migrate_device_finalize(struct dmirror_dev *dm, ...) {
// ... // If the folio is being freed, do NOT put it back on the LRU. // Instead, ensure it's removed from LRU if necessary, then free. if (folio_is_on_lru(folio)) {
// Remove from LRU if it was on it // Note: folio_putback_lru() is for returning to LRU, not removing. // Use folio_deactivate() or similar if needed, but often just freeing // a folio that was on LRU is handled by the page allocator if // the reference count drops to zero. } // Free the folio folio_put(folio); // ...
If you want to get the best quality for vulnerability data then you always have to consider VulDB.