Fix Machine Check Exception on Page Size Change.
Approved by: so Security: FreeBSD-SA-19:25.mcepsc Security: CVE-2018-12207
This commit is contained in:
parent
2140187680
commit
680f4275c1
|
@ -1789,6 +1789,51 @@ pmap_page_init(vm_page_t m)
|
|||
m->md.pat_mode = PAT_WRITE_BACK;
|
||||
}
|
||||
|
||||
static int pmap_allow_2m_x_ept;
|
||||
SYSCTL_INT(_vm_pmap, OID_AUTO, allow_2m_x_ept, CTLFLAG_RWTUN | CTLFLAG_NOFETCH,
|
||||
&pmap_allow_2m_x_ept, 0,
|
||||
"Allow executable superpage mappings in EPT");
|
||||
|
||||
void
|
||||
pmap_allow_2m_x_ept_recalculate(void)
|
||||
{
|
||||
/*
|
||||
* SKL002, SKL012S. Since the EPT format is only used by
|
||||
* Intel CPUs, the vendor check is merely a formality.
|
||||
*/
|
||||
if (!(cpu_vendor_id != CPU_VENDOR_INTEL ||
|
||||
(cpu_ia32_arch_caps & IA32_ARCH_CAP_IF_PSCHANGE_MC_NO) != 0 ||
|
||||
(CPUID_TO_FAMILY(cpu_id) == 0x6 &&
|
||||
(CPUID_TO_MODEL(cpu_id) == 0x26 || /* Atoms */
|
||||
CPUID_TO_MODEL(cpu_id) == 0x27 ||
|
||||
CPUID_TO_MODEL(cpu_id) == 0x35 ||
|
||||
CPUID_TO_MODEL(cpu_id) == 0x36 ||
|
||||
CPUID_TO_MODEL(cpu_id) == 0x37 ||
|
||||
CPUID_TO_MODEL(cpu_id) == 0x86 ||
|
||||
CPUID_TO_MODEL(cpu_id) == 0x1c ||
|
||||
CPUID_TO_MODEL(cpu_id) == 0x4a ||
|
||||
CPUID_TO_MODEL(cpu_id) == 0x4c ||
|
||||
CPUID_TO_MODEL(cpu_id) == 0x4d ||
|
||||
CPUID_TO_MODEL(cpu_id) == 0x5a ||
|
||||
CPUID_TO_MODEL(cpu_id) == 0x5c ||
|
||||
CPUID_TO_MODEL(cpu_id) == 0x5d ||
|
||||
CPUID_TO_MODEL(cpu_id) == 0x5f ||
|
||||
CPUID_TO_MODEL(cpu_id) == 0x6e ||
|
||||
CPUID_TO_MODEL(cpu_id) == 0x7a ||
|
||||
CPUID_TO_MODEL(cpu_id) == 0x57 || /* Knights */
|
||||
CPUID_TO_MODEL(cpu_id) == 0x85))))
|
||||
pmap_allow_2m_x_ept = 1;
|
||||
TUNABLE_INT_FETCH("hw.allow_2m_x_ept", &pmap_allow_2m_x_ept);
|
||||
}
|
||||
|
||||
static bool
|
||||
pmap_allow_2m_x_page(pmap_t pmap, bool executable)
|
||||
{
|
||||
|
||||
return (pmap->pm_type != PT_EPT || !executable ||
|
||||
!pmap_allow_2m_x_ept);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the pmap module.
|
||||
* Called by vm_init, to initialize any structures that the pmap
|
||||
|
@ -1833,6 +1878,9 @@ pmap_init(void)
|
|||
}
|
||||
}
|
||||
|
||||
/* IFU */
|
||||
pmap_allow_2m_x_ept_recalculate();
|
||||
|
||||
/*
|
||||
* Initialize the vm page array entries for the kernel pmap's
|
||||
* page table pages.
|
||||
|
@ -5402,6 +5450,15 @@ retry:
|
|||
}
|
||||
|
||||
#if VM_NRESERVLEVEL > 0
|
||||
static bool
|
||||
pmap_pde_ept_executable(pmap_t pmap, pd_entry_t pde)
|
||||
{
|
||||
|
||||
if (pmap->pm_type != PT_EPT)
|
||||
return (false);
|
||||
return ((pde & EPT_PG_EXECUTE) != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tries to promote the 512, contiguous 4KB page mappings that are within a
|
||||
* single page table page (PTP) to a single 2MB page mapping. For promotion
|
||||
|
@ -5437,7 +5494,9 @@ pmap_promote_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va,
|
|||
firstpte = (pt_entry_t *)PHYS_TO_DMAP(*pde & PG_FRAME);
|
||||
setpde:
|
||||
newpde = *firstpte;
|
||||
if ((newpde & ((PG_FRAME & PDRMASK) | PG_A | PG_V)) != (PG_A | PG_V)) {
|
||||
if ((newpde & ((PG_FRAME & PDRMASK) | PG_A | PG_V)) != (PG_A | PG_V) ||
|
||||
!pmap_allow_2m_x_page(pmap, pmap_pde_ept_executable(pmap,
|
||||
newpde))) {
|
||||
atomic_add_long(&pmap_pde_p_failures, 1);
|
||||
CTR2(KTR_PMAP, "pmap_promote_pde: failure for va %#lx"
|
||||
" in pmap %p", va, pmap);
|
||||
|
@ -5867,6 +5926,12 @@ pmap_enter_pde(pmap_t pmap, vm_offset_t va, pd_entry_t newpde, u_int flags,
|
|||
PG_V = pmap_valid_bit(pmap);
|
||||
PMAP_LOCK_ASSERT(pmap, MA_OWNED);
|
||||
|
||||
if (!pmap_allow_2m_x_page(pmap, pmap_pde_ept_executable(pmap,
|
||||
newpde))) {
|
||||
CTR2(KTR_PMAP, "pmap_enter_pde: 2m x blocked for va %#lx"
|
||||
" in pmap %p", va, pmap);
|
||||
return (KERN_FAILURE);
|
||||
}
|
||||
if ((pdpg = pmap_allocpde(pmap, va, (flags & PMAP_ENTER_NOSLEEP) != 0 ?
|
||||
NULL : lockp)) == NULL) {
|
||||
CTR2(KTR_PMAP, "pmap_enter_pde: failure for va %#lx"
|
||||
|
@ -6013,6 +6078,7 @@ pmap_enter_object(pmap_t pmap, vm_offset_t start, vm_offset_t end,
|
|||
va = start + ptoa(diff);
|
||||
if ((va & PDRMASK) == 0 && va + NBPDR <= end &&
|
||||
m->psind == 1 && pmap_ps_enabled(pmap) &&
|
||||
pmap_allow_2m_x_page(pmap, (prot & VM_PROT_EXECUTE) != 0) &&
|
||||
pmap_enter_2mpage(pmap, va, m, prot, &lock))
|
||||
m = &m[NBPDR / PAGE_SIZE - 1];
|
||||
else
|
||||
|
|
|
@ -424,6 +424,7 @@ struct thread;
|
|||
|
||||
void pmap_activate_boot(pmap_t pmap);
|
||||
void pmap_activate_sw(struct thread *);
|
||||
void pmap_allow_2m_x_ept_recalculate(void);
|
||||
void pmap_bootstrap(vm_paddr_t *);
|
||||
int pmap_cache_bits(pmap_t pmap, int mode, boolean_t is_pde);
|
||||
int pmap_change_attr(vm_offset_t, vm_size_t, int);
|
||||
|
|
|
@ -50,6 +50,10 @@ __FBSDID("$FreeBSD$");
|
|||
#include <sys/pmckern.h>
|
||||
#include <sys/cpuctl.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_param.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
#include <machine/cpufunc.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/specialreg.h>
|
||||
|
@ -539,6 +543,7 @@ cpuctl_do_eval_cpu_features(int cpu, struct thread *td)
|
|||
hw_ssb_recalculate(true);
|
||||
#ifdef __amd64__
|
||||
amd64_syscall_ret_flush_l1d_recalc();
|
||||
pmap_allow_2m_x_ept_recalculate();
|
||||
#endif
|
||||
hw_mds_recalculate();
|
||||
printcpuinfo();
|
||||
|
|
|
@ -447,6 +447,7 @@
|
|||
#define IA32_ARCH_CAP_SKIP_L1DFL_VMENTRY 0x00000008
|
||||
#define IA32_ARCH_CAP_SSB_NO 0x00000010
|
||||
#define IA32_ARCH_CAP_MDS_NO 0x00000020
|
||||
#define IA32_ARCH_CAP_IF_PSCHANGE_MC_NO 0x00000040
|
||||
|
||||
/*
|
||||
* CPUID manufacturers identifiers
|
||||
|
|
Loading…
Reference in New Issue