]> xenbits.xensource.com Git - xen.git/commitdiff
libxc: check failure of xc_dom_*_to_ptr, xc_map_foreign_range
authorIan Jackson <ian.jackson@eu.citrix.com>
Fri, 14 Jun 2013 15:45:40 +0000 (16:45 +0100)
committerIan Jackson <Ian.Jackson@eu.citrix.com>
Fri, 14 Jun 2013 15:45:40 +0000 (16:45 +0100)
The return values from xc_dom_*_to_ptr and xc_map_foreign_range are
sometimes dereferenced, or subjected to pointer arithmetic, without
checking whether the relevant function failed and returned NULL.

Add an appropriate error check at every call site.

Changes in the 4.2 backport of this series:
* Fix tools/libxc/xc_dom_x86.c:setup_pgtables_x86_32.
* Fix tools/libxc/xc_dom_ia64.c:start_info_ia64.
* Fix tools/libxc/ia64/xc_ia64_dom_fwloader.c:xc_dom_load_fw_kernel.

Conflicts in the 4.1 backport of this series:
* xc_dom_load_elf_kernel has less error handling in 4.1.
* the VM generation ID code is not in 4.1.

This is part of the fix to a security issue, XSA-55.

Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
tools/libxc/ia64/xc_ia64_dom_fwloader.c
tools/libxc/xc_dom_binloader.c
tools/libxc/xc_dom_core.c
tools/libxc/xc_dom_elfloader.c
tools/libxc/xc_dom_ia64.c
tools/libxc/xc_dom_x86.c
tools/libxc/xc_domain_restore.c
tools/libxc/xc_offline_page.c

index cdf3333e9dffe76fc60afec6a53c37124c794f12..dbd33499df5804e46e7f4be18c6f137431df0ae0 100644 (file)
@@ -60,6 +60,8 @@ static int xc_dom_load_fw_kernel(struct xc_dom_image *dom)
     unsigned long i;
 
     dest = xc_dom_vaddr_to_ptr(dom, dom->kernel_seg.vstart);
+    if ( dest == NULL )
+        return -1;
     memcpy(dest, dom->kernel_blob, FW_SIZE);
 
     /* Synchronize cache.  */
index 8596a2804c286dfeec97dd0d9156359d557d6f19..553b36637937e8bfe64dbdab8d37bb6efb0bbb71 100644 (file)
@@ -277,6 +277,12 @@ static int xc_dom_load_bin_kernel(struct xc_dom_image *dom)
     DOMPRINTF("  bss_size:  0x%" PRIx32 "", bss_size);
 
     dest = xc_dom_vaddr_to_ptr(dom, dom->kernel_seg.vstart, &dest_size);
+    if ( dest == NULL )
+    {
+        DOMPRINTF("%s: xc_dom_vaddr_to_ptr(dom, dom->kernel_seg.vstart)"
+                  " => NULL", __FUNCTION__);
+        return -EINVAL;
+    }
 
     if ( dest_size < text_size ||
          dest_size - text_size < bss_size )
index 8913e410602d96c2906bb107589bea8eaf0d87d2..a54ddae3d33dd466d9fa28c607e5ae519c74d6a3 100644 (file)
@@ -868,6 +868,12 @@ int xc_dom_build_image(struct xc_dom_image *dom)
                                   ramdisklen) != 0 )
             goto err;
         ramdiskmap = xc_dom_seg_to_ptr(dom, &dom->ramdisk_seg);
