xen/5548e95d-x86-allow-to-suppress-M2P-user-mode-exposure.patch
Charles Arnold f158f55e6a - Update to Xen 4.5.2
xen-4.5.2-testing-src.tar.bz2
- Drop the following
  xen-4.5.1-testing-src.tar.bz2
  552d0f49-x86-traps-identify-the-vcpu-in-context-when-dumping-regs.patch
  5576f178-kexec-add-more-pages-to-v1-environment.patch
  55780be1-x86-EFI-adjust-EFI_MEMORY_WP-handling-for-spec-version-2.5.patch
  558bfaa0-x86-traps-avoid-using-current-too-early.patch
  5592a116-nested-EPT-fix-the-handling-of-nested-EPT.patch
  559b9dd6-x86-p2m-ept-don-t-unmap-in-use-EPT-pagetable.patch
  559bc633-x86-cpupool-clear-proper-cpu_valid-bit-on-CPU-teardown.patch
  559bc64e-credit1-properly-deal-with-CPUs-not-in-any-pool.patch
  559bc87f-x86-hvmloader-avoid-data-corruption-with-xenstore-rw.patch
  559bdde5-pull-in-latest-linux-earlycpio.patch
  55a62eb0-xl-correct-handling-of-extra_config-in-main_cpupoolcreate.patch
  55a66a1e-make-rangeset_report_ranges-report-all-ranges.patch
  55a77e4f-dmar-device-scope-mem-leak-fix.patch
  55c1d83d-x86-gdt-Drop-write-only-xalloc-d-array.patch
  55c3232b-x86-mm-Make-hap-shadow-teardown-preemptible.patch
  55dc78e9-x86-amd_ucode-skip-updates-for-final-levels.patch
  55df2f76-IOMMU-skip-domains-without-page-tables-when-dumping.patch
  55e43fd8-x86-NUMA-fix-setup_node.patch
  55e43ff8-x86-NUMA-don-t-account-hotplug-regions.patch
  55e593f1-x86-NUMA-make-init_node_heap-respect-Xen-heap-limit.patch
  55f2e438-x86-hvm-fix-saved-pmtimer-and-hpet-values.patch
  55f9345b-x86-MSI-fail-if-no-hardware-support.patch
  5604f2e6-vt-d-fix-IM-bit-mask-and-unmask-of-FECTL_REG.patch
  560a4af9-x86-EPT-tighten-conditions-of-IOMMU-mapping-updates.patch
  560a7c36-x86-p2m-pt-delay-freeing-of-intermediate-page-tables.patch
  560a7c53-x86-p2m-pt-ignore-pt-share-flag-for-shadow-mode-guests.patch

OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=384
2015-11-04 20:30:31 +00:00

267 lines
11 KiB
Diff

