diff options
| author | Michael Ellerman <mpe@ellerman.id.au> | 2019-04-16 09:59:02 -0400 |
|---|---|---|
| committer | Michael Ellerman <mpe@ellerman.id.au> | 2019-04-17 04:50:26 -0400 |
| commit | 8adddf349fda0d3de2f6bb41ddf838cbf36a8ad2 (patch) | |
| tree | 38ec4223a93318178fe7ce35b5e382a3441b7808 | |
| parent | cf7cf6977f531acd5dfe55250d0ee8cbbb6f1ae8 (diff) | |
powerpc/mm/radix: Make Radix require HUGETLB_PAGE
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.
We can see this using `dv` in xmon which also uses pmd_huge():
0:mon> dv c000000000000000
pgd @ 0xc000000001740000
pgdp @ 0xc000000001740000 = 0x80000000ffffb009
pudp @ 0xc0000000ffffb000 = 0x80000000ffffa009
pmdp @ 0xc0000000ffffa000 = 0xc00000000000018f <- this is a PTE
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>
| -rw-r--r-- | arch/powerpc/configs/skiroot_defconfig | 1 | ||||
| -rw-r--r-- | arch/powerpc/platforms/Kconfig.cputype | 2 |
2 files changed, 2 insertions, 1 deletions
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 | |||
| 266 | CONFIG_MSDOS_FS=m | 266 | CONFIG_MSDOS_FS=m |
| 267 | CONFIG_VFAT_FS=m | 267 | CONFIG_VFAT_FS=m |
| 268 | CONFIG_PROC_KCORE=y | 268 | CONFIG_PROC_KCORE=y |
| 269 | CONFIG_HUGETLBFS=y | ||
| 269 | # CONFIG_MISC_FILESYSTEMS is not set | 270 | # CONFIG_MISC_FILESYSTEMS is not set |
| 270 | # CONFIG_NETWORK_FILESYSTEMS is not set | 271 | # CONFIG_NETWORK_FILESYSTEMS is not set |
| 271 | CONFIG_NLS=y | 272 | 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 | |||
| 324 | 324 | ||
| 325 | config PPC_RADIX_MMU | 325 | config PPC_RADIX_MMU |
| 326 | bool "Radix MMU Support" | 326 | bool "Radix MMU Support" |
| 327 | depends on PPC_BOOK3S_64 | 327 | depends on PPC_BOOK3S_64 && HUGETLB_PAGE |
| 328 | select ARCH_HAS_GIGANTIC_PAGE if (MEMORY_ISOLATION && COMPACTION) || CMA | 328 | select ARCH_HAS_GIGANTIC_PAGE if (MEMORY_ISOLATION && COMPACTION) || CMA |
| 329 | default y | 329 | default y |
| 330 | help | 330 | help |
