diff mbox

[09/15] x86/emul: Avoid raising faults behind the emulators back

Message ID 1479915538-15282-10-git-send-email-andrew.cooper3@citrix.com (mailing list archive)
State New, archived
Headers show

Commit Message

Andrew Cooper Nov. 23, 2016, 3:38 p.m. UTC
Introduce a new x86_emul_pagefault() similar to x86_emul_hw_exception(), and
use this instead of hvm_inject_page_fault() from emulation codepaths.

Replace one hvm_inject_hw_exception() in the shadow emulation codepaths.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
CC: Jan Beulich <JBeulich@suse.com>
CC: Paul Durrant <paul.durrant@citrix.com>
CC: Tim Deegan <tim@xen.org>
CC: George Dunlap <george.dunlap@eu.citrix.com>

NOTE: this is a functional change for the shadow code, as a #PF previously
raised properly with the guest will now cause X86EMUL_UNHANDLABLE. It is my
understanding after a discusion with Tim that this is ok, but I haven't done
extenstive testing yet.
---
 xen/arch/x86/hvm/emulate.c             |  4 ++--
 xen/arch/x86/mm/shadow/common.c        |  5 +++--
 xen/arch/x86/x86_emulate/x86_emulate.h | 13 +++++++++++++
 3 files changed, 18 insertions(+), 4 deletions(-)

Comments

Tim Deegan Nov. 23, 2016, 4:31 p.m. UTC | #1
At 15:38 +0000 on 23 Nov (1479915532), Andrew Cooper wrote:
> Introduce a new x86_emul_pagefault() similar to x86_emul_hw_exception(), and
> use this instead of hvm_inject_page_fault() from emulation codepaths.
> 
> Replace one hvm_inject_hw_exception() in the shadow emulation codepaths.
> 
> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>

> NOTE: this is a functional change for the shadow code, as a #PF previously
> raised properly with the guest will now cause X86EMUL_UNHANDLABLE. It is my
> understanding after a discusion with Tim that this is ok, but I haven't done
> extenstive testing yet.

