Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kvmi-v6: Context emulation is specific to memory events #33

Open
Wenzel opened this issue Apr 7, 2020 · 1 comment
Open

kvmi-v6: Context emulation is specific to memory events #33

Wenzel opened this issue Apr 7, 2020 · 1 comment

Comments

@Wenzel
Copy link
Member

Wenzel commented Apr 7, 2020

In the KVMi-v6 API, the ability to emulate new data or new instructions is tied to the reply of a memory event:

struct kvmi_event_pf_reply {

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.

@adlazar
Copy link
Collaborator

adlazar commented Apr 8, 2020

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants