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