mirror of
https://github.com/torvalds/linux.git
synced 2024-11-28 23:21:31 +00:00
8adddf349f
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:
|
||
---|---|---|
.. | ||
40x | ||
44x | ||
52xx | ||
83xx | ||
85xx | ||
85xx-32bit.config | ||
85xx-64bit.config | ||
85xx-hw.config | ||
85xx-smp.config | ||
86xx-hw.config | ||
86xx-smp.config | ||
adder875_defconfig | ||
altivec.config | ||
amigaone_defconfig | ||
be.config | ||
book3s_32.config | ||
cell_defconfig | ||
chrp32_defconfig | ||
corenet_basic_defconfig | ||
dpaa.config | ||
ep88xc_defconfig | ||
ep8248e_defconfig | ||
fsl-emb-nonhw.config | ||
g5_defconfig | ||
gamecube_defconfig | ||
guest.config | ||
holly_defconfig | ||
le.config | ||
linkstation_defconfig | ||
maple_defconfig | ||
mgcoge_defconfig | ||
mpc83xx_defconfig | ||
mpc85xx_basic_defconfig | ||
mpc86xx_basic_defconfig | ||
mpc512x_defconfig | ||
mpc866_ads_defconfig | ||
mpc885_ads_defconfig | ||
mpc5200_defconfig | ||
mpc7448_hpc2_defconfig | ||
mpc8272_ads_defconfig | ||
mvme5100_defconfig | ||
pasemi_defconfig | ||
pmac32_defconfig | ||
powernv_defconfig | ||
ppc6xx_defconfig | ||
ppc40x_defconfig | ||
ppc44x_defconfig | ||
ppc64_defconfig | ||
ppc64e_defconfig | ||
pq2fads_defconfig | ||
ps3_defconfig | ||
pseries_defconfig | ||
skiroot_defconfig | ||
storcenter_defconfig | ||
tqm8xx_defconfig | ||
wii_defconfig |