CVE-2024-26991

Severity CVSS v4.0:
Pending analysis
Type:
CWE-125 Out-of-bounds Read
Publication date:
01/05/2024
Last modified:
04/11/2025

Description

In the Linux kernel, the following vulnerability has been resolved:<br /> <br /> KVM: x86/mmu: x86: Don&amp;#39;t overflow lpage_info when checking attributes<br /> <br /> Fix KVM_SET_MEMORY_ATTRIBUTES to not overflow lpage_info array and trigger<br /> KASAN splat, as seen in the private_mem_conversions_test selftest.<br /> <br /> When memory attributes are set on a GFN range, that range will have<br /> specific properties applied to the TDP. A huge page cannot be used when<br /> the attributes are inconsistent, so they are disabled for those the<br /> specific huge pages. For internal KVM reasons, huge pages are also not<br /> allowed to span adjacent memslots regardless of whether the backing memory<br /> could be mapped as huge.<br /> <br /> What GFNs support which huge page sizes is tracked by an array of arrays<br /> &amp;#39;lpage_info&amp;#39; on the memslot, of ‘kvm_lpage_info’ structs. Each index of<br /> lpage_info contains a vmalloc allocated array of these for a specific<br /> supported page size. The kvm_lpage_info denotes whether a specific huge<br /> page (GFN and page size) on the memslot is supported. These arrays include<br /> indices for unaligned head and tail huge pages.<br /> <br /> Preventing huge pages from spanning adjacent memslot is covered by<br /> incrementing the count in head and tail kvm_lpage_info when the memslot is<br /> allocated, but disallowing huge pages for memory that has mixed attributes<br /> has to be done in a more complicated way. During the<br /> KVM_SET_MEMORY_ATTRIBUTES ioctl KVM updates lpage_info for each memslot in<br /> the range that has mismatched attributes. KVM does this a memslot at a<br /> time, and marks a special bit, KVM_LPAGE_MIXED_FLAG, in the kvm_lpage_info<br /> for any huge page. This bit is essentially a permanently elevated count.<br /> So huge pages will not be mapped for the GFN at that page size if the<br /> count is elevated in either case: a huge head or tail page unaligned to<br /> the memslot or if KVM_LPAGE_MIXED_FLAG is set because it has mixed<br /> attributes.<br /> <br /> To determine whether a huge page has consistent attributes, the<br /> KVM_SET_MEMORY_ATTRIBUTES operation checks an xarray to make sure it<br /> consistently has the incoming attribute. Since level - 1 huge pages are<br /> aligned to level huge pages, it employs an optimization. As long as the<br /> level - 1 huge pages are checked first, it can just check these and assume<br /> that if each level - 1 huge page contained within the level sized huge<br /> page is not mixed, then the level size huge page is not mixed. This<br /> optimization happens in the helper hugepage_has_attrs().<br /> <br /> Unfortunately, although the kvm_lpage_info array representing page size<br /> &amp;#39;level&amp;#39; will contain an entry for an unaligned tail page of size level,<br /> the array for level - 1 will not contain an entry for each GFN at page<br /> size level. The level - 1 array will only contain an index for any<br /> unaligned region covered by level - 1 huge page size, which can be a<br /> smaller region. So this causes the optimization to overflow the level - 1<br /> kvm_lpage_info and perform a vmalloc out of bounds read.<br /> <br /> In some cases of head and tail pages where an overflow could happen,<br /> callers skip the operation completely as KVM_LPAGE_MIXED_FLAG is not<br /> required to prevent huge pages as discussed earlier. But for memslots that<br /> are smaller than the 1GB page size, it does call hugepage_has_attrs(). In<br /> this case the huge page is both the head and tail page. The issue can be<br /> observed simply by compiling the kernel with CONFIG_KASAN_VMALLOC and<br /> running the selftest “private_mem_conversions_test”, which produces the<br /> output like the following:<br /> <br /> BUG: KASAN: vmalloc-out-of-bounds in hugepage_has_attrs+0x7e/0x110<br /> Read of size 4 at addr ffffc900000a3008 by task private_mem_con/169<br /> Call Trace:<br /> dump_stack_lvl<br /> print_report<br /> ? __virt_addr_valid<br /> ? hugepage_has_attrs<br /> ? hugepage_has_attrs<br /> kasan_report<br /> ? hugepage_has_attrs<br /> hugepage_has_attrs<br /> kvm_arch_post_set_memory_attributes<br /> kvm_vm_ioctl<br /> <br /> It is a little ambiguous whether the unaligned head page (in the bug case<br /> also the tail page) should be expected to have KVM_LPAGE_MIXED_FLAG set.<br /> It is not functionally required, as the unal<br /> ---truncated---

Vulnerable products and versions

CPE From Up to
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 6.8 (including) 6.8.8 (excluding)
cpe:2.3:o:linux:linux_kernel:6.9:rc1:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.9:rc2:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.9:rc3:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.9:rc4:*:*:*:*:*:*