forked from Minki/linux
49b39ec248
The entry flush mitigation can be enabled/disabled at runtime. When this
happens it results in the kernel patching its own instructions to
enable/disable the mitigation sequence.
With strict kernel RWX enabled instruction patching happens via a
secondary mapping of the kernel text, so that we don't have to make the
primary mapping writable. With the hash MMU this leads to a hash fault,
which causes us to execute the exception entry which contains the entry
flush mitigation.
This means we end up executing the entry flush in a semi-patched state,
ie. after we have patched the first instruction but before we patch the
second or third instruction of the sequence.
On machines with updated firmware the entry flush is a series of special
nops, and it's safe to to execute in a semi-patched state.
However when using the fallback flush the sequence is mflr/branch/mtlr,
and so it's not safe to execute if we have patched out the mflr but not
the other two instructions. Doing so leads to us corrputing LR, leading
to an oops, for example:
# echo 0 > /sys/kernel/debug/powerpc/entry_flush
kernel tried to execute exec-protected page (c000000002971000) - exploit attempt? (uid: 0)
BUG: Unable to handle kernel instruction fetch
Faulting instruction address: 0xc000000002971000
Oops: Kernel access of bad area, sig: 11 [#1]
LE PAGE_SIZE=64K MMU=Hash SMP NR_CPUS=2048 NUMA pSeries
CPU: 0 PID: 2215 Comm: bash Not tainted 5.13.0-rc1-00010-gda3bb206c9ce #1
NIP: c000000002971000 LR: c000000002971000 CTR: c000000000120c40
REGS: c000000013243840 TRAP: 0400 Not tainted (5.13.0-rc1-00010-gda3bb206c9ce)
MSR: 8000000010009033 <SF,EE,ME,IR,DR,RI,LE> CR: 48428482 XER: 00000000
...
NIP 0xc000000002971000
LR 0xc000000002971000
Call Trace:
do_patch_instruction+0xc4/0x340 (unreliable)
do_entry_flush_fixups+0x100/0x3b0
entry_flush_set+0x50/0xe0
simple_attr_write+0x160/0x1a0
full_proxy_write+0x8c/0x110
vfs_write+0xf0/0x340
ksys_write+0x84/0x140
system_call_exception+0x164/0x2d0
system_call_common+0xec/0x278
The simplest fix is to change the order in which we patch the
instructions, so that the sequence is always safe to execute. For the
non-fallback flushes it doesn't matter what order we patch in.
Fixes:
|
||
---|---|---|
.. | ||
alloc.c | ||
checksum_32.S | ||
checksum_64.S | ||
checksum_wrappers.c | ||
code-patching.c | ||
copy_32.S | ||
copy_mc_64.S | ||
copypage_64.S | ||
copypage_power7.S | ||
copyuser_64.S | ||
copyuser_power7.S | ||
crtsavres.S | ||
div64.S | ||
error-inject.c | ||
feature-fixups-test.S | ||
feature-fixups.c | ||
hweight_64.S | ||
ldstfp.S | ||
locks.c | ||
Makefile | ||
mem_64.S | ||
memcmp_32.S | ||
memcmp_64.S | ||
memcpy_64.S | ||
memcpy_power7.S | ||
pmem.c | ||
quad.S | ||
rheap.c | ||
sstep.c | ||
string_32.S | ||
string_64.S | ||
string.S | ||
strlen_32.S | ||
test_code-patching.S | ||
test_emulate_step_exec_instr.S | ||
test_emulate_step.c | ||
vmx-helper.c | ||
xor_vmx_glue.c | ||
xor_vmx.c | ||
xor_vmx.h |