A recent vulnerability was discovered in the Linux kernel, resulting in a use-after-free issue in the uio_open function. This article will provide an in-depth look at the vulnerability, the code snippet containing the problem, original references, and the exploit details.

Vulnerability Overview

A use-after-free vulnerability was found within the Linux kernel, specifically in the uio functions, which allow userspace programs to access kernel hardware in an abstracted, device-independent manner. The vulnerability was introduced in the synchronization between core-1 and core-2 processes, leading to a situation where the memory allocated for idev (device_handle for uio device) is incorrectly freed or accessed after it has already been freed. The affected functions are:

Original References

This vulnerability was reported as CVE-2023-52439 in the Linux kernel. The Linux kernel commit message can be found here.

Exploit Details

In the core-1 uio_unregister_device(), the device_unregister will kfree idev when the idev->dev kobject reference count is 1. However, between the core-1 device_unregister and put_device calls, and before the kfree, core-2 may acquire a reference to the device using get_device. This can lead to two issues:

1. After core-1 kfree idev, core-2 will attempt to use the freed memory of idev, resulting in a use-after-free vulnerability.
2. When core-2 calls uio_release and put_device, the idev will be freed again, leading to a double-free error.

Here is the code snippet detailing the issue

core-1                          core-2
uio_unregister_device          uio_open
                               idev = idr_find()
device_unregister(&idev->dev)
put_device(&idev->dev)
uio_device_release
                               get_device(&idev->dev)
kfree(idev)
uio_free_minor(minor)
                               uio_release
                               put_device(&idev->dev)
                               kfree(idev)

Resolution

To address this issue, a patch was proposed that changes how the idev reference is acquired and released. With this patch, when getting the idev, the code first acquires the minor_lock, then atomically increments the idev reference count. This ensures that the reference count is not modified by any other cores during the get_device/put_device process.

idev = uio_idr_find(minor);
if (idev) {
    spin_lock(&minor_lock);
    if (!kref_get_unless_zero(&idev->ref)) {
        spin_unlock(&minor_lock);
        return -ENODEV;
    }
    spin_unlock(&minor_lock);
}

By applying this patch, the use-after-free and double-free issues are resolved, and the uio_open and uio_unregister_device functions can work as expected, eliminating the CVE-2023-52439 vulnerability.

Timeline

Published on: 02/20/2024 21:15:08 UTC
Last modified on: 03/15/2024 14:21:10 UTC