diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2015-09-03 06:34:55 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2015-09-03 15:27:47 -0400 |
commit | 66c117d7fa2ae429911e60d84bf31a90b2b96189 (patch) | |
tree | b1c333f44b6bd4383ea3dab707f59b6034c9464a | |
parent | 31e09b18c863718939e3e9c30eee55f9011d85ee (diff) |
x86/alternatives: Make optimize_nops() interrupt safe and synced
Richard reported the following crash:
[ 0.036000] BUG: unable to handle kernel paging request at 55501e06
[ 0.036000] IP: [<c0aae48b>] common_interrupt+0xb/0x38
[ 0.036000] Call Trace:
[ 0.036000] [<c0409c80>] ? add_nops+0x90/0xa0
[ 0.036000] [<c040a054>] apply_alternatives+0x274/0x630
Chuck decoded:
" 0: 8d 90 90 83 04 24 lea 0x24048390(%eax),%edx
6: 80 fc 0f cmp $0xf,%ah
9: a8 0f test $0xf,%al
>> b: a0 06 1e 50 55 mov 0x55501e06,%al
10: 57 push %edi
11: 56 push %esi
Interrupt 0x30 occurred while the alternatives code was replacing the
initial 0x90,0x90,0x90 NOPs (from the ASM_CLAC macro) with the
optimized version, 0x8d,0x76,0x00. Only the first byte has been
replaced so far, and it makes a mess out of the insn decoding."
optimize_nops() is buggy in two aspects:
- It's not disabling interrupts across the modification
- It's lacking a sync_core() call
Add both.
Fixes: 4fd4b6e5537c 'x86/alternatives: Use optimized NOPs for padding'
Reported-and-tested-by: "Richard W.M. Jones" <rjones@redhat.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Richard W.M. Jones <rjones@redhat.com>
Cc: Chuck Ebbert <cebbert.lkml@gmail.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: stable@vger.kernel.org
Link: http://lkml.kernel.org/r/alpine.DEB.2.11.1509031232340.15006@nanos
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | arch/x86/kernel/alternative.c | 5 |
1 files changed, 5 insertions, 0 deletions
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index c42827eb86cf..25f909362b7a 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c | |||
@@ -338,10 +338,15 @@ done: | |||
338 | 338 | ||
339 | static void __init_or_module optimize_nops(struct alt_instr *a, u8 *instr) | 339 | static void __init_or_module optimize_nops(struct alt_instr *a, u8 *instr) |
340 | { | 340 | { |
341 | unsigned long flags; | ||
342 | |||
341 | if (instr[0] != 0x90) | 343 | if (instr[0] != 0x90) |
342 | return; | 344 | return; |
343 | 345 | ||
346 | local_irq_save(flags); | ||
344 | add_nops(instr + (a->instrlen - a->padlen), a->padlen); | 347 | add_nops(instr + (a->instrlen - a->padlen), a->padlen); |
348 | sync_core(); | ||
349 | local_irq_restore(flags); | ||
345 | 350 | ||
346 | DUMP_BYTES(instr, a->instrlen, "%p: [%d:%d) optimized NOPs: ", | 351 | DUMP_BYTES(instr, a->instrlen, "%p: [%d:%d) optimized NOPs: ", |
347 | instr, a->instrlen - a->padlen, a->padlen); | 352 | instr, a->instrlen - a->padlen, a->padlen); |