// For flags

CVE-2024-26991

KVM: x86/mmu: x86: Don't overflow lpage_info when checking attributes

Severity Score

5.5
*CVSS v3.1

Exploit Likelihood

*EPSS

Affected Versions

*CPE

Public Exploits

0
*Multiple Sources

Exploited in Wild

-
*KEV

Decision

Track
*SSVC
Descriptions

In the Linux kernel, the following vulnerability has been resolved:

KVM: x86/mmu: x86: Don't overflow lpage_info when checking attributes

Fix KVM_SET_MEMORY_ATTRIBUTES to not overflow lpage_info array and trigger
KASAN splat, as seen in the private_mem_conversions_test selftest.

When memory attributes are set on a GFN range, that range will have
specific properties applied to the TDP. A huge page cannot be used when
the attributes are inconsistent, so they are disabled for those the
specific huge pages. For internal KVM reasons, huge pages are also not
allowed to span adjacent memslots regardless of whether the backing memory
could be mapped as huge.

What GFNs support which huge page sizes is tracked by an array of arrays
'lpage_info' on the memslot, of ‘kvm_lpage_info’ structs. Each index of
lpage_info contains a vmalloc allocated array of these for a specific
supported page size. The kvm_lpage_info denotes whether a specific huge
page (GFN and page size) on the memslot is supported. These arrays include
indices for unaligned head and tail huge pages.

Preventing huge pages from spanning adjacent memslot is covered by
incrementing the count in head and tail kvm_lpage_info when the memslot is
allocated, but disallowing huge pages for memory that has mixed attributes
has to be done in a more complicated way. During the
KVM_SET_MEMORY_ATTRIBUTES ioctl KVM updates lpage_info for each memslot in
the range that has mismatched attributes. KVM does this a memslot at a
time, and marks a special bit, KVM_LPAGE_MIXED_FLAG, in the kvm_lpage_info
for any huge page. This bit is essentially a permanently elevated count.
So huge pages will not be mapped for the GFN at that page size if the
count is elevated in either case: a huge head or tail page unaligned to
the memslot or if KVM_LPAGE_MIXED_FLAG is set because it has mixed
attributes.

To determine whether a huge page has consistent attributes, the
KVM_SET_MEMORY_ATTRIBUTES operation checks an xarray to make sure it
consistently has the incoming attribute. Since level - 1 huge pages are
aligned to level huge pages, it employs an optimization. As long as the
level - 1 huge pages are checked first, it can just check these and assume
that if each level - 1 huge page contained within the level sized huge
page is not mixed, then the level size huge page is not mixed. This
optimization happens in the helper hugepage_has_attrs().

Unfortunately, although the kvm_lpage_info array representing page size
'level' will contain an entry for an unaligned tail page of size level,
the array for level - 1 will not contain an entry for each GFN at page
size level. The level - 1 array will only contain an index for any
unaligned region covered by level - 1 huge page size, which can be a
smaller region. So this causes the optimization to overflow the level - 1
kvm_lpage_info and perform a vmalloc out of bounds read.

In some cases of head and tail pages where an overflow could happen,
callers skip the operation completely as KVM_LPAGE_MIXED_FLAG is not
required to prevent huge pages as discussed earlier. But for memslots that
are smaller than the 1GB page size, it does call hugepage_has_attrs(). In
this case the huge page is both the head and tail page. The issue can be
observed simply by compiling the kernel with CONFIG_KASAN_VMALLOC and
running the selftest “private_mem_conversions_test”, which produces the
output like the following:

BUG: KASAN: vmalloc-out-of-bounds in hugepage_has_attrs+0x7e/0x110
Read of size 4 at addr ffffc900000a3008 by task private_mem_con/169
Call Trace:
dump_stack_lvl
print_report
? __virt_addr_valid
? hugepage_has_attrs
? hugepage_has_attrs
kasan_report
? hugepage_has_attrs
hugepage_has_attrs
kvm_arch_post_set_memory_attributes
kvm_vm_ioctl

It is a little ambiguous whether the unaligned head page (in the bug case
also the tail page) should be expected to have KVM_LPAGE_MIXED_FLAG set.
It is not functionally required, as the unal
---truncated---

