Files
linux/arch/x86/kernel/alternative.c
Sami Tolvanen f1befc82ad cfi: Move BPF CFI types and helpers to generic code
Instead of duplicating the same code for each architecture, move
the CFI type hash variables for BPF function types and related
helper functions to generic CFI code, and allow architectures to
override the function definitions if needed.

Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
Link: https://lore.kernel.org/r/20250801001004.1859976-7-samitolvanen@google.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2025-07-31 18:23:53 -07:00

3107 lines
75 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
#define pr_fmt(fmt) "SMP alternatives: " fmt
#include <linux/mmu_context.h>
#include <linux/perf_event.h>
#include <linux/vmalloc.h>
#include <linux/memory.h>
#include <linux/execmem.h>
#include <asm/text-patching.h>
#include <asm/insn.h>
#include <asm/ibt.h>
#include <asm/set_memory.h>
#include <asm/nmi.h>
int __read_mostly alternatives_patched;
EXPORT_SYMBOL_GPL(alternatives_patched);
#define MAX_PATCH_LEN (255-1)
#define DA_ALL (~0)
#define DA_ALT 0x01
#define DA_RET 0x02
#define DA_RETPOLINE 0x04
#define DA_ENDBR 0x08
#define DA_SMP 0x10
static unsigned int debug_alternative;
static int __init debug_alt(char *str)
{
if (str && *str == '=')
str++;
if (!str || kstrtouint(str, 0, &debug_alternative))
debug_alternative = DA_ALL;
return 1;
}
__setup("debug-alternative", debug_alt);
static int noreplace_smp;
static int __init setup_noreplace_smp(char *str)
{
noreplace_smp = 1;
return 1;
}
__setup("noreplace-smp", setup_noreplace_smp);
#define DPRINTK(type, fmt, args...) \
do { \
if (debug_alternative & DA_##type) \
printk(KERN_DEBUG pr_fmt(fmt) "\n", ##args); \
} while (0)
#define DUMP_BYTES(type, buf, len, fmt, args...) \
do { \
if (unlikely(debug_alternative & DA_##type)) { \
int j; \
\
if (!(len)) \
break; \
\
printk(KERN_DEBUG pr_fmt(fmt), ##args); \
for (j = 0; j < (len) - 1; j++) \
printk(KERN_CONT "%02hhx ", buf[j]); \
printk(KERN_CONT "%02hhx\n", buf[j]); \
} \
} while (0)
static const unsigned char x86nops[] =
{
BYTES_NOP1,
BYTES_NOP2,
BYTES_NOP3,
BYTES_NOP4,
BYTES_NOP5,
BYTES_NOP6,
BYTES_NOP7,
BYTES_NOP8,
#ifdef CONFIG_64BIT
BYTES_NOP9,
BYTES_NOP10,
BYTES_NOP11,
#endif
};
const unsigned char * const x86_nops[ASM_NOP_MAX+1] =
{
NULL,
x86nops,
x86nops + 1,
x86nops + 1 + 2,
x86nops + 1 + 2 + 3,
x86nops + 1 + 2 + 3 + 4,
x86nops + 1 + 2 + 3 + 4 + 5,
x86nops + 1 + 2 + 3 + 4 + 5 + 6,
x86nops + 1 + 2 + 3 + 4 + 5 + 6 + 7,
#ifdef CONFIG_64BIT
x86nops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8,
x86nops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9,
x86nops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10,
#endif
};
#ifdef CONFIG_FINEIBT
static bool cfi_paranoid __ro_after_init;
#endif
#ifdef CONFIG_MITIGATION_ITS
#ifdef CONFIG_MODULES
static struct module *its_mod;
#endif
static void *its_page;
static unsigned int its_offset;
struct its_array its_pages;
static void *__its_alloc(struct its_array *pages)
{
void *page __free(execmem) = execmem_alloc(EXECMEM_MODULE_TEXT, PAGE_SIZE);
if (!page)
return NULL;
void *tmp = krealloc(pages->pages, (pages->num+1) * sizeof(void *),
GFP_KERNEL);
if (!tmp)
return NULL;
pages->pages = tmp;
pages->pages[pages->num++] = page;
return no_free_ptr(page);
}
/* Initialize a thunk with the "jmp *reg; int3" instructions. */
static void *its_init_thunk(void *thunk, int reg)
{
u8 *bytes = thunk;
int offset = 0;
int i = 0;
#ifdef CONFIG_FINEIBT
if (cfi_paranoid) {
/*
* When ITS uses indirect branch thunk the fineibt_paranoid
* caller sequence doesn't fit in the caller site. So put the
* remaining part of the sequence (<ea> + JNE) into the ITS
* thunk.
*/
bytes[i++] = 0xea; /* invalid instruction */
bytes[i++] = 0x75; /* JNE */
bytes[i++] = 0xfd;
offset = 1;
}
#endif
if (reg >= 8) {
bytes[i++] = 0x41; /* REX.B prefix */
reg -= 8;
}
bytes[i++] = 0xff;
bytes[i++] = 0xe0 + reg; /* jmp *reg */
bytes[i++] = 0xcc;
return thunk + offset;
}
static void its_pages_protect(struct its_array *pages)
{
for (int i = 0; i < pages->num; i++) {
void *page = pages->pages[i];
execmem_restore_rox(page, PAGE_SIZE);
}
}
static void its_fini_core(void)
{
if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX))
its_pages_protect(&its_pages);
kfree(its_pages.pages);
}
#ifdef CONFIG_MODULES
void its_init_mod(struct module *mod)
{
if (!cpu_feature_enabled(X86_FEATURE_INDIRECT_THUNK_ITS))
return;
mutex_lock(&text_mutex);
its_mod = mod;
its_page = NULL;
}
void its_fini_mod(struct module *mod)
{
if (!cpu_feature_enabled(X86_FEATURE_INDIRECT_THUNK_ITS))
return;
WARN_ON_ONCE(its_mod != mod);
its_mod = NULL;
its_page = NULL;
mutex_unlock(&text_mutex);
if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
its_pages_protect(&mod->arch.its_pages);
}
void its_free_mod(struct module *mod)
{
if (!cpu_feature_enabled(X86_FEATURE_INDIRECT_THUNK_ITS))
return;
for (int i = 0; i < mod->arch.its_pages.num; i++) {
void *page = mod->arch.its_pages.pages[i];
execmem_free(page);
}
kfree(mod->arch.its_pages.pages);
}
#endif /* CONFIG_MODULES */
static void *its_alloc(void)
{
struct its_array *pages = &its_pages;
void *page;
#ifdef CONFIG_MODULES
if (its_mod)
pages = &its_mod->arch.its_pages;
#endif
page = __its_alloc(pages);
if (!page)
return NULL;
execmem_make_temp_rw(page, PAGE_SIZE);
if (pages == &its_pages)
set_memory_x((unsigned long)page, 1);
return page;
}
static void *its_allocate_thunk(int reg)
{
int size = 3 + (reg / 8);
void *thunk;
#ifdef CONFIG_FINEIBT
/*
* The ITS thunk contains an indirect jump and an int3 instruction so
* its size is 3 or 4 bytes depending on the register used. If CFI
* paranoid is used then 3 extra bytes are added in the ITS thunk to
* complete the fineibt_paranoid caller sequence.
*/
if (cfi_paranoid)
size += 3;
#endif
if (!its_page || (its_offset + size - 1) >= PAGE_SIZE) {
its_page = its_alloc();
if (!its_page) {
pr_err("ITS page allocation failed\n");
return NULL;
}
memset(its_page, INT3_INSN_OPCODE, PAGE_SIZE);
its_offset = 32;
}
/*
* If the indirect branch instruction will be in the lower half
* of a cacheline, then update the offset to reach the upper half.
*/
if ((its_offset + size - 1) % 64 < 32)
its_offset = ((its_offset - 1) | 0x3F) + 33;
thunk = its_page + its_offset;
its_offset += size;
return its_init_thunk(thunk, reg);
}
u8 *its_static_thunk(int reg)
{
u8 *thunk = __x86_indirect_its_thunk_array[reg];
#ifdef CONFIG_FINEIBT
/* Paranoid thunk starts 2 bytes before */
if (cfi_paranoid)
return thunk - 2;
#endif
return thunk;
}
#else
static inline void its_fini_core(void) {}
#endif /* CONFIG_MITIGATION_ITS */
/*
* Nomenclature for variable names to simplify and clarify this code and ease
* any potential staring at it:
*
* @instr: source address of the original instructions in the kernel text as
* generated by the compiler.
*
* @buf: temporary buffer on which the patching operates. This buffer is
* eventually text-poked into the kernel image.
*
* @replacement/@repl: pointer to the opcodes which are replacing @instr, located
* in the .altinstr_replacement section.
*/
/*
* Fill the buffer with a single effective instruction of size @len.
*
* In order not to issue an ORC stack depth tracking CFI entry (Call Frame Info)
* for every single-byte NOP, try to generate the maximally available NOP of
* size <= ASM_NOP_MAX such that only a single CFI entry is generated (vs one for
* each single-byte NOPs). If @len to fill out is > ASM_NOP_MAX, pad with INT3 and
* *jump* over instead of executing long and daft NOPs.
*/
static void add_nop(u8 *buf, unsigned int len)
{
u8 *target = buf + len;
if (!len)
return;
if (len <= ASM_NOP_MAX) {
memcpy(buf, x86_nops[len], len);
return;
}
if (len < 128) {
__text_gen_insn(buf, JMP8_INSN_OPCODE, buf, target, JMP8_INSN_SIZE);
buf += JMP8_INSN_SIZE;
} else {
__text_gen_insn(buf, JMP32_INSN_OPCODE, buf, target, JMP32_INSN_SIZE);
buf += JMP32_INSN_SIZE;
}
for (;buf < target; buf++)
*buf = INT3_INSN_OPCODE;
}
/*
* Matches NOP and NOPL, not any of the other possible NOPs.
*/
static bool insn_is_nop(struct insn *insn)
{
/* Anything NOP, but no REP NOP */
if (insn->opcode.bytes[0] == 0x90 &&
(!insn->prefixes.nbytes || insn->prefixes.bytes[0] != 0xF3))
return true;
/* NOPL */
if (insn->opcode.bytes[0] == 0x0F && insn->opcode.bytes[1] == 0x1F)
return true;
/* TODO: more nops */
return false;
}
/*
* Find the offset of the first non-NOP instruction starting at @offset
* but no further than @len.
*/
static int skip_nops(u8 *buf, int offset, int len)
{
struct insn insn;
for (; offset < len; offset += insn.length) {
if (insn_decode_kernel(&insn, &buf[offset]))
break;
if (!insn_is_nop(&insn))
break;
}
return offset;
}
/*
* "noinline" to cause control flow change and thus invalidate I$ and
* cause refetch after modification.
*/
static void noinline optimize_nops(const u8 * const instr, u8 *buf, size_t len)
{
for (int next, i = 0; i < len; i = next) {
struct insn insn;
if (insn_decode_kernel(&insn, &buf[i]))
return;
next = i + insn.length;
if (insn_is_nop(&insn)) {
int nop = i;
/* Has the NOP already been optimized? */
if (i + insn.length == len)
return;
next = skip_nops(buf, next, len);
add_nop(buf + nop, next - nop);
DUMP_BYTES(ALT, buf, len, "%px: [%d:%d) optimized NOPs: ", instr, nop, next);
}
}
}
/*
* In this context, "source" is where the instructions are placed in the
* section .altinstr_replacement, for example during kernel build by the
* toolchain.
* "Destination" is where the instructions are being patched in by this
* machinery.
*
* The source offset is:
*
* src_imm = target - src_next_ip (1)
*
* and the target offset is:
*
* dst_imm = target - dst_next_ip (2)
*
* so rework (1) as an expression for target like:
*
* target = src_imm + src_next_ip (1a)
*
* and substitute in (2) to get:
*
* dst_imm = (src_imm + src_next_ip) - dst_next_ip (3)
*
* Now, since the instruction stream is 'identical' at src and dst (it
* is being copied after all) it can be stated that:
*
* src_next_ip = src + ip_offset
* dst_next_ip = dst + ip_offset (4)
*
* Substitute (4) in (3) and observe ip_offset being cancelled out to
* obtain:
*
* dst_imm = src_imm + (src + ip_offset) - (dst + ip_offset)
* = src_imm + src - dst + ip_offset - ip_offset
* = src_imm + src - dst (5)
*
* IOW, only the relative displacement of the code block matters.
*/
#define apply_reloc_n(n_, p_, d_) \
do { \
s32 v = *(s##n_ *)(p_); \
v += (d_); \
BUG_ON((v >> 31) != (v >> (n_-1))); \
*(s##n_ *)(p_) = (s##n_)v; \
} while (0)
static __always_inline
void apply_reloc(int n, void *ptr, uintptr_t diff)
{
switch (n) {
case 1: apply_reloc_n(8, ptr, diff); break;
case 2: apply_reloc_n(16, ptr, diff); break;
case 4: apply_reloc_n(32, ptr, diff); break;
default: BUG();
}
}
static __always_inline
bool need_reloc(unsigned long offset, u8 *src, size_t src_len)
{
u8 *target = src + offset;
/*
* If the target is inside the patched block, it's relative to the
* block itself and does not need relocation.
*/
return (target < src || target > src + src_len);
}
static void __apply_relocation(u8 *buf, const u8 * const instr, size_t instrlen, u8 *repl, size_t repl_len)
{
for (int next, i = 0; i < instrlen; i = next) {
struct insn insn;
if (WARN_ON_ONCE(insn_decode_kernel(&insn, &buf[i])))
return;
next = i + insn.length;
switch (insn.opcode.bytes[0]) {
case 0x0f:
if (insn.opcode.bytes[1] < 0x80 ||
insn.opcode.bytes[1] > 0x8f)
break;
fallthrough; /* Jcc.d32 */
case 0x70 ... 0x7f: /* Jcc.d8 */
case JMP8_INSN_OPCODE:
case JMP32_INSN_OPCODE:
case CALL_INSN_OPCODE:
if (need_reloc(next + insn.immediate.value, repl, repl_len)) {
apply_reloc(insn.immediate.nbytes,
buf + i + insn_offset_immediate(&insn),
repl - instr);
}
/*
* Where possible, convert JMP.d32 into JMP.d8.
*/
if (insn.opcode.bytes[0] == JMP32_INSN_OPCODE) {
s32 imm = insn.immediate.value;
imm += repl - instr;
imm += JMP32_INSN_SIZE - JMP8_INSN_SIZE;
if ((imm >> 31) == (imm >> 7)) {
buf[i+0] = JMP8_INSN_OPCODE;
buf[i+1] = (s8)imm;
memset(&buf[i+2], INT3_INSN_OPCODE, insn.length - 2);
}
}
break;
}
if (insn_rip_relative(&insn)) {
if (need_reloc(next + insn.displacement.value, repl, repl_len)) {
apply_reloc(insn.displacement.nbytes,
buf + i + insn_offset_displacement(&insn),
repl - instr);
}
}
}
}
void text_poke_apply_relocation(u8 *buf, const u8 * const instr, size_t instrlen, u8 *repl, size_t repl_len)
{
__apply_relocation(buf, instr, instrlen, repl, repl_len);
optimize_nops(instr, buf, instrlen);
}
/* Low-level backend functions usable from alternative code replacements. */
DEFINE_ASM_FUNC(nop_func, "", .entry.text);
EXPORT_SYMBOL_GPL(nop_func);
noinstr void BUG_func(void)
{
BUG();
}
EXPORT_SYMBOL(BUG_func);
#define CALL_RIP_REL_OPCODE 0xff
#define CALL_RIP_REL_MODRM 0x15
/*
* Rewrite the "call BUG_func" replacement to point to the target of the
* indirect pv_ops call "call *disp(%ip)".
*/
static int alt_replace_call(u8 *instr, u8 *insn_buff, struct alt_instr *a)
{
void *target, *bug = &BUG_func;
s32 disp;
if (a->replacementlen != 5 || insn_buff[0] != CALL_INSN_OPCODE) {
pr_err("ALT_FLAG_DIRECT_CALL set for a non-call replacement instruction\n");
BUG();
}
if (a->instrlen != 6 ||
instr[0] != CALL_RIP_REL_OPCODE ||
instr[1] != CALL_RIP_REL_MODRM) {
pr_err("ALT_FLAG_DIRECT_CALL set for unrecognized indirect call\n");
BUG();
}
/* Skip CALL_RIP_REL_OPCODE and CALL_RIP_REL_MODRM */
disp = *(s32 *)(instr + 2);
#ifdef CONFIG_X86_64
/* ff 15 00 00 00 00 call *0x0(%rip) */
/* target address is stored at "next instruction + disp". */
target = *(void **)(instr + a->instrlen + disp);
#else
/* ff 15 00 00 00 00 call *0x0 */
/* target address is stored at disp. */
target = *(void **)disp;
#endif
if (!target)
target = bug;
/* (BUG_func - .) + (target - BUG_func) := target - . */
*(s32 *)(insn_buff + 1) += target - bug;
if (target == &nop_func)
return 0;
return 5;
}
static inline u8 * instr_va(struct alt_instr *i)
{
return (u8 *)&i->instr_offset + i->instr_offset;
}
/*
* Replace instructions with better alternatives for this CPU type. This runs
* before SMP is initialized to avoid SMP problems with self modifying code.
* This implies that asymmetric systems where APs have less capabilities than
* the boot processor are not handled. Tough. Make sure you disable such
* features by hand.
*
* Marked "noinline" to cause control flow change and thus insn cache
* to refetch changed I$ lines.
*/
void __init_or_module noinline apply_alternatives(struct alt_instr *start,
struct alt_instr *end)
{
u8 insn_buff[MAX_PATCH_LEN];
u8 *instr, *replacement;
struct alt_instr *a, *b;
DPRINTK(ALT, "alt table %px, -> %px", start, end);
/*
* KASAN_SHADOW_START is defined using
* cpu_feature_enabled(X86_FEATURE_LA57) and is therefore patched here.
* During the process, KASAN becomes confused seeing partial LA57
* conversion and triggers a false-positive out-of-bound report.
*
* Disable KASAN until the patching is complete.
*/
kasan_disable_current();
/*
* The scan order should be from start to end. A later scanned
* alternative code can overwrite previously scanned alternative code.
* Some kernel functions (e.g. memcpy, memset, etc) use this order to
* patch code.
*
* So be careful if you want to change the scan order to any other
* order.
*/
for (a = start; a < end; a++) {
int insn_buff_sz = 0;
/*
* In case of nested ALTERNATIVE()s the outer alternative might
* add more padding. To ensure consistent patching find the max
* padding for all alt_instr entries for this site (nested
* alternatives result in consecutive entries).
*/
for (b = a+1; b < end && instr_va(b) == instr_va(a); b++) {
u8 len = max(a->instrlen, b->instrlen);
a->instrlen = b->instrlen = len;
}
instr = instr_va(a);
replacement = (u8 *)&a->repl_offset + a->repl_offset;
BUG_ON(a->instrlen > sizeof(insn_buff));
BUG_ON(a->cpuid >= (NCAPINTS + NBUGINTS) * 32);
/*
* Patch if either:
* - feature is present
* - feature not present but ALT_FLAG_NOT is set to mean,
* patch if feature is *NOT* present.
*/
if (!boot_cpu_has(a->cpuid) == !(a->flags & ALT_FLAG_NOT)) {
memcpy(insn_buff, instr, a->instrlen);
optimize_nops(instr, insn_buff, a->instrlen);
text_poke_early(instr, insn_buff, a->instrlen);
continue;
}
DPRINTK(ALT, "feat: %d*32+%d, old: (%pS (%px) len: %d), repl: (%px, len: %d) flags: 0x%x",
a->cpuid >> 5,
a->cpuid & 0x1f,
instr, instr, a->instrlen,
replacement, a->replacementlen, a->flags);
memcpy(insn_buff, replacement, a->replacementlen);
insn_buff_sz = a->replacementlen;
if (a->flags & ALT_FLAG_DIRECT_CALL) {
insn_buff_sz = alt_replace_call(instr, insn_buff, a);
if (insn_buff_sz < 0)
continue;
}
for (; insn_buff_sz < a->instrlen; insn_buff_sz++)
insn_buff[insn_buff_sz] = 0x90;
text_poke_apply_relocation(insn_buff, instr, a->instrlen, replacement, a->replacementlen);
DUMP_BYTES(ALT, instr, a->instrlen, "%px: old_insn: ", instr);
DUMP_BYTES(ALT, replacement, a->replacementlen, "%px: rpl_insn: ", replacement);
DUMP_BYTES(ALT, insn_buff, insn_buff_sz, "%px: final_insn: ", instr);
text_poke_early(instr, insn_buff, insn_buff_sz);
}
kasan_enable_current();
}
static inline bool is_jcc32(struct insn *insn)
{
/* Jcc.d32 second opcode byte is in the range: 0x80-0x8f */
return insn->opcode.bytes[0] == 0x0f && (insn->opcode.bytes[1] & 0xf0) == 0x80;
}
#if defined(CONFIG_MITIGATION_RETPOLINE) && defined(CONFIG_OBJTOOL)
/*
* CALL/JMP *%\reg
*/
static int emit_indirect(int op, int reg, u8 *bytes)
{
int i = 0;
u8 modrm;
switch (op) {
case CALL_INSN_OPCODE:
modrm = 0x10; /* Reg = 2; CALL r/m */
break;
case JMP32_INSN_OPCODE:
modrm = 0x20; /* Reg = 4; JMP r/m */
break;
default:
WARN_ON_ONCE(1);
return -1;
}
if (reg >= 8) {
bytes[i++] = 0x41; /* REX.B prefix */
reg -= 8;
}
modrm |= 0xc0; /* Mod = 3 */
modrm += reg;
bytes[i++] = 0xff; /* opcode */
bytes[i++] = modrm;
return i;
}
static int __emit_trampoline(void *addr, struct insn *insn, u8 *bytes,
void *call_dest, void *jmp_dest)
{
u8 op = insn->opcode.bytes[0];
int i = 0;
/*
* Clang does 'weird' Jcc __x86_indirect_thunk_r11 conditional
* tail-calls. Deal with them.
*/
if (is_jcc32(insn)) {
bytes[i++] = op;
op = insn->opcode.bytes[1];
goto clang_jcc;
}
if (insn->length == 6)
bytes[i++] = 0x2e; /* CS-prefix */
switch (op) {
case CALL_INSN_OPCODE:
__text_gen_insn(bytes+i, op, addr+i,
call_dest,
CALL_INSN_SIZE);
i += CALL_INSN_SIZE;
break;
case JMP32_INSN_OPCODE:
clang_jcc:
__text_gen_insn(bytes+i, op, addr+i,
jmp_dest,
JMP32_INSN_SIZE);
i += JMP32_INSN_SIZE;
break;
default:
WARN(1, "%pS %px %*ph\n", addr, addr, 6, addr);
return -1;
}
WARN_ON_ONCE(i != insn->length);
return i;
}
static int emit_call_track_retpoline(void *addr, struct insn *insn, int reg, u8 *bytes)
{
return __emit_trampoline(addr, insn, bytes,
__x86_indirect_call_thunk_array[reg],
__x86_indirect_jump_thunk_array[reg]);
}
#ifdef CONFIG_MITIGATION_ITS
static int emit_its_trampoline(void *addr, struct insn *insn, int reg, u8 *bytes)
{
u8 *thunk = __x86_indirect_its_thunk_array[reg];
u8 *tmp = its_allocate_thunk(reg);
if (tmp)
thunk = tmp;
return __emit_trampoline(addr, insn, bytes, thunk, thunk);
}
/* Check if an indirect branch is at ITS-unsafe address */
static bool cpu_wants_indirect_its_thunk_at(unsigned long addr, int reg)
{
if (!cpu_feature_enabled(X86_FEATURE_INDIRECT_THUNK_ITS))
return false;
/* Indirect branch opcode is 2 or 3 bytes depending on reg */
addr += 1 + reg / 8;
/* Lower-half of the cacheline? */
return !(addr & 0x20);
}
#else /* CONFIG_MITIGATION_ITS */
#ifdef CONFIG_FINEIBT
static bool cpu_wants_indirect_its_thunk_at(unsigned long addr, int reg)
{
return false;
}
#endif
#endif /* CONFIG_MITIGATION_ITS */
/*
* Rewrite the compiler generated retpoline thunk calls.
*
* For spectre_v2=off (!X86_FEATURE_RETPOLINE), rewrite them into immediate
* indirect instructions, avoiding the extra indirection.
*
* For example, convert:
*
* CALL __x86_indirect_thunk_\reg
*
* into:
*
* CALL *%\reg
*
* It also tries to inline spectre_v2=retpoline,lfence when size permits.
*/
static int patch_retpoline(void *addr, struct insn *insn, u8 *bytes)
{
retpoline_thunk_t *target;
int reg, ret, i = 0;
u8 op, cc;
target = addr + insn->length + insn->immediate.value;
reg = target - __x86_indirect_thunk_array;
if (WARN_ON_ONCE(reg & ~0xf))
return -1;
/* If anyone ever does: CALL/JMP *%rsp, we're in deep trouble. */
BUG_ON(reg == 4);
if (cpu_feature_enabled(X86_FEATURE_RETPOLINE) &&
!cpu_feature_enabled(X86_FEATURE_RETPOLINE_LFENCE)) {
if (cpu_feature_enabled(X86_FEATURE_CALL_DEPTH))
return emit_call_track_retpoline(addr, insn, reg, bytes);
return -1;
}
op = insn->opcode.bytes[0];
/*
* Convert:
*
* Jcc.d32 __x86_indirect_thunk_\reg
*
* into:
*
* Jncc.d8 1f
* [ LFENCE ]
* JMP *%\reg
* [ NOP ]
* 1:
*/
if (is_jcc32(insn)) {
cc = insn->opcode.bytes[1] & 0xf;
cc ^= 1; /* invert condition */
bytes[i++] = 0x70 + cc; /* Jcc.d8 */
bytes[i++] = insn->length - 2; /* sizeof(Jcc.d8) == 2 */
/* Continue as if: JMP.d32 __x86_indirect_thunk_\reg */
op = JMP32_INSN_OPCODE;
}
/*
* For RETPOLINE_LFENCE: prepend the indirect CALL/JMP with an LFENCE.
*/
if (cpu_feature_enabled(X86_FEATURE_RETPOLINE_LFENCE)) {
bytes[i++] = 0x0f;
bytes[i++] = 0xae;
bytes[i++] = 0xe8; /* LFENCE */
}
#ifdef CONFIG_MITIGATION_ITS
/*
* Check if the address of last byte of emitted-indirect is in
* lower-half of the cacheline. Such branches need ITS mitigation.
*/
if (cpu_wants_indirect_its_thunk_at((unsigned long)addr + i, reg))
return emit_its_trampoline(addr, insn, reg, bytes);
#endif
ret = emit_indirect(op, reg, bytes + i);
if (ret < 0)
return ret;
i += ret;
/*
* The compiler is supposed to EMIT an INT3 after every unconditional
* JMP instruction due to AMD BTC. However, if the compiler is too old
* or MITIGATION_SLS isn't enabled, we still need an INT3 after
* indirect JMPs even on Intel.
*/
if (op == JMP32_INSN_OPCODE && i < insn->length)
bytes[i++] = INT3_INSN_OPCODE;
for (; i < insn->length;)
bytes[i++] = BYTES_NOP1;
return i;
}
/*
* Generated by 'objtool --retpoline'.
*/
void __init_or_module noinline apply_retpolines(s32 *start, s32 *end)
{
s32 *s;
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
struct insn insn;
int len, ret;
u8 bytes[16];
u8 op1, op2;
u8 *dest;
ret = insn_decode_kernel(&insn, addr);
if (WARN_ON_ONCE(ret < 0))
continue;
op1 = insn.opcode.bytes[0];
op2 = insn.opcode.bytes[1];
switch (op1) {
case 0x70 ... 0x7f: /* Jcc.d8 */
/* See cfi_paranoid. */
WARN_ON_ONCE(cfi_mode != CFI_FINEIBT);
continue;
case CALL_INSN_OPCODE:
case JMP32_INSN_OPCODE:
/* Check for cfi_paranoid + ITS */
dest = addr + insn.length + insn.immediate.value;
if (dest[-1] == 0xea && (dest[0] & 0xf0) == 0x70) {
WARN_ON_ONCE(cfi_mode != CFI_FINEIBT);
continue;
}
break;
case 0x0f: /* escape */
if (op2 >= 0x80 && op2 <= 0x8f)
break;
fallthrough;
default:
WARN_ON_ONCE(1);
continue;
}
DPRINTK(RETPOLINE, "retpoline at: %pS (%px) len: %d to: %pS",
addr, addr, insn.length,
addr + insn.length + insn.immediate.value);
len = patch_retpoline(addr, &insn, bytes);
if (len == insn.length) {
optimize_nops(addr, bytes, len);
DUMP_BYTES(RETPOLINE, ((u8*)addr), len, "%px: orig: ", addr);
DUMP_BYTES(RETPOLINE, ((u8*)bytes), len, "%px: repl: ", addr);
text_poke_early(addr, bytes, len);
}
}
}
#ifdef CONFIG_MITIGATION_RETHUNK
bool cpu_wants_rethunk(void)
{
return cpu_feature_enabled(X86_FEATURE_RETHUNK);
}
bool cpu_wants_rethunk_at(void *addr)
{
if (!cpu_feature_enabled(X86_FEATURE_RETHUNK))
return false;
if (x86_return_thunk != its_return_thunk)
return true;
return !((unsigned long)addr & 0x20);
}
/*
* Rewrite the compiler generated return thunk tail-calls.
*
* For example, convert:
*
* JMP __x86_return_thunk
*
* into:
*
* RET
*/
static int patch_return(void *addr, struct insn *insn, u8 *bytes)
{
int i = 0;
/* Patch the custom return thunks... */
if (cpu_wants_rethunk_at(addr)) {
i = JMP32_INSN_SIZE;
__text_gen_insn(bytes, JMP32_INSN_OPCODE, addr, x86_return_thunk, i);
} else {
/* ... or patch them out if not needed. */
bytes[i++] = RET_INSN_OPCODE;
}
for (; i < insn->length;)
bytes[i++] = INT3_INSN_OPCODE;
return i;
}
void __init_or_module noinline apply_returns(s32 *start, s32 *end)
{
s32 *s;
if (cpu_wants_rethunk())
static_call_force_reinit();
for (s = start; s < end; s++) {
void *dest = NULL, *addr = (void *)s + *s;
struct insn insn;
int len, ret;
u8 bytes[16];
u8 op;
ret = insn_decode_kernel(&insn, addr);
if (WARN_ON_ONCE(ret < 0))
continue;
op = insn.opcode.bytes[0];
if (op == JMP32_INSN_OPCODE)
dest = addr + insn.length + insn.immediate.value;
if (__static_call_fixup(addr, op, dest) ||
WARN_ONCE(dest != &__x86_return_thunk,
"missing return thunk: %pS-%pS: %*ph",
addr, dest, 5, addr))
continue;
DPRINTK(RET, "return thunk at: %pS (%px) len: %d to: %pS",
addr, addr, insn.length,
addr + insn.length + insn.immediate.value);
len = patch_return(addr, &insn, bytes);
if (len == insn.length) {
DUMP_BYTES(RET, ((u8*)addr), len, "%px: orig: ", addr);
DUMP_BYTES(RET, ((u8*)bytes), len, "%px: repl: ", addr);
text_poke_early(addr, bytes, len);
}
}
}
#else /* !CONFIG_MITIGATION_RETHUNK: */
void __init_or_module noinline apply_returns(s32 *start, s32 *end) { }
#endif /* !CONFIG_MITIGATION_RETHUNK */
#else /* !CONFIG_MITIGATION_RETPOLINE || !CONFIG_OBJTOOL */
void __init_or_module noinline apply_retpolines(s32 *start, s32 *end) { }
void __init_or_module noinline apply_returns(s32 *start, s32 *end) { }
#endif /* !CONFIG_MITIGATION_RETPOLINE || !CONFIG_OBJTOOL */
#ifdef CONFIG_X86_KERNEL_IBT
__noendbr bool is_endbr(u32 *val)
{
u32 endbr;
__get_kernel_nofault(&endbr, val, u32, Efault);
return __is_endbr(endbr);
Efault:
return false;
}
#ifdef CONFIG_FINEIBT
static __noendbr bool exact_endbr(u32 *val)
{
u32 endbr;
__get_kernel_nofault(&endbr, val, u32, Efault);
return endbr == gen_endbr();
Efault:
return false;
}
#endif
static void poison_cfi(void *addr);
static void __init_or_module poison_endbr(void *addr)
{
u32 poison = gen_endbr_poison();
if (WARN_ON_ONCE(!is_endbr(addr)))
return;
DPRINTK(ENDBR, "ENDBR at: %pS (%px)", addr, addr);
/*
* When we have IBT, the lack of ENDBR will trigger #CP
*/
DUMP_BYTES(ENDBR, ((u8*)addr), 4, "%px: orig: ", addr);
DUMP_BYTES(ENDBR, ((u8*)&poison), 4, "%px: repl: ", addr);
text_poke_early(addr, &poison, 4);
}
/*
* Generated by: objtool --ibt
*
* Seal the functions for indirect calls by clobbering the ENDBR instructions
* and the kCFI hash value.
*/
void __init_or_module noinline apply_seal_endbr(s32 *start, s32 *end)
{
s32 *s;
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
poison_endbr(addr);
if (IS_ENABLED(CONFIG_FINEIBT))
poison_cfi(addr - 16);
}
}
#else /* !CONFIG_X86_KERNEL_IBT: */
void __init_or_module apply_seal_endbr(s32 *start, s32 *end) { }
#endif /* !CONFIG_X86_KERNEL_IBT */
#ifdef CONFIG_CFI_AUTO_DEFAULT
# define __CFI_DEFAULT CFI_AUTO
#elif defined(CONFIG_CFI_CLANG)
# define __CFI_DEFAULT CFI_KCFI
#else
# define __CFI_DEFAULT CFI_OFF
#endif
enum cfi_mode cfi_mode __ro_after_init = __CFI_DEFAULT;
#ifdef CONFIG_FINEIBT_BHI
bool cfi_bhi __ro_after_init = false;
#endif
#ifdef CONFIG_CFI_CLANG
u32 cfi_get_func_hash(void *func)
{
u32 hash;
func -= cfi_get_offset();
switch (cfi_mode) {
case CFI_FINEIBT:
func += 7;
break;
case CFI_KCFI:
func += 1;
break;
default:
return 0;
}
if (get_kernel_nofault(hash, func))
return 0;
return hash;
}
int cfi_get_func_arity(void *func)
{
bhi_thunk *target;
s32 disp;
if (cfi_mode != CFI_FINEIBT && !cfi_bhi)
return 0;
if (get_kernel_nofault(disp, func - 4))
return 0;
target = func + disp;
return target - __bhi_args;
}
#endif
#ifdef CONFIG_FINEIBT
static bool cfi_rand __ro_after_init = true;
static u32 cfi_seed __ro_after_init;
/*
* Re-hash the CFI hash with a boot-time seed while making sure the result is
* not a valid ENDBR instruction.
*/
static u32 cfi_rehash(u32 hash)
{
hash ^= cfi_seed;
while (unlikely(__is_endbr(hash) || __is_endbr(-hash))) {
bool lsb = hash & 1;
hash >>= 1;
if (lsb)
hash ^= 0x80200003;
}
return hash;
}
static __init int cfi_parse_cmdline(char *str)
{
if (!str)
return -EINVAL;
while (str) {
char *next = strchr(str, ',');
if (next) {
*next = 0;
next++;
}
if (!strcmp(str, "auto")) {
cfi_mode = CFI_AUTO;
} else if (!strcmp(str, "off")) {
cfi_mode = CFI_OFF;
cfi_rand = false;
} else if (!strcmp(str, "kcfi")) {
cfi_mode = CFI_KCFI;
} else if (!strcmp(str, "fineibt")) {
cfi_mode = CFI_FINEIBT;
} else if (!strcmp(str, "norand")) {
cfi_rand = false;
} else if (!strcmp(str, "warn")) {
pr_alert("CFI mismatch non-fatal!\n");
cfi_warn = true;
} else if (!strcmp(str, "paranoid")) {
if (cfi_mode == CFI_FINEIBT) {
cfi_paranoid = true;
} else {
pr_err("Ignoring paranoid; depends on fineibt.\n");
}
} else if (!strcmp(str, "bhi")) {
#ifdef CONFIG_FINEIBT_BHI
if (cfi_mode == CFI_FINEIBT) {
cfi_bhi = true;
} else {
pr_err("Ignoring bhi; depends on fineibt.\n");
}
#else
pr_err("Ignoring bhi; depends on FINEIBT_BHI=y.\n");
#endif
} else {
pr_err("Ignoring unknown cfi option (%s).", str);
}
str = next;
}
return 0;
}
early_param("cfi", cfi_parse_cmdline);
/*
* kCFI FineIBT
*
* __cfi_\func: __cfi_\func:
* movl $0x12345678,%eax // 5 endbr64 // 4
* nop subl $0x12345678,%r10d // 7
* nop jne __cfi_\func+6 // 2
* nop nop3 // 3
* nop
* nop
* nop
* nop
* nop
* nop
* nop
* nop
*
*
* caller: caller:
* movl $(-0x12345678),%r10d // 6 movl $0x12345678,%r10d // 6
* addl $-15(%r11),%r10d // 4 lea -0x10(%r11),%r11 // 4
* je 1f // 2 nop4 // 4
* ud2 // 2
* 1: cs call __x86_indirect_thunk_r11 // 6 call *%r11; nop3; // 6
*
*/
/*
* <fineibt_preamble_start>:
* 0: f3 0f 1e fa endbr64
* 4: 41 81 <ea> 78 56 34 12 sub $0x12345678, %r10d
* b: 75 f9 jne 6 <fineibt_preamble_start+0x6>
* d: 0f 1f 00 nopl (%rax)
*
* Note that the JNE target is the 0xEA byte inside the SUB, this decodes as
* (bad) on x86_64 and raises #UD.
*/
asm( ".pushsection .rodata \n"
"fineibt_preamble_start: \n"
" endbr64 \n"
" subl $0x12345678, %r10d \n"
"fineibt_preamble_bhi: \n"
" jne fineibt_preamble_start+6 \n"
ASM_NOP3
"fineibt_preamble_end: \n"
".popsection\n"
);
extern u8 fineibt_preamble_start[];
extern u8 fineibt_preamble_bhi[];
extern u8 fineibt_preamble_end[];
#define fineibt_preamble_size (fineibt_preamble_end - fineibt_preamble_start)
#define fineibt_preamble_bhi (fineibt_preamble_bhi - fineibt_preamble_start)
#define fineibt_preamble_ud 6
#define fineibt_preamble_hash 7
/*
* <fineibt_caller_start>:
* 0: 41 ba 78 56 34 12 mov $0x12345678, %r10d
* 6: 4d 8d 5b f0 lea -0x10(%r11), %r11
* a: 0f 1f 40 00 nopl 0x0(%rax)
*/
asm( ".pushsection .rodata \n"
"fineibt_caller_start: \n"
" movl $0x12345678, %r10d \n"
" lea -0x10(%r11), %r11 \n"
ASM_NOP4
"fineibt_caller_end: \n"
".popsection \n"
);
extern u8 fineibt_caller_start[];
extern u8 fineibt_caller_end[];
#define fineibt_caller_size (fineibt_caller_end - fineibt_caller_start)
#define fineibt_caller_hash 2
#define fineibt_caller_jmp (fineibt_caller_size - 2)
/*
* Since FineIBT does hash validation on the callee side it is prone to
* circumvention attacks where a 'naked' ENDBR instruction exists that
* is not part of the fineibt_preamble sequence.
*
* Notably the x86 entry points must be ENDBR and equally cannot be
* fineibt_preamble.
*
* The fineibt_paranoid caller sequence adds additional caller side
* hash validation. This stops such circumvention attacks dead, but at the cost
* of adding a load.
*
* <fineibt_paranoid_start>:
* 0: 41 ba 78 56 34 12 mov $0x12345678, %r10d
* 6: 45 3b 53 f7 cmp -0x9(%r11), %r10d
* a: 4d 8d 5b <f0> lea -0x10(%r11), %r11
* e: 75 fd jne d <fineibt_paranoid_start+0xd>
* 10: 41 ff d3 call *%r11
* 13: 90 nop
*
* Notably LEA does not modify flags and can be reordered with the CMP,
* avoiding a dependency. Again, using a non-taken (backwards) branch
* for the failure case, abusing LEA's immediate 0xf0 as LOCK prefix for the
* Jcc.d8, causing #UD.
*/
asm( ".pushsection .rodata \n"
"fineibt_paranoid_start: \n"
" movl $0x12345678, %r10d \n"
" cmpl -9(%r11), %r10d \n"
" lea -0x10(%r11), %r11 \n"
" jne fineibt_paranoid_start+0xd \n"
"fineibt_paranoid_ind: \n"
" call *%r11 \n"
" nop \n"
"fineibt_paranoid_end: \n"
".popsection \n"
);
extern u8 fineibt_paranoid_start[];
extern u8 fineibt_paranoid_ind[];
extern u8 fineibt_paranoid_end[];
#define fineibt_paranoid_size (fineibt_paranoid_end - fineibt_paranoid_start)
#define fineibt_paranoid_ind (fineibt_paranoid_ind - fineibt_paranoid_start)
#define fineibt_paranoid_ud 0xd
static u32 decode_preamble_hash(void *addr, int *reg)
{
u8 *p = addr;
/* b8+reg 78 56 34 12 movl $0x12345678,\reg */
if (p[0] >= 0xb8 && p[0] < 0xc0) {
if (reg)
*reg = p[0] - 0xb8;
return *(u32 *)(addr + 1);
}
return 0; /* invalid hash value */
}
static u32 decode_caller_hash(void *addr)
{
u8 *p = addr;
/* 41 ba 88 a9 cb ed mov $(-0x12345678),%r10d */
if (p[0] == 0x41 && p[1] == 0xba)
return -*(u32 *)(addr + 2);
/* e8 0c 88 a9 cb ed jmp.d8 +12 */
if (p[0] == JMP8_INSN_OPCODE && p[1] == fineibt_caller_jmp)
return -*(u32 *)(addr + 2);
return 0; /* invalid hash value */
}
/* .retpoline_sites */
static int cfi_disable_callers(s32 *start, s32 *end)
{
/*
* Disable kCFI by patching in a JMP.d8, this leaves the hash immediate
* in tact for later usage. Also see decode_caller_hash() and
* cfi_rewrite_callers().
*/
const u8 jmp[] = { JMP8_INSN_OPCODE, fineibt_caller_jmp };
s32 *s;
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
u32 hash;
addr -= fineibt_caller_size;
hash = decode_caller_hash(addr);
if (!hash) /* nocfi callers */
continue;
text_poke_early(addr, jmp, 2);
}
return 0;
}
static int cfi_enable_callers(s32 *start, s32 *end)
{
/*
* Re-enable kCFI, undo what cfi_disable_callers() did.
*/
const u8 mov[] = { 0x41, 0xba };
s32 *s;
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
u32 hash;
addr -= fineibt_caller_size;
hash = decode_caller_hash(addr);
if (!hash) /* nocfi callers */
continue;
text_poke_early(addr, mov, 2);
}
return 0;
}
/* .cfi_sites */
static int cfi_rand_preamble(s32 *start, s32 *end)
{
s32 *s;
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
u32 hash;
hash = decode_preamble_hash(addr, NULL);
if (WARN(!hash, "no CFI hash found at: %pS %px %*ph\n",
addr, addr, 5, addr))
return -EINVAL;
hash = cfi_rehash(hash);
text_poke_early(addr + 1, &hash, 4);
}
return 0;
}
static void cfi_fineibt_bhi_preamble(void *addr, int arity)
{
if (!arity)
return;
if (!cfi_warn && arity == 1) {
/*
* Crazy scheme to allow arity-1 inline:
*
* __cfi_foo:
* 0: f3 0f 1e fa endbr64
* 4: 41 81 <ea> 78 56 34 12 sub 0x12345678, %r10d
* b: 49 0f 45 fa cmovne %r10, %rdi
* f: 75 f5 jne __cfi_foo+6
* 11: 0f 1f 00 nopl (%rax)
*
* Code that direct calls to foo()+0, decodes the tail end as:
*
* foo:
* 0: f5 cmc
* 1: 0f 1f 00 nopl (%rax)
*
* which clobbers CF, but does not affect anything ABI
* wise.
*
* Notably, this scheme is incompatible with permissive CFI
* because the CMOVcc is unconditional and RDI will have been
* clobbered.
*/
const u8 magic[9] = {
0x49, 0x0f, 0x45, 0xfa,
0x75, 0xf5,
BYTES_NOP3,
};
text_poke_early(addr + fineibt_preamble_bhi, magic, 9);
return;
}
text_poke_early(addr + fineibt_preamble_bhi,
text_gen_insn(CALL_INSN_OPCODE,
addr + fineibt_preamble_bhi,
__bhi_args[arity]),
CALL_INSN_SIZE);
}
static int cfi_rewrite_preamble(s32 *start, s32 *end)
{
s32 *s;
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
int arity;
u32 hash;
/*
* When the function doesn't start with ENDBR the compiler will
* have determined there are no indirect calls to it and we
* don't need no CFI either.
*/
if (!is_endbr(addr + 16))
continue;
hash = decode_preamble_hash(addr, &arity);
if (WARN(!hash, "no CFI hash found at: %pS %px %*ph\n",
addr, addr, 5, addr))
return -EINVAL;
text_poke_early(addr, fineibt_preamble_start, fineibt_preamble_size);
WARN_ON(*(u32 *)(addr + fineibt_preamble_hash) != 0x12345678);
text_poke_early(addr + fineibt_preamble_hash, &hash, 4);
WARN_ONCE(!IS_ENABLED(CONFIG_FINEIBT_BHI) && arity,
"kCFI preamble has wrong register at: %pS %*ph\n",
addr, 5, addr);
if (cfi_bhi)
cfi_fineibt_bhi_preamble(addr, arity);
}
return 0;
}
static void cfi_rewrite_endbr(s32 *start, s32 *end)
{
s32 *s;
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
if (!exact_endbr(addr + 16))
continue;
poison_endbr(addr + 16);
}
}
/* .retpoline_sites */
static int cfi_rand_callers(s32 *start, s32 *end)
{
s32 *s;
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
u32 hash;
addr -= fineibt_caller_size;
hash = decode_caller_hash(addr);
if (hash) {
hash = -cfi_rehash(hash);
text_poke_early(addr + 2, &hash, 4);
}
}
return 0;
}
static int emit_paranoid_trampoline(void *addr, struct insn *insn, int reg, u8 *bytes)
{
u8 *thunk = (void *)__x86_indirect_its_thunk_array[reg] - 2;
#ifdef CONFIG_MITIGATION_ITS
u8 *tmp = its_allocate_thunk(reg);
if (tmp)
thunk = tmp;
#endif
return __emit_trampoline(addr, insn, bytes, thunk, thunk);
}
static int cfi_rewrite_callers(s32 *start, s32 *end)
{
s32 *s;
BUG_ON(fineibt_paranoid_size != 20);
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
struct insn insn;
u8 bytes[20];
u32 hash;
int ret;
u8 op;
addr -= fineibt_caller_size;
hash = decode_caller_hash(addr);
if (!hash)
continue;
if (!cfi_paranoid) {
text_poke_early(addr, fineibt_caller_start, fineibt_caller_size);
WARN_ON(*(u32 *)(addr + fineibt_caller_hash) != 0x12345678);
text_poke_early(addr + fineibt_caller_hash, &hash, 4);
/* rely on apply_retpolines() */
continue;
}
/* cfi_paranoid */
ret = insn_decode_kernel(&insn, addr + fineibt_caller_size);
if (WARN_ON_ONCE(ret < 0))
continue;
op = insn.opcode.bytes[0];
if (op != CALL_INSN_OPCODE && op != JMP32_INSN_OPCODE) {
WARN_ON_ONCE(1);
continue;
}
memcpy(bytes, fineibt_paranoid_start, fineibt_paranoid_size);
memcpy(bytes + fineibt_caller_hash, &hash, 4);
if (cpu_wants_indirect_its_thunk_at((unsigned long)addr + fineibt_paranoid_ind, 11)) {
emit_paranoid_trampoline(addr + fineibt_caller_size,
&insn, 11, bytes + fineibt_caller_size);
} else {
ret = emit_indirect(op, 11, bytes + fineibt_paranoid_ind);
if (WARN_ON_ONCE(ret != 3))
continue;
}
text_poke_early(addr, bytes, fineibt_paranoid_size);
}
return 0;
}
static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
s32 *start_cfi, s32 *end_cfi, bool builtin)
{
int ret;
if (WARN_ONCE(fineibt_preamble_size != 16,
"FineIBT preamble wrong size: %ld", fineibt_preamble_size))
return;
if (cfi_mode == CFI_AUTO) {
cfi_mode = CFI_KCFI;
if (HAS_KERNEL_IBT && cpu_feature_enabled(X86_FEATURE_IBT)) {
/*
* FRED has much saner context on exception entry and
* is less easy to take advantage of.
*/
if (!cpu_feature_enabled(X86_FEATURE_FRED))
cfi_paranoid = true;
cfi_mode = CFI_FINEIBT;
}
}
/*
* Rewrite the callers to not use the __cfi_ stubs, such that we might
* rewrite them. This disables all CFI. If this succeeds but any of the
* later stages fails, we're without CFI.
*/
ret = cfi_disable_callers(start_retpoline, end_retpoline);
if (ret)
goto err;
if (cfi_rand) {
if (builtin) {
cfi_seed = get_random_u32();
cfi_bpf_hash = cfi_rehash(cfi_bpf_hash);
cfi_bpf_subprog_hash = cfi_rehash(cfi_bpf_subprog_hash);
}
ret = cfi_rand_preamble(start_cfi, end_cfi);
if (ret)
goto err;
ret = cfi_rand_callers(start_retpoline, end_retpoline);
if (ret)
goto err;
}
switch (cfi_mode) {
case CFI_OFF:
if (builtin)
pr_info("Disabling CFI\n");
return;
case CFI_KCFI:
ret = cfi_enable_callers(start_retpoline, end_retpoline);
if (ret)
goto err;
if (builtin)
pr_info("Using kCFI\n");
return;
case CFI_FINEIBT:
/* place the FineIBT preamble at func()-16 */
ret = cfi_rewrite_preamble(start_cfi, end_cfi);
if (ret)
goto err;
/* rewrite the callers to target func()-16 */
ret = cfi_rewrite_callers(start_retpoline, end_retpoline);
if (ret)
goto err;
/* now that nobody targets func()+0, remove ENDBR there */
cfi_rewrite_endbr(start_cfi, end_cfi);
if (builtin) {
pr_info("Using %sFineIBT%s CFI\n",
cfi_paranoid ? "paranoid " : "",
cfi_bhi ? "+BHI" : "");
}
return;
default:
break;
}
err:
pr_err("Something went horribly wrong trying to rewrite the CFI implementation.\n");
}
static inline void poison_hash(void *addr)
{
*(u32 *)addr = 0;
}
static void poison_cfi(void *addr)
{
/*
* Compilers manage to be inconsistent with ENDBR vs __cfi prefixes,
* some (static) functions for which they can determine the address
* is never taken do not get a __cfi prefix, but *DO* get an ENDBR.
*
* As such, these functions will get sealed, but we need to be careful
* to not unconditionally scribble the previous function.
*/
switch (cfi_mode) {
case CFI_FINEIBT:
/*
* FineIBT prefix should start with an ENDBR.
*/
if (!is_endbr(addr))
break;
/*
* __cfi_\func:
* osp nopl (%rax)
* subl $0, %r10d
* jz 1f
* ud2
* 1: nop
*/
poison_endbr(addr);
poison_hash(addr + fineibt_preamble_hash);
break;
case CFI_KCFI:
/*
* kCFI prefix should start with a valid hash.
*/
if (!decode_preamble_hash(addr, NULL))
break;
/*
* __cfi_\func:
* movl $0, %eax
* .skip 11, 0x90
*/
poison_hash(addr + 1);
break;
default:
break;
}
}
/*
* When regs->ip points to a 0xEA byte in the FineIBT preamble,
* return true and fill out target and type.
*
* We check the preamble by checking for the ENDBR instruction relative to the
* 0xEA instruction.
*/
static bool decode_fineibt_preamble(struct pt_regs *regs, unsigned long *target, u32 *type)
{
unsigned long addr = regs->ip - fineibt_preamble_ud;
u32 hash;
if (!exact_endbr((void *)addr))
return false;
*target = addr + fineibt_preamble_size;
__get_kernel_nofault(&hash, addr + fineibt_preamble_hash, u32, Efault);
*type = (u32)regs->r10 + hash;
/*
* Since regs->ip points to the middle of an instruction; it cannot
* continue with the normal fixup.
*/
regs->ip = *target;
return true;
Efault:
return false;
}
/*
* regs->ip points to one of the UD2 in __bhi_args[].
*/
static bool decode_fineibt_bhi(struct pt_regs *regs, unsigned long *target, u32 *type)
{
unsigned long addr;
u32 hash;
if (!cfi_bhi)
return false;
if (regs->ip < (unsigned long)__bhi_args ||
regs->ip >= (unsigned long)__bhi_args_end)
return false;
/*
* Fetch the return address from the stack, this points to the
* FineIBT preamble. Since the CALL instruction is in the 5 last
* bytes of the preamble, the return address is in fact the target
* address.
*/
__get_kernel_nofault(&addr, regs->sp, unsigned long, Efault);
*target = addr;
addr -= fineibt_preamble_size;
if (!exact_endbr((void *)addr))
return false;
__get_kernel_nofault(&hash, addr + fineibt_preamble_hash, u32, Efault);
*type = (u32)regs->r10 + hash;
/*
* The UD2 sites are constructed with a RET immediately following,
* as such the non-fatal case can use the regular fixup.
*/
return true;
Efault:
return false;
}
static bool is_paranoid_thunk(unsigned long addr)
{
u32 thunk;
__get_kernel_nofault(&thunk, (u32 *)addr, u32, Efault);
return (thunk & 0x00FFFFFF) == 0xfd75ea;
Efault:
return false;
}
/*
* regs->ip points to a LOCK Jcc.d8 instruction from the fineibt_paranoid_start[]
* sequence, or to an invalid instruction (0xea) + Jcc.d8 for cfi_paranoid + ITS
* thunk.
*/
static bool decode_fineibt_paranoid(struct pt_regs *regs, unsigned long *target, u32 *type)
{
unsigned long addr = regs->ip - fineibt_paranoid_ud;
if (!cfi_paranoid)
return false;
if (is_cfi_trap(addr + fineibt_caller_size - LEN_UD2)) {
*target = regs->r11 + fineibt_preamble_size;
*type = regs->r10;
/*
* Since the trapping instruction is the exact, but LOCK prefixed,
* Jcc.d8 that got us here, the normal fixup will work.
*/
return true;
}
/*
* The cfi_paranoid + ITS thunk combination results in:
*
* 0: 41 ba 78 56 34 12 mov $0x12345678, %r10d
* 6: 45 3b 53 f7 cmp -0x9(%r11), %r10d
* a: 4d 8d 5b f0 lea -0x10(%r11), %r11
* e: 2e e8 XX XX XX XX cs call __x86_indirect_paranoid_thunk_r11
*
* Where the paranoid_thunk looks like:
*
* 1d: <ea> (bad)
* __x86_indirect_paranoid_thunk_r11:
* 1e: 75 fd jne 1d
* __x86_indirect_its_thunk_r11:
* 20: 41 ff eb jmp *%r11
* 23: cc int3
*
*/
if (is_paranoid_thunk(regs->ip)) {
*target = regs->r11 + fineibt_preamble_size;
*type = regs->r10;
regs->ip = *target;
return true;
}
return false;
}
bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type)
{
if (decode_fineibt_paranoid(regs, target, type))
return true;
if (decode_fineibt_bhi(regs, target, type))
return true;
return decode_fineibt_preamble(regs, target, type);
}
#else /* !CONFIG_FINEIBT: */
static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
s32 *start_cfi, s32 *end_cfi, bool builtin)
{
}
#ifdef CONFIG_X86_KERNEL_IBT
static void poison_cfi(void *addr) { }
#endif
#endif /* !CONFIG_FINEIBT */
void apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
s32 *start_cfi, s32 *end_cfi)
{
return __apply_fineibt(start_retpoline, end_retpoline,
start_cfi, end_cfi,
/* .builtin = */ false);
}
#ifdef CONFIG_SMP
static void alternatives_smp_lock(const s32 *start, const s32 *end,
u8 *text, u8 *text_end)
{
const s32 *poff;
for (poff = start; poff < end; poff++) {
u8 *ptr = (u8 *)poff + *poff;
if (!*poff || ptr < text || ptr >= text_end)
continue;
/* turn DS segment override prefix into lock prefix */
if (*ptr == 0x3e)
text_poke(ptr, ((unsigned char []){0xf0}), 1);
}
}
static void alternatives_smp_unlock(const s32 *start, const s32 *end,
u8 *text, u8 *text_end)
{
const s32 *poff;
for (poff = start; poff < end; poff++) {
u8 *ptr = (u8 *)poff + *poff;
if (!*poff || ptr < text || ptr >= text_end)
continue;
/* turn lock prefix into DS segment override prefix */
if (*ptr == 0xf0)
text_poke(ptr, ((unsigned char []){0x3E}), 1);
}
}
struct smp_alt_module {
/* what is this ??? */
struct module *mod;
char *name;
/* ptrs to lock prefixes */
const s32 *locks;
const s32 *locks_end;
/* .text segment, needed to avoid patching init code ;) */
u8 *text;
u8 *text_end;
struct list_head next;
};
static LIST_HEAD(smp_alt_modules);
static bool uniproc_patched = false; /* protected by text_mutex */
void __init_or_module alternatives_smp_module_add(struct module *mod,
char *name,
void *locks, void *locks_end,
void *text, void *text_end)
{
struct smp_alt_module *smp;
mutex_lock(&text_mutex);
if (!uniproc_patched)
goto unlock;
if (num_possible_cpus() == 1)
/* Don't bother remembering, we'll never have to undo it. */
goto smp_unlock;
smp = kzalloc(sizeof(*smp), GFP_KERNEL);
if (NULL == smp)
/* we'll run the (safe but slow) SMP code then ... */
goto unlock;
smp->mod = mod;
smp->name = name;
smp->locks = locks;
smp->locks_end = locks_end;
smp->text = text;
smp->text_end = text_end;
DPRINTK(SMP, "locks %p -> %p, text %p -> %p, name %s\n",
smp->locks, smp->locks_end,
smp->text, smp->text_end, smp->name);
list_add_tail(&smp->next, &smp_alt_modules);
smp_unlock:
alternatives_smp_unlock(locks, locks_end, text, text_end);
unlock:
mutex_unlock(&text_mutex);
}
void __init_or_module alternatives_smp_module_del(struct module *mod)
{
struct smp_alt_module *item;
mutex_lock(&text_mutex);
list_for_each_entry(item, &smp_alt_modules, next) {
if (mod != item->mod)
continue;
list_del(&item->next);
kfree(item);
break;
}
mutex_unlock(&text_mutex);
}
void alternatives_enable_smp(void)
{
struct smp_alt_module *mod;
/* Why bother if there are no other CPUs? */
BUG_ON(num_possible_cpus() == 1);
mutex_lock(&text_mutex);
if (uniproc_patched) {
pr_info("switching to SMP code\n");
BUG_ON(num_online_cpus() != 1);
clear_cpu_cap(&boot_cpu_data, X86_FEATURE_UP);
clear_cpu_cap(&cpu_data(0), X86_FEATURE_UP);
list_for_each_entry(mod, &smp_alt_modules, next)
alternatives_smp_lock(mod->locks, mod->locks_end,
mod->text, mod->text_end);
uniproc_patched = false;
}
mutex_unlock(&text_mutex);
}
/*
* Return 1 if the address range is reserved for SMP-alternatives.
* Must hold text_mutex.
*/
int alternatives_text_reserved(void *start, void *end)
{
struct smp_alt_module *mod;
const s32 *poff;
u8 *text_start = start;
u8 *text_end = end;
lockdep_assert_held(&text_mutex);
list_for_each_entry(mod, &smp_alt_modules, next) {
if (mod->text > text_end || mod->text_end < text_start)
continue;
for (poff = mod->locks; poff < mod->locks_end; poff++) {
const u8 *ptr = (const u8 *)poff + *poff;
if (text_start <= ptr && text_end > ptr)
return 1;
}
}
return 0;
}
#endif /* CONFIG_SMP */
/*
* Self-test for the INT3 based CALL emulation code.
*
* This exercises int3_emulate_call() to make sure INT3 pt_regs are set up
* properly and that there is a stack gap between the INT3 frame and the
* previous context. Without this gap doing a virtual PUSH on the interrupted
* stack would corrupt the INT3 IRET frame.
*
* See entry_{32,64}.S for more details.
*/
/*
* We define the int3_magic() function in assembly to control the calling
* convention such that we can 'call' it from assembly.
*/
extern void int3_magic(unsigned int *ptr); /* defined in asm */
asm (
" .pushsection .init.text, \"ax\", @progbits\n"
" .type int3_magic, @function\n"
"int3_magic:\n"
ANNOTATE_NOENDBR
" movl $1, (%" _ASM_ARG1 ")\n"
ASM_RET
" .size int3_magic, .-int3_magic\n"
" .popsection\n"
);
extern void int3_selftest_ip(void); /* defined in asm below */
static int __init
int3_exception_notify(struct notifier_block *self, unsigned long val, void *data)
{
unsigned long selftest = (unsigned long)&int3_selftest_ip;
struct die_args *args = data;
struct pt_regs *regs = args->regs;
OPTIMIZER_HIDE_VAR(selftest);
if (!regs || user_mode(regs))
return NOTIFY_DONE;
if (val != DIE_INT3)
return NOTIFY_DONE;
if (regs->ip - INT3_INSN_SIZE != selftest)
return NOTIFY_DONE;
int3_emulate_call(regs, (unsigned long)&int3_magic);
return NOTIFY_STOP;
}
/* Must be noinline to ensure uniqueness of int3_selftest_ip. */
static noinline void __init int3_selftest(void)
{
static __initdata struct notifier_block int3_exception_nb = {
.notifier_call = int3_exception_notify,
.priority = INT_MAX-1, /* last */
};
unsigned int val = 0;
BUG_ON(register_die_notifier(&int3_exception_nb));
/*
* Basically: int3_magic(&val); but really complicated :-)
*
* INT3 padded with NOP to CALL_INSN_SIZE. The int3_exception_nb
* notifier above will emulate CALL for us.
*/
asm volatile ("int3_selftest_ip:\n\t"
ANNOTATE_NOENDBR
" int3; nop; nop; nop; nop\n\t"
: ASM_CALL_CONSTRAINT
: __ASM_SEL_RAW(a, D) (&val)
: "memory");
BUG_ON(val != 1);
unregister_die_notifier(&int3_exception_nb);
}
static __initdata int __alt_reloc_selftest_addr;
extern void __init __alt_reloc_selftest(void *arg);
__visible noinline void __init __alt_reloc_selftest(void *arg)
{
WARN_ON(arg != &__alt_reloc_selftest_addr);
}
static noinline void __init alt_reloc_selftest(void)
{
/*
* Tests text_poke_apply_relocation().
*
* This has a relative immediate (CALL) in a place other than the first
* instruction and additionally on x86_64 we get a RIP-relative LEA:
*
* lea 0x0(%rip),%rdi # 5d0: R_X86_64_PC32 .init.data+0x5566c
* call +0 # 5d5: R_X86_64_PLT32 __alt_reloc_selftest-0x4
*
* Getting this wrong will either crash and burn or tickle the WARN
* above.
*/
asm_inline volatile (
ALTERNATIVE("", "lea %[mem], %%" _ASM_ARG1 "; call __alt_reloc_selftest;", X86_FEATURE_ALWAYS)
: ASM_CALL_CONSTRAINT
: [mem] "m" (__alt_reloc_selftest_addr)
: _ASM_ARG1
);
}
void __init alternative_instructions(void)
{
u64 ibt;
int3_selftest();
/*
* The patching is not fully atomic, so try to avoid local
* interruptions that might execute the to be patched code.
* Other CPUs are not running.
*/
stop_nmi();
/*
* Don't stop machine check exceptions while patching.
* MCEs only happen when something got corrupted and in this
* case we must do something about the corruption.
* Ignoring it is worse than an unlikely patching race.
* Also machine checks tend to be broadcast and if one CPU
* goes into machine check the others follow quickly, so we don't
* expect a machine check to cause undue problems during to code
* patching.
*/
/*
* Make sure to set (artificial) features depending on used paravirt
* functions which can later influence alternative patching.
*/
paravirt_set_cap();
/* Keep CET-IBT disabled until caller/callee are patched */
ibt = ibt_save(/*disable*/ true);
__apply_fineibt(__retpoline_sites, __retpoline_sites_end,
__cfi_sites, __cfi_sites_end, true);
/*
* Rewrite the retpolines, must be done before alternatives since
* those can rewrite the retpoline thunks.
*/
apply_retpolines(__retpoline_sites, __retpoline_sites_end);
apply_returns(__return_sites, __return_sites_end);
its_fini_core();
/*
* Adjust all CALL instructions to point to func()-10, including
* those in .altinstr_replacement.
*/
callthunks_patch_builtin_calls();
apply_alternatives(__alt_instructions, __alt_instructions_end);
/*
* Seal all functions that do not have their address taken.
*/
apply_seal_endbr(__ibt_endbr_seal, __ibt_endbr_seal_end);
ibt_restore(ibt);
#ifdef CONFIG_SMP
/* Patch to UP if other cpus not imminent. */
if (!noreplace_smp && (num_present_cpus() == 1 || setup_max_cpus <= 1)) {
uniproc_patched = true;
alternatives_smp_module_add(NULL, "core kernel",
__smp_locks, __smp_locks_end,
_text, _etext);
}
if (!uniproc_patched || num_possible_cpus() == 1) {
free_init_pages("SMP alternatives",
(unsigned long)__smp_locks,
(unsigned long)__smp_locks_end);
}
#endif
restart_nmi();
alternatives_patched = 1;
alt_reloc_selftest();
}
/**
* text_poke_early - Update instructions on a live kernel at boot time
* @addr: address to modify
* @opcode: source of the copy
* @len: length to copy
*
* When you use this code to patch more than one byte of an instruction
* you need to make sure that other CPUs cannot execute this code in parallel.
* Also no thread must be currently preempted in the middle of these
* instructions. And on the local CPU you need to be protected against NMI or
* MCE handlers seeing an inconsistent instruction while you patch.
*/
void __init_or_module text_poke_early(void *addr, const void *opcode,
size_t len)
{
unsigned long flags;
if (boot_cpu_has(X86_FEATURE_NX) &&
is_module_text_address((unsigned long)addr)) {
/*
* Modules text is marked initially as non-executable, so the
* code cannot be running and speculative code-fetches are
* prevented. Just change the code.
*/
memcpy(addr, opcode, len);
} else {
local_irq_save(flags);
memcpy(addr, opcode, len);
sync_core();
local_irq_restore(flags);
/*
* Could also do a CLFLUSH here to speed up CPU recovery; but
* that causes hangs on some VIA CPUs.
*/
}
}
__ro_after_init struct mm_struct *text_poke_mm;
__ro_after_init unsigned long text_poke_mm_addr;
static void text_poke_memcpy(void *dst, const void *src, size_t len)
{
memcpy(dst, src, len);
}
static void text_poke_memset(void *dst, const void *src, size_t len)
{
int c = *(const int *)src;
memset(dst, c, len);
}
typedef void text_poke_f(void *dst, const void *src, size_t len);
static void *__text_poke(text_poke_f func, void *addr, const void *src, size_t len)
{
bool cross_page_boundary = offset_in_page(addr) + len > PAGE_SIZE;
struct page *pages[2] = {NULL};
struct mm_struct *prev_mm;
unsigned long flags;
pte_t pte, *ptep;
spinlock_t *ptl;
pgprot_t pgprot;
/*
* While boot memory allocator is running we cannot use struct pages as
* they are not yet initialized. There is no way to recover.
*/
BUG_ON(!after_bootmem);
if (!core_kernel_text((unsigned long)addr)) {
pages[0] = vmalloc_to_page(addr);
if (cross_page_boundary)
pages[1] = vmalloc_to_page(addr + PAGE_SIZE);
} else {
pages[0] = virt_to_page(addr);
WARN_ON(!PageReserved(pages[0]));
if (cross_page_boundary)
pages[1] = virt_to_page(addr + PAGE_SIZE);
}
/*
* If something went wrong, crash and burn since recovery paths are not
* implemented.
*/
BUG_ON(!pages[0] || (cross_page_boundary && !pages[1]));
/*
* Map the page without the global bit, as TLB flushing is done with
* flush_tlb_mm_range(), which is intended for non-global PTEs.
*/
pgprot = __pgprot(pgprot_val(PAGE_KERNEL) & ~_PAGE_GLOBAL);
/*
* The lock is not really needed, but this allows to avoid open-coding.
*/
ptep = get_locked_pte(text_poke_mm, text_poke_mm_addr, &ptl);
/*
* This must not fail; preallocated in poking_init().
*/
VM_BUG_ON(!ptep);
local_irq_save(flags);
pte = mk_pte(pages[0], pgprot);
set_pte_at(text_poke_mm, text_poke_mm_addr, ptep, pte);
if (cross_page_boundary) {
pte = mk_pte(pages[1], pgprot);
set_pte_at(text_poke_mm, text_poke_mm_addr + PAGE_SIZE, ptep + 1, pte);
}
/*
* Loading the temporary mm behaves as a compiler barrier, which
* guarantees that the PTE will be set at the time memcpy() is done.
*/
prev_mm = use_temporary_mm(text_poke_mm);
kasan_disable_current();
func((u8 *)text_poke_mm_addr + offset_in_page(addr), src, len);
kasan_enable_current();
/*
* Ensure that the PTE is only cleared after the instructions of memcpy
* were issued by using a compiler barrier.
*/
barrier();
pte_clear(text_poke_mm, text_poke_mm_addr, ptep);
if (cross_page_boundary)
pte_clear(text_poke_mm, text_poke_mm_addr + PAGE_SIZE, ptep + 1);
/*
* Loading the previous page-table hierarchy requires a serializing
* instruction that already allows the core to see the updated version.
* Xen-PV is assumed to serialize execution in a similar manner.
*/
unuse_temporary_mm(prev_mm);
/*
* Flushing the TLB might involve IPIs, which would require enabled
* IRQs, but not if the mm is not used, as it is in this point.
*/
flush_tlb_mm_range(text_poke_mm, text_poke_mm_addr, text_poke_mm_addr +
(cross_page_boundary ? 2 : 1) * PAGE_SIZE,
PAGE_SHIFT, false);
if (func == text_poke_memcpy) {
/*
* If the text does not match what we just wrote then something is
* fundamentally screwy; there's nothing we can really do about that.
*/
BUG_ON(memcmp(addr, src, len));
}
local_irq_restore(flags);
pte_unmap_unlock(ptep, ptl);
return addr;
}
/**
* text_poke - Update instructions on a live kernel
* @addr: address to modify
* @opcode: source of the copy
* @len: length to copy
*
* Only atomic text poke/set should be allowed when not doing early patching.
* It means the size must be writable atomically and the address must be aligned
* in a way that permits an atomic write. It also makes sure we fit on a single
* page.
*
* Note that the caller must ensure that if the modified code is part of a
* module, the module would not be removed during poking. This can be achieved
* by registering a module notifier, and ordering module removal and patching
* through a mutex.
*/
void *text_poke(void *addr, const void *opcode, size_t len)
{
lockdep_assert_held(&text_mutex);
return __text_poke(text_poke_memcpy, addr, opcode, len);
}
/**
* text_poke_kgdb - Update instructions on a live kernel by kgdb
* @addr: address to modify
* @opcode: source of the copy
* @len: length to copy
*
* Only atomic text poke/set should be allowed when not doing early patching.
* It means the size must be writable atomically and the address must be aligned
* in a way that permits an atomic write. It also makes sure we fit on a single
* page.
*
* Context: should only be used by kgdb, which ensures no other core is running,
* despite the fact it does not hold the text_mutex.
*/
void *text_poke_kgdb(void *addr, const void *opcode, size_t len)
{
return __text_poke(text_poke_memcpy, addr, opcode, len);
}
void *text_poke_copy_locked(void *addr, const void *opcode, size_t len,
bool core_ok)
{
unsigned long start = (unsigned long)addr;
size_t patched = 0;
if (WARN_ON_ONCE(!core_ok && core_kernel_text(start)))
return NULL;
while (patched < len) {
unsigned long ptr = start + patched;
size_t s;
s = min_t(size_t, PAGE_SIZE * 2 - offset_in_page(ptr), len - patched);
__text_poke(text_poke_memcpy, (void *)ptr, opcode + patched, s);
patched += s;
}
return addr;
}
/**
* text_poke_copy - Copy instructions into (an unused part of) RX memory
* @addr: address to modify
* @opcode: source of the copy
* @len: length to copy, could be more than 2x PAGE_SIZE
*
* Not safe against concurrent execution; useful for JITs to dump
* new code blocks into unused regions of RX memory. Can be used in
* conjunction with synchronize_rcu_tasks() to wait for existing
* execution to quiesce after having made sure no existing functions
* pointers are live.
*/
void *text_poke_copy(void *addr, const void *opcode, size_t len)
{
mutex_lock(&text_mutex);
addr = text_poke_copy_locked(addr, opcode, len, false);
mutex_unlock(&text_mutex);
return addr;
}
/**
* text_poke_set - memset into (an unused part of) RX memory
* @addr: address to modify
* @c: the byte to fill the area with
* @len: length to copy, could be more than 2x PAGE_SIZE
*
* This is useful to overwrite unused regions of RX memory with illegal
* instructions.
*/
void *text_poke_set(void *addr, int c, size_t len)
{
unsigned long start = (unsigned long)addr;
size_t patched = 0;
if (WARN_ON_ONCE(core_kernel_text(start)))
return NULL;
mutex_lock(&text_mutex);
while (patched < len) {
unsigned long ptr = start + patched;
size_t s;
s = min_t(size_t, PAGE_SIZE * 2 - offset_in_page(ptr), len - patched);
__text_poke(text_poke_memset, (void *)ptr, (void *)&c, s);
patched += s;
}
mutex_unlock(&text_mutex);
return addr;
}
static void do_sync_core(void *info)
{
sync_core();
}
void smp_text_poke_sync_each_cpu(void)
{
on_each_cpu(do_sync_core, NULL, 1);
}
/*
* NOTE: crazy scheme to allow patching Jcc.d32 but not increase the size of
* this thing. When len == 6 everything is prefixed with 0x0f and we map
* opcode to Jcc.d8, using len to distinguish.
*/
struct smp_text_poke_loc {
/* addr := _stext + rel_addr */
s32 rel_addr;
s32 disp;
u8 len;
u8 opcode;
const u8 text[TEXT_POKE_MAX_OPCODE_SIZE];
/* see smp_text_poke_batch_finish() */
u8 old;
};
#define TEXT_POKE_ARRAY_MAX (PAGE_SIZE / sizeof(struct smp_text_poke_loc))
static struct smp_text_poke_array {
struct smp_text_poke_loc vec[TEXT_POKE_ARRAY_MAX];
int nr_entries;
} text_poke_array;
static DEFINE_PER_CPU(atomic_t, text_poke_array_refs);
/*
* These four __always_inline annotations imply noinstr, necessary
* due to smp_text_poke_int3_handler() being noinstr:
*/
static __always_inline bool try_get_text_poke_array(void)
{
atomic_t *refs = this_cpu_ptr(&text_poke_array_refs);
if (!raw_atomic_inc_not_zero(refs))
return false;
return true;
}
static __always_inline void put_text_poke_array(void)
{
atomic_t *refs = this_cpu_ptr(&text_poke_array_refs);
smp_mb__before_atomic();
raw_atomic_dec(refs);
}
static __always_inline void *text_poke_addr(const struct smp_text_poke_loc *tpl)
{
return _stext + tpl->rel_addr;
}
static __always_inline int patch_cmp(const void *tpl_a, const void *tpl_b)
{
if (tpl_a < text_poke_addr(tpl_b))
return -1;
if (tpl_a > text_poke_addr(tpl_b))
return 1;
return 0;
}
noinstr int smp_text_poke_int3_handler(struct pt_regs *regs)
{
struct smp_text_poke_loc *tpl;
int ret = 0;
void *ip;
if (user_mode(regs))
return 0;
/*
* Having observed our INT3 instruction, we now must observe
* text_poke_array with non-zero refcount:
*
* text_poke_array_refs = 1 INT3
* WMB RMB
* write INT3 if (text_poke_array_refs != 0)
*/
smp_rmb();
if (!try_get_text_poke_array())
return 0;
/*
* Discount the INT3. See smp_text_poke_batch_finish().
*/
ip = (void *) regs->ip - INT3_INSN_SIZE;
/*
* Skip the binary search if there is a single member in the vector.
*/
if (unlikely(text_poke_array.nr_entries > 1)) {
tpl = __inline_bsearch(ip, text_poke_array.vec, text_poke_array.nr_entries,
sizeof(struct smp_text_poke_loc),
patch_cmp);
if (!tpl)
goto out_put;
} else {
tpl = text_poke_array.vec;
if (text_poke_addr(tpl) != ip)
goto out_put;
}
ip += tpl->len;
switch (tpl->opcode) {
case INT3_INSN_OPCODE:
/*
* Someone poked an explicit INT3, they'll want to handle it,
* do not consume.
*/
goto out_put;
case RET_INSN_OPCODE:
int3_emulate_ret(regs);
break;
case CALL_INSN_OPCODE:
int3_emulate_call(regs, (long)ip + tpl->disp);
break;
case JMP32_INSN_OPCODE:
case JMP8_INSN_OPCODE:
int3_emulate_jmp(regs, (long)ip + tpl->disp);
break;
case 0x70 ... 0x7f: /* Jcc */
int3_emulate_jcc(regs, tpl->opcode & 0xf, (long)ip, tpl->disp);
break;
default:
BUG();
}
ret = 1;
out_put:
put_text_poke_array();
return ret;
}
/**
* smp_text_poke_batch_finish() -- update instructions on live kernel on SMP
*
* Input state:
* text_poke_array.vec: vector of instructions to patch
* text_poke_array.nr_entries: number of entries in the vector
*
* Modify multi-byte instructions by using INT3 breakpoints on SMP.
* We completely avoid using stop_machine() here, and achieve the
* synchronization using INT3 breakpoints and SMP cross-calls.
*
* The way it is done:
* - For each entry in the vector:
* - add an INT3 trap to the address that will be patched
* - SMP sync all CPUs
* - For each entry in the vector:
* - update all but the first byte of the patched range
* - SMP sync all CPUs
* - For each entry in the vector:
* - replace the first byte (INT3) by the first byte of the
* replacing opcode
* - SMP sync all CPUs
*/
void smp_text_poke_batch_finish(void)
{
unsigned char int3 = INT3_INSN_OPCODE;
unsigned int i;
int do_sync;
if (!text_poke_array.nr_entries)
return;
lockdep_assert_held(&text_mutex);
/*
* Corresponds to the implicit memory barrier in try_get_text_poke_array() to
* ensure reading a non-zero refcount provides up to date text_poke_array data.
*/
for_each_possible_cpu(i)
atomic_set_release(per_cpu_ptr(&text_poke_array_refs, i), 1);
/*
* Function tracing can enable thousands of places that need to be
* updated. This can take quite some time, and with full kernel debugging
* enabled, this could cause the softlockup watchdog to trigger.
* This function gets called every 256 entries added to be patched.
* Call cond_resched() here to make sure that other tasks can get scheduled
* while processing all the functions being patched.
*/
cond_resched();
/*
* Corresponding read barrier in INT3 notifier for making sure the
* text_poke_array.nr_entries and handler are correctly ordered wrt. patching.
*/
smp_wmb();
/*
* First step: add a INT3 trap to the address that will be patched.
*/
for (i = 0; i < text_poke_array.nr_entries; i++) {
text_poke_array.vec[i].old = *(u8 *)text_poke_addr(&text_poke_array.vec[i]);
text_poke(text_poke_addr(&text_poke_array.vec[i]), &int3, INT3_INSN_SIZE);
}
smp_text_poke_sync_each_cpu();
/*
* Second step: update all but the first byte of the patched range.
*/
for (do_sync = 0, i = 0; i < text_poke_array.nr_entries; i++) {
u8 old[TEXT_POKE_MAX_OPCODE_SIZE+1] = { text_poke_array.vec[i].old, };
u8 _new[TEXT_POKE_MAX_OPCODE_SIZE+1];
const u8 *new = text_poke_array.vec[i].text;
int len = text_poke_array.vec[i].len;
if (len - INT3_INSN_SIZE > 0) {
memcpy(old + INT3_INSN_SIZE,
text_poke_addr(&text_poke_array.vec[i]) + INT3_INSN_SIZE,
len - INT3_INSN_SIZE);
if (len == 6) {
_new[0] = 0x0f;
memcpy(_new + 1, new, 5);
new = _new;
}
text_poke(text_poke_addr(&text_poke_array.vec[i]) + INT3_INSN_SIZE,
new + INT3_INSN_SIZE,
len - INT3_INSN_SIZE);
do_sync++;
}
/*
* Emit a perf event to record the text poke, primarily to
* support Intel PT decoding which must walk the executable code
* to reconstruct the trace. The flow up to here is:
* - write INT3 byte
* - IPI-SYNC
* - write instruction tail
* At this point the actual control flow will be through the
* INT3 and handler and not hit the old or new instruction.
* Intel PT outputs FUP/TIP packets for the INT3, so the flow
* can still be decoded. Subsequently:
* - emit RECORD_TEXT_POKE with the new instruction
* - IPI-SYNC
* - write first byte
* - IPI-SYNC
* So before the text poke event timestamp, the decoder will see
* either the old instruction flow or FUP/TIP of INT3. After the
* text poke event timestamp, the decoder will see either the
* new instruction flow or FUP/TIP of INT3. Thus decoders can
* use the timestamp as the point at which to modify the
* executable code.
* The old instruction is recorded so that the event can be
* processed forwards or backwards.
*/
perf_event_text_poke(text_poke_addr(&text_poke_array.vec[i]), old, len, new, len);
}
if (do_sync) {
/*
* According to Intel, this core syncing is very likely
* not necessary and we'd be safe even without it. But
* better safe than sorry (plus there's not only Intel).
*/
smp_text_poke_sync_each_cpu();
}
/*
* Third step: replace the first byte (INT3) by the first byte of the
* replacing opcode.
*/
for (do_sync = 0, i = 0; i < text_poke_array.nr_entries; i++) {
u8 byte = text_poke_array.vec[i].text[0];
if (text_poke_array.vec[i].len == 6)
byte = 0x0f;
if (byte == INT3_INSN_OPCODE)
continue;
text_poke(text_poke_addr(&text_poke_array.vec[i]), &byte, INT3_INSN_SIZE);
do_sync++;
}
if (do_sync)
smp_text_poke_sync_each_cpu();
/*
* Remove and wait for refs to be zero.
*
* Notably, if after step-3 above the INT3 got removed, then the
* smp_text_poke_sync_each_cpu() will have serialized against any running INT3
* handlers and the below spin-wait will not happen.
*
* IOW. unless the replacement instruction is INT3, this case goes
* unused.
*/
for_each_possible_cpu(i) {
atomic_t *refs = per_cpu_ptr(&text_poke_array_refs, i);
if (unlikely(!atomic_dec_and_test(refs)))
atomic_cond_read_acquire(refs, !VAL);
}
/* They are all completed: */
text_poke_array.nr_entries = 0;
}
static void __smp_text_poke_batch_add(void *addr, const void *opcode, size_t len, const void *emulate)
{
struct smp_text_poke_loc *tpl;
struct insn insn;
int ret, i = 0;
tpl = &text_poke_array.vec[text_poke_array.nr_entries++];
if (len == 6)
i = 1;
memcpy((void *)tpl->text, opcode+i, len-i);
if (!emulate)
emulate = opcode;
ret = insn_decode_kernel(&insn, emulate);
BUG_ON(ret < 0);
tpl->rel_addr = addr - (void *)_stext;
tpl->len = len;
tpl->opcode = insn.opcode.bytes[0];
if (is_jcc32(&insn)) {
/*
* Map Jcc.d32 onto Jcc.d8 and use len to distinguish.
*/
tpl->opcode = insn.opcode.bytes[1] - 0x10;
}
switch (tpl->opcode) {
case RET_INSN_OPCODE:
case JMP32_INSN_OPCODE:
case JMP8_INSN_OPCODE:
/*
* Control flow instructions without implied execution of the
* next instruction can be padded with INT3.
*/
for (i = insn.length; i < len; i++)
BUG_ON(tpl->text[i] != INT3_INSN_OPCODE);
break;
default:
BUG_ON(len != insn.length);
}
switch (tpl->opcode) {
case INT3_INSN_OPCODE:
case RET_INSN_OPCODE:
break;
case CALL_INSN_OPCODE:
case JMP32_INSN_OPCODE:
case JMP8_INSN_OPCODE:
case 0x70 ... 0x7f: /* Jcc */
tpl->disp = insn.immediate.value;
break;
default: /* assume NOP */
switch (len) {
case 2: /* NOP2 -- emulate as JMP8+0 */
BUG_ON(memcmp(emulate, x86_nops[len], len));
tpl->opcode = JMP8_INSN_OPCODE;
tpl->disp = 0;
break;
case 5: /* NOP5 -- emulate as JMP32+0 */
BUG_ON(memcmp(emulate, x86_nops[len], len));
tpl->opcode = JMP32_INSN_OPCODE;
tpl->disp = 0;
break;
default: /* unknown instruction */
BUG();
}
break;
}
}
/*
* We hard rely on the text_poke_array.vec being ordered; ensure this is so by flushing
* early if needed.
*/
static bool text_poke_addr_ordered(void *addr)
{
WARN_ON_ONCE(!addr);
if (!text_poke_array.nr_entries)
return true;
/*
* If the last current entry's address is higher than the
* new entry's address we'd like to add, then ordering
* is violated and we must first flush all pending patching
* requests:
*/
if (text_poke_addr(text_poke_array.vec + text_poke_array.nr_entries-1) > addr)
return false;
return true;
}
/**
* smp_text_poke_batch_add() -- update instruction on live kernel on SMP, batched
* @addr: address to patch
* @opcode: opcode of new instruction
* @len: length to copy
* @emulate: instruction to be emulated
*
* Add a new instruction to the current queue of to-be-patched instructions
* the kernel maintains. The patching request will not be executed immediately,
* but becomes part of an array of patching requests, optimized for batched
* execution. All pending patching requests will be executed on the next
* smp_text_poke_batch_finish() call.
*/
void __ref smp_text_poke_batch_add(void *addr, const void *opcode, size_t len, const void *emulate)
{
if (text_poke_array.nr_entries == TEXT_POKE_ARRAY_MAX || !text_poke_addr_ordered(addr))
smp_text_poke_batch_finish();
__smp_text_poke_batch_add(addr, opcode, len, emulate);
}
/**
* smp_text_poke_single() -- update instruction on live kernel on SMP immediately
* @addr: address to patch
* @opcode: opcode of new instruction
* @len: length to copy
* @emulate: instruction to be emulated
*
* Update a single instruction with the vector in the stack, avoiding
* dynamically allocated memory. This function should be used when it is
* not possible to allocate memory for a vector. The single instruction
* is patched in immediately.
*/
void __ref smp_text_poke_single(void *addr, const void *opcode, size_t len, const void *emulate)
{
smp_text_poke_batch_add(addr, opcode, len, emulate);
smp_text_poke_batch_finish();
}