cve-2024-26991
Vulnerability from cvelistv5
Published
2024-05-01 05:27
Modified
2024-08-02 00:21
Severity
Summary
KVM: x86/mmu: x86: Don't overflow lpage_info when checking attributes
Impacted products
VendorProduct
LinuxLinux
LinuxLinux
Show details on NVD website


{
  "containers": {
    "adp": [
      {
        "metrics": [
          {
            "other": {
              "content": {
                "id": "CVE-2024-26991",
                "options": [
                  {
                    "Exploitation": "none"
                  },
                  {
                    "Automatable": "no"
                  },
                  {
                    "Technical Impact": "partial"
                  }
                ],
                "role": "CISA Coordinator",
                "timestamp": "2024-06-06T18:48:18.659568Z",
                "version": "2.0.3"
              },
              "type": "ssvc"
            }
          }
        ],
        "providerMetadata": {
          "dateUpdated": "2024-06-06T18:48:36.875Z",
          "orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
          "shortName": "CISA-ADP"
        },
        "title": "CISA ADP Vulnrichment"
      },
      {
        "providerMetadata": {
          "dateUpdated": "2024-08-02T00:21:05.801Z",
          "orgId": "af854a3a-2127-422b-91ae-364da2661108",
          "shortName": "CVE"
        },
        "references": [
          {
            "tags": [
              "x_transferred"
            ],
            "url": "https://git.kernel.org/stable/c/048cc4a028e635d339687ed968985d2d1669494c"
          },
          {
            "tags": [
              "x_transferred"
            ],
            "url": "https://git.kernel.org/stable/c/992b54bd083c5bee24ff7cc35991388ab08598c4"
          }
        ],
        "title": "CVE Program Container"
      }
    ],
    "cna": {
      "affected": [
        {
          "defaultStatus": "unaffected",
          "product": "Linux",
          "programFiles": [
            "arch/x86/kvm/mmu/mmu.c"
          ],
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "vendor": "Linux",
          "versions": [
            {
              "lessThan": "048cc4a028e6",
              "status": "affected",
              "version": "90b4fe17981e",
              "versionType": "git"
            },
            {
              "lessThan": "992b54bd083c",
              "status": "affected",
              "version": "90b4fe17981e",
              "versionType": "git"
            }
          ]
        },
        {
          "defaultStatus": "affected",
          "product": "Linux",
          "programFiles": [
            "arch/x86/kvm/mmu/mmu.c"
          ],
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "vendor": "Linux",
          "versions": [
            {
              "status": "affected",
              "version": "6.8"
            },
            {
              "lessThan": "6.8",
              "status": "unaffected",
              "version": "0",
              "versionType": "custom"
            },
            {
              "lessThanOrEqual": "6.8.*",
              "status": "unaffected",
              "version": "6.8.8",
              "versionType": "custom"
            },
            {
              "lessThanOrEqual": "*",
              "status": "unaffected",
              "version": "6.9",
              "versionType": "original_commit_for_fix"
            }
          ]
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "In the Linux kernel, the following vulnerability has been resolved:\n\nKVM: x86/mmu: x86: Don\u0027t overflow lpage_info when checking attributes\n\nFix KVM_SET_MEMORY_ATTRIBUTES to not overflow lpage_info array and trigger\nKASAN splat, as seen in the private_mem_conversions_test selftest.\n\nWhen memory attributes are set on a GFN range, that range will have\nspecific properties applied to the TDP. A huge page cannot be used when\nthe attributes are inconsistent, so they are disabled for those the\nspecific huge pages. For internal KVM reasons, huge pages are also not\nallowed to span adjacent memslots regardless of whether the backing memory\ncould be mapped as huge.\n\nWhat GFNs support which huge page sizes is tracked by an array of arrays\n\u0027lpage_info\u0027 on the memslot, of \u2018kvm_lpage_info\u2019 structs. Each index of\nlpage_info contains a vmalloc allocated array of these for a specific\nsupported page size. The kvm_lpage_info denotes whether a specific huge\npage (GFN and page size) on the memslot is supported. These arrays include\nindices for unaligned head and tail huge pages.\n\nPreventing huge pages from spanning adjacent memslot is covered by\nincrementing the count in head and tail kvm_lpage_info when the memslot is\nallocated, but disallowing huge pages for memory that has mixed attributes\nhas to be done in a more complicated way. During the\nKVM_SET_MEMORY_ATTRIBUTES ioctl KVM updates lpage_info for each memslot in\nthe range that has mismatched attributes. KVM does this a memslot at a\ntime, and marks a special bit, KVM_LPAGE_MIXED_FLAG, in the kvm_lpage_info\nfor any huge page. This bit is essentially a permanently elevated count.\nSo huge pages will not be mapped for the GFN at that page size if the\ncount is elevated in either case: a huge head or tail page unaligned to\nthe memslot or if KVM_LPAGE_MIXED_FLAG is set because it has mixed\nattributes.\n\nTo determine whether a huge page has consistent attributes, the\nKVM_SET_MEMORY_ATTRIBUTES operation checks an xarray to make sure it\nconsistently has the incoming attribute. Since level - 1 huge pages are\naligned to level huge pages, it employs an optimization. As long as the\nlevel - 1 huge pages are checked first, it can just check these and assume\nthat if each level - 1 huge page contained within the level sized huge\npage is not mixed, then the level size huge page is not mixed. This\noptimization happens in the helper hugepage_has_attrs().\n\nUnfortunately, although the kvm_lpage_info array representing page size\n\u0027level\u0027 will contain an entry for an unaligned tail page of size level,\nthe array for level - 1  will not contain an entry for each GFN at page\nsize level. The level - 1 array will only contain an index for any\nunaligned region covered by level - 1 huge page size, which can be a\nsmaller region. So this causes the optimization to overflow the level - 1\nkvm_lpage_info and perform a vmalloc out of bounds read.\n\nIn some cases of head and tail pages where an overflow could happen,\ncallers skip the operation completely as KVM_LPAGE_MIXED_FLAG is not\nrequired to prevent huge pages as discussed earlier. But for memslots that\nare smaller than the 1GB page size, it does call hugepage_has_attrs(). In\nthis case the huge page is both the head and tail page. The issue can be\nobserved simply by compiling the kernel with CONFIG_KASAN_VMALLOC and\nrunning the selftest \u201cprivate_mem_conversions_test\u201d, which produces the\noutput like the following:\n\nBUG: KASAN: vmalloc-out-of-bounds in hugepage_has_attrs+0x7e/0x110\nRead of size 4 at addr ffffc900000a3008 by task private_mem_con/169\nCall Trace:\n  dump_stack_lvl\n  print_report\n  ? __virt_addr_valid\n  ? hugepage_has_attrs\n  ? hugepage_has_attrs\n  kasan_report\n  ? hugepage_has_attrs\n  hugepage_has_attrs\n  kvm_arch_post_set_memory_attributes\n  kvm_vm_ioctl\n\nIt is a little ambiguous whether the unaligned head page (in the bug case\nalso the tail page) should be expected to have KVM_LPAGE_MIXED_FLAG set.\nIt is not functionally required, as the unal\n---truncated---"
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2024-05-29T05:26:33.536Z",
        "orgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
        "shortName": "Linux"
      },
      "references": [
        {
          "url": "https://git.kernel.org/stable/c/048cc4a028e635d339687ed968985d2d1669494c"
        },
        {
          "url": "https://git.kernel.org/stable/c/992b54bd083c5bee24ff7cc35991388ab08598c4"
        }
      ],
      "title": "KVM: x86/mmu: x86: Don\u0027t overflow lpage_info when checking attributes",
      "x_generator": {
        "engine": "bippy-a5840b7849dd"
      }
    }
  },
  "cveMetadata": {
    "assignerOrgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
    "assignerShortName": "Linux",
    "cveId": "CVE-2024-26991",
    "datePublished": "2024-05-01T05:27:53.427Z",
    "dateReserved": "2024-02-19T14:20:24.205Z",
    "dateUpdated": "2024-08-02T00:21:05.801Z",
    "state": "PUBLISHED"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.1",
  "meta": {
    "nvd": "{\"cve\":{\"id\":\"CVE-2024-26991\",\"sourceIdentifier\":\"416baaa9-dc9f-4396-8d5f-8c081fb06d67\",\"published\":\"2024-05-01T06:15:16.820\",\"lastModified\":\"2024-05-13T08:15:11.137\",\"vulnStatus\":\"Awaiting Analysis\",\"descriptions\":[{\"lang\":\"en\",\"value\":\"In the Linux kernel, the following vulnerability has been resolved:\\n\\nKVM: x86/mmu: x86: Don\u0027t overflow lpage_info when checking attributes\\n\\nFix KVM_SET_MEMORY_ATTRIBUTES to not overflow lpage_info array and trigger\\nKASAN splat, as seen in the private_mem_conversions_test selftest.\\n\\nWhen memory attributes are set on a GFN range, that range will have\\nspecific properties applied to the TDP. A huge page cannot be used when\\nthe attributes are inconsistent, so they are disabled for those the\\nspecific huge pages. For internal KVM reasons, huge pages are also not\\nallowed to span adjacent memslots regardless of whether the backing memory\\ncould be mapped as huge.\\n\\nWhat GFNs support which huge page sizes is tracked by an array of arrays\\n\u0027lpage_info\u0027 on the memslot, of \u2018kvm_lpage_info\u2019 structs. Each index of\\nlpage_info contains a vmalloc allocated array of these for a specific\\nsupported page size. The kvm_lpage_info denotes whether a specific huge\\npage (GFN and page size) on the memslot is supported. These arrays include\\nindices for unaligned head and tail huge pages.\\n\\nPreventing huge pages from spanning adjacent memslot is covered by\\nincrementing the count in head and tail kvm_lpage_info when the memslot is\\nallocated, but disallowing huge pages for memory that has mixed attributes\\nhas to be done in a more complicated way. During the\\nKVM_SET_MEMORY_ATTRIBUTES ioctl KVM updates lpage_info for each memslot in\\nthe range that has mismatched attributes. KVM does this a memslot at a\\ntime, and marks a special bit, KVM_LPAGE_MIXED_FLAG, in the kvm_lpage_info\\nfor any huge page. This bit is essentially a permanently elevated count.\\nSo huge pages will not be mapped for the GFN at that page size if the\\ncount is elevated in either case: a huge head or tail page unaligned to\\nthe memslot or if KVM_LPAGE_MIXED_FLAG is set because it has mixed\\nattributes.\\n\\nTo determine whether a huge page has consistent attributes, the\\nKVM_SET_MEMORY_ATTRIBUTES operation checks an xarray to make sure it\\nconsistently has the incoming attribute. Since level - 1 huge pages are\\naligned to level huge pages, it employs an optimization. As long as the\\nlevel - 1 huge pages are checked first, it can just check these and assume\\nthat if each level - 1 huge page contained within the level sized huge\\npage is not mixed, then the level size huge page is not mixed. This\\noptimization happens in the helper hugepage_has_attrs().\\n\\nUnfortunately, although the kvm_lpage_info array representing page size\\n\u0027level\u0027 will contain an entry for an unaligned tail page of size level,\\nthe array for level - 1  will not contain an entry for each GFN at page\\nsize level. The level - 1 array will only contain an index for any\\nunaligned region covered by level - 1 huge page size, which can be a\\nsmaller region. So this causes the optimization to overflow the level - 1\\nkvm_lpage_info and perform a vmalloc out of bounds read.\\n\\nIn some cases of head and tail pages where an overflow could happen,\\ncallers skip the operation completely as KVM_LPAGE_MIXED_FLAG is not\\nrequired to prevent huge pages as discussed earlier. But for memslots that\\nare smaller than the 1GB page size, it does call hugepage_has_attrs(). In\\nthis case the huge page is both the head and tail page. The issue can be\\nobserved simply by compiling the kernel with CONFIG_KASAN_VMALLOC and\\nrunning the selftest \u201cprivate_mem_conversions_test\u201d, which produces the\\noutput like the following:\\n\\nBUG: KASAN: vmalloc-out-of-bounds in hugepage_has_attrs+0x7e/0x110\\nRead of size 4 at addr ffffc900000a3008 by task private_mem_con/169\\nCall Trace:\\n  dump_stack_lvl\\n  print_report\\n  ? __virt_addr_valid\\n  ? hugepage_has_attrs\\n  ? hugepage_has_attrs\\n  kasan_report\\n  ? hugepage_has_attrs\\n  hugepage_has_attrs\\n  kvm_arch_post_set_memory_attributes\\n  kvm_vm_ioctl\\n\\nIt is a little ambiguous whether the unaligned head page (in the bug case\\nalso the tail page) should be expected to have KVM_LPAGE_MIXED_FLAG set.\\nIt is not functionally required, as the unal\\n---truncated---\"},{\"lang\":\"es\",\"value\":\"En el kernel de Linux, se resolvi\u00f3 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\u00e1 propiedades espec\u00edficas aplicadas al TDP. No se puede utilizar una p\u00e1gina enorme cuando los atributos son inconsistentes, por lo que est\u00e1n deshabilitados para aquellas p\u00e1ginas enormes espec\u00edficas. Por razones internas de KVM, tampoco se permite que p\u00e1ginas grandes abarquen ranuras de memoria adyacentes, independientemente de si la memoria de respaldo podr\u00eda asignarse como enorme. Qu\u00e9 GFN admite qu\u00e9 tama\u00f1os de p\u00e1gina enormes se rastrea mediante una serie de matrices \u0027lpage_info\u0027 en el memslot, de estructuras \u0027kvm_lpage_info\u0027. Cada \u00edndice de lpage_info contiene una matriz asignada por vmalloc para un tama\u00f1o de p\u00e1gina compatible espec\u00edfico. kvm_lpage_info indica si se admite una p\u00e1gina enorme espec\u00edfica (GFN y tama\u00f1o de p\u00e1gina) en la ranura de memoria. Estas matrices incluyen \u00edndices para p\u00e1ginas grandes de cabecera y cola no alineadas. Para evitar que p\u00e1ginas 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\u00e1ginas grandes para memoria que tenga atributos mixtos debe hacerse de una manera m\u00e1s 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\u00e1gina grande. Este bit es esencialmente un recuento elevado permanentemente. Por lo tanto, las p\u00e1ginas grandes no se asignar\u00e1n para GFN en ese tama\u00f1o de p\u00e1gina si el recuento es elevado en cualquier caso: una p\u00e1gina principal o final enorme no alineada con la ranura de memoria o si KVM_LPAGE_MIXED_FLAG est\u00e1 configurado porque tiene atributos mixtos. Para determinar si una p\u00e1gina enorme tiene atributos consistentes, la operaci\u00f3n KVM_SET_MEMORY_ATTRIBUTES verifica una matriz x para asegurarse de que tenga consistentemente el atributo entrante. Dado que las p\u00e1ginas grandes de nivel 1 est\u00e1n alineadas con las p\u00e1ginas grandes de nivel, se emplea una optimizaci\u00f3n. Siempre que se verifiquen primero las p\u00e1ginas grandes de nivel - 1, puede simplemente verificarlas y asumir que si cada p\u00e1gina enorme de nivel - 1 contenida dentro de la p\u00e1gina enorme de tama\u00f1o de nivel no est\u00e1 mezclada, entonces la p\u00e1gina enorme de tama\u00f1o de nivel no est\u00e1 mezclada. Esta optimizaci\u00f3n ocurre en el ayudante Hugepage_has_attrs(). Desafortunadamente, aunque la matriz kvm_lpage_info que representa el tama\u00f1o de p\u00e1gina \u0027nivel\u0027 contendr\u00e1 una entrada para una p\u00e1gina final no alineada de nivel de tama\u00f1o, la matriz para el nivel - 1 no contendr\u00e1 una entrada para cada GFN en el nivel de tama\u00f1o de p\u00e1gina. La matriz de nivel 1 solo contendr\u00e1 un \u00edndice para cualquier regi\u00f3n no alineada cubierta por el tama\u00f1o de p\u00e1gina enorme de nivel 1, que puede ser una regi\u00f3n m\u00e1s peque\u00f1a. Entonces, esto hace que la optimizaci\u00f3n desborde el nivel - 1 kvm_lpage_info y realice una lectura vmalloc fuera de los l\u00edmites. En algunos casos de p\u00e1ginas principales y finales donde podr\u00eda ocurrir un desbordamiento, las personas que llaman omiten la operaci\u00f3n por completo ya que KVM_LPAGE_MIXED_FLAG no es necesario para evitar p\u00e1ginas grandes como se analiz\u00f3 anteriormente. Pero para las ranuras de memoria que son m\u00e1s peque\u00f1as que el tama\u00f1o de p\u00e1gina de 1 GB, llama a hugepage_has_attrs(). En este caso, la p\u00e1gina enorme es tanto la p\u00e1gina principal como la final. --truncado---\"}],\"metrics\":{},\"references\":[{\"url\":\"https://git.kernel.org/stable/c/048cc4a028e635d339687ed968985d2d1669494c\",\"source\":\"416baaa9-dc9f-4396-8d5f-8c081fb06d67\"},{\"url\":\"https://git.kernel.org/stable/c/992b54bd083c5bee24ff7cc35991388ab08598c4\",\"source\":\"416baaa9-dc9f-4396-8d5f-8c081fb06d67\"}]}}"
  }
}


Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading...

Loading...