262 lines
7.5 KiB
Plaintext
262 lines
7.5 KiB
Plaintext
$NetBSD: patch-CVE-2013-1918_11,v 1.1 2013/05/03 16:48:37 drochner Exp $
|
|
|
|
--- xen/arch/x86/domain.c.orig 2013-05-03 13:27:23.000000000 +0000
|
|
+++ xen/arch/x86/domain.c
|
|
@@ -70,8 +70,6 @@ void (*dead_idle) (void) __read_mostly =
|
|
static void paravirt_ctxt_switch_from(struct vcpu *v);
|
|
static void paravirt_ctxt_switch_to(struct vcpu *v);
|
|
|
|
-static void vcpu_destroy_pagetables(struct vcpu *v);
|
|
-
|
|
static void continue_idle_domain(struct vcpu *v)
|
|
{
|
|
reset_stack_and_jump(idle_loop);
|
|
@@ -678,6 +676,7 @@ int arch_set_info_guest(
|
|
{
|
|
struct domain *d = v->domain;
|
|
unsigned long cr3_pfn = INVALID_MFN;
|
|
+ struct page_info *cr3_page;
|
|
unsigned long flags, cr4;
|
|
int i, rc = 0, compat;
|
|
|
|
@@ -817,72 +816,103 @@ int arch_set_info_guest(
|
|
if ( rc != 0 )
|
|
return rc;
|
|
|
|
+ set_bit(_VPF_in_reset, &v->pause_flags);
|
|
+
|
|
if ( !compat )
|
|
- {
|
|
cr3_pfn = gmfn_to_mfn(d, xen_cr3_to_pfn(c.nat->ctrlreg[3]));
|
|
+#ifdef __x86_64__
|
|
+ else
|
|
+ cr3_pfn = gmfn_to_mfn(d, compat_cr3_to_pfn(c.cmp->ctrlreg[3]));
|
|
+#endif
|
|
+ cr3_page = mfn_to_page(cr3_pfn);
|
|
|
|
- if ( !mfn_valid(cr3_pfn) ||
|
|
- (paging_mode_refcounts(d)
|
|
- ? !get_page(mfn_to_page(cr3_pfn), d)
|
|
- : !get_page_and_type(mfn_to_page(cr3_pfn), d,
|
|
- PGT_base_page_table)) )
|
|
- {
|
|
- destroy_gdt(v);
|
|
- return -EINVAL;
|
|
- }
|
|
+ if ( !mfn_valid(cr3_pfn) || !get_page(cr3_page, d) )
|
|
+ {
|
|
+ cr3_page = NULL;
|
|
+ rc = -EINVAL;
|
|
+ }
|
|
+ else if ( paging_mode_refcounts(d) )
|
|
+ /* nothing */;
|
|
+ else if ( cr3_page == v->arch.old_guest_table )
|
|
+ {
|
|
+ v->arch.old_guest_table = NULL;
|
|
+ put_page(cr3_page);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /*
|
|
+ * Since v->arch.guest_table{,_user} are both NULL, this effectively
|
|
+ * is just a call to put_old_guest_table().
|
|
+ */
|
|
+ if ( !compat )
|
|
+ rc = vcpu_destroy_pagetables(v);
|
|
+ if ( !rc )
|
|
+ rc = get_page_type_preemptible(cr3_page,
|
|
+ !compat ? PGT_root_page_table
|
|
+ : PGT_l3_page_table);
|
|
+ if ( rc == -EINTR )
|
|
+ rc = -EAGAIN;
|
|
+ }
|
|
|
|
+ if ( rc )
|
|
+ /* handled below */;
|
|
+ else if ( !compat )
|
|
+ {
|
|
v->arch.guest_table = pagetable_from_pfn(cr3_pfn);
|
|
|
|
#ifdef __x86_64__
|
|
if ( c.nat->ctrlreg[1] )
|
|
{
|
|
cr3_pfn = gmfn_to_mfn(d, xen_cr3_to_pfn(c.nat->ctrlreg[1]));
|
|
+ cr3_page = mfn_to_page(cr3_pfn);
|
|
|
|
- if ( !mfn_valid(cr3_pfn) ||
|
|
- (paging_mode_refcounts(d)
|
|
- ? !get_page(mfn_to_page(cr3_pfn), d)
|
|
- : !get_page_and_type(mfn_to_page(cr3_pfn), d,
|
|
- PGT_base_page_table)) )
|
|
+ if ( !mfn_valid(cr3_pfn) || !get_page(cr3_page, d) )
|
|
{
|
|
- cr3_pfn = pagetable_get_pfn(v->arch.guest_table);
|
|
- v->arch.guest_table = pagetable_null();
|
|
- if ( paging_mode_refcounts(d) )
|
|
- put_page(mfn_to_page(cr3_pfn));
|
|
- else
|
|
- put_page_and_type(mfn_to_page(cr3_pfn));
|
|
- destroy_gdt(v);
|
|
- return -EINVAL;
|
|
+ cr3_page = NULL;
|
|
+ rc = -EINVAL;
|
|
+ }
|
|
+ else if ( !paging_mode_refcounts(d) )
|
|
+ {
|
|
+ rc = get_page_type_preemptible(cr3_page, PGT_root_page_table);
|
|
+ switch ( rc )
|
|
+ {
|
|
+ case -EINTR:
|
|
+ rc = -EAGAIN;
|
|
+ case -EAGAIN:
|
|
+ v->arch.old_guest_table =
|
|
+ pagetable_get_page(v->arch.guest_table);
|
|
+ v->arch.guest_table = pagetable_null();
|
|
+ break;
|
|
+ }
|
|
}
|
|
|
|
- v->arch.guest_table_user = pagetable_from_pfn(cr3_pfn);
|
|
+ if ( !rc )
|
|
+ v->arch.guest_table_user = pagetable_from_pfn(cr3_pfn);
|
|
}
|
|
else if ( !(flags & VGCF_in_kernel) )
|
|
{
|
|
- destroy_gdt(v);
|
|
- return -EINVAL;
|
|
+ cr3_page = NULL;
|
|
+ rc = -EINVAL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
l4_pgentry_t *l4tab;
|
|
|
|
- cr3_pfn = gmfn_to_mfn(d, compat_cr3_to_pfn(c.cmp->ctrlreg[3]));
|
|
-
|
|
- if ( !mfn_valid(cr3_pfn) ||
|
|
- (paging_mode_refcounts(d)
|
|
- ? !get_page(mfn_to_page(cr3_pfn), d)
|
|
- : !get_page_and_type(mfn_to_page(cr3_pfn), d,
|
|
- PGT_l3_page_table)) )
|
|
- {
|
|
- destroy_gdt(v);
|
|
- return -EINVAL;
|
|
- }
|
|
-
|
|
l4tab = __va(pagetable_get_paddr(v->arch.guest_table));
|
|
*l4tab = l4e_from_pfn(
|
|
cr3_pfn, _PAGE_PRESENT|_PAGE_RW|_PAGE_USER|_PAGE_ACCESSED);
|
|
#endif
|
|
}
|
|
+ if ( rc )
|
|
+ {
|
|
+ if ( cr3_page )
|
|
+ put_page(cr3_page);
|
|
+ destroy_gdt(v);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ clear_bit(_VPF_in_reset, &v->pause_flags);
|
|
|
|
if ( v->vcpu_id == 0 )
|
|
update_domain_wallclock_time(d);
|
|
@@ -904,17 +934,16 @@ int arch_set_info_guest(
|
|
#undef c
|
|
}
|
|
|
|
-void arch_vcpu_reset(struct vcpu *v)
|
|
+int arch_vcpu_reset(struct vcpu *v)
|
|
{
|
|
if ( !is_hvm_vcpu(v) )
|
|
{
|
|
destroy_gdt(v);
|
|
- vcpu_destroy_pagetables(v);
|
|
- }
|
|
- else
|
|
- {
|
|
- vcpu_end_shutdown_deferral(v);
|
|
+ return vcpu_destroy_pagetables(v);
|
|
}
|
|
+
|
|
+ vcpu_end_shutdown_deferral(v);
|
|
+ return 0;
|
|
}
|
|
|
|
/*
|
|
@@ -1917,63 +1946,6 @@ static int relinquish_memory(
|
|
return ret;
|
|
}
|
|
|
|
-static void vcpu_destroy_pagetables(struct vcpu *v)
|
|
-{
|
|
- struct domain *d = v->domain;
|
|
- unsigned long pfn;
|
|
-
|
|
-#ifdef __x86_64__
|
|
- if ( is_pv_32on64_vcpu(v) )
|
|
- {
|
|
- pfn = l4e_get_pfn(*(l4_pgentry_t *)
|
|
- __va(pagetable_get_paddr(v->arch.guest_table)));
|
|
-
|
|
- if ( pfn != 0 )
|
|
- {
|
|
- if ( paging_mode_refcounts(d) )
|
|
- put_page(mfn_to_page(pfn));
|
|
- else
|
|
- put_page_and_type(mfn_to_page(pfn));
|
|
- }
|
|
-
|
|
- l4e_write(
|
|
- (l4_pgentry_t *)__va(pagetable_get_paddr(v->arch.guest_table)),
|
|
- l4e_empty());
|
|
-
|
|
- v->arch.cr3 = 0;
|
|
- return;
|
|
- }
|
|
-#endif
|
|
-
|
|
- pfn = pagetable_get_pfn(v->arch.guest_table);
|
|
- if ( pfn != 0 )
|
|
- {
|
|
- if ( paging_mode_refcounts(d) )
|
|
- put_page(mfn_to_page(pfn));
|
|
- else
|
|
- put_page_and_type(mfn_to_page(pfn));
|
|
- v->arch.guest_table = pagetable_null();
|
|
- }
|
|
-
|
|
-#ifdef __x86_64__
|
|
- /* Drop ref to guest_table_user (from MMUEXT_NEW_USER_BASEPTR) */
|
|
- pfn = pagetable_get_pfn(v->arch.guest_table_user);
|
|
- if ( pfn != 0 )
|
|
- {
|
|
- if ( !is_pv_32bit_vcpu(v) )
|
|
- {
|
|
- if ( paging_mode_refcounts(d) )
|
|
- put_page(mfn_to_page(pfn));
|
|
- else
|
|
- put_page_and_type(mfn_to_page(pfn));
|
|
- }
|
|
- v->arch.guest_table_user = pagetable_null();
|
|
- }
|
|
-#endif
|
|
-
|
|
- v->arch.cr3 = 0;
|
|
-}
|
|
-
|
|
int domain_relinquish_resources(struct domain *d)
|
|
{
|
|
int ret;
|
|
@@ -1992,7 +1964,9 @@ int domain_relinquish_resources(struct d
|
|
for_each_vcpu ( d, v )
|
|
{
|
|
/* Drop the in-use references to page-table bases. */
|
|
- vcpu_destroy_pagetables(v);
|
|
+ ret = vcpu_destroy_pagetables(v);
|
|
+ if ( ret )
|
|
+ return ret;
|
|
|
|
/*
|
|
* Relinquish GDT mappings. No need for explicit unmapping of the
|