WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-ia64-devel

[Xen-ia64-devel] [PATCH] Fix vulnerability of copy_to_user in PAL emulat

To: xen-ia64-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-ia64-devel] [PATCH] Fix vulnerability of copy_to_user in PAL emulation
From: Kouya Shimura <kouya@xxxxxxxxxxxxxx>
Date: Tue, 11 Dec 2007 16:11:12 +0900
Delivery-date: Mon, 10 Dec 2007 23:11:28 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-ia64-devel-request@lists.xensource.com?subject=help>
List-id: Discussion of the ia64 port of Xen <xen-ia64-devel.lists.xensource.com>
List-post: <mailto:xen-ia64-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-ia64-devel>, <mailto:xen-ia64-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-ia64-devel>, <mailto:xen-ia64-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-ia64-devel-bounces@xxxxxxxxxxxxxxxxxxx
There is a security vulnerability in PAL emulation
since alt-dtlb miss handler of HVM absolutely 
inserts a identity-mapped TLB when psr.vm=0.

HVM guest can access an arbitrary machine physical
memory with this security hole.

Actually windows 2008 destroys the content of machine 
physical address 0x108000. This is a serious problem.

I tried to support PV domain with the same logic too
but it doesn't work well since PV domain can't hold
more than one vtlb.

Signed-off-by: Kouya Shimura <kouya@xxxxxxxxxxxxxx>

diff -r 4054cd60895b xen/arch/ia64/vmx/pal_emul.c
--- a/xen/arch/ia64/vmx/pal_emul.c      Mon Dec 10 13:49:22 2007 +0000
+++ b/xen/arch/ia64/vmx/pal_emul.c      Tue Dec 11 14:52:19 2007 +0900
@@ -24,11 +24,12 @@
 #include <asm/pal.h>
 #include <asm/sal.h>
 
-void
+IA64FAULT
 pal_emul(struct vcpu *vcpu)
 {
        u64 gr28, gr29, gr30, gr31;
        struct ia64_pal_retval result;
+       IA64FAULT fault;
 
        vcpu_get_gr_nat(vcpu, 28, &gr28);  //bank1
 
@@ -38,12 +39,17 @@ pal_emul(struct vcpu *vcpu)
        vcpu_get_gr_nat(vcpu, 31, &gr31);
 
        perfc_incr(vmx_pal_emul);
-       result = xen_pal_emulator(gr28, gr29, gr30, gr31);
-
+       fault = xen_pal_emulator(&result, gr28, gr29, gr30, gr31);
+       if (fault != IA64_NO_FAULT) {
+               printk(XENLOG_DEBUG "PAL(%ld) TLB-miss 0x%lx 0x%lx 0x%lx\n",
+                      gr28, gr29, gr30, gr31);
+               return fault;
+       }
        vcpu_set_gr(vcpu, 8, result.status, 0);
        vcpu_set_gr(vcpu, 9, result.v0, 0);
        vcpu_set_gr(vcpu, 10, result.v1, 0);
        vcpu_set_gr(vcpu, 11, result.v2, 0);
+       return fault;
 }
 
 void
