$NetBSD: patch-CVE-2015-2752,v 1.1 2015/04/19 13:13:20 spz Exp $ Patch for CVE-2015-2752 aka XSA-125 from http://xenbits.xenproject.org/xsa/xsa125-4.2.patch --- tools/libxc/xc_domain.c.orig 2014-09-02 06:22:57.000000000 +0000 +++ tools/libxc/xc_domain.c @@ -1352,6 +1352,13 @@ int xc_domain_bind_pt_isa_irq( PT_IRQ_TYPE_ISA, 0, 0, 0, machine_irq)); } +#ifndef min +#define min(X, Y) ({ \ + const typeof (X) _x = (X); \ + const typeof (Y) _y = (Y); \ + (void) (&_x == &_y); \ + (_x < _y) ? _x : _y; }) +#endif int xc_domain_memory_mapping( xc_interface *xch, uint32_t domid, @@ -1361,17 +1368,55 @@ int xc_domain_memory_mapping( uint32_t add_mapping) { DECLARE_DOMCTL; + int ret = 0, err; + unsigned long done = 0, nr, max_batch_sz; + + if ( !nr_mfns ) + return 0; domctl.cmd = XEN_DOMCTL_memory_mapping; domctl.domain = domid; - domctl.u.memory_mapping.first_gfn = first_gfn; - domctl.u.memory_mapping.first_mfn = first_mfn; - domctl.u.memory_mapping.nr_mfns = nr_mfns; domctl.u.memory_mapping.add_mapping = add_mapping; + max_batch_sz = nr_mfns; + do + { + nr = min(nr_mfns - done, max_batch_sz); + domctl.u.memory_mapping.nr_mfns = nr; + domctl.u.memory_mapping.first_gfn = first_gfn + done; + domctl.u.memory_mapping.first_mfn = first_mfn + done; + err = do_domctl(xch, &domctl); + if ( err && errno == E2BIG ) + { + if ( max_batch_sz <= 1 ) + break; + max_batch_sz >>= 1; + continue; + } + /* Save the first error... */ + if ( !ret ) + ret = err; + /* .. and ignore the rest of them when removing. */ + if ( err && add_mapping != DPCI_REMOVE_MAPPING ) + break; + + done += nr; + } while ( done < nr_mfns ); + + /* + * Undo what we have done unless unmapping, by unmapping the entire region. + * Errors here are ignored. + */ + if ( ret && add_mapping != DPCI_REMOVE_MAPPING ) + xc_domain_memory_mapping(xch, domid, first_gfn, first_mfn, nr_mfns, + DPCI_REMOVE_MAPPING); + + /* We might get E2BIG so many times that we never advance. */ + if ( !done && !ret ) + ret = -1; - return do_domctl(xch, &domctl); + return ret; } - +#undef min int xc_domain_ioport_mapping( xc_interface *xch, uint32_t domid, --- xen/arch/x86/domctl.c.orig 2014-09-02 06:22:57.000000000 +0000 +++ xen/arch/x86/domctl.c @@ -865,6 +865,11 @@ long arch_do_domctl( (gfn + nr_mfns - 1) < gfn ) /* wrap? */ break; + ret = -E2BIG; + /* Must break hypercall up as this could take a while. */ + if ( nr_mfns > 64 ) + break; + ret = -EPERM; if ( !IS_PRIV(current->domain) && !iomem_access_permitted(current->domain, mfn, mfn + nr_mfns - 1) ) --- xen/include/public/domctl.h.orig 2014-09-02 06:22:57.000000000 +0000 +++ xen/include/public/domctl.h @@ -507,6 +507,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_bind_ /* Bind machine I/O address range -> HVM address range. */ +/* If this returns -E2BIG lower nr_mfns value. */ /* XEN_DOMCTL_memory_mapping */ #define DPCI_ADD_MAPPING 1 #define DPCI_REMOVE_MAPPING 0