x86/mm: suppress vm_events caused by page-walks
authorAlexandru Isaila <aisaila@bitdefender.com>
Thu, 5 Jul 2018 13:25:20 +0000 (15:25 +0200)
committerJan Beulich <jbeulich@suse.com>
Thu, 5 Jul 2018 13:25:20 +0000 (15:25 +0200)
This patch is adding a way to enable/disable inguest pagefault
events. It introduces the xc_monitor_inguest_pagefault function
and adds the inguest_pagefault_disabled in the monitor structure.
This is needed by the introspection so it will only get gla
faults and not get spammed with other faults.
In p2m_mem_access_check() we emulate so no event will get sent.

Signed-off-by: Alexandru Isaila <aisaila@bitdefender.com>
Acked-by: Tamas K Lengyel <tamas@tklengyel.com>
Acked-by: Wei Liu <wei.liu2@citrix.com>
tools/libxc/include/xenctrl.h
tools/libxc/xc_monitor.c
tools/tests/xen-access/xen-access.c
xen/arch/x86/mm/mem_access.c
xen/arch/x86/monitor.c
xen/include/asm-x86/domain.h
xen/include/asm-x86/monitor.h
xen/include/public/domctl.h

index e8285dbb5fef66317c4b064c1dec4726ea5d3979..580d2cdb0692274fd43af4ea1468b26d5106885f 100644 (file)
@@ -2047,6 +2047,13 @@ int xc_monitor_descriptor_access(xc_interface *xch, uint32_t domain_id,
                                  bool enable);
 int xc_monitor_guest_request(xc_interface *xch, uint32_t domain_id,
                              bool enable, bool sync, bool allow_userspace);
+/*
+ * Disables page-walk mem_access events by emulating. If the
+ * emulation can not be performed then a VM_EVENT_REASON_EMUL_UNIMPLEMENTED
+ * event will be issued.
+ */
+int xc_monitor_inguest_pagefault(xc_interface *xch, uint32_t domain_id,
+                                 bool disable);
 int xc_monitor_debug_exceptions(xc_interface *xch, uint32_t domain_id,
                                 bool enable, bool sync);
 int xc_monitor_cpuid(xc_interface *xch, uint32_t domain_id, bool enable);
index 0233b87b3fedf4c9681c4b4bc34a6285392671c8..4ac823e775656ae825138fea71af4392c1d8b5a0 100644 (file)
@@ -163,6 +163,20 @@ int xc_monitor_guest_request(xc_interface *xch, uint32_t domain_id, bool enable,
     return do_domctl(xch, &domctl);
 }
 
+int xc_monitor_inguest_pagefault(xc_interface *xch, uint32_t domain_id,
+                                bool disable)
+{
+    DECLARE_DOMCTL;
+
+    domctl.cmd = XEN_DOMCTL_monitor_op;
+    domctl.domain = domain_id;
+    domctl.u.monitor_op.op = disable ? XEN_DOMCTL_MONITOR_OP_ENABLE
+                                    : XEN_DOMCTL_MONITOR_OP_DISABLE;
+    domctl.u.monitor_op.event = XEN_DOMCTL_MONITOR_EVENT_INGUEST_PAGEFAULT;
+
+    return do_domctl(xch, &domctl);
+}
+
 int xc_monitor_emulate_each_rep(xc_interface *xch, uint32_t domain_id,
                                 bool enable)
 {
index 8c32bfbc3f816e1567ea0514dd2e390e1c4c3841..6aaee16d6751a96db964063c59d7644954502569 100644 (file)
@@ -360,7 +360,7 @@ void usage(char* progname)
 {
     fprintf(stderr, "Usage: %s [-m] <domain_id> write|exec", progname);
 #if defined(__i386__) || defined(__x86_64__)
-            fprintf(stderr, "|breakpoint|altp2m_write|altp2m_exec|debug|cpuid|desc_access|write_ctrlreg_cr4");
+            fprintf(stderr, "|breakpoint|altp2m_write|altp2m_exec|debug|cpuid|desc_access|write_ctrlreg_cr4|altp2m_write_no_gpt");
 #elif defined(__arm__) || defined(__aarch64__)
             fprintf(stderr, "|privcall");
 #endif
@@ -393,6 +393,7 @@ int main(int argc, char *argv[])
     int cpuid = 0;
     int desc_access = 0;
     int write_ctrlreg_cr4 = 0;
+    int altp2m_write_no_gpt = 0;
     uint16_t altp2m_view_id = 0;
 
     char* progname = argv[0];
@@ -451,6 +452,13 @@ int main(int argc, char *argv[])
         altp2m = 1;
         memaccess = 1;
     }
+    else if ( !strcmp(argv[0], "altp2m_write_no_gpt") )
+    {
+        default_access = XENMEM_access_rw;
+        altp2m_write_no_gpt = 1;
+        memaccess = 1;
+        altp2m = 1;
+    }
     else if ( !strcmp(argv[0], "debug") )
     {
         debug = 1;
@@ -511,6 +519,22 @@ int main(int argc, char *argv[])
         xen_pfn_t gfn = 0;
         unsigned long perm_set = 0;
 
+        if( altp2m_write_no_gpt )
+        {
+            rc = xc_monitor_inguest_pagefault(xch, domain_id, 1);
+            if ( rc < 0 )
+            {
+                ERROR("Error %d setting inguest pagefault\n", rc);
+                goto exit;
+            }
+            rc = xc_monitor_emul_unimplemented(xch, domain_id, 1);
+            if ( rc < 0 )
+            {
+                ERROR("Error %d failed to enable emul unimplemented\n", rc);
+                goto exit;
+            }
+        }
+
         rc = xc_altp2m_set_domain_state( xch, domain_id, 1 );
         if ( rc < 0 )
         {
@@ -857,6 +881,16 @@ int main(int argc, char *argv[])
                        req.u.write_ctrlreg.old_value,
                        req.u.write_ctrlreg.new_value);
                 break;
+            case VM_EVENT_REASON_EMUL_UNIMPLEMENTED:
+                if ( altp2m_write_no_gpt && req.flags & VM_EVENT_FLAG_ALTERNATE_P2M )
+                {
+                    DPRINTF("\tSwitching back to default view!\n");
+
+                    rsp.flags |= (VM_EVENT_FLAG_ALTERNATE_P2M |
+                                  VM_EVENT_FLAG_TOGGLE_SINGLESTEP);
+                    rsp.altp2m_idx = 0;
+                }
+                break;
             default:
                 fprintf(stderr, "UNKNOWN REASON CODE %d\n", req.reason);
             }
index c0cd0174cf1690912589cfd3d28fc3164d8e55c2..febe38d8df026beb43e898162304558a4fa69e47 100644 (file)
@@ -28,6 +28,7 @@
 #include <public/vm_event.h>
 #include <asm/p2m.h>
 #include <asm/altp2m.h>
+#include <asm/hvm/emulate.h>
 #include <asm/vm_event.h>
 
 #include "mm-locks.h"
@@ -207,6 +208,14 @@ bool p2m_mem_access_check(paddr_t gpa, unsigned long gla,
             return true;
         }
     }