diff -r 4054cd60895b xen/arch/ia64/vmx/vmx_fault.c
--- a/xen/arch/ia64/vmx/vmx_fault.c     Mon Dec 10 13:49:22 2007 +0000
+++ b/xen/arch/ia64/vmx/vmx_fault.c     Mon Dec 10 18:39:23 2007 +0900
@@ -174,6 +174,7 @@ vmx_ia64_handle_break (unsigned long ifa
 {
     struct domain *d = current->domain;
     struct vcpu *v = current;
+    IA64FAULT fault;
 
     perfc_incr(vmx_ia64_handle_break);
 #ifdef CRASH_DEBUG
@@ -196,9 +197,9 @@ vmx_ia64_handle_break (unsigned long ifa
                 return IA64_NO_FAULT;
             }
             else if (iim == DOMN_PAL_REQUEST) {
-                pal_emul(v);
-                vcpu_increment_iip(v);
-                return IA64_NO_FAULT;
+                if ((fault = pal_emul(v)) == IA64_NO_FAULT)
+                    vcpu_increment_iip(v);
+                return fault;
             } else if (iim == DOMN_SAL_REQUEST) {
                 sal_emul(v);
                 vcpu_increment_iip(v);
diff -r 4054cd60895b xen/arch/ia64/xen/fw_emul.c
--- a/xen/arch/ia64/xen/fw_emul.c       Mon Dec 10 13:49:22 2007 +0000
+++ b/xen/arch/ia64/xen/fw_emul.c       Tue Dec 11 15:00:36 2007 +0900
@@ -37,6 +37,7 @@
 #include <xen/softirq.h>
 #include <xen/time.h>
 #include <asm/debugger.h>
+#include <asm/vmx_phy_mode.h>
 
 static DEFINE_SPINLOCK(efi_time_services_lock);
 
@@ -82,6 +83,97 @@ static const char * const rec_name[] = {
 #else
 # define IA64_SAL_DEBUG(fmt...)
 #endif
+
+#define MIN_PAGE_SIZE 4096
+
+struct palcomm_ctxt {
+       void *va[2];
+};
+
+static void
+palcomm_done(struct palcomm_ctxt *comm)
+{
+       int i;
+       struct page_info* page;
+
+       for (i = 0; i < 2; i++) {
+               if (comm->va[i]) {
+                       page = virt_to_page(comm->va[i]);
+                       put_page(page);
+                       comm->va[i] = NULL;
+               }
+       }
+}
+
+static IA64FAULT
+palcomm_init(struct palcomm_ctxt *comm, unsigned long buf, long size)
+{
+       IA64FAULT fault = IA64_NO_FAULT;
+       int i;
+       unsigned long paddr, maddr, poff;
+       struct page_info* page;
+
+       BUG_ON((unsigned)size > MIN_PAGE_SIZE);
+
+       /* check for vulnerability. NB - go through in metaphysical mode. */
+       if (IS_VMM_ADDRESS(buf) || IS_VMM_ADDRESS(buf + size))
+               panic_domain(NULL, "copy to bad address:0x%lx\n", buf);
+
+       comm->va[0] = comm->va[1] = NULL;
+
+       /* XXX: not implemented for PV domain */
+       if (!VMX_DOMAIN(current))
+               return fault;
+
+       for (i = 0; i < 2; i++) {
+               if (is_virtual_mode(current)) {
+                       fault = vmx_vcpu_tpa(current, buf, &paddr);
+                       if (fault != IA64_NO_FAULT)
+                               goto fail;
+               } else
+                       paddr = buf;
+               if ((maddr = paddr_to_maddr(paddr)) == 0)
+                       goto fail;
+               page = maddr_to_page(maddr);
+               if (get_page(page, current->domain) == 0)
+                       goto fail;
+               comm->va[i] = __va(maddr);
+               poff = buf & (MIN_PAGE_SIZE - 1);
+               if (likely(poff + size <= MIN_PAGE_SIZE))
+                       break;
+
+               /* crossing page boundary */
+               buf = buf - poff + MIN_PAGE_SIZE;
+       }
+       return fault;
+fail:
+       palcomm_done(comm);
+       return fault;
+}
+
+static int
+palcomm_copy_to_guest(struct palcomm_ctxt *comm,
+               unsigned long to, void *from, long size)
+{
+       long poff, len;
+
+       if (VMX_DOMAIN(current)) {
+               if (comm->va[0] == NULL)
+                       return -1;
+               poff = to & (MIN_PAGE_SIZE - 1);
+               if (poff + size <= MIN_PAGE_SIZE) {
+                       memcpy(comm->va[0], from, size);
+               } else {
+                       len = MIN_PAGE_SIZE - poff;
+                       memcpy(comm->va[0], from, len);
+                       memcpy(comm->va[1], from + len, size - len);
+               }
+               return 0;
+       } else {
+               return copy_to_user((void __user *)to, from, size);
+       }
+}
+
 
 void get_state_info_on(void *data) {
        struct smp_call_args_t *arg = data;
@@ -605,8 +697,9 @@ remote_pal_mc_drain(void *v)
        ia64_pal_mc_drain();
 }
 
-struct ia64_pal_retval
-xen_pal_emulator(unsigned long index, u64 in1, u64 in2, u64 in3)
+IA64FAULT
+xen_pal_emulator(struct ia64_pal_retval *ret,
+               unsigned long index, u64 in1, u64 in2, u64 in3)
 {
        unsigned long r9  = 0;
        unsigned long r10 = 0;
@@ -615,8 +708,10 @@ xen_pal_emulator(unsigned long index, u6
        unsigned long flags;
        int processor;
 
-       if (unlikely(running_on_sim))
-               return pal_emulator_static(index);
+       if (unlikely(running_on_sim)) {
+               *ret = pal_emulator_static(index);
+               return IA64_NO_FAULT;
+       }
 
        debugger_event(XEN_IA64_DEBUG_ON_PAL);
 
@@ -801,21 +896,22 @@ xen_pal_emulator(unsigned long index, u6
            case PAL_PERF_MON_INFO:
                {
                        unsigned long pm_buffer[16];
+                       struct palcomm_ctxt comm;
+                       IA64FAULT fault;
+
+                       fault = palcomm_init(&comm, in1, 128);
+                       if (fault != IA64_NO_FAULT)
+                               return fault;
+
                        status = ia64_pal_perf_mon_info(
                                        pm_buffer,
                                        (pal_perf_mon_info_u_t *) &r9);
-                       if (status != 0) {
-                               while(1)
-                               printk("PAL_PERF_MON_INFO fails ret=%ld\n", 
status);
-                               break;
+                       if (status == PAL_STATUS_SUCCESS) {
+                               if (palcomm_copy_to_guest(&comm, in1,
+                                                         pm_buffer, 128))
+                                       status = PAL_STATUS_ERROR;
                        }
-                       if (copy_to_user((void __user *)in1,pm_buffer,128)) {
-                               while(1)
-                               printk("xen_pal_emulator: PAL_PERF_MON_INFO "
-                                       "can't copy to user!!!!\n");
-                               status = PAL_STATUS_UNIMPLEMENTED;
-                               break;
-                       }
+                       palcomm_done(&comm);
                }
                break;
            case PAL_CACHE_INFO:
@@ -837,10 +933,17 @@ xen_pal_emulator(unsigned long index, u6
                       consumes 10 mW, implemented and cache/TLB coherent.  */
                    unsigned long res = 1000UL | (1000UL << 16) | (10UL << 32)
                            | (1UL << 61) | (1UL << 60);
-                   if (copy_to_user ((void *)in1, &res, sizeof (res)))
-                           status = PAL_STATUS_EINVAL;    
+                   struct palcomm_ctxt comm;
+                   IA64FAULT fault;
+
+                   fault = palcomm_init(&comm, in1, sizeof(res));
+                   if (fault != IA64_NO_FAULT)
+                           return fault;
+                   if (palcomm_copy_to_guest(&comm, in1, &res, sizeof (res)))
+                           status = PAL_STATUS_ERROR;
                    else
                            status = PAL_STATUS_SUCCESS;
+                   palcomm_done(&comm);
                }
                break;
            case PAL_HALT:
@@ -885,9 +988,19 @@ xen_pal_emulator(unsigned long index, u6
            case PAL_BRAND_INFO:
                if (in1 == 0) {
                        char brand_info[128];
+                       struct palcomm_ctxt comm;
+                       IA64FAULT fault;
+
+                       fault = palcomm_init(&comm, in2, 128);
+                       if (fault != IA64_NO_FAULT)
+                               return fault;
                        status = ia64_pal_get_brand_info(brand_info);
-                       if (status == PAL_STATUS_SUCCESS)
-                               copy_to_user((void *)in2, brand_info, 128);
+                       if (status == PAL_STATUS_SUCCESS) {
+                               if (palcomm_copy_to_guest(&comm, in2,
+                                                         brand_info, 128))
+                                       status = PAL_STATUS_ERROR;
+                       }
+                       palcomm_done(&comm);
                } else {
                        status = PAL_STATUS_EINVAL;
                }
@@ -901,7 +1014,11 @@ xen_pal_emulator(unsigned long index, u6
                printk("%s: Unimplemented PAL Call %lu\n", __func__, index);
                break;
        }
-       return ((struct ia64_pal_retval) {status, r9, r10, r11});
+       ret->status = status;
+       ret->v0 = r9;
+       ret->v1 = r10;
+       ret->v2 = r11;
+       return IA64_NO_FAULT;
 }
 
 // given a current domain (virtual or metaphysical) address, return the 
virtual address
diff -r 4054cd60895b xen/arch/ia64/xen/hypercall.c
--- a/xen/arch/ia64/xen/hypercall.c     Mon Dec 10 13:49:22 2007 +0000
+++ b/xen/arch/ia64/xen/hypercall.c     Mon Dec 10 18:39:23 2007 +0900
@@ -184,12 +184,12 @@ ia64_hypercall(struct pt_regs *regs)
                        struct ia64_pal_retval y;
 
                        if (regs->r28 >= PAL_COPY_PAL)
-                               y = xen_pal_emulator
-                                       (regs->r28, vcpu_get_gr (v, 33),
+                               xen_pal_emulator
+                                       (&y, regs->r28, vcpu_get_gr (v, 33),
                                         vcpu_get_gr (v, 34),
                                         vcpu_get_gr (v, 35));
                        else
-                               y = xen_pal_emulator(regs->r28,regs->r29,
+                               xen_pal_emulator(&y, regs->r28,regs->r29,
                                                     regs->r30,regs->r31);
                        regs->r8 = y.status; regs->r9 = y.v0;
                        regs->r10 = y.v1; regs->r11 = y.v2;
diff -r 4054cd60895b xen/include/asm-ia64/dom_fw.h
--- a/xen/include/asm-ia64/dom_fw.h     Mon Dec 10 13:49:22 2007 +0000
+++ b/xen/include/asm-ia64/dom_fw.h     Mon Dec 10 18:39:23 2007 +0900
@@ -185,7 +185,8 @@
 
 #ifdef __XEN__
 #include <linux/efi.h>
-extern struct ia64_pal_retval xen_pal_emulator(u64, u64, u64, u64);
+#include <asm/ia64_int.h>
+extern IA64FAULT xen_pal_emulator(struct ia64_pal_retval *, u64, u64, u64, 
u64);
 extern struct sal_ret_values sal_emulator (long index, unsigned long in1, 
unsigned long in2, unsigned long in3, unsigned long in4, unsigned long in5, 
unsigned long in6, unsigned long in7);
 extern struct ia64_pal_retval pal_emulator_static (unsigned long);
 extern efi_status_t efi_emulator (struct pt_regs *regs, unsigned long *fault);
diff -r 4054cd60895b xen/include/asm-ia64/vmx_pal.h
--- a/xen/include/asm-ia64/vmx_pal.h    Mon Dec 10 13:49:22 2007 +0000
+++ b/xen/include/asm-ia64/vmx_pal.h    Mon Dec 10 18:39:23 2007 +0900
@@ -25,6 +25,7 @@
  */
 
 #include <xen/types.h>
+#include <asm/ia64_int.h>
 /* PAL PROCEDURE FOR VIRTUALIZATION */
 #define                PAL_VP_CREATE   265
 /* Stacked Virt. Initializes a new VPD for the operation of
@@ -115,7 +116,7 @@ ia64_pal_vp_save (u64 *vpd, u64 pal_proc
        PAL_CALL_STK(iprv, PAL_VP_SAVE, (u64)vpd, pal_proc_vector, 0);
        return iprv.status;
 }
-extern void pal_emul(struct vcpu *vcpu);
+extern IA64FAULT pal_emul(struct vcpu *vcpu);
 extern void sal_emul(struct vcpu *vcpu);
 #define PAL_PROC_VM_BIT                (1UL << 40)
 #define PAL_PROC_VMSW_BIT      (1UL << 54)
_______________________________________________
Xen-ia64-devel mailing list
Xen-ia64-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-ia64-devel