Summary:
CVE-2021-47024 describes a memory leak vulnerability in the Linux kernel's virtio vsock implementation. Malicious or buggy applications could exploit this bug to consume system memory, potentially causing resource exhaustion. In this article, we'll break down how this happened, show relevant code snippets, reference the original discovery, and explain how it was fixed.


## What is vsock/virtio?

The vsock (Virtual Socket) subsystem in Linux is used for efficient communication between virtual machines (VMs) and their host systems. It's a key driver for modern virtualization tools (such as QEMU and Docker), and relies on virtio, a standardized interface for virtual devices.

Discovery

The issue was originally found by syzbot, an automated kernel fuzzing tool. Here is the original bug report.

The Root Cause

When a vsock socket was closed, not all of its resources were freed properly. Specifically, any packets still queued (waiting) in the RX (receive) buffer were not released. So if you opened and closed vsock sockets repetitively, the kernel's memory use would steadily grow, potentially leading to an out-of-memory condition.

A partial fix was introduced with commit ac03046ece2b, which released some packets during the socket's release phase. But that didn't handle packets stuck in the RX queue when the socket was finally closed, often by cleanup work scheduled in the kernel’s background tasks.

Repeat these steps many times.

Over time, this would leave many orphaned packets in memory, slowly exhausting kernel resources.

Here's a simplified example in C-like pseudocode

int fd = socket(AF_VSOCK, SOCK_STREAM, );
connect(fd, ...); // connect to vsock
for (int i = ; i < 100; i++) {
    send(fd, buffer, sizeof(buffer), ); // send lots of data
}
close(fd); // close without reading
// Repeat the steps in a loop to exhaust RX queues

Each closed socket could leave data in the RX queue, leaking memory!

Real-World Impact

While this issue doesn’t allow direct code execution or privilege escalation, it can lead to denial-of-service (DoS) if exploited repeatedly, especially in environments with untrusted guests (like public clouds).

The Fix

To solve the leak, maintainers introduced code ensuring all RX-queued packets are freed when the socket is truly closed—even if this happens in the kernel's deferred background cleanup.

Previously, cleanup looked like this (incomplete, thus problematic)

// ac03046ece2b added freeing on socket release but missed RX draining
vsock_remove_sock(vsock); // but leftover RX packets stayed leaked

With the fix, the RX queue is properly drained

// New safe cleanup for closed vsock sockets
virtio_transport_remove_sock(vsock); // drains RX queue safely
vsock_remove_sock(vsock); // now it's safe to fully remove the socket

Technical Details

The crucial change is calling virtio_transport_remove_sock() before actually removing the socket structure. This function ensures all queued RX packets are properly deallocated, even in deferred destruction cases.

Here is the relevant section in the Linux commit.

References

- Original syzbot bug report
- Linux kernel fix commit
- Partial earlier fix
- CVE-2021-47024 at NVD

Always monitor kernel memory consumption in VM host environments.

CVE-2021-47024 is an example of how a seemingly small oversight (failing to clean up all buffers) can have outsize effects in a cloud or virtualization environment. Take patches seriously and stay vigilant!

Timeline

Published on: 02/28/2024 09:15:39 UTC
Last modified on: 12/06/2024 20:53:23 UTC