+    if ( vm_event_check_ring(d->vm_event_monitor) &&
+         d->arch.monitor.inguest_pagefault_disabled &&
+         npfec.kind != npfec_kind_with_gla ) /* don't send a mem_event */
+    {
+        hvm_emulate_one_vm_event(EMUL_KIND_NORMAL, TRAP_invalid_op, X86_EVENT_NO_EC);
+
+        return true;
+    }
 
     *req_ptr = NULL;
     req = xzalloc(vm_event_request_t);
index 3fb6531f6e9d2dd948e202c48238afec5e55ba5c..3c42e21906741646a23cf37ca892f7fc13aafd45 100644 (file)
@@ -242,6 +242,19 @@ int arch_monitor_domctl_event(struct domain *d,
         break;
     }
 
+    case XEN_DOMCTL_MONITOR_EVENT_INGUEST_PAGEFAULT:
+    {
+        bool old_status = ad->monitor.inguest_pagefault_disabled;
+
+        if ( unlikely(old_status == requested_status) )
+            return -EEXIST;
+
+        domain_pause(d);
+        ad->monitor.inguest_pagefault_disabled = requested_status;
+        domain_unpause(d);
+        break;
+    }
+
     case XEN_DOMCTL_MONITOR_EVENT_DESC_ACCESS:
     {
         bool old_status = ad->monitor.descriptor_access_enabled;
index e0d413c7de85c1a4d3b8e36d9faa558f529fe1b7..5a6332c2b7e4affcf54d4eecd1f76bd5a7c554d1 100644 (file)
@@ -417,6 +417,11 @@ struct arch_domain
         unsigned int descriptor_access_enabled                             : 1;
         unsigned int guest_request_userspace_enabled                       : 1;
         unsigned int emul_unimplemented_enabled                            : 1;
+        /*
+         * By default all events are sent.
+         * This is used to filter out pagefaults.
+         */
+        unsigned int inguest_pagefault_disabled                            : 1;
         struct monitor_msr_bitmap *msr_bitmap;
         uint64_t write_ctrlreg_mask[4];
     } monitor;
index 4f1c7ffe0afb4c075b69c0d1c7281186738930a9..49889033f48491d44804681178a9f741c0eb3a3f 100644 (file)
@@ -84,7 +84,8 @@ static inline uint32_t arch_monitor_get_capabilities(struct domain *d)
                     (1U << XEN_DOMCTL_MONITOR_EVENT_CPUID) |
                     (1U << XEN_DOMCTL_MONITOR_EVENT_DEBUG_EXCEPTION) |
                     (1U << XEN_DOMCTL_MONITOR_EVENT_WRITE_CTRLREG) |
-                    (1U << XEN_DOMCTL_MONITOR_EVENT_EMUL_UNIMPLEMENTED));
+                    (1U << XEN_DOMCTL_MONITOR_EVENT_EMUL_UNIMPLEMENTED) |
+                    (1U << XEN_DOMCTL_MONITOR_EVENT_INGUEST_PAGEFAULT));
 
     if ( hvm_is_singlestep_supported() )
         capabilities |= (1U << XEN_DOMCTL_MONITOR_EVENT_SINGLESTEP);
index 0535da81c627283fd105b7d63882df65ec00d5dc..5c3916caaf2a520cf5b2da8a56a20d92e3395d4b 100644 (file)
@@ -998,6 +998,8 @@ struct xen_domctl_psr_cmt_op {
 #define XEN_DOMCTL_MONITOR_EVENT_INTERRUPT             8
 #define XEN_DOMCTL_MONITOR_EVENT_DESC_ACCESS           9
 #define XEN_DOMCTL_MONITOR_EVENT_EMUL_UNIMPLEMENTED    10
+/* Enabled by default */
+#define XEN_DOMCTL_MONITOR_EVENT_INGUEST_PAGEFAULT     11
 
 struct xen_domctl_monitor_op {
     uint32_t op; /* XEN_DOMCTL_MONITOR_OP_* */