diff mbox

[v3,15/17] livepatch/x86/arm: Utilize the arch_livepatch_lookup_mfn

Message ID 20170912003726.368-16-konrad.wilk@oracle.com (mailing list archive)
State New, archived
Headers show

Commit Message

Konrad Rzeszutek Wilk Sept. 12, 2017, 12:37 a.m. UTC
Without this patch on x86 we would get a DOUBLE FAULT
as the virt_to_mfn does not lookup virtual addresses
that are in vmap region. This means that the livepatch_vmap.funcs
would point to an incorrect MFN (with either garbage or all
zeros).

We only use the livepatch_vmap.funcs to save the old contents
of the instruction (f->opaque) so during patching all works fine.

But when we revert and copy the contents of f->opaque we would
either get the right values, or zeros (again, depending on where the
MFN is) - and then starting instructions in the unpatched function
would end up with 00000000 .. causing a double fault.

Using the arch_livepatch_lookup_mfn solves the problem and
the applying/reverting works on all platforms properly.

Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
---
 xen/common/livepatch.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)
diff mbox

Patch

diff --git a/xen/common/livepatch.c b/xen/common/livepatch.c
index 2f5ee1ae75..2526d3a0ca 100644
--- a/xen/common/livepatch.c
+++ b/xen/common/livepatch.c
@@ -1073,7 +1073,10 @@  static int livepatch_quiesce(struct livepatch_func *funcs, unsigned int nfuncs)
     if ( livepatch_vmap.text || livepatch_vmap.funcs )
         return -EINVAL;
 
-    text_mfn = _mfn(virt_to_mfn(_start));
+    text_mfn = arch_livepatch_lookup_mfn((unsigned long)_start);
+    if ( mfn_eq(text_mfn, INVALID_MFN) )
+        return -EINVAL;
+
     text_order = get_order_from_bytes(_end - _start);
 
     /*
@@ -1093,7 +1096,14 @@  static int livepatch_quiesce(struct livepatch_func *funcs, unsigned int nfuncs)
     livepatch_vmap.text = vmap_addr;
     livepatch_vmap.offset = offs;
 
-    rodata_mfn = _mfn(virt_to_mfn(va & PAGE_MASK));
+    rodata_mfn = arch_livepatch_lookup_mfn(va & PAGE_MASK);
+    if ( mfn_eq(rodata_mfn, INVALID_MFN) )
+    {
+        vunmap(livepatch_vmap.text);
+        livepatch_vmap.text = NULL;
+        return -EINVAL;
+    }
+
     vmap_addr  = __vmap(&rodata_mfn, size, 1, 1, PAGE_HYPERVISOR, VMAP_DEFAULT);
     if ( !vmap_addr )
     {