kvm icon indicating copy to clipboard operation
kvm copied to clipboard

kvmi-v6: Context emulation is specific to memory events

Open Wenzel opened this issue 5 years ago • 1 comments

In the KVMi-v6 API, the ability to emulate new data or new instructions is tied to the reply of a memory event: https://github.com/KVM-VMI/kvm/blob/5205f803008a2ee5788ba0a9cc7a475a546889ba/include/uapi/linux/kvmi.h#L251

struct kvmi_event_pf_reply {
	__u64 ctx_addr;
	__u32 ctx_size;
	__u8 singlestep;
	__u8 rep_complete;
	__u16 padding;
	__u8 ctx_data[256];
};

It might be beneficial to have the same fields in a breakpoint response too. In fact, upon a breakpoint event, you can do a couple of things:

  1. recoiling
  • replace the original instruction
  • trigger singlestep
  • replace breakpoint
  1. emulate the original instruction in breakpoint even handler (a.k.a RIP++), but this is not very reliable, unless you can embed a decompiler and can implement a specific behavior for each instruction.

  2. configure the original instruction to be emulated, via the breakpoint event response. In LibVMI, this behavior is already implemented in breakpoint-emulate-example.c: https://github.com/libvmi/libvmi/blob/master/examples/breakpoint-emulate-example.c#L87


    if (data->vaddr == event->interrupt_event.gla) {
        // our breakpoint !
        printf("We hit our breakpoint on %s, setting emulation buffer to 0x%"PRIx64"\n",
               data->symbol, *(uint64_t*)data->emul.data);
        // don't reinject
        event->interrupt_event.reinject = 0;
        // set previous opcode for emulation
        event->emul_insn = &data->emul;
        // set response to emulate instruction
        rsp |= VMI_EVENT_RESPONSE_SET_EMUL_INSN;
    }

Amond the benefits of simplifying recoiling on a breakpoint (which is tedius since you need to handle one event handler for the interrupt, and a second for the singlestep event), this solution has the advantage of being race-condition free in a multi-VCPU context.

Also, on a side note, this makes it more difficult to implement VMI_EVENT_RESPONSE_SET_EMUL_READ_DATA and VMI_EVENT_RESPONSE_SET_EMUL_INSN, as for kvmi-v6, they should be specific to a kvmi_event_pf.

So this type of generic process_cb_response() is not possible: https://github.com/libvmi/libvmi/blob/master/libvmi/driver/xen/xen_events.c#L604

On Xen, I'm not sure, but LibVMI has an internal structure, with emulation context available for all events: https://github.com/libvmi/libvmi/blob/master/libvmi/driver/xen/xen_events_private.h#L97

typedef struct vm_event_compat {
    uint32_t version;
    uint32_t flags;
    uint32_t reason;
    uint32_t vcpu_id;
    uint16_t altp2m_idx;

    union {
        struct vm_event_mem_access            mem_access;
        struct vm_event_write_ctrlreg         write_ctrlreg;
        struct vm_event_mov_to_msr_3          mov_to_msr;
        struct vm_event_desc_access_3         desc_access;
        struct vm_event_singlestep            singlestep;
        struct vm_event_debug_6               software_breakpoint;
        struct vm_event_debug_6               debug_exception;
        struct vm_event_cpuid                 cpuid;
        struct vm_event_interrupt_x86         x86_interrupt;
    };

    union {
        union {
            x86_registers_t x86;
            arm_registers_t arm;
        } regs;

        union {
            struct vm_event_emul_read_data_4 read;
            struct vm_event_emul_insn_data insn;
        } emul;
    } data;
} vm_event_compat_t;

@tklengyel , can you tell us if an emulation context is theoretically available for all VM events on Xen ?

Thanks.

Wenzel avatar Apr 07 '20 13:04 Wenzel

It looks like read data is used for mem access and descriptor access events, while insn data for breakpoint events - https://github.com/hisilicon/Xen/blob/36e29dd9e580cb0f847f5ac1e72afdb5febe3e99/xen/arch/x86/vm_event.c#L184

adlazar avatar Apr 08 '20 23:04 adlazar