[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] Tracking guest code execution with EPT violations

  • To: <tim@xxxxxxx>
  • From: <Kevin.Mayer@xxxxxxxx>
  • Date: Fri, 23 Jan 2015 14:09:28 +0000
  • Accept-language: de-DE, en-US
  • Cc: xen-devel@xxxxxxxxxxxxx
  • Delivery-date: Fri, 23 Jan 2015 14:09:52 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xen.org>
  • Thread-index: AdAxqPW5cV0WRMKaSQ2CJ/YrqF21EwEpUEqAAC9fmoA=
  • Thread-topic: [Xen-devel] Tracking guest code execution with EPT violations

Thanks for your reply.

> Hi,
> > So whenever a nonexisting memory page gets requested an EPT violation is
> caused (and handled by ept_handle_violation). Extending the
> EXIT_REASON_EPT_VIOLATION I should be able to set the access rights for
> every new page to access_rw(By using the p2m->get_entry and p2m->
> set_entry functions right after the violation was handled), leading to a new
> EPT violation every time an instruction is fetched from this page.
> >
> > There are several problems with my approach so far:
> >
> > *         I get to few unique GFN (derived from the gpa by PAGE_SHIFT in the
> EPT violations when booting a WinXP guest.  I get about 250 EPT_VIOLATIONS
> with unique GFNs when booting the guest OS and none when starting new
> programs in the guest. So something seems to be wrong there. Also I read
> the access rights of the pages back after setting them. Most of the time the
> initial access rights are access_n before and the same after I tried setting
> them to access_rw (this happens when the type is p2m_mmio_dm, when
> the type is p2m_ram_rw the setting works temporarily).
> I can't really tell from that what you're doing, but:
>  - I suspect that the 'p2m_mmio_dm' cases are gfns that don't map to
>    anything.  Accesses to unmapped addresses are assumed to be
>    emulated devices and passed to qemu.
>  - If you are having trouble with access types changing underfoot,
>    make sure that you are setting the domain's p2m->default_access
>    to something sensible.

My idea was that when a guest wants to access a new page (let`s say a guest 
wants to start a new process and therefore needs to copy the code into the 
memory) then an EPT-violation should be raised because the corresponding EPTE 
for this new page isn`t there since the page was now accessed for the first 
This does not happen though.

I played a bit with the p2m->default_access and got a new problem now.
I hardcode the default access in 
static int p2m_initialise(struct domain *d, struct p2m_domain *p2m) 
p2m->default_access = p2m_access_rw;
This works well as I get several thousand EPT_VIOLATIONS (with unique GFN) when 
booting the guest (and several thousand more when starting new processes).
When I set the default_access to
p2m->default_access = p2m_access_rwx;
I get no EPT_VIOLATIONS with execution attempts (no surprise here).
Then I wanted to see if I could get only the EPT_VIOLATIONS of let`s say 
Firefox (or any new process). So I let my guest-OS boot up, changed the 
default_access to read+write with the help of
xc_hvm_set_mem_access(xch, domid, HVMMEM_access_rw,~0ull, 0);
as shown in xen-access.c (I didn`t want to get any EPT_VIOLATIONS for pages 
that are already present, i.e. the OS so I didn't set the existing pages to 
access_rw) and then started Firefox in the guest.
The idea behind this was that the guest needs to access new pages to start up 
Firefox, which would be set to the default_access (rw in this case). So when 
Firefox is running I would get EPT_VIOLATIONS with EPT_EXEC_VIOLATION in the 
This doesn`t work as expected, as I get none of these EPT_VIOLATIONS. 
I suspect that the default_access gets used to initialize the domain and then 
some initialized value gets used instead of the p2m->default_access. Another 
possibility is that my idea of how the memory is accessed is flawed or that all 
pages the OS uses for Firefox are already initialized.

> > 3.       Are the p2m->get_entry/p2m->set_entry functions the right tools for
> this purpose?
> Probably not.  p2m_set_mem_access() and p2m_get_mem_access() should
> be better.

Yeah, I now use those. The p2m->get/set_entry worked, but the 
p2m_set/get_mem_access() are definitely the better choice.

> > 4.       To get the domain I use struct vcpu *curr = current; and struct
> p2m_domain *p2m = p2m_get_hostp2m(curr->domain); before using the
> get/set_entry-functions. Do I get confused with wrong domains or
> something like that?
> Maybe.  Those things will get you the currently executing domain, so if your
> code is part of a hypercall handler it will adjust the _caller_'s p2m.

I was able to solve the problem with the wrong access rights. Turns out I was 
using the wrong domain, as you suggested... :-\

> > 5.       Because I just set the access rights to rw every time
> EXIT_REASON_EPT_VIOLATION is called the whole domain should
> freeze/crash as soon as the first page tries to execute an instruction, 
> right? It
> doesn't because I get no execution attempts on the pages I set the
> access_rw, but why don't I get an execution attempt?
> >
> I can't really tell, but it does sounds like something is confused.
> Possibly you are using the wrong kind of addresses?  These p2m operations
> work on GFNs, i.e. whet the guest thinks are physical addresses, and not
> MFNs (actual physical addresses) or virtual addresses.

I use the gfn I get with
gfn = gpa >> PAGE_SHIFT;
in the EXIT_REASON_EPT_VIOLATION case of the vmexit_handler.
The problem was that my initial assumption (EPT_VIOLATION being risen when the 
guest tries to access a page for the first time) was wrong, though I can`t 
figure out how the memory allocation is really working.
Now when setting the access rights to access_rw after 
ept_handle_violation(exit_qualification, gpa);
was called I successfully put the machine into a livelock (as expected since 
the ept_handle_violation  sets the access rights to rwx, then I set them to rw 
again and the same instruction gets executed again leading to a new 
EPT_VIOLATION. Then the cycle repeats infinitely).

I hope you can identify the error in my assumptions or point me to some code 
that might help regarding my problem with the default_access.


Virus checked by G Data MailSecurity
Version: AVA 24.6214 dated 23.01.2015
Virus news: www.antiviruslab.com

Xen-devel mailing list



Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.