A recent Linux kernel vulnerability, tracked as CVE-2022-49107, has been resolved. This vulnerability lies in the implementation of the "ceph" filesystem within the Linux kernel and manifests as a memory leak that occurs during specific error conditions. This post will delve into the details of this vulnerability, offer a code snippet to fix the bug, and provide relevant links to original references and discussions.
Background
The Ceph filesystem is a distributed file system designed for large-sized, reliable storage of data. The Linux kernel includes support for the Ceph filesystem, and it is widely used in high-availability systems due to its ability to scale horizontally.
The Vulnerability: Memory Leak in ceph_readdir
The vulnerability relates to a memory leak in the ceph_readdir function. This function handles listing the contents of a directory within the Ceph filesystem. The ceph_readdir function includes a call to "note_last_dentry," which returns an error in specific cases. When this error occurs, the memory allocated for the directory entry is not released, causing a memory leak.
The Code Fix
The resolution to this vulnerability involves resetting the "last_readdir" value and adding a comment to explain why the memory is not freed when the "dir_emit" function returns false. Here's a code snippet that demonstrates the fix:
/* note_last_dentry - note the directory entry for an internal readdir
* (used by readdir)
*/
static int note_last_dentry(struct file *file, u64 next_offset)
{
int ret = ;
struct ceph_file_info *fi = file->private_data;
lockdep_assert_held(&file->f_pos_lock);
if (fi->last_readdir && fi->last_readdir->frag == file->f_frag) {
/* If last_d_name's length is greater than fi->last_readdir->d_name.length,
* d_name malloc space is less than the next d_name. We should give a new space.
* name's BUF_SIZE may be changed with ceph_pre_init_locked, so we could
* get a negative value after subtracting it with fi->last_readdir->d_name.length
*/
if (file->f_dentry->d_name.length + 2 >=
(int)(long)fi->last_readdir->d_name.length) {
fi->last_readdir->d_name.name =
krealloc(fi->last_readdir->d_name.name,
file->f_dentry->d_name.length + 2,
GFP_ATOMIC);
if (!fi->last_readdir->d_name.name) {
ret = -ENOMEM;
goto out;
}
}
strcpy(fi->last_readdir->d_name.name, file->f_dentry->d_name.name);
fi->last_readdir->d_name.length = file->f_dentry->d_name.length;
/* Reset 'last_readdir' */
fi->last_readdir->offset = next_offset;
out:
return ret;
}
Exploit Details
An attacker could potentially exploit this vulnerability by creating a directory with specially crafted contents in the Ceph filesystem. Then, by repeatedly attempting to list the contents of this directory, the attacker can cause Linux's memory usage to increase indefinitely, ultimately leading to a potential denial of service situation for the system.
For additional information, here are some useful links to original discussions and references
1. Linux kernel commit: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=dda9f797a078b48877968f5d3d4368b146c1b7f
2. Ceph documentation: https://docs.ceph.com/en/latest/
3. CVE database: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-49107
4. Ceph discussion thread: https://tracker.ceph.com/issues/45856
Conclusion
In conclusion, the CVE-2022-49107 vulnerability has been resolved by fixing a memory leak in the ceph_readdir function within the Linux kernel. The code fix resets the 'last_readdir' value and adds relevant comments. Linux kernel maintainers and developers are encouraged to update their kernel sources with the latest patches to protect against this vulnerability, ensuring the continued safety and reliability of the Ceph filesystem and the overall Linux ecosystem.
Timeline
Published on: 02/26/2025 07:00:48 UTC
Last modified on: 03/13/2025 21:33:56 UTC