A vulnerability has been discovered and resolved in the Linux kernel's suspend behavior for the virtio-blk driver. The issue is related to the usage of the queue freeze mechanism, which could lead to deadlocks during system suspend. This post provides an overview of the vulnerability, as well as details about the changes made to address the issue.

CVE-2024-57946 details

The Linux kernel vulnerability in question is related to the commit 4ce6e2db00de ("virtio-blk: Ensure no requests in virtqueues before deleting vqs.") in the virtio-blk driver. This commit replaced the previous queue quiesce function with a new queue freeze implementation in the PM (Power Management) callbacks of the driver. The main purpose of this change was to drain in-flight I/O requests before the system is suspended.

However, this new queue freeze mechanism has the potential to cause deadlocks. In particular, any attempt to call the bio_queue_enter() function while the queue is frozen can result in a deadlock. Since various suspend functions are called during the suspend context, keeping the queue frozen throughout this process can be problematic.

A lockdep warning[1] was reported by Marek Szyprowski, which helped identify the root cause of this issue. The warning was triggered because of the virtio-blk driver's freeze queue used in the virtblk_freeze() function.

Reference: [1] https://lore.kernel.org/linux-block/ca16370e-d646-4eee-b9cc-87277c89c43c@samsung.com/

Solution

To address this vulnerability and avoid deadlocks during system suspend, the original motivation of draining in-flight I/O requests can be achieved by calling the freeze and unfreeze functions. In addition, the driver behavior can be restored to its previous state by keeping the queue quiesced instead of frozen during the suspend process.

The following code snippet demonstrates the changes made to resolve the issue

/* Original code using queue freeze in virtio-blk driver:
 * virtblk_freeze() and virtblk_thaw() */

/* Solution: Replace queue freeze with quiesce in virtio-blk driver:
 * virtblk_quiesce() and virtblk_unquiesce() */

// New virtblk_quiesce() function to keep queue quiesced during system suspend
static int virtblk_quiesce(struct virtio_device *vdev)
{
    struct virtio_blk *vblk = vdev->priv;

    blk_mq_freeze_queue(vblk->disk->queue);
    blk_mq_quiesce_queue(vblk->disk->queue);
    blk_mq_unfreeze_queue(vblk->disk->queue);

    return ;
}

// New virtblk_unquiesce() function to unquiesce the queue during system resume
static int virtblk_unquiesce(struct virtio_device *vdev)
{
    struct virtio_blk *vblk = vdev->priv;

    blk_mq_unquiesce_queue(vblk->disk->queue);

    return ;
}

By implementing these changes, the Linux kernel's suspend behavior for the virtio-blk driver is improved, avoiding deadlocks caused by the queue freeze mechanism. Thus, the vulnerability identified as CVE-2024-57946 has been effectively resolved.

Timeline

Published on: 01/21/2025 13:15:09 UTC
Last modified on: 02/28/2025 19:03:34 UTC