# Commit d72a4605e18d3a61c4469ff092dbbbfa4ac919f7
# Date 2015-05-05 18:01:33 +0200
# Author Jan Beulich <jbeulich@suse.com>
# Committer Jan Beulich <jbeulich@suse.com>
x86: allow 64-bit PV guest kernels to suppress user mode exposure of M2P
Xen L4 entries being uniformly installed into any L4 table and 64-bit
PV kernels running in ring 3 means that user mode was able to see the
read-only M2P presented by Xen to the guests. While apparently not
really representing an exploitable information leak, this still very
certainly was never meant to be that way.
Building on the fact that these guests already have separate kernel and
user mode page tables we can allow guest kernels to tell Xen that they
don't want user mode to see this table. We can't, however, do this by
default: There is no ABI requirement that kernel and user mode page
tables be separate. Therefore introduce a new VM-assist flag allowing
the guest to control respective hypervisor behavior:
- when not set, L4 tables get created with the respective slot blank,
and whenever the L4 table gets used as a kernel one the missing
mapping gets inserted,
- when set, L4 tables get created with the respective slot initialized
as before, and whenever the L4 table gets used as a user one the
mapping gets zapped.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Tim Deegan <tim@xen.org>
Index: xen-4.5.2-testing/xen/arch/x86/domain.c
===================================================================
--- xen-4.5.2-testing.orig/xen/arch/x86/domain.c
+++ xen-4.5.2-testing/xen/arch/x86/domain.c
@@ -338,7 +338,7 @@ static int setup_compat_l4(struct vcpu *
l4tab = __map_domain_page(pg);
clear_page(l4tab);
- init_guest_l4_table(l4tab, v->domain);
+ init_guest_l4_table(l4tab, v->domain, 1);
unmap_domain_page(l4tab);
v->arch.guest_table = pagetable_from_page(pg);
@@ -977,7 +977,11 @@ int arch_set_info_guest(
case -EINTR:
rc = -ERESTART;
case -ERESTART:
+ break;
case 0:
+ if ( !compat && !VM_ASSIST(d, VMASST_TYPE_m2p_strict) &&
+ !paging_mode_refcounts(d) )
+ fill_ro_mpt(cr3_gfn);
break;
default:
if ( cr3_page == current->arch.old_guest_table )
@@ -1012,7 +1016,10 @@ int arch_set_info_guest(
default:
if ( cr3_page == current->arch.old_guest_table )
cr3_page = NULL;
+ break;
case 0:
+ if ( VM_ASSIST(d, VMASST_TYPE_m2p_strict) )
+ zap_ro_mpt(cr3_gfn);
break;
}
}
Index: xen-4.5.2-testing/xen/arch/x86/domain_build.c
===================================================================
--- xen-4.5.2-testing.orig/xen/arch/x86/domain_build.c
+++ xen-4.5.2-testing/xen/arch/x86/domain_build.c
@@ -1096,7 +1096,7 @@ int __init construct_dom0(
l3start = __va(mpt_alloc); mpt_alloc += PAGE_SIZE;
}
clear_page(l4tab);
- init_guest_l4_table(l4tab, d);
+ init_guest_l4_table(l4tab, d, 0);
v->arch.guest_table = pagetable_from_paddr(__pa(l4start));
if ( is_pv_32on64_domain(d) )
v->arch.guest_table_user = v->arch.guest_table;
Index: xen-4.5.2-testing/xen/arch/x86/mm.c
===================================================================
--- xen-4.5.2-testing.orig/xen/arch/x86/mm.c
+++ xen-4.5.2-testing/xen/arch/x86/mm.c
@@ -1383,7 +1383,8 @@ static int alloc_l3_table(struct page_in
return rc > 0 ? 0 : rc;
}
-void init_guest_l4_table(l4_pgentry_t l4tab[], const struct domain *d)
+void init_guest_l4_table(l4_pgentry_t l4tab[], const struct domain *d,
+ bool_t zap_ro_mpt)
{
/* Xen private mappings. */
memcpy(&l4tab[ROOT_PAGETABLE_FIRST_XEN_SLOT],
@@ -1398,6 +1399,25 @@ void init_guest_l4_table(l4_pgentry_t l4
l4e_from_pfn(domain_page_map_to_mfn(l4tab), __PAGE_HYPERVISOR);
l4tab[l4_table_offset(PERDOMAIN_VIRT_START)] =
l4e_from_page(d->arch.perdomain_l3_pg, __PAGE_HYPERVISOR);
+ if ( zap_ro_mpt || is_pv_32on64_domain(d) || paging_mode_refcounts(d) )
+ l4tab[l4_table_offset(RO_MPT_VIRT_START)] = l4e_empty();
+}
+
+void fill_ro_mpt(unsigned long mfn)
+{
+ l4_pgentry_t *l4tab = map_domain_page(mfn);
+
+ l4tab[l4_table_offset(RO_MPT_VIRT_START)] =
+ idle_pg_table[l4_table_offset(RO_MPT_VIRT_START)];
+ unmap_domain_page(l4tab);
+}
+
+void zap_ro_mpt(unsigned long mfn)
+{
+ l4_pgentry_t *l4tab = map_domain_page(mfn);
+
+ l4tab[l4_table_offset(RO_MPT_VIRT_START)] = l4e_empty();
+ unmap_domain_page(l4tab);
}
static int alloc_l4_table(struct page_info *page)
@@ -1447,7 +1467,7 @@ static int alloc_l4_table(struct page_in
adjust_guest_l4e(pl4e[i], d);
}
- init_guest_l4_table(pl4e, d);
+ init_guest_l4_table(pl4e, d, !VM_ASSIST(d, VMASST_TYPE_m2p_strict));
unmap_domain_page(pl4e);
return rc > 0 ? 0 : rc;
@@ -2761,6 +2781,8 @@ int new_guest_cr3(unsigned long mfn)
invalidate_shadow_ldt(curr, 0);
+ if ( !VM_ASSIST(d, VMASST_TYPE_m2p_strict) && !paging_mode_refcounts(d) )
+ fill_ro_mpt(mfn);
curr->arch.guest_table = pagetable_from_pfn(mfn);
update_cr3(curr);
@@ -3117,6 +3139,9 @@ long do_mmuext_op(
op.arg1.mfn);
break;
}
+ if ( VM_ASSIST(d, VMASST_TYPE_m2p_strict) &&
+ !paging_mode_refcounts(d) )
+ zap_ro_mpt(op.arg1.mfn);
}
curr->arch.guest_table_user = pagetable_from_pfn(op.arg1.mfn);
Index: xen-4.5.2-testing/xen/arch/x86/mm/shadow/multi.c
===================================================================
--- xen-4.5.2-testing.orig/xen/arch/x86/mm/shadow/multi.c
+++ xen-4.5.2-testing/xen/arch/x86/mm/shadow/multi.c
@@ -1438,6 +1438,13 @@ void sh_install_xen_entries_in_l4(struct
shadow_l4e_from_mfn(page_to_mfn(d->arch.perdomain_l3_pg),
__PAGE_HYPERVISOR);
+ if ( !shadow_mode_external(d) && !is_pv_32on64_domain(d) &&
+ !VM_ASSIST(d, VMASST_TYPE_m2p_strict) )
+ {
+ /* open coded zap_ro_mpt(mfn_x(sl4mfn)): */
+ sl4e[shadow_l4_table_offset(RO_MPT_VIRT_START)] = shadow_l4e_empty();
+ }
+
/* Shadow linear mapping for 4-level shadows. N.B. for 3-level
* shadows on 64-bit xen, this linear mapping is later replaced by the
* monitor pagetable structure, which is built in make_monitor_table
@@ -4062,6 +4069,17 @@ sh_update_cr3(struct vcpu *v, int do_loc
if ( sh_remove_write_access(v, gmfn, 4, 0) != 0 )
flush_tlb_mask(d->domain_dirty_cpumask);
sh_set_toplevel_shadow(v, 0, gmfn, SH_type_l4_shadow);
+ if ( !shadow_mode_external(d) && !is_pv_32on64_domain(d) )
+ {
+ mfn_t smfn = pagetable_get_mfn(v->arch.shadow_table[0]);
+
+ if ( !(v->arch.flags & TF_kernel_mode) &&
+ VM_ASSIST(d, VMASST_TYPE_m2p_strict) )
+ zap_ro_mpt(mfn_x(smfn));
+ else if ( (v->arch.flags & TF_kernel_mode) &&
+ !VM_ASSIST(d, VMASST_TYPE_m2p_strict) )
+ fill_ro_mpt(mfn_x(smfn));
+ }
#else
#error This should never happen
#endif
Index: xen-4.5.2-testing/xen/arch/x86/x86_64/mm.c
===================================================================
--- xen-4.5.2-testing.orig/xen/arch/x86/x86_64/mm.c
+++ xen-4.5.2-testing/xen/arch/x86/x86_64/mm.c
@@ -480,7 +480,7 @@ static int setup_m2p_table(struct mem_ho
l2_ro_mpt += l2_table_offset(va);
}
- /* NB. Cannot be GLOBAL as shadow_mode_translate reuses this area. */
+ /* NB. Cannot be GLOBAL: guest user mode should not see it. */
l2e_write(l2_ro_mpt, l2e_from_pfn(mfn,
/*_PAGE_GLOBAL|*/_PAGE_PSE|_PAGE_USER|_PAGE_PRESENT));
}
@@ -583,7 +583,7 @@ void __init paging_init(void)
0x77, 1UL << L3_PAGETABLE_SHIFT);
ASSERT(!l2_table_offset(va));
- /* NB. Cannot be GLOBAL as shadow_mode_translate reuses this area. */
+ /* NB. Cannot be GLOBAL: guest user mode should not see it. */
l3e_write(&l3_ro_mpt[l3_table_offset(va)],
l3e_from_page(l1_pg,
/*_PAGE_GLOBAL|*/_PAGE_PSE|_PAGE_USER|_PAGE_PRESENT));
@@ -621,7 +621,7 @@ void __init paging_init(void)
l3e_from_page(l2_pg, __PAGE_HYPERVISOR | _PAGE_USER));
ASSERT(!l2_table_offset(va));
}
- /* NB. Cannot be GLOBAL as shadow_mode_translate reuses this area. */
+ /* NB. Cannot be GLOBAL: guest user mode should not see it. */
if ( l1_pg )
l2e_write(l2_ro_mpt, l2e_from_page(
l1_pg, /*_PAGE_GLOBAL|*/_PAGE_PSE|_PAGE_USER|_PAGE_PRESENT));
Index: xen-4.5.2-testing/xen/include/asm-x86/config.h
===================================================================
--- xen-4.5.2-testing.orig/xen/include/asm-x86/config.h
+++ xen-4.5.2-testing/xen/include/asm-x86/config.h
@@ -330,7 +330,8 @@ extern unsigned long xen_phys_start;
#define NATIVE_VM_ASSIST_VALID ((1UL << VMASST_TYPE_4gb_segments) | \
(1UL << VMASST_TYPE_4gb_segments_notify) | \
(1UL << VMASST_TYPE_writable_pagetables) | \
- (1UL << VMASST_TYPE_pae_extended_cr3))
+ (1UL << VMASST_TYPE_pae_extended_cr3) | \
+ (1UL << VMASST_TYPE_m2p_strict))
#define VM_ASSIST_VALID NATIVE_VM_ASSIST_VALID
#define COMPAT_VM_ASSIST_VALID (NATIVE_VM_ASSIST_VALID & \
((1UL << COMPAT_BITS_PER_LONG) - 1))
Index: xen-4.5.2-testing/xen/include/asm-x86/mm.h
===================================================================
--- xen-4.5.2-testing.orig/xen/include/asm-x86/mm.h
+++ xen-4.5.2-testing/xen/include/asm-x86/mm.h
@@ -314,7 +314,10 @@ static inline void *__page_to_virt(const
int free_page_type(struct page_info *page, unsigned long type,
int preemptible);
-void init_guest_l4_table(l4_pgentry_t[], const struct domain *);
+void init_guest_l4_table(l4_pgentry_t[], const struct domain *,
+ bool_t zap_ro_mpt);
+void fill_ro_mpt(unsigned long mfn);
+void zap_ro_mpt(unsigned long mfn);
int is_iomem_page(unsigned long mfn);
Index: xen-4.5.2-testing/xen/include/public/xen.h
===================================================================
--- xen-4.5.2-testing.orig/xen/include/public/xen.h
+++ xen-4.5.2-testing/xen/include/public/xen.h
@@ -486,6 +486,18 @@ DEFINE_XEN_GUEST_HANDLE(mmuext_op_t);
/* x86/PAE guests: support PDPTs above 4GB. */
#define VMASST_TYPE_pae_extended_cr3 3
+/*
+ * x86/64 guests: strictly hide M2P from user mode.
+ * This allows the guest to control respective hypervisor behavior:
+ * - when not set, L4 tables get created with the respective slot blank,
+ * and whenever the L4 table gets used as a kernel one the missing
+ * mapping gets inserted,
+ * - when set, L4 tables get created with the respective slot initialized
+ * as before, and whenever the L4 table gets used as a user one the
+ * mapping gets zapped.
+ */
+#define VMASST_TYPE_m2p_strict 32
+
#if __XEN_INTERFACE_VERSION__ < 0x00040600
#define MAX_VMASST_TYPE 3
#endif