En el kernel de Linux, se resolvió la siguiente vulnerabilidad: KVM: x86/mmu: x86: no desborde lpage_info al verificar los atributos. Corrija KVM_SET_MEMORY_ATTRIBUTES para no desbordar la matriz lpage_info y activar KASAN splat, como se ve en la autoprueba private_mem_conversions_test. Cuando los atributos de memoria se configuran en un rango GFN, ese rango tendrá propiedades específicas aplicadas al TDP. No se puede utilizar una página enorme cuando los atributos son inconsistentes, por lo que están deshabilitados para aquellas páginas enormes específicas. Por razones internas de KVM, tampoco se permite que páginas grandes abarquen ranuras de memoria adyacentes, independientemente de si la memoria de respaldo podría asignarse como enorme. Qué GFN admite qué tamaños de página enormes se rastrea mediante una serie de matrices 'lpage_info' en el memslot, de estructuras 'kvm_lpage_info'. Cada índice de lpage_info contiene una matriz asignada por vmalloc para un tamaño de página compatible específico. kvm_lpage_info indica si se admite una página enorme específica (GFN y tamaño de página) en la ranura de memoria. Estas matrices incluyen índices para páginas grandes de cabecera y cola no alineadas. Para evitar que páginas grandes abarquen ranuras de memoria adyacentes, se incrementa el recuento en head y tail kvm_lpage_info cuando se asigna la ranura de memoria, pero no permitir páginas grandes para memoria que tenga atributos mixtos debe hacerse de una manera más complicada. Durante KVM_SET_MEMORY_ATTRIBUTES ioctl, KVM actualiza lpage_info para cada ranura de memoria en el rango que tiene atributos que no coinciden. KVM hace esto una ranura de memoria a la vez y marca un bit especial, KVM_LPAGE_MIXED_FLAG, en kvm_lpage_info para cualquier página grande. Este bit es esencialmente un recuento elevado permanentemente. Por lo tanto, las páginas grandes no se asignarán para GFN en ese tamaño de página si el recuento es elevado en cualquier caso: una página principal o final enorme no alineada con la ranura de memoria o si KVM_LPAGE_MIXED_FLAG está configurado porque tiene atributos mixtos. Para determinar si una página enorme tiene atributos consistentes, la operación KVM_SET_MEMORY_ATTRIBUTES verifica una matriz x para asegurarse de que tenga consistentemente el atributo entrante. Dado que las páginas grandes de nivel 1 están alineadas con las páginas grandes de nivel, se emplea una optimización. Siempre que se verifiquen primero las páginas grandes de nivel - 1, puede simplemente verificarlas y asumir que si cada página enorme de nivel - 1 contenida dentro de la página enorme de tamaño de nivel no está mezclada, entonces la página enorme de tamaño de nivel no está mezclada. Esta optimización ocurre en el ayudante Hugepage_has_attrs(). Desafortunadamente, aunque la matriz kvm_lpage_info que representa el tamaño de página 'nivel' contendrá una entrada para una página final no alineada de nivel de tamaño, la matriz para el nivel - 1 no contendrá una entrada para cada GFN en el nivel de tamaño de página. La matriz de nivel 1 solo contendrá un índice para cualquier región no alineada cubierta por el tamaño de página enorme de nivel 1, que puede ser una región más pequeña. Entonces, esto hace que la optimización desborde el nivel - 1 kvm_lpage_info y realice una lectura vmalloc fuera de los límites. En algunos casos de páginas principales y finales donde podría ocurrir un desbordamiento, las personas que llaman omiten la operación por completo ya que KVM_LPAGE_MIXED_FLAG no es necesario para evitar páginas grandes como se analizó anteriormente. Pero para las ranuras de memoria que son más pequeñas que el tamaño de página de 1 GB, llama a hugepage_has_attrs(). En este caso, la página enorme es tanto la página principal como la final. --truncado---

A flaw was found in the Linux Kernel. A lpage_info overflow can occur when checking attributes. This may lead to a crash.

*Credits: N/A
CVSS Scores
Attack Vector
Local
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
None
Availability
High
* Common Vulnerability Scoring System
SSVC
  • Decision:Track
Exploitation
None
Automatable
No
Tech. Impact
Partial
* Organization's Worst-case Scenario
Timeline
  • 2024-02-19 CVE Reserved
  • 2024-05-01 CVE Published
  • 2024-05-13 EPSS Updated
  • 2024-08-02 CVE Updated
  • ---------- Exploited in Wild
  • ---------- KEV Due Date
  • ---------- First Exploit
CWE
CAPEC
Affected Vendors, Products, and Versions
Vendor Product Version Other Status
Vendor Product Version Other Status <-- --> Vendor Product Version Other Status
Linux
Search vendor "Linux"
Linux Kernel
Search vendor "Linux" for product "Linux Kernel"
>= 6.8 < 6.8.8
Search vendor "Linux" for product "Linux Kernel" and version " >= 6.8 < 6.8.8"
en
Affected
Linux
Search vendor "Linux"
Linux Kernel
Search vendor "Linux" for product "Linux Kernel"
>= 6.8 < 6.9
Search vendor "Linux" for product "Linux Kernel" and version " >= 6.8 < 6.9"
en
Affected