From: Borislav Petkov <bp@suse.de>
To: David Woodhouse <dwmw2@infradead.org>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>,
"tglx@linutronix.de" <tglx@linutronix.de>,
"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
"tim.c.chen@linux.intel.com" <tim.c.chen@linux.intel.com>,
"peterz@infradead.org" <peterz@infradead.org>,
"torvalds@linux-foundation.org" <torvalds@linux-foundation.org>,
"ak@linux.intel.com" <ak@linux.intel.com>,
"riel@redhat.com" <riel@redhat.com>,
"keescook@google.com" <keescook@google.com>,
"gnomes@lxorguk.ukuu.org.uk" <gnomes@lxorguk.ukuu.org.uk>,
"pjt@google.com" <pjt@google.com>,
"dave.hansen@intel.com" <dave.hansen@intel.com>,
"luto@amacapital.net" <luto@amacapital.net>,
"jikos@kernel.org" <jikos@kernel.org>,
"gregkh@linux-foundation.org" <gregkh@linux-foundation.org>
Subject: Re: [PATCH v3 01/13] x86/retpoline: Add initial retpoline support
Date: Sat, 6 Jan 2018 18:02:43 +0100 [thread overview]
Message-ID: <20180106170243.ndkn3bfj5ezbijdd@pd.tnic> (raw)
In-Reply-To: <1515227001.29312.205.camel@infradead.org>
On Sat, Jan 06, 2018 at 08:23:21AM +0000, David Woodhouse wrote:
> Thanks. From code inspection, I couldn't see that it was smart enough
> *not* to process a relative jump in the 'altinstr' section which was
> jumping to a target *within* that same altinstr section, and thus
> didn't need to be touched at all. Does this work?
>
> alternative("", "xor %%rdi, %%rdi; jmp 2f; 2: jmp startup_64", X86_FEATURE_K8);
So this is fine because it gets turned into a two-byte jump:
[ 0.816005] apply_alternatives: feat: 3*32+4, old: (ffffffff810273c9, len: 10), repl: (ffffffff824759d2, len: 10), pad: 10
[ 0.820001] ffffffff810273c9: old_insn: 90 90 90 90 90 90 90 90 90 90
[ 0.821247] ffffffff824759d2: rpl_insn: 48 31 ff eb 00 e9 24 a6 b8 fe
[ 0.822455] process_jumps: insn start 0x48, at 0, len: 3
[ 0.823496] process_jumps: insn start 0xeb, at 3, len: 2
[ 0.824002] process_jumps: insn start 0xe9, at 5, len: 5
[ 0.825120] recompute_jump: target RIP: ffffffff81000000, new_displ: 0xfffd8c37
[ 0.826567] recompute_jump: final displ: 0xfffd8c32, JMP 0xffffffff81000000
[ 0.828001] ffffffff810273c9: final_insn: e9 32 8c fd ff e9 24 a6 b8 fe
i.e., notice the "eb 00" thing.
Which, when copied into the kernel proper, will simply work as it is
a small offset which, when referring to other code which gets copied
*together* with it, should work. I.e., we're not changing the offsets
during the copy so all good.
It becomes more tricky when you force a 5-byte jump:
alternative("", "xor %%rdi, %%rdi; .byte 0xe9; .long 2f - .altinstr_replacement; 2: jmp startup_64", X86_FEATURE_K8);
because then you need to know whether the offset is within the
.altinstr_replacement section itself or it is meant to be an absolute
offset like jmp startup_64 or within another section.
On that I need to sleep more to figure out what a reliable way to do it,
would be. I mean, not that we need it now. If all we care is two-byte
offsets, those should work now. The stress being on "should".
The current version:
---
From: Borislav Petkov <bp@suse.de>
Date: Fri, 5 Jan 2018 20:32:58 +0100
Subject: [PATCH] WIP
Signed-off-by: Borislav Petkov <bp@suse.de>
---
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index dbaf14d69ebd..0cb4f886e6d7 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -21,6 +21,7 @@
#include <asm/tlbflush.h>
#include <asm/io.h>
#include <asm/fixmap.h>
+#include <asm/insn.h>
int __read_mostly alternatives_patched;
@@ -280,25 +281,35 @@ static inline bool is_jmp(const u8 opcode)
return opcode == 0xeb || opcode == 0xe9;
}
+/**
+ * @orig_insn: pointer to the original insn
+ * @repl_insn: pointer to the replacement insn
+ * @repl_len: length of the replacement insn
+ * @insnbuf: buffer we're working on massaging the insns
+ * @i_off: offset within the buffer
+ */
static void __init_or_module
-recompute_jump(struct alt_instr *a, u8 *orig_insn, u8 *repl_insn, u8 *insnbuf)
+recompute_jump(struct alt_instr *a, u8 *orig_insn, u8 *repl_insn, u8 repl_len,
+ u8 *insnbuf, u8 i_off)
{
u8 *next_rip, *tgt_rip;
s32 n_dspl, o_dspl;
- int repl_len;
- if (a->replacementlen != 5)
+ if (repl_len != 5)
return;
- o_dspl = *(s32 *)(insnbuf + 1);
+ o_dspl = *(s32 *)(repl_insn + 1);
+
+ DPRINTK("o_dspl: 0x%x, orig_insn: %px", o_dspl, orig_insn);
/* next_rip of the replacement JMP */
- next_rip = repl_insn + a->replacementlen;
+ next_rip = repl_insn + repl_len;
+
/* target rip of the replacement JMP */
tgt_rip = next_rip + o_dspl;
n_dspl = tgt_rip - orig_insn;
- DPRINTK("target RIP: %p, new_displ: 0x%x", tgt_rip, n_dspl);
+ DPRINTK("target RIP: %px, new_displ: 0x%x", tgt_rip, n_dspl);
if (tgt_rip - orig_insn >= 0) {
if (n_dspl - 2 <= 127)
@@ -316,8 +327,8 @@ recompute_jump(struct alt_instr *a, u8 *orig_insn, u8 *repl_insn, u8 *insnbuf)
two_byte_jmp:
n_dspl -= 2;
- insnbuf[0] = 0xeb;
- insnbuf[1] = (s8)n_dspl;
+ insnbuf[i_off] = 0xeb;
+ insnbuf[i_off + 1] = (s8)n_dspl;
add_nops(insnbuf + 2, 3);
repl_len = 2;
@@ -326,8 +337,8 @@ recompute_jump(struct alt_instr *a, u8 *orig_insn, u8 *repl_insn, u8 *insnbuf)
five_byte_jmp:
n_dspl -= 5;
- insnbuf[0] = 0xe9;
- *(s32 *)&insnbuf[1] = n_dspl;
+ insnbuf[i_off] = 0xe9;
+ *(s32 *)&insnbuf[i_off + 1] = n_dspl;
repl_len = 5;
@@ -337,6 +348,32 @@ recompute_jump(struct alt_instr *a, u8 *orig_insn, u8 *repl_insn, u8 *insnbuf)
n_dspl, (unsigned long)orig_insn + n_dspl + repl_len);
}
+static void __init_or_module process_jumps(struct alt_instr *a, u8 *insnbuf)
+{
+ u8 *repl = (u8 *)&a->repl_offset + a->repl_offset;
+ u8 *instr = (u8 *)&a->instr_offset + a->instr_offset;
+ struct insn insn;
+ int i = 0;
+
+ if (!a->replacementlen)
+ return;
+
+ while (i < a->replacementlen) {
+ kernel_insn_init(&insn, repl, a->replacementlen);
+
+ insn_get_length(&insn);
+
+ DPRINTK("insn start 0x%x, at %d, len: %d", repl[0], i, insn.length);
+
+ if (is_jmp(repl[0]))
+ recompute_jump(a, instr, repl, insn.length, insnbuf, i);
+
+ i += insn.length;
+ repl += insn.length;
+ instr += insn.length;
+ }
+}
+
/*
* "noinline" to cause control flow change and thus invalidate I$ and
* cause refetch after modification.
@@ -352,7 +389,7 @@ static void __init_or_module noinline optimize_nops(struct alt_instr *a, u8 *ins
add_nops(instr + (a->instrlen - a->padlen), a->padlen);
local_irq_restore(flags);
- DUMP_BYTES(instr, a->instrlen, "%p: [%d:%d) optimized NOPs: ",
+ DUMP_BYTES(instr, a->instrlen, "%px: [%d:%d) optimized NOPs: ",
instr, a->instrlen - a->padlen, a->padlen);
}
@@ -373,7 +410,7 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start,
u8 *instr, *replacement;
u8 insnbuf[MAX_PATCH_LEN];
- DPRINTK("alt table %p -> %p", start, end);
+ DPRINTK("alt table %px -> %px", start, end);
/*
* The scan order should be from start to end. A later scanned
* alternative code can overwrite previously scanned alternative code.
@@ -397,14 +434,14 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start,
continue;
}
- DPRINTK("feat: %d*32+%d, old: (%p, len: %d), repl: (%p, len: %d), pad: %d",
+ DPRINTK("feat: %d*32+%d, old: (%px, len: %d), repl: (%px, len: %d), pad: %d",
a->cpuid >> 5,
a->cpuid & 0x1f,
instr, a->instrlen,
replacement, a->replacementlen, a->padlen);
- DUMP_BYTES(instr, a->instrlen, "%p: old_insn: ", instr);
- DUMP_BYTES(replacement, a->replacementlen, "%p: rpl_insn: ", replacement);
+ DUMP_BYTES(instr, a->instrlen, "%px: old_insn: ", instr);
+ DUMP_BYTES(replacement, a->replacementlen, "%px: rpl_insn: ", replacement);
memcpy(insnbuf, replacement, a->replacementlen);
insnbuf_sz = a->replacementlen;
@@ -422,15 +459,14 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start,
(unsigned long)instr + *(s32 *)(insnbuf + 1) + 5);
}
- if (a->replacementlen && is_jmp(replacement[0]))
- recompute_jump(a, instr, replacement, insnbuf);
+ process_jumps(a, insnbuf);
if (a->instrlen > a->replacementlen) {
add_nops(insnbuf + a->replacementlen,
a->instrlen - a->replacementlen);
insnbuf_sz += a->instrlen - a->replacementlen;
}
- DUMP_BYTES(insnbuf, insnbuf_sz, "%p: final_insn: ", instr);
+ DUMP_BYTES(insnbuf, insnbuf_sz, "%px: final_insn: ", instr);
text_poke_early(instr, insnbuf, insnbuf_sz);
}
--
2.13.0
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)
--
next prev parent reply other threads:[~2018-01-06 17:02 UTC|newest]
Thread overview: 79+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-01-04 9:10 [RFC] Retpoline: Binary mitigation for branch-target-injection (aka "Spectre") Paul Turner
2018-01-04 9:12 ` Paul Turner
2018-01-04 9:24 ` Paul Turner
2018-01-04 9:48 ` Greg Kroah-Hartman
2018-01-04 9:56 ` Woodhouse, David
2018-01-04 9:30 ` Woodhouse, David
2018-01-04 14:36 ` [PATCH v3 01/13] x86/retpoline: Add initial retpoline support David Woodhouse
2018-01-04 18:03 ` Linus Torvalds
2018-01-04 19:32 ` Woodhouse, David
2018-01-04 18:17 ` Alexei Starovoitov
2018-01-04 18:25 ` Linus Torvalds
2018-01-04 18:36 ` Alexei Starovoitov
2018-01-04 19:27 ` David Woodhouse
2018-01-05 10:28 ` Paul Turner
2018-01-05 10:55 ` David Woodhouse
2018-01-05 11:19 ` Paul Turner
2018-01-05 11:25 ` Paul Turner
2018-01-05 11:26 ` Paolo Bonzini
2018-01-05 12:20 ` Paul Turner
2018-01-05 10:40 ` Paul Turner
2018-01-04 18:40 ` Andi Kleen
2018-01-05 10:32 ` Paul Turner
2018-01-05 12:54 ` Thomas Gleixner
2018-01-05 13:01 ` Juergen Gross
2018-01-05 13:03 ` Thomas Gleixner
2018-01-05 13:56 ` Woodhouse, David
2018-01-05 16:41 ` Woodhouse, David
2018-01-05 16:45 ` Borislav Petkov
2018-01-05 17:08 ` Josh Poimboeuf
2018-01-06 0:30 ` Borislav Petkov
2018-01-06 8:23 ` David Woodhouse
2018-01-06 17:02 ` Borislav Petkov [this message]
2018-01-07 9:40 ` David Woodhouse
2018-01-07 11:46 ` Borislav Petkov
2018-01-07 12:21 ` David Woodhouse
2018-01-07 14:03 ` Borislav Petkov
2018-01-08 21:50 ` David Woodhouse
2018-01-08 5:06 ` Josh Poimboeuf
2018-01-08 7:55 ` Woodhouse, David
2018-01-05 17:12 ` Woodhouse, David
2018-01-05 17:28 ` Linus Torvalds
2018-01-05 17:48 ` David Woodhouse
2018-01-05 18:05 ` Andi Kleen
2018-01-05 20:32 ` Woodhouse, David
2018-01-05 21:11 ` Brian Gerst
2018-01-05 22:16 ` Woodhouse, David
2018-01-05 22:43 ` Borislav Petkov
2018-01-05 22:00 ` Woodhouse, David
2018-01-05 22:06 ` Borislav Petkov
2018-01-05 23:50 ` Linus Torvalds
2018-01-06 10:53 ` Woodhouse, David
2018-01-04 14:36 ` [PATCH v3 02/13] x86/retpoline/crypto: Convert crypto assembler indirect jumps David Woodhouse
2018-01-04 14:37 ` [PATCH v3 03/13] x86/retpoline/entry: Convert entry " David Woodhouse
2018-01-04 14:46 ` Dave Hansen
2018-01-04 14:49 ` Woodhouse, David
2018-01-04 14:37 ` [PATCH v3 04/13] x86/retpoline/ftrace: Convert ftrace " David Woodhouse
2018-01-04 14:37 ` [PATCH v3 05/13] x86/retpoline/hyperv: Convert " David Woodhouse
2018-01-04 14:37 ` [PATCH v3 06/13] x86/retpoline/xen: Convert Xen hypercall " David Woodhouse
2018-01-04 15:10 ` Juergen Gross
2018-01-04 15:18 ` David Woodhouse
2018-01-04 15:54 ` Juergen Gross
2018-01-04 14:37 ` [PATCH v3 07/13] x86/retpoline/checksum32: Convert assembler " David Woodhouse
2018-01-04 14:37 ` [PATCH v3 08/13] x86/alternatives: Add missing \n at end of ALTERNATIVE inline asm David Woodhouse
2018-01-05 13:04 ` [tip:x86/pti] x86/alternatives: Add missing '\n' " tip-bot for David Woodhouse
2018-01-04 14:37 ` [PATCH v3 09/13] x86/retpoline/irq32: Convert assembler indirect jumps David Woodhouse
2018-01-04 14:37 ` [PATCH v3 10/13] x86/retpoline/pvops: " David Woodhouse
2018-01-04 15:02 ` Juergen Gross
2018-01-04 15:12 ` Woodhouse, David
2018-01-04 15:18 ` Andrew Cooper
2018-01-04 16:04 ` Juergen Gross
2018-01-04 16:37 ` Andi Kleen
2018-01-04 14:37 ` [PATCH v3 11/13] retpoline/taint: Taint kernel for missing retpoline in compiler David Woodhouse
2018-01-04 22:06 ` Justin Forbes
2018-01-04 14:37 ` [PATCH v3 12/13] retpoline/objtool: Disable some objtool warnings David Woodhouse
2018-01-04 14:37 ` [PATCH v3 13/13] retpoline: Attempt to quiten objtool warning for unreachable code David Woodhouse
2018-01-04 16:18 ` [RFC] Retpoline: Binary mitigation for branch-target-injection (aka "Spectre") Andy Lutomirski
2018-01-04 16:24 ` David Woodhouse
2018-01-05 10:49 ` Paul Turner
2018-01-05 11:43 ` Woodhouse, David
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180106170243.ndkn3bfj5ezbijdd@pd.tnic \
--to=bp@suse.de \
--cc=ak@linux.intel.com \
--cc=dave.hansen@intel.com \
--cc=dwmw2@infradead.org \
--cc=gnomes@lxorguk.ukuu.org.uk \
--cc=gregkh@linux-foundation.org \
--cc=jikos@kernel.org \
--cc=jpoimboe@redhat.com \
--cc=keescook@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=luto@amacapital.net \
--cc=peterz@infradead.org \
--cc=pjt@google.com \
--cc=riel@redhat.com \
--cc=tglx@linutronix.de \
--cc=tim.c.chen@linux.intel.com \
--cc=torvalds@linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).