triple fault从字面含义理解就是三次错误(失误)。
在X86的世界里,triple-fault真的就是三振出局了,因为系统会被shut down。
通常这个错误很不容易触发,因为X86的设计者也知道“再一再二,不能再三再四”。当系统接连出现了两次fault,第三次fault就会导致系统的关机,这个是硬件的行为,软件没法干预,或者说虽然叫fault,但是没有triple-fault的出错处理的机会!
这个triple-fault一般在虚机环境里比较容易发生,通常是因为内存的问题,导致页表挂了,然后page fault再次被触发,第三次就直接把虚机shutdown了。
在虚拟化环境里面进行调试运行软件的好处在于,有hypervisor的存在,CPU的triple-fault会导致一个VMExit到host(需要正确配置VMCS),hypervisor会保留当时虚机的现场,从而便于后期做Post-mortem分析。
下面demo一下怎么故意触发triple-fault,以及在虚拟化环境下triple-fault的VMEXIT都包含哪些信息。
要在guest里面触发一个triple fault,最简单的就是在double-fault handler里面再触发一个fault就可以。
例如,在Linux内核当中进行下面的修改。
dotraplinkage void
do_general_protection(struct pt_regs *regs, long error_code)
{
struct task_struct *tsk;
printk("XXXXXXXXXXX TaoW: %s, %d\n", __func__, __LINE__);
error_code /= 0; /// TaoW: divided by 0, to trigger triple-fault
RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
conditional_sti(regs);
if (v8086_mode(regs)) {
local_irq_enable();
handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
return;
}
...
}
我自己的toyvmm hypervisor的VMEXIT里面可以得到
[237699.178169] VM-instruction error: 0 [-----]
[237699.178191] Exit Reason: 0x2 (2)
[237699.178203] Exit Qualif: 0
[237699.178219] VMexit-interruption-information: 00000000
[237699.178230] VMexit-interruption-error-code: 00000000
[237699.178241] VMexit-instruction-length: 00000001
[237699.178282] EXIT REASON: (launched = 1), 02 EXIT_REASON_TRIPLE_FAULT
[237699.178288] guest Interrupt State: 0x0
[237699.178301] guest Active State: 0x0
[237699.179084] # GUEST_RIP = 0x8a07
[237699.179097] # GUEST_RFLAGS = 0x10046
that is it, 说简单也简单。