From: Jan Kiszka <[email protected]> This allows to mitigate CVE-2018-12207: On affected Intel machines, a guest can trigger an unrecoverable machine check exception when running a certain code pattern on an executable huge page. The suggested mitigation pattern of Intel involves on-demand break-up of huge pages when the guest tries to execute on them and also consolidating them into non-executable huge pages dynamically. This pattern is not compatible with the static and deterministic behavior of Jailhouse.
Therefore, this introduces a memory region flag to exclude huge page mappings for a region. System configurators can use this flag for executable regions on affected CPUs, while still allowing huge pages for non-executable regions. Signed-off-by: Jan Kiszka <[email protected]> --- Almost forgotten, but it should go into a release. We "just" need a reliable reproducer to validate... hypervisor/arch/arm-common/mmu_cell.c | 5 ++++- hypervisor/arch/x86/svm.c | 5 ++++- hypervisor/arch/x86/vmx.c | 6 ++++-- hypervisor/arch/x86/vtd.c | 5 ++++- hypervisor/include/jailhouse/paging.h | 5 +++++ hypervisor/paging.c | 3 ++- hypervisor/setup.c | 5 +++-- include/jailhouse/cell-config.h | 3 ++- 8 files changed, 28 insertions(+), 9 deletions(-) diff --git a/hypervisor/arch/arm-common/mmu_cell.c b/hypervisor/arch/arm-common/mmu_cell.c index a00997c3..56db2e8c 100644 --- a/hypervisor/arch/arm-common/mmu_cell.c +++ b/hypervisor/arch/arm-common/mmu_cell.c @@ -22,6 +22,7 @@ int arch_map_memory_region(struct cell *cell, { u64 phys_start = mem->phys_start; unsigned long access_flags = PTE_FLAG_VALID | PTE_ACCESS_FLAG; + unsigned long paging_flags = PAGING_COHERENT | PAGING_ALLOW_HUGE; int err = 0; if (mem->flags & JAILHOUSE_MEM_READ) @@ -38,13 +39,15 @@ int arch_map_memory_region(struct cell *cell, if (!(mem->flags & JAILHOUSE_MEM_EXECUTE)) flags |= S2_PAGE_ACCESS_XN; */ + if (mem->flags & JAILHOUSE_MEM_NO_HUGEPAGES) + paging_flags &= ~PAGING_ALLOW_HUGE; err = iommu_map_memory_region(cell, mem); if (err) return err; err = paging_create(&cell->arch.mm, phys_start, mem->size, - mem->virt_start, access_flags, PAGING_COHERENT); + mem->virt_start, access_flags, paging_flags); if (err) iommu_unmap_memory_region(cell, mem); diff --git a/hypervisor/arch/x86/svm.c b/hypervisor/arch/x86/svm.c index 513c696c..d85d2b50 100644 --- a/hypervisor/arch/x86/svm.c +++ b/hypervisor/arch/x86/svm.c @@ -349,6 +349,7 @@ int vcpu_map_memory_region(struct cell *cell, { u64 phys_start = mem->phys_start; u64 access_flags = PAGE_FLAG_US; /* See APMv2, Section 15.25.5 */ + u64 paging_flags = PAGING_COHERENT | PAGING_ALLOW_HUGE; if (mem->flags & JAILHOUSE_MEM_READ) access_flags |= PAGE_FLAG_PRESENT; @@ -358,6 +359,8 @@ int vcpu_map_memory_region(struct cell *cell, access_flags |= PAGE_FLAG_NOEXECUTE; if (mem->flags & JAILHOUSE_MEM_COMM_REGION) phys_start = paging_hvirt2phys(&cell->comm_page); + if (mem->flags & JAILHOUSE_MEM_NO_HUGEPAGES) + paging_flags &= ~PAGING_ALLOW_HUGE; access_flags |= amd_iommu_get_memory_region_flags(mem); @@ -367,7 +370,7 @@ int vcpu_map_memory_region(struct cell *cell, */ return paging_create(&cell->arch.svm.npt_iommu_structs, phys_start, mem->size, mem->virt_start, access_flags, - PAGING_COHERENT); + paging_flags); } int vcpu_unmap_memory_region(struct cell *cell, diff --git a/hypervisor/arch/x86/vmx.c b/hypervisor/arch/x86/vmx.c index f0a2534b..1cbc6417 100644 --- a/hypervisor/arch/x86/vmx.c +++ b/hypervisor/arch/x86/vmx.c @@ -353,6 +353,7 @@ int vcpu_map_memory_region(struct cell *cell, { u64 phys_start = mem->phys_start; unsigned long access_flags = EPT_FLAG_WB_TYPE; + unsigned long paging_flags = PAGING_NON_COHERENT | PAGING_ALLOW_HUGE; if (mem->flags & JAILHOUSE_MEM_READ) access_flags |= EPT_FLAG_READ; @@ -362,10 +363,11 @@ int vcpu_map_memory_region(struct cell *cell, access_flags |= EPT_FLAG_EXECUTE; if (mem->flags & JAILHOUSE_MEM_COMM_REGION) phys_start = paging_hvirt2phys(&cell->comm_page); + if (mem->flags & JAILHOUSE_MEM_NO_HUGEPAGES) + paging_flags &= ~PAGING_ALLOW_HUGE; return paging_create(&cell->arch.vmx.ept_structs, phys_start, mem->size, - mem->virt_start, access_flags, - PAGING_NON_COHERENT); + mem->virt_start, access_flags, paging_flags); } int vcpu_unmap_memory_region(struct cell *cell, diff --git a/hypervisor/arch/x86/vtd.c b/hypervisor/arch/x86/vtd.c index e5f9bfb0..51649662 100644 --- a/hypervisor/arch/x86/vtd.c +++ b/hypervisor/arch/x86/vtd.c @@ -751,6 +751,7 @@ int iommu_map_memory_region(struct cell *cell, const struct jailhouse_memory *mem) { unsigned long access_flags = 0; + unsigned long paging_flags = PAGING_COHERENT | PAGING_ALLOW_HUGE; if (!(mem->flags & JAILHOUSE_MEM_DMA)) return 0; @@ -762,10 +763,12 @@ int iommu_map_memory_region(struct cell *cell, access_flags |= VTD_PAGE_READ; if (mem->flags & JAILHOUSE_MEM_WRITE) access_flags |= VTD_PAGE_WRITE; + if (mem->flags & JAILHOUSE_MEM_NO_HUGEPAGES) + paging_flags &= ~PAGING_ALLOW_HUGE; return paging_create(&cell->arch.vtd.pg_structs, mem->phys_start, mem->size, mem->virt_start, access_flags, - PAGING_COHERENT); + paging_flags); } int iommu_unmap_memory_region(struct cell *cell, diff --git a/hypervisor/include/jailhouse/paging.h b/hypervisor/include/jailhouse/paging.h index dcf77829..96e3fdbc 100644 --- a/hypervisor/include/jailhouse/paging.h +++ b/hypervisor/include/jailhouse/paging.h @@ -63,6 +63,11 @@ struct page_pool { #define PAGING_NON_COHERENT 0 /** Make changes visible to non-snooping readers, i.e. commit them to RAM. */ #define PAGING_COHERENT 0x1 + +/** Do not use huge pages for creating a mapping. */ +#define PAGING_NO_HUGE 0 +/** When possible, use huge pages for creating a mapping. */ +#define PAGING_ALLOW_HUGE 0x2 /** @} */ /** Page table reference. */ diff --git a/hypervisor/paging.c b/hypervisor/paging.c index 94ca1812..6d0cbcc8 100644 --- a/hypervisor/paging.c +++ b/hypervisor/paging.c @@ -302,7 +302,8 @@ int paging_create(const struct paging_structures *pg_structs, while (1) { pte = paging->get_entry(pt, virt); - if (paging->page_size > 0 && + if (paging_flags & PAGING_ALLOW_HUGE && + paging->page_size > 0 && paging->page_size <= size && ((phys | virt) & (paging->page_size - 1)) == 0) { /* diff --git a/hypervisor/setup.c b/hypervisor/setup.c index 99a2b0c3..a49d857e 100644 --- a/hypervisor/setup.c +++ b/hypervisor/setup.c @@ -128,7 +128,8 @@ static void cpu_init(struct per_cpu *cpu_data) /* set up private mapping of per-CPU data structure */ err = paging_create(&cpu_data->pg_structs, paging_hvirt2phys(cpu_data), sizeof(*cpu_data), LOCAL_CPU_BASE, - PAGE_DEFAULT_FLAGS, PAGING_NON_COHERENT); + PAGE_DEFAULT_FLAGS, + PAGING_NON_COHERENT | PAGING_ALLOW_HUGE); if (err) goto failed; @@ -141,7 +142,7 @@ static void cpu_init(struct per_cpu *cpu_data) err = paging_create(&cpu_data->pg_structs, 0, NUM_TEMPORARY_PAGES * PAGE_SIZE, TEMPORARY_MAPPING_BASE, PAGE_NONPRESENT_FLAGS, - PAGING_NON_COHERENT); + PAGING_NON_COHERENT | PAGING_ALLOW_HUGE); if (err) goto failed; diff --git a/include/jailhouse/cell-config.h b/include/jailhouse/cell-config.h index b8e1f038..30ec5d06 100644 --- a/include/jailhouse/cell-config.h +++ b/include/jailhouse/cell-config.h @@ -113,7 +113,8 @@ struct jailhouse_cell_desc { #define JAILHOUSE_MEM_COMM_REGION 0x0020 #define JAILHOUSE_MEM_LOADABLE 0x0040 #define JAILHOUSE_MEM_ROOTSHARED 0x0080 -#define JAILHOUSE_MEM_IO_UNALIGNED 0x0100 +#define JAILHOUSE_MEM_NO_HUGEPAGES 0x0100 +#define JAILHOUSE_MEM_IO_UNALIGNED 0x8000 #define JAILHOUSE_MEM_IO_WIDTH_SHIFT 16 /* uses bits 16..19 */ #define JAILHOUSE_MEM_IO_8 (1 << JAILHOUSE_MEM_IO_WIDTH_SHIFT) #define JAILHOUSE_MEM_IO_16 (2 << JAILHOUSE_MEM_IO_WIDTH_SHIFT) -- 2.16.4 -- Siemens AG, Corporate Technology, CT RDA IOT SES-DE Corporate Competence Center Embedded Linux -- You received this message because you are subscribed to the Google Groups "Jailhouse" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/jailhouse-dev/9ca086db-d475-938c-f362-62d325eadec7%40siemens.com.