Do you plan to?  I think this is indeed OK, but there may be some edge
case, e.g. an instruction that writes to both the current top-level
pagetable (which can't be unshadowed) and an unmapped virtual address.
That ought to raise #PF in the guest but might now spin retrying?  

Tim.
Andrew Cooper Nov. 23, 2016, 4:40 p.m. UTC | #2
On 23/11/16 16:31, Tim Deegan wrote:
> At 15:38 +0000 on 23 Nov (1479915532), Andrew Cooper wrote:
>> Introduce a new x86_emul_pagefault() similar to x86_emul_hw_exception(), and
>> use this instead of hvm_inject_page_fault() from emulation codepaths.
>>
>> Replace one hvm_inject_hw_exception() in the shadow emulation codepaths.
>>
>> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
>> NOTE: this is a functional change for the shadow code, as a #PF previously
>> raised properly with the guest will now cause X86EMUL_UNHANDLABLE. It is my
>> understanding after a discusion with Tim that this is ok, but I haven't done
>> extenstive testing yet.
> Do you plan to?  I think this is indeed OK, but there may be some edge
> case, e.g. an instruction that writes to both the current top-level
> pagetable (which can't be unshadowed) and an unmapped virtual address.
> That ought to raise #PF in the guest but might now spin retrying?

That is a devious corner case.  I take it you have been there before?

The more I think about these changes, the more I think that the shadow
code would be better by selectively looking a pending event, injecting
pagefaults, but rejecting and retrying if any other event shows up.

~Andrew
Tim Deegan Nov. 23, 2016, 4:50 p.m. UTC | #3
At 16:40 +0000 on 23 Nov (1479919254), Andrew Cooper wrote:
> On 23/11/16 16:31, Tim Deegan wrote:
> > At 15:38 +0000 on 23 Nov (1479915532), Andrew Cooper wrote:
> >> Introduce a new x86_emul_pagefault() similar to x86_emul_hw_exception(), and
> >> use this instead of hvm_inject_page_fault() from emulation codepaths.
> >>
> >> Replace one hvm_inject_hw_exception() in the shadow emulation codepaths.
> >>
> >> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
> >> NOTE: this is a functional change for the shadow code, as a #PF previously
> >> raised properly with the guest will now cause X86EMUL_UNHANDLABLE. It is my
> >> understanding after a discusion with Tim that this is ok, but I haven't done
> >> extenstive testing yet.
> > Do you plan to?  I think this is indeed OK, but there may be some edge
> > case, e.g. an instruction that writes to both the current top-level
> > pagetable (which can't be unshadowed) and an unmapped virtual address.
> > That ought to raise #PF in the guest but might now spin retrying?
> 
> That is a devious corner case.  I take it you have been there before?

In similar situations, yes. :)

> The more I think about these changes, the more I think that the shadow
> code would be better by selectively looking a pending event, injecting
> pagefaults, but rejecting and retrying if any other event shows up.

That sounds like a good idea, and seems like the smallest deviation
from the current behaviour.  It might also be OK to inject any event
that the emulator raises.  That's a bigger change but maybe a more
coherent end result?

Cheers,

Tim.
Andrew Cooper Nov. 23, 2016, 4:58 p.m. UTC | #4
On 23/11/16 16:50, Tim Deegan wrote:
> At 16:40 +0000 on 23 Nov (1479919254), Andrew Cooper wrote:
>> On 23/11/16 16:31, Tim Deegan wrote:
>>> At 15:38 +0000 on 23 Nov (1479915532), Andrew Cooper wrote:
>>>> Introduce a new x86_emul_pagefault() similar to x86_emul_hw_exception(), and
>>>> use this instead of hvm_inject_page_fault() from emulation codepaths.
>>>>
>>>> Replace one hvm_inject_hw_exception() in the shadow emulation codepaths.
>>>>
>>>> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
>>>> NOTE: this is a functional change for the shadow code, as a #PF previously
>>>> raised properly with the guest will now cause X86EMUL_UNHANDLABLE. It is my
>>>> understanding after a discusion with Tim that this is ok, but I haven't done
>>>> extenstive testing yet.
>>> Do you plan to?  I think this is indeed OK, but there may be some edge
>>> case, e.g. an instruction that writes to both the current top-level
>>> pagetable (which can't be unshadowed) and an unmapped virtual address.
>>> That ought to raise #PF in the guest but might now spin retrying?
>> That is a devious corner case.  I take it you have been there before?
> In similar situations, yes. :)
>
>> The more I think about these changes, the more I think that the shadow
>> code would be better by selectively looking a pending event, injecting
>> pagefaults, but rejecting and retrying if any other event shows up.
> That sounds like a good idea, and seems like the smallest deviation
> from the current behaviour.  It might also be OK to inject any event
> that the emulator raises.  That's a bigger change but maybe a more
> coherent end result?

Well - now this isn't hidden in a security fix, I am less averse to
functional changes.

My only concern is that the previous lack of the ->inject_hw_exception()
hook cut off large chunks of functionality from the shadow and PV PT
emulation paths, and I am not sure opening this up in general is a good
idea.

Longterm the plan is to fully split the decode and emulate calls even
for external callers, at which point the the pagetable code could check
that the instruction is write which matches %cr2 before proceeding with
emulation.  Even then however, I am not sure it would be a good idea to
follow anything other than a pagefault which surfaces from emulation.

~Andrew
Jan Beulich Nov. 24, 2016, 10:43 a.m. UTC | #5
>>> On 23.11.16 at 17:58, <andrew.cooper3@citrix.com> wrote:
> Longterm the plan is to fully split the decode and emulate calls even
> for external callers,

This is news to me - why would that be? My PV priv-op series will
add a hook called between decode and execute, but I don't see
why we should bother all callers with invoking decode and execute
separately.

Jan
Andrew Cooper Nov. 24, 2016, 10:46 a.m. UTC | #6
On 24/11/16 10:43, Jan Beulich wrote:
>>>> On 23.11.16 at 17:58, <andrew.cooper3@citrix.com> wrote:
>> Longterm the plan is to fully split the decode and emulate calls even
>> for external callers,
> This is news to me - why would that be? My PV priv-op series will
> add a hook called between decode and execute, but I don't see
> why we should bother all callers with invoking decode and execute
> separately.

Having an audit hook is also fine.  It achieves the same overall effect.

Without seeing how you planned to do this, I was referring back to the
discussion which was had at the April Hackathon.

~Andrew
Jan Beulich Nov. 24, 2016, 11:24 a.m. UTC | #7
>>> On 24.11.16 at 11:46, <andrew.cooper3@citrix.com> wrote:
> On 24/11/16 10:43, Jan Beulich wrote:
>>>>> On 23.11.16 at 17:58, <andrew.cooper3@citrix.com> wrote:
>>> Longterm the plan is to fully split the decode and emulate calls even
>>> for external callers,
>> This is news to me - why would that be? My PV priv-op series will
>> add a hook called between decode and execute, but I don't see
>> why we should bother all callers with invoking decode and execute
>> separately.
> 
> Having an audit hook is also fine.  It achieves the same overall effect.
> 
> Without seeing how you planned to do this, I was referring back to the
> discussion which was had at the April Hackathon.

Oh, I see. We actually did briefly discuss the hook later (see e.g.
lists.xenproject.org/archives/html/xen-devel/2016-09/msg03367.html),
and it doesn't make much sense for me to post v3 without your
XSA-191 follow-up finished and in place.

Jan
diff mbox

Patch

diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
index c0fbde1..3ebb200 100644
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -459,7 +459,7 @@  static int hvmemul_linear_to_phys(
     {
         if ( pfec & (PFEC_page_paged | PFEC_page_shared) )
             return X86EMUL_RETRY;
-        hvm_inject_page_fault(pfec, addr);
+        x86_emul_pagefault(pfec, addr, &hvmemul_ctxt->ctxt);
         return X86EMUL_EXCEPTION;
     }
 
@@ -483,7 +483,7 @@  static int hvmemul_linear_to_phys(
                 ASSERT(!reverse);
                 if ( npfn != gfn_x(INVALID_GFN) )
                     return X86EMUL_UNHANDLEABLE;
-                hvm_inject_page_fault(pfec, addr & PAGE_MASK);
+                x86_emul_pagefault(pfec, addr & PAGE_MASK, &hvmemul_ctxt->ctxt);
                 return X86EMUL_EXCEPTION;
             }
             *reps = done;
diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c
index 6f6668d..c8b61b9 100644
--- a/xen/arch/x86/mm/shadow/common.c
+++ b/xen/arch/x86/mm/shadow/common.c
@@ -162,8 +162,9 @@  static int hvm_translate_linear_addr(
 
     if ( !okay )
     {
-        hvm_inject_hw_exception(
-            (seg == x86_seg_ss) ? TRAP_stack_error : TRAP_gp_fault, 0);
+        x86_emul_hw_exception(
+            (seg == x86_seg_ss) ? TRAP_stack_error : TRAP_gp_fault,
+            0, &sh_ctxt->ctxt);
         return X86EMUL_EXCEPTION;
     }
 
diff --git a/xen/arch/x86/x86_emulate/x86_emulate.h b/xen/arch/x86/x86_emulate/x86_emulate.h
index ddcd93c..cc26e9d 100644
--- a/xen/arch/x86/x86_emulate/x86_emulate.h
+++ b/xen/arch/x86/x86_emulate/x86_emulate.h
@@ -600,6 +600,19 @@  static inline void x86_emul_hw_exception(
     ctxt->event_pending = true;
 }
 
+static inline void x86_emul_pagefault(
+    unsigned int error_code, unsigned long cr2, struct x86_emulate_ctxt *ctxt)
+{
+    ASSERT(!ctxt->event_pending);
+
+    ctxt->event.vector = 14; /* TRAP_page_fault */
+    ctxt->event.type = X86_EVENTTYPE_HW_EXCEPTION;
+    ctxt->event.error_code = error_code;
+    ctxt->event.cr2 = cr2;
+
+    ctxt->event_pending = true;
+}
+
 static inline void x86_emul_software_event(
     enum x86_swint_type type, uint8_t vector, uint8_t insn_len,
     struct x86_emulate_ctxt *ctxt)