linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] powerpc/mm/radix: Make Radix require HUGETLB_PAGE
@ 2019-04-17  7:41 Michael Ellerman
  2019-04-17  8:51 ` Michael Ellerman
  2019-04-21 14:07 ` Michael Ellerman
  0 siblings, 2 replies; 3+ messages in thread
From: Michael Ellerman @ 2019-04-17  7:41 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: stewart, aneesh.kumar, joel

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(-)

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
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] powerpc/mm/radix: Make Radix require HUGETLB_PAGE
  2019-04-17  7:41 [PATCH] powerpc/mm/radix: Make Radix require HUGETLB_PAGE Michael Ellerman
@ 2019-04-17  8:51 ` Michael Ellerman
  2019-04-21 14:07 ` Michael Ellerman
  1 sibling, 0 replies; 3+ messages in thread
From: Michael Ellerman @ 2019-04-17  8:51 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: stewart, aneesh.kumar, joel

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

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: powerpc/mm/radix: Make Radix require HUGETLB_PAGE
  2019-04-17  7:41 [PATCH] powerpc/mm/radix: Make Radix require HUGETLB_PAGE Michael Ellerman
  2019-04-17  8:51 ` Michael Ellerman
@ 2019-04-21 14:07 ` Michael Ellerman
  1 sibling, 0 replies; 3+ messages in thread
From: Michael Ellerman @ 2019-04-21 14:07 UTC (permalink / raw)
  To: Michael Ellerman, linuxppc-dev; +Cc: stewart, aneesh.kumar, joel

On Wed, 2019-04-17 at 07:41:40 UTC, Michael Ellerman wrote:
> 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>

Applied to powerpc fixes.

https://git.kernel.org/powerpc/c/8adddf349fda0d3de2f6bb41ddf838cb

cheers

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2019-04-21 14:12 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-17  7:41 [PATCH] powerpc/mm/radix: Make Radix require HUGETLB_PAGE Michael Ellerman
2019-04-17  8:51 ` Michael Ellerman
2019-04-21 14:07 ` Michael Ellerman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).