A vulnerability has been discovered and resolved in the Linux kernel related to file locking. This vulnerability, tracked as CVE-2024-41012, involves a race condition between the fcntl_setlk() function and the close() function, and affects the file locking mechanism in the kernel. The bug could lead to use-after-free reads when userspace reads /proc/locks, potentially allowing attackers to read arbitrary kernel memory, although it does not provide the ability to corrupt kernel memory.

The resolution to this vulnerability comes with the implementation of a more reliable method of removing locks, specifically by calling the locks_remove_posix() function. In this post, we will examine the details of this vulnerability, the code snippets involved in its resolution, and explore how the vulnerability could be exploited.

Original References

- Linux kernel Git commit: filelock: Remove locks reliably when fcntl/close race is detected
- Conversation on the Linux kernel mailing list: Vulnerability report

Exploit Details

The original issue stems from the way the Linux kernel handles file locks when there is a race between the fcntl_setlk() function and the close() function. The kernel uses the do_lock_file_wait() function to remove the created lock if this race occurs. However, certain conditions can lead to issues when removing locks.

Linux Security Module (LSM) could potentially allow the first do_lock_file_wait() call, while denying the second call, leading to the lock not being removed. Another issue could arise if the posix_lock_file() function fails to remove the lock due to a GFP_KERNEL allocation failure, which could occur when splitting a range in the middle.

When the bug is triggered, use-after-free reads will occur in the lock_get_status() function when userspace reads /proc/locks. While this does not allow modification of kernel memory, it does provide an opportunity for unauthorized access to the kernel memory, which could be exploited.

Code Snippet

The vulnerability can be resolved by replacing the do_lock_file_wait() function with the locks_remove_posix() function, which is designed to reliably remove POSIX locks associated with the given file and files_struct. This function is also used by the filp_flush() function.

Here is a code snippet that demonstrates the change

/* 
Before:
... 
if (unlikely(race)) {
    error = do_lock_file_wait(file, F_SETLK, &before);
    goto out_nolock;
}
... 

Change to:

After:
... 
if (unlikely(race)) {
    locks_remove_posix(file, fl);
    goto out_nolock;
}
...
*/

Conclusion

CVE-2024-41012 is a vulnerability in the Linux kernel that could allow attackers to read arbitrary kernel memory through a race condition between fcntl_setlk() and the close() function. The resolution involves replacing the previously used do_lock_file_wait() function with the locks_remove_posix() function, which offers a more reliable way of removing locks in the presence of a detected race. This fix not only resolves the vulnerability but also serves as an example of appropriate measures to ensure secure and stable operation of the kernel.

Timeline

Published on: 07/23/2024 08:15:01 UTC
Last modified on: 09/12/2024 15:28:48 UTC