Message ID | 20190417074140.25130-1-mpe@ellerman.id.au (mailing list archive) |
---|---|
State | Accepted |
Commit | 8adddf349fda0d3de2f6bb41ddf838cbf36a8ad2 |
Headers | show |
Series | powerpc/mm/radix: Make Radix require HUGETLB_PAGE | expand |
Context | Check | Description |
---|---|---|
snowpatch_ozlabs/apply_patch | success | Successfully applied on branch next (8c2ffd9174779014c3fe1f96d9dc3641d9175f00) |
snowpatch_ozlabs/build-ppc64le | success | Build succeeded |
snowpatch_ozlabs/build-ppc64be | success | Build succeeded |
snowpatch_ozlabs/build-ppc64e | success | Build succeeded |
snowpatch_ozlabs/build-pmac32 | success | Build succeeded |
snowpatch_ozlabs/checkpatch | warning | total: 0 errors, 1 warnings, 0 checks, 15 lines checked |
Michael Ellerman <mpe@ellerman.id.au> writes: > Joel reported weird crashes using skiroot_defconfig, in his case we > jumped into an NX page: > > kernel tried to execute exec-protected page (c000000002bff4f0) - exploit attempt? (uid: 0) > BUG: Unable to handle kernel instruction fetch > Faulting instruction address: 0xc000000002bff4f0 > > Looking at the disassembly, we had simply branched to that address: > > c000000000c001bc 49fff335 bl c000000002bff4f0 > > But that didn't match the original kernel image: > > c000000000c001bc 4bfff335 bl c000000000bff4f0 <kobject_get+0x8> > > When STRICT_KERNEL_RWX is enabled, and we're using the radix MMU, we > call radix__change_memory_range() late in boot to change page > protections. We do that both to mark rodata read only and also to mark > init text no-execute. That involves walking the kernel page tables, > and clearing _PAGE_WRITE or _PAGE_EXEC respectively. > > With radix we may use hugepages for the linear mapping, so the code in > radix__change_memory_range() uses eg. pmd_huge() to test if it has > found a huge mapping, and if so it stops the page table walk and > changes the PMD permissions. > > However if the kernel is built without HUGETLBFS support, pmd_huge() > is just a #define that always returns 0. That causes the code in > radix__change_memory_range() to incorrectly interpret the PMD value as > a pointer to a PTE page rather than as a PTE at the PMD level. > > Unfortunately the combination of _PAGE_PTE and _PAGE_PRESENT in the > high bits of the PMD entry give us 0xc in the top nibble which means > the PMD entry happens to look like a valid pointer into the linear > mapping. Aneesh points out this paragraph is confusing. Those bits only make the pointer *look* valid, it doesn't actually make any difference to the code, as we mask and re-add those bits anyway. I'll drop this paragraph when committing. cheers
diff --git a/arch/powerpc/configs/skiroot_defconfig b/arch/powerpc/configs/skiroot_defconfig index 5ba131c30f6b..1bcd468ab422 100644 --- a/arch/powerpc/configs/skiroot_defconfig +++ b/arch/powerpc/configs/skiroot_defconfig @@ -266,6 +266,7 @@ CONFIG_UDF_FS=m CONFIG_MSDOS_FS=m CONFIG_VFAT_FS=m CONFIG_PROC_KCORE=y +CONFIG_HUGETLBFS=y # CONFIG_MISC_FILESYSTEMS is not set # CONFIG_NETWORK_FILESYSTEMS is not set CONFIG_NLS=y diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index 842b2c7e156a..50cd09b4e05d 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -324,7 +324,7 @@ config ARCH_ENABLE_SPLIT_PMD_PTLOCK config PPC_RADIX_MMU bool "Radix MMU Support" - depends on PPC_BOOK3S_64 + depends on PPC_BOOK3S_64 && HUGETLB_PAGE select ARCH_HAS_GIGANTIC_PAGE if (MEMORY_ISOLATION && COMPACTION) || CMA default y help
Joel reported weird crashes using skiroot_defconfig, in his case we jumped into an NX page: kernel tried to execute exec-protected page (c000000002bff4f0) - exploit attempt? (uid: 0) BUG: Unable to handle kernel instruction fetch Faulting instruction address: 0xc000000002bff4f0 Looking at the disassembly, we had simply branched to that address: c000000000c001bc 49fff335 bl c000000002bff4f0 But that didn't match the original kernel image: c000000000c001bc 4bfff335 bl c000000000bff4f0 <kobject_get+0x8> When STRICT_KERNEL_RWX is enabled, and we're using the radix MMU, we call radix__change_memory_range() late in boot to change page protections. We do that both to mark rodata read only and also to mark init text no-execute. That involves walking the kernel page tables, and clearing _PAGE_WRITE or _PAGE_EXEC respectively. With radix we may use hugepages for the linear mapping, so the code in radix__change_memory_range() uses eg. pmd_huge() to test if it has found a huge mapping, and if so it stops the page table walk and changes the PMD permissions. However if the kernel is built without HUGETLBFS support, pmd_huge() is just a #define that always returns 0. That causes the code in radix__change_memory_range() to incorrectly interpret the PMD value as a pointer to a PTE page rather than as a PTE at the PMD level. Unfortunately the combination of _PAGE_PTE and _PAGE_PRESENT in the high bits of the PMD entry give us 0xc in the top nibble which means the PMD entry happens to look like a valid pointer into the linear mapping. We can see this using `dv` in xmon: 0:mon> dv c000000000000000 pgd @ 0xc000000001740000 pgdp @ 0xc000000001740000 = 0x80000000ffffb009 pudp @ 0xc0000000ffffb000 = 0x80000000ffffa009 pmdp @ 0xc0000000ffffa000 = 0xc00000000000018f <- not a pointer ptep @ 0xc000000000000100 = 0xa64bb17da64ab07d <- kernel text The end result is we treat the value at 0xc000000000000100 as a PTE and clear _PAGE_WRITE or _PAGE_EXEC, potentially corrupting the code at that address. In Joel's specific case we cleared the sign bit in the offset of the branch, causing a backward branch to turn into a forward branch which caused us to branch into a non-executable page. However the exact nature of the crash depends on kernel version, compiler version, and other factors. We need to fix radix__change_memory_range() to not use accessors that depend on HUGETLBFS, but we also have radix memory hotplug code that uses pmd_huge() etc that will also need fixing. So for now just disallow the broken combination of Radix with HUGETLBFS disabled. The only defconfig we have that is affected is skiroot_defconfig, so turn on HUGETLBFS there so that it still gets Radix. Fixes: 566ca99af026 ("powerpc/mm/radix: Add dummy radix_enabled()") Cc: stable@vger.kernel.org # v4.7+ Reported-by: Joel Stanley <joel@jms.id.au> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> --- arch/powerpc/configs/skiroot_defconfig | 1 + arch/powerpc/platforms/Kconfig.cputype | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-)