XSA-108

CVE-2014-7188


问题描述

http://xenbits.xen.org/xsa/advisory-108.html

Improper MSR range used for x2APIC emulation:

The MSR range specified for APIC use in the x2APIC access model spans 256 MSRs. Hypervisor code emulating read and write accesses to these MSRs erroneously covered 1024 MSRs. While the write emulation path is written such that accesses to the extra MSRs would not have any bad effect (they end up being no-ops), the read path would (attempt to) access memory beyond the single page set up for APIC emulation.

A buggy or malicious HVM guest can crash the host or read data relating to other guests or the hypervisor itself.

很容易理解,就是原来只有256个MSR,但是在hvm的emulation里面却变成了1024个。

对于MSR_write,这个没有太大问题,因为大于256个的不会有任何操作。

但是对于MSR_read,这可能会造成host crash,或者读到hypervisor或者其它虚拟机的相关数据。

这里我只有一个问题:为什么在hvm的emulation里面会把0xff写成0x3ff,难道单纯只是笔误吗???

logic error (out-of-bound read)


Patch描述

http://xenbits.xen.org/xsa/xsa108.patch

While the write path change appears to be purely cosmetic (but still gets done here for consistency), the read side istake permitted accesses beyond the virtual APIC page.

Note that while this isn’t fully in line with the specification (digesting MSRs 0x800-0xBFF for the x2APIC), this is the minimal possible fix addressing the security issue and getting x2APIC related code into a consistent shape (elsewhere a 256 rather than 1024 wide window is being used too). This will be dealt with subsequently.

Fix很简单,仅仅是在read和write之前,将MSR的寄存器数量从0x3ff改为0xff。来看read的代码:

int hvm_msr_read_intercept(unsigned int msr, uint64_t *msr_content)
{
    ....
    case MSR_IA32_APICBASE_MSR ... MSR_IA32_APICBASE_MSR + 0x3ff:
        if ( hvm_x2apic_msr_read(v, msr, msr_content) )
            goto gp_fault;
        break;
}

int hvm_x2apic_msr_read(struct vcpu *v, unsigned int msr, uint64_t *msr_content)
{
    struct vlapic *vlapic = vcpu_vlapic(v);
    uint32_t low, high = 0, offset = (msr - MSR_IA32_APICBASE_MSR) << 4;
    if ( !vlapic_x2apic_mode(vlapic) )
        return X86EMUL_UNHANDLEABLE;
    switch ( offset )
    {
    case APIC_ICR:
        vlapic_read_aligned(vlapic, APIC_ICR2, &high);
        /* Fallthrough. */
    case APIC_ID:
    case APIC_LVR:
    case APIC_TASKPRI:
    case APIC_PROCPRI:
    case APIC_LDR:
    case APIC_SPIV:
    case APIC_ISR ... APIC_ISR + 0x70:
    case APIC_TMR ... APIC_TMR + 0x70:
    case APIC_IRR ... APIC_IRR + 0x70:
    case APIC_ESR:
    case APIC_CMCI:
    case APIC_LVTT:
    case APIC_LVTTHMR:
    case APIC_LVTPC:
    case APIC_LVT0:
    case APIC_LVT1:
    case APIC_LVTERR:
    case APIC_TMICT:
    case APIC_TMCCT:
    case APIC_TDCR:
        vlapic_read_aligned(vlapic, offset, &low);
        break;
    default:
        return X86EMUL_UNHANDLEABLE;
    }
    *msr_content = (((uint64_t)high) << 32) | low;
    return X86EMUL_OKAY;
}

代码分析:在 hvmx2apicmsrread 中,offset的最大值为0xff<<4,即0xff0。case语句中,最大的APICTDCR为0x3E0,没有溢出。所以,没看出来有什么问题,这也许是为什么描述中写了attempt to的原因(猜)。

另外,patch中写道,这个fix并没有考虑到x2APIC的范围(0x800-0xBFF ),因此会在后续进一步改进。


Consequences

A buggy or malicious HVM guest can crash the host or read data relating to other guests or the hypervisor itself.

DoS, information leak