* [merged mm-stable] x86-module-prepare-module-loading-for-rox-allocations-of-text.patch removed from -mm tree
@ 2024-11-06 1:00 Andrew Morton
2024-11-06 6:50 ` Mike Rapoport
0 siblings, 1 reply; 6+ messages in thread
From: Andrew Morton @ 2024-11-06 1:00 UTC (permalink / raw)
To: mm-commits, will, vgupta, urezki, tsbogend, tglx, surenb, song,
shorne, rostedt, richard, peterz, palmer, oleg, mpe, monstr,
mingo, mhiramat, mcgrof, mattst88, mark.rutland, luto, linux,
Liam.Howlett, kent.overstreet, kdevops, johannes, jcmvbkbc, hch,
guoren, glaubitz, geert, dinguyen, deller, dave.hansen,
christophe.leroy, chenhuacai, catalin.marinas, bp, bcain, arnd,
ardb, andreas, rppt, akpm
The quilt patch titled
Subject: x86/module: prepare module loading for ROX allocations of text
has been removed from the -mm tree. Its filename was
x86-module-prepare-module-loading-for-rox-allocations-of-text.patch
This patch was dropped because it was merged into the mm-stable branch
of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
------------------------------------------------------
From: "Mike Rapoport (Microsoft)" <rppt@kernel.org>
Subject: x86/module: prepare module loading for ROX allocations of text
Date: Wed, 23 Oct 2024 19:27:09 +0300
When module text memory will be allocated with ROX permissions, the memory
at the actual address where the module will live will contain invalid
instructions and there will be a writable copy that contains the actual
module code.
Update relocations and alternatives patching to deal with it.
Link: https://lkml.kernel.org/r/20241023162711.2579610-7-rppt@kernel.org
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Tested-by: kdevops <kdevops@lists.linux.dev>
Cc: Andreas Larsson <andreas@gaisler.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Ard Biesheuvel <ardb@kernel.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Borislav Petkov (AMD) <bp@alien8.de>
Cc: Brian Cain <bcain@quicinc.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Dinh Nguyen <dinguyen@kernel.org>
Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Cc: Guo Ren <guoren@kernel.org>
Cc: Helge Deller <deller@gmx.de>
Cc: Huacai Chen <chenhuacai@kernel.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Johannes Berg <johannes@sipsolutions.net>
Cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
Cc: Kent Overstreet <kent.overstreet@linux.dev>
Cc: Liam R. Howlett <Liam.Howlett@Oracle.com>
Cc: Luis Chamberlain <mcgrof@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Cc: Matt Turner <mattst88@gmail.com>
Cc: Max Filippov <jcmvbkbc@gmail.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Michal Simek <monstr@monstr.eu>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Palmer Dabbelt <palmer@dabbelt.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Richard Weinberger <richard@nod.at>
Cc: Russell King <linux@armlinux.org.uk>
Cc: Song Liu <song@kernel.org>
Cc: Stafford Horne <shorne@gmail.com>
Cc: Steven Rostedt (Google) <rostedt@goodmis.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Uladzislau Rezki (Sony) <urezki@gmail.com>
Cc: Vineet Gupta <vgupta@kernel.org>
Cc: Will Deacon <will@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
arch/um/kernel/um_arch.c | 11 -
arch/x86/entry/vdso/vma.c | 3
arch/x86/include/asm/alternative.h | 14 +-
arch/x86/kernel/alternative.c | 181 +++++++++++++++------------
arch/x86/kernel/ftrace.c | 30 ++--
arch/x86/kernel/module.c | 45 ++++--
6 files changed, 167 insertions(+), 117 deletions(-)
--- a/arch/um/kernel/um_arch.c~x86-module-prepare-module-loading-for-rox-allocations-of-text
+++ a/arch/um/kernel/um_arch.c
@@ -435,24 +435,25 @@ void __init arch_cpu_finalize_init(void)
os_check_bugs();
}
-void apply_seal_endbr(s32 *start, s32 *end)
+void apply_seal_endbr(s32 *start, s32 *end, struct module *mod)
{
}
-void apply_retpolines(s32 *start, s32 *end)
+void apply_retpolines(s32 *start, s32 *end, struct module *mod)
{
}
-void apply_returns(s32 *start, s32 *end)
+void apply_returns(s32 *start, s32 *end, struct module *mod)
{
}
void apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
- s32 *start_cfi, s32 *end_cfi)
+ s32 *start_cfi, s32 *end_cfi, struct module *mod)
{
}
-void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
+void apply_alternatives(struct alt_instr *start, struct alt_instr *end,
+ struct module *mod)
{
}
--- a/arch/x86/entry/vdso/vma.c~x86-module-prepare-module-loading-for-rox-allocations-of-text
+++ a/arch/x86/entry/vdso/vma.c
@@ -54,7 +54,8 @@ int __init init_vdso_image(const struct
apply_alternatives((struct alt_instr *)(image->data + image->alt),
(struct alt_instr *)(image->data + image->alt +
- image->alt_len));
+ image->alt_len),
+ NULL);
return 0;
}
--- a/arch/x86/include/asm/alternative.h~x86-module-prepare-module-loading-for-rox-allocations-of-text
+++ a/arch/x86/include/asm/alternative.h
@@ -96,16 +96,16 @@ extern struct alt_instr __alt_instructio
* instructions were patched in already:
*/
extern int alternatives_patched;
+struct module;
extern void alternative_instructions(void);
-extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
-extern void apply_retpolines(s32 *start, s32 *end);
-extern void apply_returns(s32 *start, s32 *end);
-extern void apply_seal_endbr(s32 *start, s32 *end);
+extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end,
+ struct module *mod);
+extern void apply_retpolines(s32 *start, s32 *end, struct module *mod);
+extern void apply_returns(s32 *start, s32 *end, struct module *mod);
+extern void apply_seal_endbr(s32 *start, s32 *end, struct module *mod);
extern void apply_fineibt(s32 *start_retpoline, s32 *end_retpoine,
- s32 *start_cfi, s32 *end_cfi);
-
-struct module;
+ s32 *start_cfi, s32 *end_cfi, struct module *mod);
struct callthunk_sites {
s32 *call_start, *call_end;
--- a/arch/x86/kernel/alternative.c~x86-module-prepare-module-loading-for-rox-allocations-of-text
+++ a/arch/x86/kernel/alternative.c
@@ -392,8 +392,10 @@ EXPORT_SYMBOL(BUG_func);
* 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)
+static int alt_replace_call(u8 *instr, u8 *insn_buff, struct alt_instr *a,
+ struct module *mod)
{
+ u8 *wr_instr = module_writable_address(mod, instr);
void *target, *bug = &BUG_func;
s32 disp;
@@ -403,14 +405,14 @@ static int alt_replace_call(u8 *instr, u
}
if (a->instrlen != 6 ||
- instr[0] != CALL_RIP_REL_OPCODE ||
- instr[1] != CALL_RIP_REL_MODRM) {
+ wr_instr[0] != CALL_RIP_REL_OPCODE ||
+ wr_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);
+ disp = *(s32 *)(wr_instr + 2);
#ifdef CONFIG_X86_64
/* ff 15 00 00 00 00 call *0x0(%rip) */
/* target address is stored at "next instruction + disp". */
@@ -448,7 +450,8 @@ static inline u8 * instr_va(struct alt_i
* to refetch changed I$ lines.
*/
void __init_or_module noinline apply_alternatives(struct alt_instr *start,
- struct alt_instr *end)
+ struct alt_instr *end,
+ struct module *mod)
{
u8 insn_buff[MAX_PATCH_LEN];
u8 *instr, *replacement;
@@ -477,6 +480,7 @@ void __init_or_module noinline apply_alt
*/
for (a = start; a < end; a++) {
int insn_buff_sz = 0;
+ u8 *wr_instr, *wr_replacement;
/*
* In case of nested ALTERNATIVE()s the outer alternative might
@@ -490,7 +494,11 @@ void __init_or_module noinline apply_alt
}
instr = instr_va(a);
+ wr_instr = module_writable_address(mod, instr);
+
replacement = (u8 *)&a->repl_offset + a->repl_offset;
+ wr_replacement = module_writable_address(mod, replacement);
+
BUG_ON(a->instrlen > sizeof(insn_buff));
BUG_ON(a->cpuid >= (NCAPINTS + NBUGINTS) * 32);
@@ -501,9 +509,9 @@ void __init_or_module noinline apply_alt
* patch if feature is *NOT* present.
*/
if (!boot_cpu_has(a->cpuid) == !(a->flags & ALT_FLAG_NOT)) {
- memcpy(insn_buff, instr, a->instrlen);
+ memcpy(insn_buff, wr_instr, a->instrlen);
optimize_nops(instr, insn_buff, a->instrlen);
- text_poke_early(instr, insn_buff, a->instrlen);
+ text_poke_early(wr_instr, insn_buff, a->instrlen);
continue;
}
@@ -513,11 +521,12 @@ void __init_or_module noinline apply_alt
instr, instr, a->instrlen,
replacement, a->replacementlen, a->flags);
- memcpy(insn_buff, replacement, a->replacementlen);
+ memcpy(insn_buff, wr_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);
+ insn_buff_sz = alt_replace_call(instr, insn_buff, a,
+ mod);
if (insn_buff_sz < 0)
continue;
}
@@ -527,11 +536,11 @@ void __init_or_module noinline apply_alt
apply_relocation(insn_buff, instr, a->instrlen, replacement, a->replacementlen);
- DUMP_BYTES(ALT, instr, a->instrlen, "%px: old_insn: ", instr);
+ DUMP_BYTES(ALT, wr_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);
+ text_poke_early(wr_instr, insn_buff, insn_buff_sz);
}
kasan_enable_current();
@@ -722,18 +731,20 @@ static int patch_retpoline(void *addr, s
/*
* Generated by 'objtool --retpoline'.
*/
-void __init_or_module noinline apply_retpolines(s32 *start, s32 *end)
+void __init_or_module noinline apply_retpolines(s32 *start, s32 *end,
+ struct module *mod)
{
s32 *s;
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
+ void *wr_addr = module_writable_address(mod, addr);
struct insn insn;
int len, ret;
u8 bytes[16];
u8 op1, op2;
- ret = insn_decode_kernel(&insn, addr);
+ ret = insn_decode_kernel(&insn, wr_addr);
if (WARN_ON_ONCE(ret < 0))
continue;
@@ -761,9 +772,9 @@ void __init_or_module noinline apply_ret
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*)wr_addr), len, "%px: orig: ", addr);
DUMP_BYTES(RETPOLINE, ((u8*)bytes), len, "%px: repl: ", addr);
- text_poke_early(addr, bytes, len);
+ text_poke_early(wr_addr, bytes, len);
}
}
}
@@ -799,7 +810,8 @@ static int patch_return(void *addr, stru
return i;
}
-void __init_or_module noinline apply_returns(s32 *start, s32 *end)
+void __init_or_module noinline apply_returns(s32 *start, s32 *end,
+ struct module *mod)
{
s32 *s;
@@ -808,12 +820,13 @@ void __init_or_module noinline apply_ret
for (s = start; s < end; s++) {
void *dest = NULL, *addr = (void *)s + *s;
+ void *wr_addr = module_writable_address(mod, addr);
struct insn insn;
int len, ret;
u8 bytes[16];
u8 op;
- ret = insn_decode_kernel(&insn, addr);
+ ret = insn_decode_kernel(&insn, wr_addr);
if (WARN_ON_ONCE(ret < 0))
continue;
@@ -833,32 +846,35 @@ void __init_or_module noinline apply_ret
len = patch_return(addr, &insn, bytes);
if (len == insn.length) {
- DUMP_BYTES(RET, ((u8*)addr), len, "%px: orig: ", addr);
+ DUMP_BYTES(RET, ((u8*)wr_addr), len, "%px: orig: ", addr);
DUMP_BYTES(RET, ((u8*)bytes), len, "%px: repl: ", addr);
- text_poke_early(addr, bytes, len);
+ text_poke_early(wr_addr, bytes, len);
}
}
}
#else
-void __init_or_module noinline apply_returns(s32 *start, s32 *end) { }
+void __init_or_module noinline apply_returns(s32 *start, s32 *end,
+ struct module *mod) { }
#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) { }
+void __init_or_module noinline apply_retpolines(s32 *start, s32 *end,
+ struct module *mod) { }
+void __init_or_module noinline apply_returns(s32 *start, s32 *end,
+ struct module *mod) { }
#endif /* CONFIG_MITIGATION_RETPOLINE && CONFIG_OBJTOOL */
#ifdef CONFIG_X86_KERNEL_IBT
-static void poison_cfi(void *addr);
+static void poison_cfi(void *addr, void *wr_addr);
-static void __init_or_module poison_endbr(void *addr, bool warn)
+static void __init_or_module poison_endbr(void *addr, void *wr_addr, bool warn)
{
u32 endbr, poison = gen_endbr_poison();
- if (WARN_ON_ONCE(get_kernel_nofault(endbr, addr)))
+ if (WARN_ON_ONCE(get_kernel_nofault(endbr, wr_addr)))
return;
if (!is_endbr(endbr)) {
@@ -873,7 +889,7 @@ static void __init_or_module poison_endb
*/
DUMP_BYTES(ENDBR, ((u8*)addr), 4, "%px: orig: ", addr);
DUMP_BYTES(ENDBR, ((u8*)&poison), 4, "%px: repl: ", addr);
- text_poke_early(addr, &poison, 4);
+ text_poke_early(wr_addr, &poison, 4);
}
/*
@@ -882,22 +898,23 @@ static void __init_or_module poison_endb
* 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)
+void __init_or_module noinline apply_seal_endbr(s32 *start, s32 *end, struct module *mod)
{
s32 *s;
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
+ void *wr_addr = module_writable_address(mod, addr);
- poison_endbr(addr, true);
+ poison_endbr(addr, wr_addr, true);
if (IS_ENABLED(CONFIG_FINEIBT))
- poison_cfi(addr - 16);
+ poison_cfi(addr - 16, wr_addr - 16);
}
}
#else
-void __init_or_module apply_seal_endbr(s32 *start, s32 *end) { }
+void __init_or_module apply_seal_endbr(s32 *start, s32 *end, struct module *mod) { }
#endif /* CONFIG_X86_KERNEL_IBT */
@@ -1119,7 +1136,7 @@ static u32 decode_caller_hash(void *addr
}
/* .retpoline_sites */
-static int cfi_disable_callers(s32 *start, s32 *end)
+static int cfi_disable_callers(s32 *start, s32 *end, struct module *mod)
{
/*
* Disable kCFI by patching in a JMP.d8, this leaves the hash immediate
@@ -1131,20 +1148,23 @@ static int cfi_disable_callers(s32 *star
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
+ void *wr_addr;
u32 hash;
addr -= fineibt_caller_size;
- hash = decode_caller_hash(addr);
+ wr_addr = module_writable_address(mod, addr);
+ hash = decode_caller_hash(wr_addr);
+
if (!hash) /* nocfi callers */
continue;
- text_poke_early(addr, jmp, 2);
+ text_poke_early(wr_addr, jmp, 2);
}
return 0;
}
-static int cfi_enable_callers(s32 *start, s32 *end)
+static int cfi_enable_callers(s32 *start, s32 *end, struct module *mod)
{
/*
* Re-enable kCFI, undo what cfi_disable_callers() did.
@@ -1154,106 +1174,115 @@ static int cfi_enable_callers(s32 *start
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
+ void *wr_addr;
u32 hash;
addr -= fineibt_caller_size;
- hash = decode_caller_hash(addr);
+ wr_addr = module_writable_address(mod, addr);
+ hash = decode_caller_hash(wr_addr);
if (!hash) /* nocfi callers */
continue;
- text_poke_early(addr, mov, 2);
+ text_poke_early(wr_addr, mov, 2);
}
return 0;
}
/* .cfi_sites */
-static int cfi_rand_preamble(s32 *start, s32 *end)
+static int cfi_rand_preamble(s32 *start, s32 *end, struct module *mod)
{
s32 *s;
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
+ void *wr_addr = module_writable_address(mod, addr);
u32 hash;
- hash = decode_preamble_hash(addr);
+ hash = decode_preamble_hash(wr_addr);
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);
+ text_poke_early(wr_addr + 1, &hash, 4);
}
return 0;
}
-static int cfi_rewrite_preamble(s32 *start, s32 *end)
+static int cfi_rewrite_preamble(s32 *start, s32 *end, struct module *mod)
{
s32 *s;
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
+ void *wr_addr = module_writable_address(mod, addr);
u32 hash;
- hash = decode_preamble_hash(addr);
+ hash = decode_preamble_hash(wr_addr);
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);
+ text_poke_early(wr_addr, fineibt_preamble_start, fineibt_preamble_size);
+ WARN_ON(*(u32 *)(wr_addr + fineibt_preamble_hash) != 0x12345678);
+ text_poke_early(wr_addr + fineibt_preamble_hash, &hash, 4);
}
return 0;
}
-static void cfi_rewrite_endbr(s32 *start, s32 *end)
+static void cfi_rewrite_endbr(s32 *start, s32 *end, struct module *mod)
{
s32 *s;
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
+ void *wr_addr = module_writable_address(mod, addr);
- poison_endbr(addr+16, false);
+ poison_endbr(addr+16, wr_addr, false);
}
}
/* .retpoline_sites */
-static int cfi_rand_callers(s32 *start, s32 *end)
+static int cfi_rand_callers(s32 *start, s32 *end, struct module *mod)
{
s32 *s;
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
+ void *wr_addr;
u32 hash;
addr -= fineibt_caller_size;
- hash = decode_caller_hash(addr);
+ wr_addr = module_writable_address(mod, addr);
+ hash = decode_caller_hash(wr_addr);
if (hash) {
hash = -cfi_rehash(hash);
- text_poke_early(addr + 2, &hash, 4);
+ text_poke_early(wr_addr + 2, &hash, 4);
}
}
return 0;
}
-static int cfi_rewrite_callers(s32 *start, s32 *end)
+static int cfi_rewrite_callers(s32 *start, s32 *end, struct module *mod)
{
s32 *s;
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
+ void *wr_addr;
u32 hash;
addr -= fineibt_caller_size;
- hash = decode_caller_hash(addr);
+ wr_addr = module_writable_address(mod, addr);
+ hash = decode_caller_hash(wr_addr);
if (hash) {
- 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);
+ text_poke_early(wr_addr, fineibt_caller_start, fineibt_caller_size);
+ WARN_ON(*(u32 *)(wr_addr + fineibt_caller_hash) != 0x12345678);
+ text_poke_early(wr_addr + fineibt_caller_hash, &hash, 4);
}
/* rely on apply_retpolines() */
}
@@ -1262,8 +1291,9 @@ static int cfi_rewrite_callers(s32 *star
}
static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
- s32 *start_cfi, s32 *end_cfi, bool builtin)
+ s32 *start_cfi, s32 *end_cfi, struct module *mod)
{
+ bool builtin = mod ? false : true;
int ret;
if (WARN_ONCE(fineibt_preamble_size != 16,
@@ -1281,7 +1311,7 @@ static void __apply_fineibt(s32 *start_r
* 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);
+ ret = cfi_disable_callers(start_retpoline, end_retpoline, mod);
if (ret)
goto err;
@@ -1292,11 +1322,11 @@ static void __apply_fineibt(s32 *start_r
cfi_bpf_subprog_hash = cfi_rehash(cfi_bpf_subprog_hash);
}
- ret = cfi_rand_preamble(start_cfi, end_cfi);
+ ret = cfi_rand_preamble(start_cfi, end_cfi, mod);
if (ret)
goto err;
- ret = cfi_rand_callers(start_retpoline, end_retpoline);
+ ret = cfi_rand_callers(start_retpoline, end_retpoline, mod);
if (ret)
goto err;
}
@@ -1308,7 +1338,7 @@ static void __apply_fineibt(s32 *start_r
return;
case CFI_KCFI:
- ret = cfi_enable_callers(start_retpoline, end_retpoline);
+ ret = cfi_enable_callers(start_retpoline, end_retpoline, mod);
if (ret)
goto err;
@@ -1318,17 +1348,17 @@ static void __apply_fineibt(s32 *start_r
case CFI_FINEIBT:
/* place the FineIBT preamble at func()-16 */
- ret = cfi_rewrite_preamble(start_cfi, end_cfi);
+ ret = cfi_rewrite_preamble(start_cfi, end_cfi, mod);
if (ret)
goto err;
/* rewrite the callers to target func()-16 */
- ret = cfi_rewrite_callers(start_retpoline, end_retpoline);
+ ret = cfi_rewrite_callers(start_retpoline, end_retpoline, mod);
if (ret)
goto err;
/* now that nobody targets func()+0, remove ENDBR there */
- cfi_rewrite_endbr(start_cfi, end_cfi);
+ cfi_rewrite_endbr(start_cfi, end_cfi, mod);
if (builtin)
pr_info("Using FineIBT CFI\n");
@@ -1347,7 +1377,7 @@ static inline void poison_hash(void *add
*(u32 *)addr = 0;
}
-static void poison_cfi(void *addr)
+static void poison_cfi(void *addr, void *wr_addr)
{
switch (cfi_mode) {
case CFI_FINEIBT:
@@ -1359,8 +1389,8 @@ static void poison_cfi(void *addr)
* ud2
* 1: nop
*/
- poison_endbr(addr, false);
- poison_hash(addr + fineibt_preamble_hash);
+ poison_endbr(addr, wr_addr, false);
+ poison_hash(wr_addr + fineibt_preamble_hash);
break;
case CFI_KCFI:
@@ -1369,7 +1399,7 @@ static void poison_cfi(void *addr)
* movl $0, %eax
* .skip 11, 0x90
*/
- poison_hash(addr + 1);
+ poison_hash(wr_addr + 1);
break;
default:
@@ -1380,22 +1410,21 @@ static void poison_cfi(void *addr)
#else
static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
- s32 *start_cfi, s32 *end_cfi, bool builtin)
+ s32 *start_cfi, s32 *end_cfi, struct module *mod)
{
}
#ifdef CONFIG_X86_KERNEL_IBT
-static void poison_cfi(void *addr) { }
+static void poison_cfi(void *addr, void *wr_addr) { }
#endif
#endif
void apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
- s32 *start_cfi, s32 *end_cfi)
+ s32 *start_cfi, s32 *end_cfi, struct module *mod)
{
return __apply_fineibt(start_retpoline, end_retpoline,
- start_cfi, end_cfi,
- /* .builtin = */ false);
+ start_cfi, end_cfi, mod);
}
#ifdef CONFIG_SMP
@@ -1692,16 +1721,16 @@ void __init alternative_instructions(voi
paravirt_set_cap();
__apply_fineibt(__retpoline_sites, __retpoline_sites_end,
- __cfi_sites, __cfi_sites_end, true);
+ __cfi_sites, __cfi_sites_end, NULL);
/*
* 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);
+ apply_retpolines(__retpoline_sites, __retpoline_sites_end, NULL);
+ apply_returns(__return_sites, __return_sites_end, NULL);
- apply_alternatives(__alt_instructions, __alt_instructions_end);
+ apply_alternatives(__alt_instructions, __alt_instructions_end, NULL);
/*
* Now all calls are established. Apply the call thunks if
@@ -1712,7 +1741,7 @@ void __init alternative_instructions(voi
/*
* Seal all functions that do not have their address taken.
*/
- apply_seal_endbr(__ibt_endbr_seal, __ibt_endbr_seal_end);
+ apply_seal_endbr(__ibt_endbr_seal, __ibt_endbr_seal_end, NULL);
#ifdef CONFIG_SMP
/* Patch to UP if other cpus not imminent. */
--- a/arch/x86/kernel/ftrace.c~x86-module-prepare-module-loading-for-rox-allocations-of-text
+++ a/arch/x86/kernel/ftrace.c
@@ -118,10 +118,13 @@ ftrace_modify_code_direct(unsigned long
return ret;
/* replace the text with the new text */
- if (ftrace_poke_late)
+ if (ftrace_poke_late) {
text_poke_queue((void *)ip, new_code, MCOUNT_INSN_SIZE, NULL);
- else
- text_poke_early((void *)ip, new_code, MCOUNT_INSN_SIZE);
+ } else {
+ mutex_lock(&text_mutex);
+ text_poke((void *)ip, new_code, MCOUNT_INSN_SIZE);
+ mutex_unlock(&text_mutex);
+ }
return 0;
}
@@ -318,7 +321,7 @@ create_trampoline(struct ftrace_ops *ops
unsigned const char op_ref[] = { 0x48, 0x8b, 0x15 };
unsigned const char retq[] = { RET_INSN_OPCODE, INT3_INSN_OPCODE };
union ftrace_op_code_union op_ptr;
- int ret;
+ void *ret;
if (ops->flags & FTRACE_OPS_FL_SAVE_REGS) {
start_offset = (unsigned long)ftrace_regs_caller;
@@ -349,15 +352,15 @@ create_trampoline(struct ftrace_ops *ops
npages = DIV_ROUND_UP(*tramp_size, PAGE_SIZE);
/* Copy ftrace_caller onto the trampoline memory */
- ret = copy_from_kernel_nofault(trampoline, (void *)start_offset, size);
- if (WARN_ON(ret < 0))
+ ret = text_poke_copy(trampoline, (void *)start_offset, size);
+ if (WARN_ON(!ret))
goto fail;
ip = trampoline + size;
if (cpu_feature_enabled(X86_FEATURE_RETHUNK))
__text_gen_insn(ip, JMP32_INSN_OPCODE, ip, x86_return_thunk, JMP32_INSN_SIZE);
else
- memcpy(ip, retq, sizeof(retq));
+ text_poke_copy(ip, retq, sizeof(retq));
/* No need to test direct calls on created trampolines */
if (ops->flags & FTRACE_OPS_FL_SAVE_REGS) {
@@ -365,8 +368,7 @@ create_trampoline(struct ftrace_ops *ops
ip = trampoline + (jmp_offset - start_offset);
if (WARN_ON(*(char *)ip != 0x75))
goto fail;
- ret = copy_from_kernel_nofault(ip, x86_nops[2], 2);
- if (ret < 0)
+ if (!text_poke_copy(ip, x86_nops[2], 2))
goto fail;
}
@@ -379,7 +381,7 @@ create_trampoline(struct ftrace_ops *ops
*/
ptr = (unsigned long *)(trampoline + size + RET_SIZE);
- *ptr = (unsigned long)ops;
+ text_poke_copy(ptr, &ops, sizeof(unsigned long));
op_offset -= start_offset;
memcpy(&op_ptr, trampoline + op_offset, OP_REF_SIZE);
@@ -395,7 +397,7 @@ create_trampoline(struct ftrace_ops *ops
op_ptr.offset = offset;
/* put in the new offset to the ftrace_ops */
- memcpy(trampoline + op_offset, &op_ptr, OP_REF_SIZE);
+ text_poke_copy(trampoline + op_offset, &op_ptr, OP_REF_SIZE);
/* put in the call to the function */
mutex_lock(&text_mutex);
@@ -405,9 +407,9 @@ create_trampoline(struct ftrace_ops *ops
* the depth accounting before the call already.
*/
dest = ftrace_ops_get_func(ops);
- memcpy(trampoline + call_offset,
- text_gen_insn(CALL_INSN_OPCODE, trampoline + call_offset, dest),
- CALL_INSN_SIZE);
+ text_poke_copy_locked(trampoline + call_offset,
+ text_gen_insn(CALL_INSN_OPCODE, trampoline + call_offset, dest),
+ CALL_INSN_SIZE, false);
mutex_unlock(&text_mutex);
/* ALLOC_TRAMP flags lets us know we created it */
--- a/arch/x86/kernel/module.c~x86-module-prepare-module-loading-for-rox-allocations-of-text
+++ a/arch/x86/kernel/module.c
@@ -146,18 +146,21 @@ static int __write_relocate_add(Elf64_Sh
}
if (apply) {
- if (memcmp(loc, &zero, size)) {
+ void *wr_loc = module_writable_address(me, loc);
+
+ if (memcmp(wr_loc, &zero, size)) {
pr_err("x86/modules: Invalid relocation target, existing value is nonzero for type %d, loc %p, val %Lx\n",
(int)ELF64_R_TYPE(rel[i].r_info), loc, val);
return -ENOEXEC;
}
- write(loc, &val, size);
+ write(wr_loc, &val, size);
} else {
if (memcmp(loc, &val, size)) {
pr_warn("x86/modules: Invalid relocation target, existing value does not match expected value for type %d, loc %p, val %Lx\n",
(int)ELF64_R_TYPE(rel[i].r_info), loc, val);
return -ENOEXEC;
}
+ /* FIXME: needs care for ROX module allocations */
write(loc, &zero, size);
}
}
@@ -224,7 +227,7 @@ int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs,
struct module *me)
{
- const Elf_Shdr *s, *alt = NULL, *locks = NULL,
+ const Elf_Shdr *s, *alt = NULL,
*orc = NULL, *orc_ip = NULL,
*retpolines = NULL, *returns = NULL, *ibt_endbr = NULL,
*calls = NULL, *cfi = NULL;
@@ -233,8 +236,6 @@ int module_finalize(const Elf_Ehdr *hdr,
for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
if (!strcmp(".altinstructions", secstrings + s->sh_name))
alt = s;
- if (!strcmp(".smp_locks", secstrings + s->sh_name))
- locks = s;
if (!strcmp(".orc_unwind", secstrings + s->sh_name))
orc = s;
if (!strcmp(".orc_unwind_ip", secstrings + s->sh_name))
@@ -265,20 +266,20 @@ int module_finalize(const Elf_Ehdr *hdr,
csize = cfi->sh_size;
}
- apply_fineibt(rseg, rseg + rsize, cseg, cseg + csize);
+ apply_fineibt(rseg, rseg + rsize, cseg, cseg + csize, me);
}
if (retpolines) {
void *rseg = (void *)retpolines->sh_addr;
- apply_retpolines(rseg, rseg + retpolines->sh_size);
+ apply_retpolines(rseg, rseg + retpolines->sh_size, me);
}
if (returns) {
void *rseg = (void *)returns->sh_addr;
- apply_returns(rseg, rseg + returns->sh_size);
+ apply_returns(rseg, rseg + returns->sh_size, me);
}
if (alt) {
/* patch .altinstructions */
void *aseg = (void *)alt->sh_addr;
- apply_alternatives(aseg, aseg + alt->sh_size);
+ apply_alternatives(aseg, aseg + alt->sh_size, me);
}
if (calls || alt) {
struct callthunk_sites cs = {};
@@ -297,8 +298,28 @@ int module_finalize(const Elf_Ehdr *hdr,
}
if (ibt_endbr) {
void *iseg = (void *)ibt_endbr->sh_addr;
- apply_seal_endbr(iseg, iseg + ibt_endbr->sh_size);
+ apply_seal_endbr(iseg, iseg + ibt_endbr->sh_size, me);
}
+
+ if (orc && orc_ip)
+ unwind_module_init(me, (void *)orc_ip->sh_addr, orc_ip->sh_size,
+ (void *)orc->sh_addr, orc->sh_size);
+
+ return 0;
+}
+
+int module_post_finalize(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs,
+ struct module *me)
+{
+ const Elf_Shdr *s, *locks = NULL;
+ char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
+ for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
+ if (!strcmp(".smp_locks", secstrings + s->sh_name))
+ locks = s;
+ }
+
if (locks) {
void *lseg = (void *)locks->sh_addr;
void *text = me->mem[MOD_TEXT].base;
@@ -308,10 +329,6 @@ int module_finalize(const Elf_Ehdr *hdr,
text, text_end);
}
- if (orc && orc_ip)
- unwind_module_init(me, (void *)orc_ip->sh_addr, orc_ip->sh_size,
- (void *)orc->sh_addr, orc->sh_size);
-
return 0;
}
_
Patches currently in -mm which might be from rppt@kernel.org are
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [merged mm-stable] x86-module-prepare-module-loading-for-rox-allocations-of-text.patch removed from -mm tree
2024-11-06 1:00 [merged mm-stable] x86-module-prepare-module-loading-for-rox-allocations-of-text.patch removed from -mm tree Andrew Morton
@ 2024-11-06 6:50 ` Mike Rapoport
2024-11-06 21:30 ` Andrew Morton
2024-12-05 8:41 ` Peter Zijlstra
0 siblings, 2 replies; 6+ messages in thread
From: Mike Rapoport @ 2024-11-06 6:50 UTC (permalink / raw)
To: Andrew Morton
Cc: mm-commits, will, vgupta, urezki, tsbogend, tglx, surenb, song,
shorne, rostedt, richard, peterz, palmer, oleg, mpe, monstr,
mingo, mhiramat, mcgrof, mattst88, mark.rutland, luto, linux,
Liam.Howlett, kent.overstreet, kdevops, johannes, jcmvbkbc, hch,
guoren, glaubitz, geert, dinguyen, deller, dave.hansen,
christophe.leroy, chenhuacai, catalin.marinas, bp, bcain, arnd,
ardb, andreas
Hi Andrew,
Yesterday Nathan discovered and I fixed another small issue with fineibt.
I suspect it's too late to add this as a fixup, so here's a formal patch
with the fix.
From b31fd8493c4e1b6042776642a812690f16575b51 Mon Sep 17 00:00:00 2001
From: "Mike Rapoport (Microsoft)" <rppt@kernel.org>
Date: Tue, 5 Nov 2024 10:49:57 +0200
Subject: [PATCH] x86/alternatives: fix writable address in cfi_rewrite_endbr()
Commit a159950eb69f ("x86/module: prepare module loading for ROX
allocations of text") missed the offset that should be added to the
writable address passed to poison_endbr() from cfi_rewrite_endbr() and
this causes boot failures on kernels running with cfi=fineibt on
machines that support IBT.
Add required offset to wr_addr argument to fix the issue.
Reported-by: Nathan Chancellor <nathan@kernel.org>
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Fixes: a159950eb69f ("x86/module: prepare module loading for ROX allocations of text")
Tested-by: Nathan Chancellor <nathan@kernel.org>
---
arch/x86/kernel/alternative.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 3407efc26528..243843e44e89 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -1241,7 +1241,7 @@ static void cfi_rewrite_endbr(s32 *start, s32 *end, struct module *mod)
void *addr = (void *)s + *s;
void *wr_addr = module_writable_address(mod, addr);
- poison_endbr(addr+16, wr_addr, false);
+ poison_endbr(addr + 16, wr_addr + 16, false);
}
}
--
2.45.2
On Tue, Nov 05, 2024 at 05:00:47PM -0800, Andrew Morton wrote:
>
> The quilt patch titled
> Subject: x86/module: prepare module loading for ROX allocations of text
> has been removed from the -mm tree. Its filename was
> x86-module-prepare-module-loading-for-rox-allocations-of-text.patch
>
> This patch was dropped because it was merged into the mm-stable branch
> of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
>
> ------------------------------------------------------
> From: "Mike Rapoport (Microsoft)" <rppt@kernel.org>
> Subject: x86/module: prepare module loading for ROX allocations of text
> Date: Wed, 23 Oct 2024 19:27:09 +0300
>
> When module text memory will be allocated with ROX permissions, the memory
> at the actual address where the module will live will contain invalid
> instructions and there will be a writable copy that contains the actual
> module code.
>
> Update relocations and alternatives patching to deal with it.
>
> Link: https://lkml.kernel.org/r/20241023162711.2579610-7-rppt@kernel.org
> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> Tested-by: kdevops <kdevops@lists.linux.dev>
> Cc: Andreas Larsson <andreas@gaisler.com>
> Cc: Andy Lutomirski <luto@kernel.org>
> Cc: Ard Biesheuvel <ardb@kernel.org>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Borislav Petkov (AMD) <bp@alien8.de>
> Cc: Brian Cain <bcain@quicinc.com>
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
> Cc: Christoph Hellwig <hch@lst.de>
> Cc: Dave Hansen <dave.hansen@linux.intel.com>
> Cc: Dinh Nguyen <dinguyen@kernel.org>
> Cc: Geert Uytterhoeven <geert@linux-m68k.org>
> Cc: Guo Ren <guoren@kernel.org>
> Cc: Helge Deller <deller@gmx.de>
> Cc: Huacai Chen <chenhuacai@kernel.org>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: Johannes Berg <johannes@sipsolutions.net>
> Cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
> Cc: Kent Overstreet <kent.overstreet@linux.dev>
> Cc: Liam R. Howlett <Liam.Howlett@Oracle.com>
> Cc: Luis Chamberlain <mcgrof@kernel.org>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Masami Hiramatsu (Google) <mhiramat@kernel.org>
> Cc: Matt Turner <mattst88@gmail.com>
> Cc: Max Filippov <jcmvbkbc@gmail.com>
> Cc: Michael Ellerman <mpe@ellerman.id.au>
> Cc: Michal Simek <monstr@monstr.eu>
> Cc: Oleg Nesterov <oleg@redhat.com>
> Cc: Palmer Dabbelt <palmer@dabbelt.com>
> Cc: Peter Zijlstra <peterz@infradead.org>
> Cc: Richard Weinberger <richard@nod.at>
> Cc: Russell King <linux@armlinux.org.uk>
> Cc: Song Liu <song@kernel.org>
> Cc: Stafford Horne <shorne@gmail.com>
> Cc: Steven Rostedt (Google) <rostedt@goodmis.org>
> Cc: Suren Baghdasaryan <surenb@google.com>
> Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Uladzislau Rezki (Sony) <urezki@gmail.com>
> Cc: Vineet Gupta <vgupta@kernel.org>
> Cc: Will Deacon <will@kernel.org>
> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
> ---
>
> arch/um/kernel/um_arch.c | 11 -
> arch/x86/entry/vdso/vma.c | 3
> arch/x86/include/asm/alternative.h | 14 +-
> arch/x86/kernel/alternative.c | 181 +++++++++++++++------------
> arch/x86/kernel/ftrace.c | 30 ++--
> arch/x86/kernel/module.c | 45 ++++--
> 6 files changed, 167 insertions(+), 117 deletions(-)
>
> --- a/arch/um/kernel/um_arch.c~x86-module-prepare-module-loading-for-rox-allocations-of-text
> +++ a/arch/um/kernel/um_arch.c
> @@ -435,24 +435,25 @@ void __init arch_cpu_finalize_init(void)
> os_check_bugs();
> }
>
> -void apply_seal_endbr(s32 *start, s32 *end)
> +void apply_seal_endbr(s32 *start, s32 *end, struct module *mod)
> {
> }
>
> -void apply_retpolines(s32 *start, s32 *end)
> +void apply_retpolines(s32 *start, s32 *end, struct module *mod)
> {
> }
>
> -void apply_returns(s32 *start, s32 *end)
> +void apply_returns(s32 *start, s32 *end, struct module *mod)
> {
> }
>
> void apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
> - s32 *start_cfi, s32 *end_cfi)
> + s32 *start_cfi, s32 *end_cfi, struct module *mod)
> {
> }
>
> -void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
> +void apply_alternatives(struct alt_instr *start, struct alt_instr *end,
> + struct module *mod)
> {
> }
>
> --- a/arch/x86/entry/vdso/vma.c~x86-module-prepare-module-loading-for-rox-allocations-of-text
> +++ a/arch/x86/entry/vdso/vma.c
> @@ -54,7 +54,8 @@ int __init init_vdso_image(const struct
>
> apply_alternatives((struct alt_instr *)(image->data + image->alt),
> (struct alt_instr *)(image->data + image->alt +
> - image->alt_len));
> + image->alt_len),
> + NULL);
>
> return 0;
> }
> --- a/arch/x86/include/asm/alternative.h~x86-module-prepare-module-loading-for-rox-allocations-of-text
> +++ a/arch/x86/include/asm/alternative.h
> @@ -96,16 +96,16 @@ extern struct alt_instr __alt_instructio
> * instructions were patched in already:
> */
> extern int alternatives_patched;
> +struct module;
>
> extern void alternative_instructions(void);
> -extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
> -extern void apply_retpolines(s32 *start, s32 *end);
> -extern void apply_returns(s32 *start, s32 *end);
> -extern void apply_seal_endbr(s32 *start, s32 *end);
> +extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end,
> + struct module *mod);
> +extern void apply_retpolines(s32 *start, s32 *end, struct module *mod);
> +extern void apply_returns(s32 *start, s32 *end, struct module *mod);
> +extern void apply_seal_endbr(s32 *start, s32 *end, struct module *mod);
> extern void apply_fineibt(s32 *start_retpoline, s32 *end_retpoine,
> - s32 *start_cfi, s32 *end_cfi);
> -
> -struct module;
> + s32 *start_cfi, s32 *end_cfi, struct module *mod);
>
> struct callthunk_sites {
> s32 *call_start, *call_end;
> --- a/arch/x86/kernel/alternative.c~x86-module-prepare-module-loading-for-rox-allocations-of-text
> +++ a/arch/x86/kernel/alternative.c
> @@ -392,8 +392,10 @@ EXPORT_SYMBOL(BUG_func);
> * 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)
> +static int alt_replace_call(u8 *instr, u8 *insn_buff, struct alt_instr *a,
> + struct module *mod)
> {
> + u8 *wr_instr = module_writable_address(mod, instr);
> void *target, *bug = &BUG_func;
> s32 disp;
>
> @@ -403,14 +405,14 @@ static int alt_replace_call(u8 *instr, u
> }
>
> if (a->instrlen != 6 ||
> - instr[0] != CALL_RIP_REL_OPCODE ||
> - instr[1] != CALL_RIP_REL_MODRM) {
> + wr_instr[0] != CALL_RIP_REL_OPCODE ||
> + wr_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);
> + disp = *(s32 *)(wr_instr + 2);
> #ifdef CONFIG_X86_64
> /* ff 15 00 00 00 00 call *0x0(%rip) */
> /* target address is stored at "next instruction + disp". */
> @@ -448,7 +450,8 @@ static inline u8 * instr_va(struct alt_i
> * to refetch changed I$ lines.
> */
> void __init_or_module noinline apply_alternatives(struct alt_instr *start,
> - struct alt_instr *end)
> + struct alt_instr *end,
> + struct module *mod)
> {
> u8 insn_buff[MAX_PATCH_LEN];
> u8 *instr, *replacement;
> @@ -477,6 +480,7 @@ void __init_or_module noinline apply_alt
> */
> for (a = start; a < end; a++) {
> int insn_buff_sz = 0;
> + u8 *wr_instr, *wr_replacement;
>
> /*
> * In case of nested ALTERNATIVE()s the outer alternative might
> @@ -490,7 +494,11 @@ void __init_or_module noinline apply_alt
> }
>
> instr = instr_va(a);
> + wr_instr = module_writable_address(mod, instr);
> +
> replacement = (u8 *)&a->repl_offset + a->repl_offset;
> + wr_replacement = module_writable_address(mod, replacement);
> +
> BUG_ON(a->instrlen > sizeof(insn_buff));
> BUG_ON(a->cpuid >= (NCAPINTS + NBUGINTS) * 32);
>
> @@ -501,9 +509,9 @@ void __init_or_module noinline apply_alt
> * patch if feature is *NOT* present.
> */
> if (!boot_cpu_has(a->cpuid) == !(a->flags & ALT_FLAG_NOT)) {
> - memcpy(insn_buff, instr, a->instrlen);
> + memcpy(insn_buff, wr_instr, a->instrlen);
> optimize_nops(instr, insn_buff, a->instrlen);
> - text_poke_early(instr, insn_buff, a->instrlen);
> + text_poke_early(wr_instr, insn_buff, a->instrlen);
> continue;
> }
>
> @@ -513,11 +521,12 @@ void __init_or_module noinline apply_alt
> instr, instr, a->instrlen,
> replacement, a->replacementlen, a->flags);
>
> - memcpy(insn_buff, replacement, a->replacementlen);
> + memcpy(insn_buff, wr_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);
> + insn_buff_sz = alt_replace_call(instr, insn_buff, a,
> + mod);
> if (insn_buff_sz < 0)
> continue;
> }
> @@ -527,11 +536,11 @@ void __init_or_module noinline apply_alt
>
> apply_relocation(insn_buff, instr, a->instrlen, replacement, a->replacementlen);
>
> - DUMP_BYTES(ALT, instr, a->instrlen, "%px: old_insn: ", instr);
> + DUMP_BYTES(ALT, wr_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);
> + text_poke_early(wr_instr, insn_buff, insn_buff_sz);
> }
>
> kasan_enable_current();
> @@ -722,18 +731,20 @@ static int patch_retpoline(void *addr, s
> /*
> * Generated by 'objtool --retpoline'.
> */
> -void __init_or_module noinline apply_retpolines(s32 *start, s32 *end)
> +void __init_or_module noinline apply_retpolines(s32 *start, s32 *end,
> + struct module *mod)
> {
> s32 *s;
>
> for (s = start; s < end; s++) {
> void *addr = (void *)s + *s;
> + void *wr_addr = module_writable_address(mod, addr);
> struct insn insn;
> int len, ret;
> u8 bytes[16];
> u8 op1, op2;
>
> - ret = insn_decode_kernel(&insn, addr);
> + ret = insn_decode_kernel(&insn, wr_addr);
> if (WARN_ON_ONCE(ret < 0))
> continue;
>
> @@ -761,9 +772,9 @@ void __init_or_module noinline apply_ret
> 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*)wr_addr), len, "%px: orig: ", addr);
> DUMP_BYTES(RETPOLINE, ((u8*)bytes), len, "%px: repl: ", addr);
> - text_poke_early(addr, bytes, len);
> + text_poke_early(wr_addr, bytes, len);
> }
> }
> }
> @@ -799,7 +810,8 @@ static int patch_return(void *addr, stru
> return i;
> }
>
> -void __init_or_module noinline apply_returns(s32 *start, s32 *end)
> +void __init_or_module noinline apply_returns(s32 *start, s32 *end,
> + struct module *mod)
> {
> s32 *s;
>
> @@ -808,12 +820,13 @@ void __init_or_module noinline apply_ret
>
> for (s = start; s < end; s++) {
> void *dest = NULL, *addr = (void *)s + *s;
> + void *wr_addr = module_writable_address(mod, addr);
> struct insn insn;
> int len, ret;
> u8 bytes[16];
> u8 op;
>
> - ret = insn_decode_kernel(&insn, addr);
> + ret = insn_decode_kernel(&insn, wr_addr);
> if (WARN_ON_ONCE(ret < 0))
> continue;
>
> @@ -833,32 +846,35 @@ void __init_or_module noinline apply_ret
>
> len = patch_return(addr, &insn, bytes);
> if (len == insn.length) {
> - DUMP_BYTES(RET, ((u8*)addr), len, "%px: orig: ", addr);
> + DUMP_BYTES(RET, ((u8*)wr_addr), len, "%px: orig: ", addr);
> DUMP_BYTES(RET, ((u8*)bytes), len, "%px: repl: ", addr);
> - text_poke_early(addr, bytes, len);
> + text_poke_early(wr_addr, bytes, len);
> }
> }
> }
> #else
> -void __init_or_module noinline apply_returns(s32 *start, s32 *end) { }
> +void __init_or_module noinline apply_returns(s32 *start, s32 *end,
> + struct module *mod) { }
> #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) { }
> +void __init_or_module noinline apply_retpolines(s32 *start, s32 *end,
> + struct module *mod) { }
> +void __init_or_module noinline apply_returns(s32 *start, s32 *end,
> + struct module *mod) { }
>
> #endif /* CONFIG_MITIGATION_RETPOLINE && CONFIG_OBJTOOL */
>
> #ifdef CONFIG_X86_KERNEL_IBT
>
> -static void poison_cfi(void *addr);
> +static void poison_cfi(void *addr, void *wr_addr);
>
> -static void __init_or_module poison_endbr(void *addr, bool warn)
> +static void __init_or_module poison_endbr(void *addr, void *wr_addr, bool warn)
> {
> u32 endbr, poison = gen_endbr_poison();
>
> - if (WARN_ON_ONCE(get_kernel_nofault(endbr, addr)))
> + if (WARN_ON_ONCE(get_kernel_nofault(endbr, wr_addr)))
> return;
>
> if (!is_endbr(endbr)) {
> @@ -873,7 +889,7 @@ static void __init_or_module poison_endb
> */
> DUMP_BYTES(ENDBR, ((u8*)addr), 4, "%px: orig: ", addr);
> DUMP_BYTES(ENDBR, ((u8*)&poison), 4, "%px: repl: ", addr);
> - text_poke_early(addr, &poison, 4);
> + text_poke_early(wr_addr, &poison, 4);
> }
>
> /*
> @@ -882,22 +898,23 @@ static void __init_or_module poison_endb
> * 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)
> +void __init_or_module noinline apply_seal_endbr(s32 *start, s32 *end, struct module *mod)
> {
> s32 *s;
>
> for (s = start; s < end; s++) {
> void *addr = (void *)s + *s;
> + void *wr_addr = module_writable_address(mod, addr);
>
> - poison_endbr(addr, true);
> + poison_endbr(addr, wr_addr, true);
> if (IS_ENABLED(CONFIG_FINEIBT))
> - poison_cfi(addr - 16);
> + poison_cfi(addr - 16, wr_addr - 16);
> }
> }
>
> #else
>
> -void __init_or_module apply_seal_endbr(s32 *start, s32 *end) { }
> +void __init_or_module apply_seal_endbr(s32 *start, s32 *end, struct module *mod) { }
>
> #endif /* CONFIG_X86_KERNEL_IBT */
>
> @@ -1119,7 +1136,7 @@ static u32 decode_caller_hash(void *addr
> }
>
> /* .retpoline_sites */
> -static int cfi_disable_callers(s32 *start, s32 *end)
> +static int cfi_disable_callers(s32 *start, s32 *end, struct module *mod)
> {
> /*
> * Disable kCFI by patching in a JMP.d8, this leaves the hash immediate
> @@ -1131,20 +1148,23 @@ static int cfi_disable_callers(s32 *star
>
> for (s = start; s < end; s++) {
> void *addr = (void *)s + *s;
> + void *wr_addr;
> u32 hash;
>
> addr -= fineibt_caller_size;
> - hash = decode_caller_hash(addr);
> + wr_addr = module_writable_address(mod, addr);
> + hash = decode_caller_hash(wr_addr);
> +
> if (!hash) /* nocfi callers */
> continue;
>
> - text_poke_early(addr, jmp, 2);
> + text_poke_early(wr_addr, jmp, 2);
> }
>
> return 0;
> }
>
> -static int cfi_enable_callers(s32 *start, s32 *end)
> +static int cfi_enable_callers(s32 *start, s32 *end, struct module *mod)
> {
> /*
> * Re-enable kCFI, undo what cfi_disable_callers() did.
> @@ -1154,106 +1174,115 @@ static int cfi_enable_callers(s32 *start
>
> for (s = start; s < end; s++) {
> void *addr = (void *)s + *s;
> + void *wr_addr;
> u32 hash;
>
> addr -= fineibt_caller_size;
> - hash = decode_caller_hash(addr);
> + wr_addr = module_writable_address(mod, addr);
> + hash = decode_caller_hash(wr_addr);
> if (!hash) /* nocfi callers */
> continue;
>
> - text_poke_early(addr, mov, 2);
> + text_poke_early(wr_addr, mov, 2);
> }
>
> return 0;
> }
>
> /* .cfi_sites */
> -static int cfi_rand_preamble(s32 *start, s32 *end)
> +static int cfi_rand_preamble(s32 *start, s32 *end, struct module *mod)
> {
> s32 *s;
>
> for (s = start; s < end; s++) {
> void *addr = (void *)s + *s;
> + void *wr_addr = module_writable_address(mod, addr);
> u32 hash;
>
> - hash = decode_preamble_hash(addr);
> + hash = decode_preamble_hash(wr_addr);
> 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);
> + text_poke_early(wr_addr + 1, &hash, 4);
> }
>
> return 0;
> }
>
> -static int cfi_rewrite_preamble(s32 *start, s32 *end)
> +static int cfi_rewrite_preamble(s32 *start, s32 *end, struct module *mod)
> {
> s32 *s;
>
> for (s = start; s < end; s++) {
> void *addr = (void *)s + *s;
> + void *wr_addr = module_writable_address(mod, addr);
> u32 hash;
>
> - hash = decode_preamble_hash(addr);
> + hash = decode_preamble_hash(wr_addr);
> 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);
> + text_poke_early(wr_addr, fineibt_preamble_start, fineibt_preamble_size);
> + WARN_ON(*(u32 *)(wr_addr + fineibt_preamble_hash) != 0x12345678);
> + text_poke_early(wr_addr + fineibt_preamble_hash, &hash, 4);
> }
>
> return 0;
> }
>
> -static void cfi_rewrite_endbr(s32 *start, s32 *end)
> +static void cfi_rewrite_endbr(s32 *start, s32 *end, struct module *mod)
> {
> s32 *s;
>
> for (s = start; s < end; s++) {
> void *addr = (void *)s + *s;
> + void *wr_addr = module_writable_address(mod, addr);
>
> - poison_endbr(addr+16, false);
> + poison_endbr(addr+16, wr_addr, false);
> }
> }
>
> /* .retpoline_sites */
> -static int cfi_rand_callers(s32 *start, s32 *end)
> +static int cfi_rand_callers(s32 *start, s32 *end, struct module *mod)
> {
> s32 *s;
>
> for (s = start; s < end; s++) {
> void *addr = (void *)s + *s;
> + void *wr_addr;
> u32 hash;
>
> addr -= fineibt_caller_size;
> - hash = decode_caller_hash(addr);
> + wr_addr = module_writable_address(mod, addr);
> + hash = decode_caller_hash(wr_addr);
> if (hash) {
> hash = -cfi_rehash(hash);
> - text_poke_early(addr + 2, &hash, 4);
> + text_poke_early(wr_addr + 2, &hash, 4);
> }
> }
>
> return 0;
> }
>
> -static int cfi_rewrite_callers(s32 *start, s32 *end)
> +static int cfi_rewrite_callers(s32 *start, s32 *end, struct module *mod)
> {
> s32 *s;
>
> for (s = start; s < end; s++) {
> void *addr = (void *)s + *s;
> + void *wr_addr;
> u32 hash;
>
> addr -= fineibt_caller_size;
> - hash = decode_caller_hash(addr);
> + wr_addr = module_writable_address(mod, addr);
> + hash = decode_caller_hash(wr_addr);
> if (hash) {
> - 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);
> + text_poke_early(wr_addr, fineibt_caller_start, fineibt_caller_size);
> + WARN_ON(*(u32 *)(wr_addr + fineibt_caller_hash) != 0x12345678);
> + text_poke_early(wr_addr + fineibt_caller_hash, &hash, 4);
> }
> /* rely on apply_retpolines() */
> }
> @@ -1262,8 +1291,9 @@ static int cfi_rewrite_callers(s32 *star
> }
>
> static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
> - s32 *start_cfi, s32 *end_cfi, bool builtin)
> + s32 *start_cfi, s32 *end_cfi, struct module *mod)
> {
> + bool builtin = mod ? false : true;
> int ret;
>
> if (WARN_ONCE(fineibt_preamble_size != 16,
> @@ -1281,7 +1311,7 @@ static void __apply_fineibt(s32 *start_r
> * 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);
> + ret = cfi_disable_callers(start_retpoline, end_retpoline, mod);
> if (ret)
> goto err;
>
> @@ -1292,11 +1322,11 @@ static void __apply_fineibt(s32 *start_r
> cfi_bpf_subprog_hash = cfi_rehash(cfi_bpf_subprog_hash);
> }
>
> - ret = cfi_rand_preamble(start_cfi, end_cfi);
> + ret = cfi_rand_preamble(start_cfi, end_cfi, mod);
> if (ret)
> goto err;
>
> - ret = cfi_rand_callers(start_retpoline, end_retpoline);
> + ret = cfi_rand_callers(start_retpoline, end_retpoline, mod);
> if (ret)
> goto err;
> }
> @@ -1308,7 +1338,7 @@ static void __apply_fineibt(s32 *start_r
> return;
>
> case CFI_KCFI:
> - ret = cfi_enable_callers(start_retpoline, end_retpoline);
> + ret = cfi_enable_callers(start_retpoline, end_retpoline, mod);
> if (ret)
> goto err;
>
> @@ -1318,17 +1348,17 @@ static void __apply_fineibt(s32 *start_r
>
> case CFI_FINEIBT:
> /* place the FineIBT preamble at func()-16 */
> - ret = cfi_rewrite_preamble(start_cfi, end_cfi);
> + ret = cfi_rewrite_preamble(start_cfi, end_cfi, mod);
> if (ret)
> goto err;
>
> /* rewrite the callers to target func()-16 */
> - ret = cfi_rewrite_callers(start_retpoline, end_retpoline);
> + ret = cfi_rewrite_callers(start_retpoline, end_retpoline, mod);
> if (ret)
> goto err;
>
> /* now that nobody targets func()+0, remove ENDBR there */
> - cfi_rewrite_endbr(start_cfi, end_cfi);
> + cfi_rewrite_endbr(start_cfi, end_cfi, mod);
>
> if (builtin)
> pr_info("Using FineIBT CFI\n");
> @@ -1347,7 +1377,7 @@ static inline void poison_hash(void *add
> *(u32 *)addr = 0;
> }
>
> -static void poison_cfi(void *addr)
> +static void poison_cfi(void *addr, void *wr_addr)
> {
> switch (cfi_mode) {
> case CFI_FINEIBT:
> @@ -1359,8 +1389,8 @@ static void poison_cfi(void *addr)
> * ud2
> * 1: nop
> */
> - poison_endbr(addr, false);
> - poison_hash(addr + fineibt_preamble_hash);
> + poison_endbr(addr, wr_addr, false);
> + poison_hash(wr_addr + fineibt_preamble_hash);
> break;
>
> case CFI_KCFI:
> @@ -1369,7 +1399,7 @@ static void poison_cfi(void *addr)
> * movl $0, %eax
> * .skip 11, 0x90
> */
> - poison_hash(addr + 1);
> + poison_hash(wr_addr + 1);
> break;
>
> default:
> @@ -1380,22 +1410,21 @@ static void poison_cfi(void *addr)
> #else
>
> static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
> - s32 *start_cfi, s32 *end_cfi, bool builtin)
> + s32 *start_cfi, s32 *end_cfi, struct module *mod)
> {
> }
>
> #ifdef CONFIG_X86_KERNEL_IBT
> -static void poison_cfi(void *addr) { }
> +static void poison_cfi(void *addr, void *wr_addr) { }
> #endif
>
> #endif
>
> void apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
> - s32 *start_cfi, s32 *end_cfi)
> + s32 *start_cfi, s32 *end_cfi, struct module *mod)
> {
> return __apply_fineibt(start_retpoline, end_retpoline,
> - start_cfi, end_cfi,
> - /* .builtin = */ false);
> + start_cfi, end_cfi, mod);
> }
>
> #ifdef CONFIG_SMP
> @@ -1692,16 +1721,16 @@ void __init alternative_instructions(voi
> paravirt_set_cap();
>
> __apply_fineibt(__retpoline_sites, __retpoline_sites_end,
> - __cfi_sites, __cfi_sites_end, true);
> + __cfi_sites, __cfi_sites_end, NULL);
>
> /*
> * 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);
> + apply_retpolines(__retpoline_sites, __retpoline_sites_end, NULL);
> + apply_returns(__return_sites, __return_sites_end, NULL);
>
> - apply_alternatives(__alt_instructions, __alt_instructions_end);
> + apply_alternatives(__alt_instructions, __alt_instructions_end, NULL);
>
> /*
> * Now all calls are established. Apply the call thunks if
> @@ -1712,7 +1741,7 @@ void __init alternative_instructions(voi
> /*
> * Seal all functions that do not have their address taken.
> */
> - apply_seal_endbr(__ibt_endbr_seal, __ibt_endbr_seal_end);
> + apply_seal_endbr(__ibt_endbr_seal, __ibt_endbr_seal_end, NULL);
>
> #ifdef CONFIG_SMP
> /* Patch to UP if other cpus not imminent. */
> --- a/arch/x86/kernel/ftrace.c~x86-module-prepare-module-loading-for-rox-allocations-of-text
> +++ a/arch/x86/kernel/ftrace.c
> @@ -118,10 +118,13 @@ ftrace_modify_code_direct(unsigned long
> return ret;
>
> /* replace the text with the new text */
> - if (ftrace_poke_late)
> + if (ftrace_poke_late) {
> text_poke_queue((void *)ip, new_code, MCOUNT_INSN_SIZE, NULL);
> - else
> - text_poke_early((void *)ip, new_code, MCOUNT_INSN_SIZE);
> + } else {
> + mutex_lock(&text_mutex);
> + text_poke((void *)ip, new_code, MCOUNT_INSN_SIZE);
> + mutex_unlock(&text_mutex);
> + }
> return 0;
> }
>
> @@ -318,7 +321,7 @@ create_trampoline(struct ftrace_ops *ops
> unsigned const char op_ref[] = { 0x48, 0x8b, 0x15 };
> unsigned const char retq[] = { RET_INSN_OPCODE, INT3_INSN_OPCODE };
> union ftrace_op_code_union op_ptr;
> - int ret;
> + void *ret;
>
> if (ops->flags & FTRACE_OPS_FL_SAVE_REGS) {
> start_offset = (unsigned long)ftrace_regs_caller;
> @@ -349,15 +352,15 @@ create_trampoline(struct ftrace_ops *ops
> npages = DIV_ROUND_UP(*tramp_size, PAGE_SIZE);
>
> /* Copy ftrace_caller onto the trampoline memory */
> - ret = copy_from_kernel_nofault(trampoline, (void *)start_offset, size);
> - if (WARN_ON(ret < 0))
> + ret = text_poke_copy(trampoline, (void *)start_offset, size);
> + if (WARN_ON(!ret))
> goto fail;
>
> ip = trampoline + size;
> if (cpu_feature_enabled(X86_FEATURE_RETHUNK))
> __text_gen_insn(ip, JMP32_INSN_OPCODE, ip, x86_return_thunk, JMP32_INSN_SIZE);
> else
> - memcpy(ip, retq, sizeof(retq));
> + text_poke_copy(ip, retq, sizeof(retq));
>
> /* No need to test direct calls on created trampolines */
> if (ops->flags & FTRACE_OPS_FL_SAVE_REGS) {
> @@ -365,8 +368,7 @@ create_trampoline(struct ftrace_ops *ops
> ip = trampoline + (jmp_offset - start_offset);
> if (WARN_ON(*(char *)ip != 0x75))
> goto fail;
> - ret = copy_from_kernel_nofault(ip, x86_nops[2], 2);
> - if (ret < 0)
> + if (!text_poke_copy(ip, x86_nops[2], 2))
> goto fail;
> }
>
> @@ -379,7 +381,7 @@ create_trampoline(struct ftrace_ops *ops
> */
>
> ptr = (unsigned long *)(trampoline + size + RET_SIZE);
> - *ptr = (unsigned long)ops;
> + text_poke_copy(ptr, &ops, sizeof(unsigned long));
>
> op_offset -= start_offset;
> memcpy(&op_ptr, trampoline + op_offset, OP_REF_SIZE);
> @@ -395,7 +397,7 @@ create_trampoline(struct ftrace_ops *ops
> op_ptr.offset = offset;
>
> /* put in the new offset to the ftrace_ops */
> - memcpy(trampoline + op_offset, &op_ptr, OP_REF_SIZE);
> + text_poke_copy(trampoline + op_offset, &op_ptr, OP_REF_SIZE);
>
> /* put in the call to the function */
> mutex_lock(&text_mutex);
> @@ -405,9 +407,9 @@ create_trampoline(struct ftrace_ops *ops
> * the depth accounting before the call already.
> */
> dest = ftrace_ops_get_func(ops);
> - memcpy(trampoline + call_offset,
> - text_gen_insn(CALL_INSN_OPCODE, trampoline + call_offset, dest),
> - CALL_INSN_SIZE);
> + text_poke_copy_locked(trampoline + call_offset,
> + text_gen_insn(CALL_INSN_OPCODE, trampoline + call_offset, dest),
> + CALL_INSN_SIZE, false);
> mutex_unlock(&text_mutex);
>
> /* ALLOC_TRAMP flags lets us know we created it */
> --- a/arch/x86/kernel/module.c~x86-module-prepare-module-loading-for-rox-allocations-of-text
> +++ a/arch/x86/kernel/module.c
> @@ -146,18 +146,21 @@ static int __write_relocate_add(Elf64_Sh
> }
>
> if (apply) {
> - if (memcmp(loc, &zero, size)) {
> + void *wr_loc = module_writable_address(me, loc);
> +
> + if (memcmp(wr_loc, &zero, size)) {
> pr_err("x86/modules: Invalid relocation target, existing value is nonzero for type %d, loc %p, val %Lx\n",
> (int)ELF64_R_TYPE(rel[i].r_info), loc, val);
> return -ENOEXEC;
> }
> - write(loc, &val, size);
> + write(wr_loc, &val, size);
> } else {
> if (memcmp(loc, &val, size)) {
> pr_warn("x86/modules: Invalid relocation target, existing value does not match expected value for type %d, loc %p, val %Lx\n",
> (int)ELF64_R_TYPE(rel[i].r_info), loc, val);
> return -ENOEXEC;
> }
> + /* FIXME: needs care for ROX module allocations */
> write(loc, &zero, size);
> }
> }
> @@ -224,7 +227,7 @@ int module_finalize(const Elf_Ehdr *hdr,
> const Elf_Shdr *sechdrs,
> struct module *me)
> {
> - const Elf_Shdr *s, *alt = NULL, *locks = NULL,
> + const Elf_Shdr *s, *alt = NULL,
> *orc = NULL, *orc_ip = NULL,
> *retpolines = NULL, *returns = NULL, *ibt_endbr = NULL,
> *calls = NULL, *cfi = NULL;
> @@ -233,8 +236,6 @@ int module_finalize(const Elf_Ehdr *hdr,
> for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
> if (!strcmp(".altinstructions", secstrings + s->sh_name))
> alt = s;
> - if (!strcmp(".smp_locks", secstrings + s->sh_name))
> - locks = s;
> if (!strcmp(".orc_unwind", secstrings + s->sh_name))
> orc = s;
> if (!strcmp(".orc_unwind_ip", secstrings + s->sh_name))
> @@ -265,20 +266,20 @@ int module_finalize(const Elf_Ehdr *hdr,
> csize = cfi->sh_size;
> }
>
> - apply_fineibt(rseg, rseg + rsize, cseg, cseg + csize);
> + apply_fineibt(rseg, rseg + rsize, cseg, cseg + csize, me);
> }
> if (retpolines) {
> void *rseg = (void *)retpolines->sh_addr;
> - apply_retpolines(rseg, rseg + retpolines->sh_size);
> + apply_retpolines(rseg, rseg + retpolines->sh_size, me);
> }
> if (returns) {
> void *rseg = (void *)returns->sh_addr;
> - apply_returns(rseg, rseg + returns->sh_size);
> + apply_returns(rseg, rseg + returns->sh_size, me);
> }
> if (alt) {
> /* patch .altinstructions */
> void *aseg = (void *)alt->sh_addr;
> - apply_alternatives(aseg, aseg + alt->sh_size);
> + apply_alternatives(aseg, aseg + alt->sh_size, me);
> }
> if (calls || alt) {
> struct callthunk_sites cs = {};
> @@ -297,8 +298,28 @@ int module_finalize(const Elf_Ehdr *hdr,
> }
> if (ibt_endbr) {
> void *iseg = (void *)ibt_endbr->sh_addr;
> - apply_seal_endbr(iseg, iseg + ibt_endbr->sh_size);
> + apply_seal_endbr(iseg, iseg + ibt_endbr->sh_size, me);
> }
> +
> + if (orc && orc_ip)
> + unwind_module_init(me, (void *)orc_ip->sh_addr, orc_ip->sh_size,
> + (void *)orc->sh_addr, orc->sh_size);
> +
> + return 0;
> +}
> +
> +int module_post_finalize(const Elf_Ehdr *hdr,
> + const Elf_Shdr *sechdrs,
> + struct module *me)
> +{
> + const Elf_Shdr *s, *locks = NULL;
> + char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
> +
> + for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
> + if (!strcmp(".smp_locks", secstrings + s->sh_name))
> + locks = s;
> + }
> +
> if (locks) {
> void *lseg = (void *)locks->sh_addr;
> void *text = me->mem[MOD_TEXT].base;
> @@ -308,10 +329,6 @@ int module_finalize(const Elf_Ehdr *hdr,
> text, text_end);
> }
>
> - if (orc && orc_ip)
> - unwind_module_init(me, (void *)orc_ip->sh_addr, orc_ip->sh_size,
> - (void *)orc->sh_addr, orc->sh_size);
> -
> return 0;
> }
>
> _
>
> Patches currently in -mm which might be from rppt@kernel.org are
>
>
--
Sincerely yours,
Mike.
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [merged mm-stable] x86-module-prepare-module-loading-for-rox-allocations-of-text.patch removed from -mm tree
2024-11-06 6:50 ` Mike Rapoport
@ 2024-11-06 21:30 ` Andrew Morton
2024-12-05 8:41 ` Peter Zijlstra
1 sibling, 0 replies; 6+ messages in thread
From: Andrew Morton @ 2024-11-06 21:30 UTC (permalink / raw)
To: Mike Rapoport
Cc: mm-commits, will, vgupta, urezki, tsbogend, tglx, surenb, song,
shorne, rostedt, richard, peterz, palmer, oleg, mpe, monstr,
mingo, mhiramat, mcgrof, mattst88, mark.rutland, luto, linux,
Liam.Howlett, kent.overstreet, kdevops, johannes, jcmvbkbc, hch,
guoren, glaubitz, geert, dinguyen, deller, dave.hansen,
christophe.leroy, chenhuacai, catalin.marinas, bp, bcain, arnd,
ardb, andreas
On Wed, 6 Nov 2024 08:50:41 +0200 Mike Rapoport <rppt@kernel.org> wrote:
> Hi Andrew,
>
> Yesterday Nathan discovered and I fixed another small issue with fineibt.
> I suspect it's too late to add this as a fixup, so here's a formal patch
> with the fix.
Thanks. I only moved this series into mm-stable yesterday so I'll do
the rebase and get this fixup integrated in the cleaner way.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [merged mm-stable] x86-module-prepare-module-loading-for-rox-allocations-of-text.patch removed from -mm tree
2024-11-06 6:50 ` Mike Rapoport
2024-11-06 21:30 ` Andrew Morton
@ 2024-12-05 8:41 ` Peter Zijlstra
2024-12-06 10:39 ` Mike Rapoport
1 sibling, 1 reply; 6+ messages in thread
From: Peter Zijlstra @ 2024-12-05 8:41 UTC (permalink / raw)
To: Mike Rapoport
Cc: Andrew Morton, mm-commits, will, vgupta, urezki, tsbogend, tglx,
surenb, song, shorne, rostedt, richard, palmer, oleg, mpe, monstr,
mingo, mhiramat, mcgrof, mattst88, mark.rutland, luto, linux,
Liam.Howlett, kent.overstreet, kdevops, johannes, jcmvbkbc, hch,
guoren, glaubitz, geert, dinguyen, deller, dave.hansen,
christophe.leroy, chenhuacai, catalin.marinas, bp, bcain, arnd,
ardb, andreas
On Wed, Nov 06, 2024 at 08:50:41AM +0200, Mike Rapoport wrote:
> Hi Andrew,
>
> Yesterday Nathan discovered and I fixed another small issue with fineibt.
> I suspect it's too late to add this as a fixup, so here's a formal patch
> with the fix.
>
> From b31fd8493c4e1b6042776642a812690f16575b51 Mon Sep 17 00:00:00 2001
> From: "Mike Rapoport (Microsoft)" <rppt@kernel.org>
> Date: Tue, 5 Nov 2024 10:49:57 +0200
> Subject: [PATCH] x86/alternatives: fix writable address in cfi_rewrite_endbr()
>
> Commit a159950eb69f ("x86/module: prepare module loading for ROX
> allocations of text") missed the offset that should be added to the
> writable address passed to poison_endbr() from cfi_rewrite_endbr() and
> this causes boot failures on kernels running with cfi=fineibt on
> machines that support IBT.
>
> Add required offset to wr_addr argument to fix the issue.
>
> Reported-by: Nathan Chancellor <nathan@kernel.org>
> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> Fixes: a159950eb69f ("x86/module: prepare module loading for ROX allocations of text")
> Tested-by: Nathan Chancellor <nathan@kernel.org>
> ---
> arch/x86/kernel/alternative.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
> index 3407efc26528..243843e44e89 100644
> --- a/arch/x86/kernel/alternative.c
> +++ b/arch/x86/kernel/alternative.c
> @@ -1241,7 +1241,7 @@ static void cfi_rewrite_endbr(s32 *start, s32 *end, struct module *mod)
> void *addr = (void *)s + *s;
> void *wr_addr = module_writable_address(mod, addr);
>
> - poison_endbr(addr+16, wr_addr, false);
> + poison_endbr(addr + 16, wr_addr + 16, false);
> }
> }
So... *sigh*. I had to rebase quite a few patches on top of this, and
while doing do I got quite annoyed at how messy all this is, so I
cleaned it all up.
Only to find out that it's all broken, even with the above fix (my ADL
will currently die when it tries to load a module).
So it's a good thing these patches got an ack from the x86 people I
suppose :-(((
Anyway, while noodling with all that, I think there's a fairly
fundamental error in all of this. The mem->rw_copy should not be a whole
second allocation, it should be a (page granular) RW alias of the
(large) ROX map.
That also gets rid of that whole copy operation.
I'm having to chase a few regressions of my own first, but after that
I'll look at reworking all this.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [merged mm-stable] x86-module-prepare-module-loading-for-rox-allocations-of-text.patch removed from -mm tree
2024-12-05 8:41 ` Peter Zijlstra
@ 2024-12-06 10:39 ` Mike Rapoport
2024-12-09 8:38 ` Peter Zijlstra
0 siblings, 1 reply; 6+ messages in thread
From: Mike Rapoport @ 2024-12-06 10:39 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Andrew Morton, mm-commits, will, vgupta, urezki, tsbogend, tglx,
surenb, song, shorne, rostedt, richard, palmer, oleg, mpe, monstr,
mingo, mhiramat, mcgrof, mattst88, mark.rutland, luto, linux,
Liam.Howlett, kent.overstreet, kdevops, johannes, jcmvbkbc, hch,
guoren, glaubitz, geert, dinguyen, deller, dave.hansen,
christophe.leroy, chenhuacai, catalin.marinas, bp, bcain, arnd,
ardb, andreas
Hi Peter,
On Thu, Dec 05, 2024 at 09:41:28AM +0100, Peter Zijlstra wrote:
> On Wed, Nov 06, 2024 at 08:50:41AM +0200, Mike Rapoport wrote:
>
> Anyway, while noodling with all that, I think there's a fairly
> fundamental error in all of this. The mem->rw_copy should not be a whole
> second allocation, it should be a (page granular) RW alias of the
> (large) ROX map.
I've made mem->rw_copy an allocation because Andy raised a concern [1] that
we'll have an executable mapping of semi-formed code.
With an actual copy rather than an alias the ROX pages contain invalid
instructions up to the point we're through with relocations and
alternatives patching and the actual code appears in ROX mappings in one
go.
[1] https://lore.kernel.org/all/a17c65c6-863f-4026-9c6f-a04b659e9ab4@app.fastmail.com
> That also gets rid of that whole copy operation.
>
> I'm having to chase a few regressions of my own first, but after that
> I'll look at reworking all this.
--
Sincerely yours,
Mike.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [merged mm-stable] x86-module-prepare-module-loading-for-rox-allocations-of-text.patch removed from -mm tree
2024-12-06 10:39 ` Mike Rapoport
@ 2024-12-09 8:38 ` Peter Zijlstra
0 siblings, 0 replies; 6+ messages in thread
From: Peter Zijlstra @ 2024-12-09 8:38 UTC (permalink / raw)
To: Mike Rapoport
Cc: Andrew Morton, mm-commits, will, vgupta, urezki, tsbogend, tglx,
surenb, song, shorne, rostedt, richard, palmer, oleg, mpe, monstr,
mingo, mhiramat, mcgrof, mattst88, mark.rutland, luto, linux,
Liam.Howlett, kent.overstreet, kdevops, johannes, jcmvbkbc, hch,
guoren, glaubitz, geert, dinguyen, deller, dave.hansen,
christophe.leroy, chenhuacai, catalin.marinas, bp, bcain, arnd,
ardb, andreas
On Fri, Dec 06, 2024 at 12:39:32PM +0200, Mike Rapoport wrote:
> Hi Peter,
>
> On Thu, Dec 05, 2024 at 09:41:28AM +0100, Peter Zijlstra wrote:
> > On Wed, Nov 06, 2024 at 08:50:41AM +0200, Mike Rapoport wrote:
> >
> > Anyway, while noodling with all that, I think there's a fairly
> > fundamental error in all of this. The mem->rw_copy should not be a whole
> > second allocation, it should be a (page granular) RW alias of the
> > (large) ROX map.
>
> I've made mem->rw_copy an allocation because Andy raised a concern [1] that
> we'll have an executable mapping of semi-formed code.
> With an actual copy rather than an alias the ROX pages contain invalid
> instructions up to the point we're through with relocations and
> alternatives patching and the actual code appears in ROX mappings in one
> go.
>
> [1] https://lore.kernel.org/all/a17c65c6-863f-4026-9c6f-a04b659e9ab4@app.fastmail.com
Right, but at the same time he also calls out the problem with this;
you're now forced to carry two pointers, one to indicate where the code
is going to live and one to actually read/write to.
(Not to mention the disparity of module_writable_address() only implying
writes, but in actual reality it is required for reads too.)
Pushing this dual pointer through all the pre-existing code that
rewrites our code is done haphazardly and incomplete (and is quite
ugly and error prone -- as evidenced by my ADL's current inability to
load modules).
He also then goes on to suggest a better approach would be to remap
inplace to RW and back to RX. Now the problem with this is ofcourse
that the remap to RW will shatter the large pages we're so very keen on
preserving, but this can be rectified at the point where er remap back
to RX -- it's just that the current code does not.
All in all, I really don't like the place where we've end up, it is
quite horrible :/
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2024-12-09 8:39 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-11-06 1:00 [merged mm-stable] x86-module-prepare-module-loading-for-rox-allocations-of-text.patch removed from -mm tree Andrew Morton
2024-11-06 6:50 ` Mike Rapoport
2024-11-06 21:30 ` Andrew Morton
2024-12-05 8:41 ` Peter Zijlstra
2024-12-06 10:39 ` Mike Rapoport
2024-12-09 8:38 ` Peter Zijlstra
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox