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

Add basic KVMI event support for CR/MSR/interrupt/mem_access (v5) #9

Merged
merged 50 commits into from
Oct 7, 2019

Conversation

mtarral
Copy link
Collaborator

@mtarral mtarral commented Aug 28, 2019

Hi,

this PR adds basic event support for

  • CR
  • MSR
  • memory
  • interrupt (int 3)

Implementation

Details

  • no event response logic is implemented ATM, simply reply to continue execution

  • kvm_set_reg_access

    • handles CR0/CR3/CR4
    • handles MSR_ANY, where the MSR index is specified in reg_event.msr field
    • handles MSR_ALL by looping over all MSRs in Libvmi MSR index msr_all
    • CR0/CR3/CR4 kvmi equivalent reg values are hardcoded
    • VMI_REGACCESS_R and VMI_REGACCESS_RW not supported (?)
    • doesn't support MSR_HYPERVISOR: 0x40000000
    • on failure (a call to a VCPU failed, goto error_exit), it disables everything, but without checking the return value. (any ideas how to improve that ?)
  • msr-event-example

    • modified to accept kvmi socket path (optional)
    • modified to init libvmi without os config, so can be init when OS boots, and intercept MSR being setup
  • kvm_set_intr_access

    • simply call kvmi_control_events for every VCPU, enabling breakpint, or disabling everything
  • kvm_set_mem_access

    • declares a static variable, and checks it to enable KVMI_EVENT_PF_FLAG on the first call, if necessary, this avoids to enable them at kvm_init_vmi, even though the app might never use them. What do you think ?
    • assumes VMI_MEMACCESS_N and VMI_MEMACCESS_RWX are the same (is it though ?)
    • hardcoded 12 shift to get a gpa from a gfn
    • again, per VCPU events and page config makes it difficult for error handling
  • kvm_events_listen

    • wait next event
    • pop from event queue
    • checks if event reason makes sense
    • call the handler if defined

For all events i'm assigning a pointer to a x86_regs struct from the stack,
and call fill_ev_common_kvmi_to_libvmi to fill the regs.

-> Any suggestions of how this should be done ?

  • process_register
    not handled because it doesn't work for CR3 when i tested :-)

  • process_msr

    • TODO: fill reg_event
      • out_access
  • process_interrupt

    • hardcoded page shift 12
    • TODO: fill interrupt_event
      • vector
      • type
      • Should we set the insn_length here ?
      • What are INT_NEXT interrupts ?
  • process_pagefault

    • hardcoded page shift 12
    • TODO: fill mem_event
      • valid
      • gptw
  • process_pause_event

    • we should never reach this code, since kvm_resume_vm should pop this type of event
    • print and error and return a failure
  • kvm_init_vmi

    • set event handlers if VMI_INIT_EVENTS

Notes

  • msr-index.h has been moved from libvmi/driver/xen/ to libvmi
  • add enum to string msr_to_str array
  • activating the same event/flag for every VCPU can be a bit cumbersome sometimes, and makes error handling more tricky in my opinion.
  • sorry for this big PR, I wanted to makes multiples PR for every feature, but I ended up building static functions and helpers, so I had to stack them up.

Issues

  • catching CR3 doesn't work as I expected (at context switch) (fix in Kvmi v6 kvm#21)
  • catching MSR_HYPERVISOR 0x40000000 is not supported by the API

Future

Fixes

  • use a global event_flags for all VCPU, to store the old state and avoid erasing it

V6

Rebase on #8

cc @mdontu, @adlazar, @tklengyel

Thanks.

libvmi/events.c Outdated
@@ -94,6 +94,8 @@ void step_event_free(vmi_event_t *event, status_t rc)
status_t events_init(vmi_instance_t vmi)
{
switch (vmi->mode) {
case VMI_KVM:
// intentional fall-through

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why fall-through instead of break?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch, it's a mistake.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

if (event->reg != MSR_ALL) {
// enable event monitoring for all vcpus
for (unsigned int i = 0; i < vmi->num_vcpus; i++) {
if (kvmi_control_events(kvm->kvmi_dom, i, event_flags)) {
Copy link
Collaborator Author

@mtarral mtarral Aug 30, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adlazar: does enabling the interception of KVMi events, without generating this type of events, has a slight performance impact, or close to none ?

The idea is that I would like to move enabling/disabling event interception at driver init, so I could enable all of them at once, and disable them at teardown.

Otherwise, with the current implementation, we have to keep track of what reg_access has been enabled for example, or the following use case won't work:

  • enable an event to intercept CR3
  • enable an event to intercept CR0
  • disable CR0 event -> CR3 is disabled too because KVMI_EVENT_CR(_FLAG) has been disabled

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For MSR and CR events, you can enable them with kvmi_control_events() without worrying about the the performance impact, because the interception does something when you enable a specific MSR/CR (kvmi_control_msr/kvmi_control_cr).

But, if you enable KVMI_EVENT_BREAKPOINT and KVMI_EVENT_DESCRIPTOR, you might get a lot of events when the guest starts. For the second one we might filter out the read events in the future (intercepting only the write accesses).

Copy link
Collaborator Author

@mtarral mtarral left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General questions I have regarding the implementation


#include "libvmi.h"

extern const reg_t msr_all[];
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tklengyel I also wanted your review about moving msr-index out of the Xen driver, to be used by KVM as well.
I had to declare the arrays as extern to use them multiple times in the code, and give them an implementation in libvmi/msr-index.c

}

static status_t
process_msr(vmi_instance_t vmi, struct kvmi_dom_event *kvmi_event)
Copy link
Collaborator Author

@mtarral mtarral Aug 30, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tklengyel a naïve implementation of event handlers that I choose:

  • fill the libvmi event with fill_ev_common_kvmi_to_libvmi()
  • call the user callback with call_event_callback()
  • declare the kvmi reply struct
  • process the callback response with process_cb_response()

As you have written the Xen driver, you may have suggestions how the code should be structured, which helpers should be used, etc.

@@ -52,6 +53,9 @@
#include <sys/time.h>
#include "driver/kvm/include/kvmi/libkvmi.h"

/*
* Helpers
*/
static uint32_t
translate_msr_index(int index, int *err) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this function will be removed thanks to msr-index array:
https://github.com/KVM-VMI/libvmi/pull/9/files#diff-a342220ea96575ee149235454636ce4eR55

@mtarral
Copy link
Collaborator Author

mtarral commented Aug 30, 2019

Once this will be approved and merged in kvmi branch, I will proceed to rebase on V6.

@Wenzel
Copy link
Member

Wenzel commented Sep 16, 2019

pinging also @smaresca, if he is interested for a review 👋

@smaresca
Copy link

@Wenzel thanks! Will take a look

@tklengyel
Copy link

@Wenzel I would suggest moving the events code out of kvm.c into a separate kvm_events.c, just helps with not making these files so large

@Wenzel
Copy link
Member

Wenzel commented Sep 16, 2019

@tklengyel this has been done already, it's in a future PR, after a rebase on V6.

@mtarral
Copy link
Collaborator Author

mtarral commented Sep 18, 2019

@tklengyel , @smaresca actually I'm waiting for this one to be merged to publish my other PR based on v6.
It will bring events splitted into their own modules, singlestepping and other small improvments.

How do you feel so far about this one ?

@smaresca
Copy link

@mtarral I had some time over the weekend to set up a test environment. I'll have specific feedback tonight/tomorrow.

@mtarral
Copy link
Collaborator Author

mtarral commented Sep 25, 2019

@smaresca thanks for the feedback.
If you have any issues regarding the setup, or any questions, don't forget the KVM-VMI Slack channel.

@mtarral
Copy link
Collaborator Author

mtarral commented Oct 1, 2019

@smaresca how did it go ?
were you able to run the examples ?

@mtarral
Copy link
Collaborator Author

mtarral commented Oct 4, 2019

Rebased on latest kvmi branch.

@mtarral
Copy link
Collaborator Author

mtarral commented Oct 4, 2019

@smaresca , @tklengyel since I published the v6 PR, which is cleaner because the events are splitted and it uses the new libkvmi API to control events (which is better), I'm inclined to merge this one and focus on v6.

@Wenzel Wenzel merged commit deaaa74 into KVM-VMI:kvmi Oct 7, 2019
@mtarral mtarral deleted the kvmi_events branch October 7, 2019 08:08
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

Successfully merging this pull request may close these issues.

5 participants