+        if ( ramdiskmap == NULL )
+        {
+            DOMPRINTF("%s: xc_dom_seg_to_ptr(dom, &dom->ramdisk_seg) => NULL",
+                      __FUNCTION__);
+            goto err;
+        }
         if ( unziplen )
         {
             if ( xc_dom_do_gunzip(dom->xch,
index 3fc88b0e6b09266cd7d2abcb63b09c404a4b6c27..aa6b5f054678f8ce7f344a5e45ed8dc48031ed8d 100644 (file)
@@ -139,6 +139,12 @@ static elf_errorstatus xc_dom_load_elf_symtab(struct xc_dom_image *dom,
             return 0;
         size = dom->kernel_seg.vend - dom->bsd_symtab_start;
         hdr_ptr = xc_dom_vaddr_to_ptr(dom, dom->bsd_symtab_start, &allow_size);
+        if ( hdr_ptr == NULL )
+        {
+            DOMPRINTF("%s/load: xc_dom_vaddr_to_ptr(dom,dom->bsd_symtab_start"
+                      " => NULL", __FUNCTION__);
+            return -1;
+        }
         elf->caller_xdest_base = hdr_ptr;
         elf->caller_xdest_size = allow_size;
         hdr = ELF_REALPTR2PTRVAL(hdr_ptr);
@@ -375,6 +381,12 @@ static elf_errorstatus xc_dom_load_elf_kernel(struct xc_dom_image *dom)
     xen_pfn_t pages;
 
     elf->dest_base = xc_dom_seg_to_ptr_pages(dom, &dom->kernel_seg, &pages);
+    if ( elf->dest_base == NULL )
+    {
+        DOMPRINTF("%s: xc_dom_vaddr_to_ptr(dom,dom->kernel_seg)"
+                  " => NULL", __FUNCTION__);
+        return -1;
+    }
     elf->dest_size = pages * XC_DOM_PAGE_SIZE(dom);
     elf_load_binary(elf);
     if ( dom->parms.bsd_symtab )
index dcd1523936c21d4b7752782a9173e8abbab4834b..7c0eff15d83f470842e2f88c624d0d137c7de118 100644 (file)
@@ -60,6 +60,12 @@ int start_info_ia64(struct xc_dom_image *dom)
 
     DOMPRINTF_CALLED(dom->xch);
 
+    if ( start_info == NULL )
+    {
+        DOMPRINTF("%s: xc_dom_pfn_to_ptr failed on start_info", __FUNCTION__);
+        return -1; /* our caller throws away our return value :-/ */
+    }
+
     memset(start_info, 0, sizeof(*start_info));
     sprintf(start_info->magic, dom->guest_type);
     start_info->flags = dom->flags;
index 0cf16877184dae51adc2ed1f92828e5d3aa9c60b..75d6b8336ca4a73349677739262d651fed042ccf 100644 (file)
@@ -144,6 +144,9 @@ static int setup_pgtables_x86_32(struct xc_dom_image *dom)
     xen_vaddr_t addr;
     xen_pfn_t pgpfn;
 
+    if ( l2tab == NULL )
+        goto pfn_error;
+
     for ( addr = dom->parms.virt_base; addr < dom->virt_pgtab_end;
           addr += PAGE_SIZE_X86 )
     {
@@ -151,6 +154,8 @@ static int setup_pgtables_x86_32(struct xc_dom_image *dom)
         {
             /* get L1 tab, make L2 entry */
             l1tab = xc_dom_pfn_to_ptr(dom, l1pfn, 1);
+            if ( l1tab == NULL )
+                goto pfn_error;
             l2off = l2_table_offset_i386(addr);
             l2tab[l2off] =
                 pfn_to_paddr(xc_dom_p2m_guest(dom, l1pfn)) | L2_PROT;
@@ -169,6 +174,11 @@ static int setup_pgtables_x86_32(struct xc_dom_image *dom)
             l1tab = NULL;
     }
     return 0;
+
+pfn_error:
+    xc_dom_panic(dom->xch, XC_INTERNAL_ERROR,
+                 "%s: xc_dom_pfn_to_ptr failed", __FUNCTION__);
+    return -EINVAL;
 }
 
 /*
@@ -219,6 +229,12 @@ static xen_pfn_t move_l3_below_4G(struct xc_dom_image *dom,
         goto out;
 
     l3tab = xc_dom_pfn_to_ptr(dom, l3pfn, 1);
+    if ( l3tab == NULL )
+    {
+        DOMPRINTF("%s: xc_dom_pfn_to_ptr(dom, l3pfn, 1) => NULL",
+                  __FUNCTION__);
+        return l3mfn; /* our one call site will call xc_dom_panic and fail */
+    }
     memset(l3tab, 0, XC_DOM_PAGE_SIZE(dom));
 
     DOMPRINTF("%s: successfully relocated L3 below 4G. "
@@ -262,6 +278,8 @@ static int setup_pgtables_x86_32_pae(struct xc_dom_image *dom)
     }
 
     l3tab = xc_dom_pfn_to_ptr(dom, l3pfn, 1);
+    if ( l3tab == NULL )
+        goto pfn_error;
 
     for ( addr = dom->parms.virt_base; addr < dom->virt_pgtab_end;
           addr += PAGE_SIZE_X86 )
@@ -270,6 +288,8 @@ static int setup_pgtables_x86_32_pae(struct xc_dom_image *dom)
         {
             /* get L2 tab, make L3 entry */
             l2tab = xc_dom_pfn_to_ptr(dom, l2pfn, 1);
+            if ( l2tab == NULL )
+                goto pfn_error;
             l3off = l3_table_offset_pae(addr);
             l3tab[l3off] =
                 pfn_to_paddr(xc_dom_p2m_guest(dom, l2pfn)) | L3_PROT;
@@ -280,6 +300,8 @@ static int setup_pgtables_x86_32_pae(struct xc_dom_image *dom)
         {
             /* get L1 tab, make L2 entry */
             l1tab = xc_dom_pfn_to_ptr(dom, l1pfn, 1);
+            if ( l1tab == NULL )
+                goto pfn_error;
             l2off = l2_table_offset_pae(addr);
             l2tab[l2off] =
                 pfn_to_paddr(xc_dom_p2m_guest(dom, l1pfn)) | L2_PROT;
@@ -306,6 +328,11 @@ static int setup_pgtables_x86_32_pae(struct xc_dom_image *dom)
         l3tab[3] = pfn_to_paddr(xc_dom_p2m_guest(dom, l2pfn)) | L3_PROT;
     }
     return 0;
+
+pfn_error:
+    xc_dom_panic(dom->xch, XC_INTERNAL_ERROR,
+                 "%s: xc_dom_pfn_to_ptr failed", __FUNCTION__);
+    return -EINVAL;
 }
 
 #undef L1_PROT
@@ -344,6 +371,9 @@ static int setup_pgtables_x86_64(struct xc_dom_image *dom)
     uint64_t addr;
     xen_pfn_t pgpfn;
 
+    if ( l4tab == NULL )
+        goto pfn_error;
+
     for ( addr = dom->parms.virt_base; addr < dom->virt_pgtab_end;
           addr += PAGE_SIZE_X86 )
     {
@@ -351,6 +381,8 @@ static int setup_pgtables_x86_64(struct xc_dom_image *dom)
         {
             /* get L3 tab, make L4 entry */
             l3tab = xc_dom_pfn_to_ptr(dom, l3pfn, 1);
+            if ( l3tab == NULL )
+                goto pfn_error;
             l4off = l4_table_offset_x86_64(addr);
             l4tab[l4off] =
                 pfn_to_paddr(xc_dom_p2m_guest(dom, l3pfn)) | L4_PROT;
@@ -361,6 +393,8 @@ static int setup_pgtables_x86_64(struct xc_dom_image *dom)
         {
             /* get L2 tab, make L3 entry */
             l2tab = xc_dom_pfn_to_ptr(dom, l2pfn, 1);
+            if ( l2tab == NULL )
+                goto pfn_error;
             l3off = l3_table_offset_x86_64(addr);
             l3tab[l3off] =
                 pfn_to_paddr(xc_dom_p2m_guest(dom, l2pfn)) | L3_PROT;
@@ -373,6 +407,8 @@ static int setup_pgtables_x86_64(struct xc_dom_image *dom)
         {
             /* get L1 tab, make L2 entry */
             l1tab = xc_dom_pfn_to_ptr(dom, l1pfn, 1);
+            if ( l1tab == NULL )
+                goto pfn_error;
             l2off = l2_table_offset_x86_64(addr);
             l2tab[l2off] =
                 pfn_to_paddr(xc_dom_p2m_guest(dom, l1pfn)) | L2_PROT;
@@ -393,6 +429,11 @@ static int setup_pgtables_x86_64(struct xc_dom_image *dom)
             l1tab = NULL;
     }
     return 0;
+
+pfn_error:
+    xc_dom_panic(dom->xch, XC_INTERNAL_ERROR,
+                 "%s: xc_dom_pfn_to_ptr failed", __FUNCTION__);
+    return -EINVAL;
 }
 
 #undef L1_PROT
@@ -410,6 +451,8 @@ static int alloc_magic_pages(struct xc_dom_image *dom)
     if ( xc_dom_alloc_segment(dom, &dom->p2m_seg, "phys2mach", 0, p2m_size) )
         return -1;
     dom->p2m_guest = xc_dom_seg_to_ptr(dom, &dom->p2m_seg);
+    if ( dom->p2m_guest == NULL )
+        return -1;
 
     /* allocate special pages */
     dom->start_info_pfn = xc_dom_alloc_page(dom, "start info");
@@ -434,6 +477,12 @@ static int start_info_x86_32(struct xc_dom_image *dom)
 
     DOMPRINTF_CALLED(dom->xch);
 
+    if ( start_info == NULL )
+    {
+        DOMPRINTF("%s: xc_dom_pfn_to_ptr failed on start_info", __FUNCTION__);
+        return -1; /* our caller throws away our return value :-/ */
+    }
+
     memset(start_info, 0, sizeof(*start_info));
     strncpy(start_info->magic, dom->guest_type, sizeof(start_info->magic));
     start_info->magic[sizeof(start_info->magic) - 1] = '\0';
@@ -474,6 +523,12 @@ static int start_info_x86_64(struct xc_dom_image *dom)
 
     DOMPRINTF_CALLED(dom->xch);
 
+    if ( start_info == NULL )
+    {
+        DOMPRINTF("%s: xc_dom_pfn_to_ptr failed on start_info", __FUNCTION__);
+        return -1; /* our caller throws away our return value :-/ */
+    }
+
     memset(start_info, 0, sizeof(*start_info));
     strncpy(start_info->magic, dom->guest_type, sizeof(start_info->magic));
     start_info->magic[sizeof(start_info->magic) - 1] = '\0';
index 95644806513f1a4dea3e9c688e5d5a543ba237b7..29af52bac6321b2e48c8914ea19173259739f4c0 100644 (file)
@@ -1434,6 +1434,11 @@ int xc_domain_restore(xc_interface *xch, int io_fd, uint32_t dom,
                 l3tab = (uint64_t *)
                     xc_map_foreign_range(xch, dom, PAGE_SIZE,
                                          PROT_READ, ctx->p2m[i]);
+                if ( l3tab == NULL )
+                {
+                    PERROR("xc_map_foreign_range failed (for l3tab)");
+                    goto out;
+                }
 
                 for ( j = 0; j < 4; j++ )
                     l3ptes[j] = l3tab[j];
@@ -1460,6 +1465,11 @@ int xc_domain_restore(xc_interface *xch, int io_fd, uint32_t dom,
                 l3tab = (uint64_t *)
                     xc_map_foreign_range(xch, dom, PAGE_SIZE,
                                          PROT_READ | PROT_WRITE, ctx->p2m[i]);
+                if ( l3tab == NULL )
+                {
+                    PERROR("xc_map_foreign_range failed (for l3tab, 2nd)");
+                    goto out;
+                }
 
                 for ( j = 0; j < 4; j++ )
                     l3tab[j] = l3ptes[j];
@@ -1630,6 +1640,12 @@ int xc_domain_restore(xc_interface *xch, int io_fd, uint32_t dom,
             SET_FIELD(ctxt, user_regs.edx, mfn);
             start_info = xc_map_foreign_range(
                 xch, dom, PAGE_SIZE, PROT_READ | PROT_WRITE, mfn);
+            if ( start_info == NULL )
+            {
+                PERROR("xc_map_foreign_range failed (for start_info)");
+                goto out;
+            }
+
             SET_FIELD(start_info, nr_pages, dinfo->p2m_size);
             SET_FIELD(start_info, shared_info, shared_info_frame<<PAGE_SHIFT);
             SET_FIELD(start_info, flags, 0);
@@ -1765,6 +1781,11 @@ int xc_domain_restore(xc_interface *xch, int io_fd, uint32_t dom,
     /* Restore contents of shared-info page. No checking needed. */
     new_shared_info = xc_map_foreign_range(
         xch, dom, PAGE_SIZE, PROT_WRITE, shared_info_frame);
+    if ( new_shared_info == NULL )
+    {
+        PERROR("xc_map_foreign_range failed (for new_shared_info)");
+        goto out;
+    }
 
     /* restore saved vcpu_info and arch specific info */
     MEMCPY_FIELD(new_shared_info, old_shared_info, vcpu_info);
index ad8e24cf3737d4040a40fefa99c229ed9751c564..7b39b59863530070ce5fd158b4aac62843268273 100644 (file)
@@ -715,6 +715,11 @@ int xc_exchange_page(xc_interface *xch, int domid, xen_pfn_t mfn)
 
         new_p = xc_map_foreign_range(xch, domid, PAGE_SIZE,
                                      PROT_READ|PROT_WRITE, new_mfn);
+        if ( new_p == NULL )
+        {
+            ERROR("failed to map new_p for copy, guest may be broken?");
+            goto failed;
+        }
         memcpy(new_p, backup, PAGE_SIZE);
         munmap(new_p, PAGE_SIZE);
         mops.arg1.mfn = new_mfn;