Dear all, we discovered a bug in hvm64 x86 Xen. Using the attached xtf test we are able to trigger an assert in arch/x86/hvm/emulate.c:
if ( (hvmemul_ctxt->ctxt.regs->eflags & X86_EFLAGS_DF) && (reps > 1) ) { /* * x86_emulate() clips the repetition count to ensure we don't wrap * the effective-address index register. Hence this assertion holds. */ ASSERT(offset >= ((reps - 1) * bytes_per_rep)); okay = hvm_virtual_to_linear_addr( seg, reg, offset - (reps - 1) * bytes_per_rep, reps * bytes_per_rep, access_type, hvmemul_get_seg_reg(x86_seg_cs, hvmemul_ctxt), linear); *linear += (reps - 1) * bytes_per_rep; if ( hvmemul_ctxt->ctxt.addr_size != 64 ) *linear = (uint32_t)*linear; } If debug mode is not enabled, this will later on result in an integer underflow, however we were not able to find any severe problems. The test below will not work with vanilla xtf. To get it working, we have to edit 'pae_l1_identmap' in arch/x86/hvm/pagetables.S in xtf from PAGETABLE_START(pae_l1_identmap) .long 0, 0 .rept PAE_L1_PT_ENTRIES - 1 .long (PAE_IDX(pae_l1_identmap) << PAE_L1_PT_SHIFT) + _PAGE_LEAF .long 0 .endr PAGETABLE_END(pae_l1_identmap) to the following value: PAGETABLE_START(pae_l1_identmap) .quad (0x5564000000) + _PAGE_LEAF .rept PAE_L1_PT_ENTRIES - 1 .long (PAE_IDX(pae_l1_identmap) << PAE_L1_PT_SHIFT) + _PAGE_LEAF .long 0 .endr PAGETABLE_END(pae_l1_identmap) We were able to reproduce this bug in several versions including the most current one at the time of writing this. Best, Fabian
/** * @file tests/poc/main.c * @ref test-poc * * @page test-poc poc * * @todo Docs for test-poc * * @see tests/poc/main.c */ #include <xtf.h> const char test_title[] = "Test poc"; void test_main(void) { printk("Starting up reps offset assert poc!\n"); asm volatile ( "mov $0xd000f8, %%eax;" "mov $0x0, %%rdi;" "mov $0x1900000000000000, %%rcx;" "std;" "rep stos %%eax, %%es:(%%rdi);" ::: "memory", "cc", "rax", "rdi", "rcx" ); printk("Unreachable with enabled debug asserts!\n"); xtf_success(NULL); xtf_success(NULL); } /* * Local variables: * mode: C * c-file-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */