为什么这个mov gs指令导致运行Windows 7操作系统的VMWare Workstation guest虚拟机出现故障?

c00*_*0fd 3 virtualization vmware assembly kernel windows-kernel

当我在VMWare Workstation虚拟机中运行的Windows 7 x64的内核模式下运行以下汇编序列时:

xor eax, eax
mov ax, gs
mov gs, ax     ; this instruction
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

最后一条mov gs, ax指令会立即导致该VM崩溃(或可能是错误检查),并显示以下弹出消息:

在此输入图像描述

发生故障导致虚拟CPU进入关闭状态.如果此故障发生在虚拟机之外,则会导致物理计算机重新启动.通过错误配置虚拟机,客户机操作系统中的错误或VMWare Workstation中的问题可以达到关闭状态.

重新加载gs寄存器会导致内核中的问题,还是虚拟化问题?

我没有看到mov英特尔手册中有关该指令的任何异常.

PS.顺便说一句,更换gs寄存器fs不会导致此错误.


编辑:回答有关GDT中段描述符状态的问题.这里是:

0: kd> r gs
gs=002b
0: kd> dg 28
                                                    P Si Gr Pr Lo
Sel        Base              Limit          Type    l ze an es ng Flags
---- ----------------- ----------------- ---------- - -- -- -- -- --------
0028 00000000`00000000 00000000`ffffffff Data RW Ac 3 Bg Pg P  Nl 00000cf3
Run Code Online (Sandbox Code Playgroud)

Ros*_*dge 6

我不确定为什么这一举动mov gs,ax会导致Windows立即出现三重故障,但很快就会导致它崩溃.在64位Windows内核中,GS段用作访问当前CPU的处理器控制区域(PCR)的指针.每个CPU具有指向不同PCR的不同GS基值.您的mov ax,gs mov gs,ax序列实际上打破了这个,因为它将GS基址的不正确值加载到描述符缓存中.

GDT实际上并不包含GS寄存器的正确基础.由于GDT只能保存32位地址,因此实际上并不用于加载GS基址.相反,IA32_GS_BASE和IA32_KERNEL_GS_BASE MSR(后者与SWAPGS指令组合)用于为GS段设置64位基址.存储在GS寄存器中的选择器值只是一个虚拟值.

因此,您的mov gs,ax指令会加载存储在GDT中的虚拟32位基值,而不是存储在IA32_GS_BASE中的64位值.这意味着GS段的基地址设置为0,而不是当前CPU的PCR地址.在加载这个不正确的GS库之后,Windows内核尝试使用GS寄存器访问PCR(使用类似指令mov rax, gs:[10])只是时间问题,并最终读取可能未映射的内存导致意外的内核页面错误和崩溃.

  • @ c00000fd Windows中不使用GDT中的基址,但在将描述符加载到GS(或FS)寄存器时,CPU会使用它.这就是导致问题的原因,GDT(00000000)中的基地址不正确,而不是之前GS段基址的值.您已使用相同的值重新加载GS寄存器,但这不会重新加载具有相同值的GS.base.GDT中的限制和属性被CPU忽略.我知道这是一个三重故障,因为它们导致CPU进入关机状态. (3认同)
  • @ c00000fd SWAPGS指令交换GS.base和IA32_KERNEL_GS_BASE MSR的值.也可以使用IA32_GS_BASE MSR读取和写入GS.base值,这样也可以交换这两个MSR.SWAPGS指令用于将GS设置为在进入内核时指向PCR,并将GS设置为在从内核退出时指向64位TIB/TEB. (2认同)