Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP2:Update
xen.12882
xsa273-4.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File xsa273-4.patch of Package xen.12882
x86/mm: Plumbing to allow any PTE update to fail with -ERESTART Switching to shadow mode is performed in tasklet context. To facilitate this, we schedule the tasklet, then create a hypercall continuation to allow the switch to take place. As a consequence, the x86 mm code needs to cope with an L1e operation being continuable. do_mmu{,ext}_op() may no longer assert that a continuation doesn't happen on the final iteration. To handle the arguments correctly on continuation, compat_update_va_mapping*() may no longer call into their non-compat counterparts. Move the compat functions into mm.c rather than exporting __do_update_va_mapping() and {get,put}_pg_owner(), and fix an unsigned long/int inconsistency with compat_update_va_mapping_otherdomain(). This is part of XSA-273 / CVE-2018-3620. Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com> Reviewed-by: Jan Beulich <jbeulich@suse.com> --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -746,6 +746,8 @@ static int get_page_from_pagenr(unsigned return 1; } +static int __get_page_type(struct page_info *page, unsigned long type, + int preemptible); static int get_page_and_type_from_pagenr(unsigned long page_nr, unsigned long type, @@ -760,9 +762,7 @@ static int get_page_and_type_from_pagenr unlikely(!get_page_from_pagenr(page_nr, d)) ) return -EINVAL; - rc = (preemptible ? - get_page_type_preemptible(page, type) : - (get_page_type(page, type) ? 0 : -EINVAL)); + rc = __get_page_type(page, type, preemptible); if ( unlikely(rc) && partial >= 0 && (!preemptible || page != current->arch.old_guest_table) ) @@ -1609,8 +1609,7 @@ static int create_pae_xen_mappings(struc return 1; } -static int alloc_l2_table(struct page_info *page, unsigned long type, - int preemptible) +static int alloc_l2_table(struct page_info *page, unsigned long type) { struct domain *d = page_get_owner(page); unsigned long pfn = page_to_mfn(page); @@ -1622,8 +1621,7 @@ static int alloc_l2_table(struct page_in for ( i = page->nr_validated_ptes; i < L2_PAGETABLE_ENTRIES; i++ ) { - if ( preemptible && i > page->nr_validated_ptes - && hypercall_preempt_check() ) + if ( i > page->nr_validated_ptes && hypercall_preempt_check() ) { page->nr_validated_ptes = i; rc = -ERESTART; @@ -1634,6 +1632,12 @@ static int alloc_l2_table(struct page_in (rc = get_page_from_l2e(pl2e[i], pfn, d)) > 0 ) continue; + if ( unlikely(rc == -ERESTART) ) + { + page->nr_validated_ptes = i; + break; + } + if ( rc < 0 ) { MEM_LOG("Failure in alloc_l2_table: entry %d", i); @@ -1858,7 +1862,7 @@ static void free_l1_table(struct page_in } -static int free_l2_table(struct page_info *page, int preemptible) +static int free_l2_table(struct page_info *page) { struct domain *d = page_get_owner(page); unsigned long pfn = page_to_mfn(page); @@ -1872,7 +1876,7 @@ static int free_l2_table(struct page_inf do { if ( is_guest_l2_slot(d, page->u.inuse.type_info, i) && put_page_from_l2e(pl2e[i], pfn) == 0 && - preemptible && i && hypercall_preempt_check() ) + i && hypercall_preempt_check() ) { page->nr_validated_ptes = i; err = -ERESTART; @@ -2477,7 +2481,8 @@ static int alloc_page_type(struct page_i rc = alloc_l1_table(page); break; case PGT_l2_page_table: - rc = alloc_l2_table(page, type, preemptible); + ASSERT(preemptible); + rc = alloc_l2_table(page, type); break; case PGT_l3_page_table: ASSERT(preemptible); @@ -2568,7 +2573,8 @@ int free_page_type(struct page_info *pag rc = 0; break; case PGT_l2_page_table: - rc = free_l2_table(page, preemptible); + ASSERT(preemptible); + rc = free_l2_table(page); break; case PGT_l3_page_table: ASSERT(preemptible); @@ -3855,12 +3861,9 @@ long do_mmuext_op( } if ( rc == -ERESTART ) - { - ASSERT(i < count); rc = hypercall_create_continuation( __HYPERVISOR_mmuext_op, "hihi", uops, (count - i) | MMU_UPDATE_PREEMPTED, pdone, foreigndom); - } else if ( curr->arch.old_guest_table ) { XEN_GUEST_HANDLE_PARAM(void) null; @@ -4151,12 +4154,9 @@ long do_mmu_update( } if ( rc == -ERESTART ) - { - ASSERT(i < count); rc = hypercall_create_continuation( __HYPERVISOR_mmu_update, "hihi", ureqs, (count - i) | MMU_UPDATE_PREEMPTED, pdone, foreigndom); - } else if ( curr->arch.old_guest_table ) { XEN_GUEST_HANDLE_PARAM(void) null; @@ -4864,7 +4864,13 @@ static int __do_update_va_mapping( long do_update_va_mapping(unsigned long va, u64 val64, unsigned long flags) { - return __do_update_va_mapping(va, val64, flags, current->domain); + int rc = __do_update_va_mapping(va, val64, flags, current->domain); + + if ( rc == -ERESTART ) + rc = hypercall_create_continuation( + __HYPERVISOR_update_va_mapping, "lll", va, val64, flags); + + return rc; } long do_update_va_mapping_otherdomain(unsigned long va, u64 val64, @@ -4881,6 +4887,46 @@ long do_update_va_mapping_otherdomain(un put_pg_owner(pg_owner); + if ( rc == -ERESTART ) + rc = hypercall_create_continuation( + __HYPERVISOR_update_va_mapping_otherdomain, + "llli", va, val64, flags, domid); + + return rc; +} + +int compat_update_va_mapping(unsigned int va, uint32_t lo, uint32_t hi, + unsigned int flags) +{ + int rc = __do_update_va_mapping(va, ((uint64_t)hi << 32) | lo, + flags, current->domain); + + if ( rc == -ERESTART ) + rc = hypercall_create_continuation( + __HYPERVISOR_update_va_mapping, "iiii", va, lo, hi, flags); + + return rc; +} + +int compat_update_va_mapping_otherdomain(unsigned int va, + uint32_t lo, uint32_t hi, + unsigned int flags, domid_t domid) +{ + struct domain *pg_owner; + int rc; + + if ( (pg_owner = get_pg_owner(domid)) == NULL ) + return -ESRCH; + + rc = __do_update_va_mapping(va, ((uint64_t)hi << 32) | lo, flags, pg_owner); + + put_pg_owner(pg_owner); + + if ( rc == -ERESTART ) + rc = hypercall_create_continuation( + __HYPERVISOR_update_va_mapping_otherdomain, + "iiiii", va, lo, hi, flags, domid); + return rc; } --- a/xen/arch/x86/x86_64/compat/mm.c +++ b/xen/arch/x86/x86_64/compat/mm.c @@ -200,19 +200,6 @@ int compat_arch_memory_op(unsigned long return rc; } -int compat_update_va_mapping(unsigned int va, u32 lo, u32 hi, - unsigned int flags) -{ - return do_update_va_mapping(va, lo | ((u64)hi << 32), flags); -} - -int compat_update_va_mapping_otherdomain(unsigned long va, u32 lo, u32 hi, - unsigned long flags, - domid_t domid) -{ - return do_update_va_mapping_otherdomain(va, lo | ((u64)hi << 32), flags, domid); -} - DEFINE_XEN_GUEST_HANDLE(mmuext_op_compat_t); int compat_mmuext_op(XEN_GUEST_HANDLE_PARAM(void) arg,
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor