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

Re: [Xen-ia64-devel] [PATCH] Fix vulnerability of copy_to_user in PAL em

To: Alex Williamson <alex.williamson@xxxxxx>
Subject: Re: [Xen-ia64-devel] [PATCH] Fix vulnerability of copy_to_user in PAL emulation
From: Kouya Shimura <kouya@xxxxxxxxxxxxxx>
Date: Wed, 12 Dec 2007 13:07:13 +0900
Cc: xen-ia64-devel@xxxxxxxxxxxxxxxxxxx
Delivery-date: Tue, 11 Dec 2007 20:07:32 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
In-reply-to: <1197391269.7945.43.camel@lappy>
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>
References: <7k8x41puy7.fsf@xxxxxxxxxxxxxxxxxxxxxxxxxx> <1197391269.7945.43.camel@lappy>
Sender: xen-ia64-devel-bounces@xxxxxxxxxxxxxxxxxxx
Hi Alex,

Thank you for reviewing. 
I updated the patch as your comments. please apply.
I also long for a xencomm.

Thanks,
Kouya

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

Alex Williamson writes:
>    I think there's a off by one issue as noted below.  Also a few
> cleanups.  Like Tristan, I'd rather see a xencomm for GFW, but that
> might be too intrusive for 3.2 at this point.  So this seems like a
> reasonable temporary fix.  Thanks,

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 15:02:02 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     Wed Dec 12 11:47:04 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,10 @@ 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;
+                fault = pal_emul(v);
+                if (fault == 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       Wed Dec 12 12:06:17 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,98 @@ 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 - 1))
+               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;
+               maddr = paddr_to_maddr(paddr);
+               if (maddr == 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 +698,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 +709,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 +897,23 @@ 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, sizeof(pm_buffer));
+                       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, sizeof(pm_buffer)))
+                                       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 +935,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 +990,20 @@ 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, sizeof(brand_info));
+                       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, 
+                                               sizeof(brand_info)))
+                                       status = PAL_STATUS_ERROR;
+                       }
+                       palcomm_done(&comm);
                } else {
                        status = PAL_STATUS_EINVAL;
                }
@@ -901,7 +1017,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     Tue Dec 11 15:02:02 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     Tue Dec 11 15:02:02 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    Tue Dec 11 15:02:02 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