* [PATCH 0/3] arm64: Fix text-poke byte-order and late PLT/veneer ROX handling @ 2026-10-10 8:47 Rui Qi 2026-10-10 8:47 ` [PATCH 1/3] arm64/module: Fix big-endian breakage in late data relocations Rui Qi 2026-10-10 8:50 ` [PATCH 2/3] arm64: patching: Fix instruction byte order in aarch64_insn_set() Rui Qi 0 siblings, 2 replies; 5+ messages in thread From: Rui Qi @ 2026-10-10 8:47 UTC (permalink / raw) To: catalin.marinas, will Cc: mark.rutland, ardb, song, dylanbhatch, linux-arm-kernel, linux-kernel, Rui Qi This series fixes three bugs in the arm64 text-poke / module relocation path, all introduced by the recent text-poke rework (451c3cab9a65 "arm64: patching: implement text_poke API" and 91b89a634487 "arm64/module: Use text-poke API for late relocations."). The first two are big-endian byte-order issues; the third is a panic when livepatch emits PLT entries into read-only executable memory. Patch 1 fixes big-endian breakage in late data relocations. The WRITE_PLACE() macro declared its temporary with the type of the source argument (s64), but aarch64_insn_copy() copies only sizeof(*place) bytes from the start of that temporary. On a big-endian kernel the most significant bytes sit at the lowest address, so a 16- or 32-bit relocation copies the sign-extension upper half instead of the computed value. Typing the temporary after the destination element fixes this. Patch 2 fixes big-endian breakage in aarch64_insn_set(). The instruction is passed to text_poke_memset() in host byte order, but A64 instructions must be little-endian in memory. On a big-endian kernel the written bytes are reversed and the CPU takes an UNDEFINED instruction exception when fetching them. This is reachable in-tree: bpf_arch_text_invalidate() fills freed JIT regions with AARCH64_BREAK_FAULT through aarch64_insn_set(), and arm64 selects HAVE_EBPF_JIT without a big-endian guard. Converting to little-endian before the memset, mirroring aarch64_insn_write(), fixes this. Patch 3 (the main fix) routes PLT/veneer emission through the text-poke API. module_emit_plt_entry() and module_emit_veneer_for_adrp() wrote PLT entries into the .plt section by direct assignment, but once a module is fully formed its .plt is read-only/executable. A late (livepatch) relocation that falls back to PLT emission -- an out-of-range R_AARCH64_CALL26/JUMP26, or an ADRP under CONFIG_ARM64_ERRATUM_843419 -- triggers a synchronous Data Abort and panics. Routing through the text-poke API (mirroring WRITE_PLACE()) maps the page through the fixmap, avoiding the fault. All three are tagged for stable. Base-commit: next-20261008 Rui Qi (3): arm64/module: Fix big-endian breakage in late data relocations arm64: patching: Fix instruction byte order in aarch64_insn_set() arm64: module: Use text-poke for late PLT/veneer emission arch/arm64/kernel/module-plts.c | 35 ++++++++++++++++++++++++++++++--- arch/arm64/kernel/module.c | 2 +- arch/arm64/kernel/patching.c | 4 +++- 3 files changed, 36 insertions(+), 5 deletions(-) -- 2.20.1 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/3] arm64/module: Fix big-endian breakage in late data relocations 2026-10-10 8:47 [PATCH 0/3] arm64: Fix text-poke byte-order and late PLT/veneer ROX handling Rui Qi @ 2026-10-10 8:47 ` Rui Qi 2026-10-10 8:50 ` [PATCH 2/3] arm64: patching: Fix instruction byte order in aarch64_insn_set() Rui Qi 1 sibling, 0 replies; 5+ messages in thread From: Rui Qi @ 2026-10-10 8:47 UTC (permalink / raw) To: catalin.marinas, will Cc: mark.rutland, ardb, song, dylanbhatch, linux-arm-kernel, linux-kernel, Rui Qi, stable The WRITE_PLACE macro declares its temporary value with the type of the source argument: __typeof__(val) __val = (val); For the 16-bit and 32-bit data relocations in reloc_data(), val is the s64 result of do_reloc(), so __val is an 8-byte integer. When the module is already loaded (state != MODULE_STATE_UNFORMED), the macro hands the address of __val to aarch64_insn_copy() and asks it to copy only sizeof(*place) -- 2 or 4 -- bytes. aarch64_insn_copy() performs a raw byte copy with no endian conversion. On a big-endian kernel the most significant bytes of the s64 sit at the lowest address, so copying only the first 2/4 bytes grabs the sign-extension upper half instead of the computed relocation value, corrupting the patched location. The UNFORMED direct-assignment path is unaffected because the compiler narrows the s64 to the destination type. Type the temporary after the destination element instead. Fixes: 91b89a634487d5614e51ee773a889ed57f5551ca ("arm64/module: Use text-poke API for late relocations.") Cc: stable@vger.kernel.org Signed-off-by: Rui Qi <qirui.001@bytedance.com> --- arch/arm64/kernel/module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c index 24adb581af0e..0fdf4c1c4e05 100644 --- a/arch/arm64/kernel/module.c +++ b/arch/arm64/kernel/module.c @@ -50,7 +50,7 @@ static u64 do_reloc(enum aarch64_reloc_op reloc_op, __le32 *place, u64 val) } #define WRITE_PLACE(place, val, mod) do { \ - __typeof__(val) __val = (val); \ + __typeof__(*place) __val = (val); \ \ if (mod->state == MODULE_STATE_UNFORMED) \ *(place) = __val; \ -- 2.20.1 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/3] arm64: patching: Fix instruction byte order in aarch64_insn_set() 2026-10-10 8:47 [PATCH 0/3] arm64: Fix text-poke byte-order and late PLT/veneer ROX handling Rui Qi 2026-10-10 8:47 ` [PATCH 1/3] arm64/module: Fix big-endian breakage in late data relocations Rui Qi @ 2026-10-10 8:50 ` Rui Qi 2026-10-10 8:50 ` [PATCH 3/3] arm64: module: Use text-poke for late PLT/veneer emission Rui Qi 2026-10-15 16:57 ` [PATCH 2/3] arm64: patching: Fix instruction byte order in aarch64_insn_set() Catalin Marinas 1 sibling, 2 replies; 5+ messages in thread From: Rui Qi @ 2026-10-10 8:50 UTC (permalink / raw) To: catalin.marinas, will Cc: mark.rutland, ardb, song, dylanbhatch, linux-arm-kernel, linux-kernel, Rui Qi, stable aarch64_insn_set() passes the host-endian u32 instruction straight to text_poke_memset(), which memset32()'s it into memory in host byte order. AArch64 instructions must be little-endian in memory, so on a big-endian kernel the written bytes are reversed and the CPU takes an UNDEFINED instruction exception when fetching them. The sibling aarch64_insn_write() already converts with cpu_to_le32(); aarch64_insn_set() does not. This is reachable in-tree: bpf_arch_text_invalidate() fills freed JIT regions with AARCH64_BREAK_FAULT through aarch64_insn_set(), and arm64 selects HAVE_EBPF_JIT without a big-endian guard, so the path is taken on BE kernels with BPF JIT. The direct-fill loop in the same file already cpu_to_le32()'s the constant, confirming the expected byte order. Convert the instruction to little-endian before the memset, mirroring aarch64_insn_write(). On LE the conversion is a no-op, so behaviour is unchanged. Fixes: 451c3cab9a65e656c3b3d106831fc02d56b8c34a ("arm64: patching: implement text_poke API") Cc: stable@vger.kernel.org Signed-off-by: Rui Qi <qirui.001@bytedance.com> --- arch/arm64/kernel/patching.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kernel/patching.c b/arch/arm64/kernel/patching.c index 09f019c6547a..ffd790b2b277 100644 --- a/arch/arm64/kernel/patching.c +++ b/arch/arm64/kernel/patching.c @@ -170,10 +170,12 @@ noinstr void *aarch64_insn_copy(void *dst, void *src, size_t len) */ noinstr void *aarch64_insn_set(void *dst, u32 insn, size_t len) { + __le32 __insn = cpu_to_le32(insn); + if ((uintptr_t)dst & 0x3) return NULL; - return __text_poke(text_poke_memset, dst, &insn, len); + return __text_poke(text_poke_memset, dst, &__insn, len); } int __kprobes aarch64_insn_patch_text_nosync(void *addr, u32 insn) -- 2.20.1 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 3/3] arm64: module: Use text-poke for late PLT/veneer emission 2026-10-10 8:50 ` [PATCH 2/3] arm64: patching: Fix instruction byte order in aarch64_insn_set() Rui Qi @ 2026-10-10 8:50 ` Rui Qi 2026-10-15 16:57 ` [PATCH 2/3] arm64: patching: Fix instruction byte order in aarch64_insn_set() Catalin Marinas 1 sibling, 0 replies; 5+ messages in thread From: Rui Qi @ 2026-10-10 8:50 UTC (permalink / raw) To: catalin.marinas, will Cc: mark.rutland, ardb, song, dylanbhatch, linux-arm-kernel, linux-kernel, Rui Qi, stable module_emit_plt_entry() and module_emit_veneer_for_adrp() write PLT entries into the .plt section by direct assignment. Once a module is fully formed its .plt is read-only/executable, so a late (livepatch) relocation that falls back to PLT emission -- an out-of-range R_AARCH64_CALL26/JUMP26, or an ADRP under CONFIG_ARM64_ERRATUM_843419 -- triggers a synchronous Data Abort and panics. This is the same ROX premise that commit 91b89a634487 ("arm64/module: Use text-poke API for late relocations.") handled for the relocation writes through WRITE_PLACE(); the PLT/veneer emitters were left using direct assignment. The late path is reachable without remapping: klp_write_section_relocs() applies .klp.rela.* sections through apply_relocate_add() with the patch module already MODULE_STATE_LIVE, so .plt is ROX. Route the emitters through the text-poke API, mirroring WRITE_PLACE(). Fixes: 91b89a634487d5614e51ee773a889ed57f5551ca ("arm64/module: Use text-poke API for late relocations.") Cc: stable@vger.kernel.org Signed-off-by: Rui Qi <qirui.001@bytedance.com> --- arch/arm64/kernel/module-plts.c | 35 ++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kernel/module-plts.c b/arch/arm64/kernel/module-plts.c index 7afd370da9f4..fa89ed014bd1 100644 --- a/arch/arm64/kernel/module-plts.c +++ b/arch/arm64/kernel/module-plts.c @@ -9,6 +9,29 @@ #include <linux/module.h> #include <linux/moduleloader.h> #include <linux/sort.h> +#include <linux/text-patching.h> + +/* + * The .plt section is marked ROX once the module is fully formed, so + * late (livepatch) relocations that emit PLT entries cannot use direct + * assignment. Mirror WRITE_PLACE() and route the write through the + * text-poke API when the module is already loaded. + * + * Return: 0 on success, -EINVAL if the text-poke write failed. + */ +static int plt_entry_write(struct plt_entry *plt, + struct plt_entry *entry, struct module *mod) +{ + if (mod->state == MODULE_STATE_UNFORMED) { + *plt = *entry; + return 0; + } + + if (!aarch64_insn_copy(plt, entry, sizeof(*plt))) + return -EINVAL; + + return 0; +} static struct plt_entry __get_adrp_add_pair(u64 dst, u64 pc, enum aarch64_insn_register reg) @@ -76,11 +99,14 @@ u64 module_emit_plt_entry(struct module *mod, Elf64_Shdr *sechdrs, int i = pltsec->plt_num_entries; int j = i - 1; u64 val = sym->st_value + rela->r_addend; + struct plt_entry entry; if (is_forbidden_offset_for_adrp(&plt[i].adrp)) i++; - plt[i] = get_plt_entry(val, &plt[i]); + entry = get_plt_entry(val, &plt[i]); + if (plt_entry_write(&plt[i], &entry, mod)) + return 0; /* * Check if the entry we just created is a duplicate. Given that the @@ -107,6 +133,7 @@ u64 module_emit_veneer_for_adrp(struct module *mod, Elf64_Shdr *sechdrs, int i = pltsec->plt_num_entries++; u32 br; int rd; + struct plt_entry entry; if (WARN_ON(pltsec->plt_num_entries > pltsec->plt_max_entries)) return 0; @@ -121,8 +148,10 @@ u64 module_emit_veneer_for_adrp(struct module *mod, Elf64_Shdr *sechdrs, br = aarch64_insn_gen_branch_imm((u64)&plt[i].br, (u64)loc + 4, AARCH64_INSN_BRANCH_NOLINK); - plt[i] = __get_adrp_add_pair(val, (u64)&plt[i], rd); - plt[i].br = cpu_to_le32(br); + entry = __get_adrp_add_pair(val, (u64)&plt[i], rd); + entry.br = cpu_to_le32(br); + if (plt_entry_write(&plt[i], &entry, mod)) + return 0; return (u64)&plt[i]; } -- 2.20.1 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 2/3] arm64: patching: Fix instruction byte order in aarch64_insn_set() 2026-10-10 8:50 ` [PATCH 2/3] arm64: patching: Fix instruction byte order in aarch64_insn_set() Rui Qi 2026-10-10 8:50 ` [PATCH 3/3] arm64: module: Use text-poke for late PLT/veneer emission Rui Qi @ 2026-10-15 16:57 ` Catalin Marinas 1 sibling, 0 replies; 5+ messages in thread From: Catalin Marinas @ 2026-10-15 16:57 UTC (permalink / raw) To: Rui Qi Cc: will, mark.rutland, ardb, song, dylanbhatch, linux-arm-kernel, linux-kernel, stable On Sat, Oct 10, 2026 at 04:50:54PM +0800, Rui Qi wrote: > aarch64_insn_set() passes the host-endian u32 instruction straight to > text_poke_memset(), which memset32()'s it into memory in host byte order. > AArch64 instructions must be little-endian in memory, so on a big-endian > kernel the written bytes are reversed and the CPU takes an UNDEFINED > instruction exception when fetching them. The sibling aarch64_insn_write() > already converts with cpu_to_le32(); aarch64_insn_set() does not. > > This is reachable in-tree: bpf_arch_text_invalidate() fills freed JIT > regions with AARCH64_BREAK_FAULT through aarch64_insn_set(), and arm64 > selects HAVE_EBPF_JIT without a big-endian guard, so the path is taken on > BE kernels with BPF JIT. The direct-fill loop in the same file already > cpu_to_le32()'s the constant, confirming the expected byte order. > > Convert the instruction to little-endian before the memset, mirroring > aarch64_insn_write(). On LE the conversion is a no-op, so behaviour is > unchanged. We are just about to remove big-endian support (in 7.4). -- Catalin ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-10-15 16:57 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-10-10 8:47 [PATCH 0/3] arm64: Fix text-poke byte-order and late PLT/veneer ROX handling Rui Qi 2026-10-10 8:47 ` [PATCH 1/3] arm64/module: Fix big-endian breakage in late data relocations Rui Qi 2026-10-10 8:50 ` [PATCH 2/3] arm64: patching: Fix instruction byte order in aarch64_insn_set() Rui Qi 2026-10-10 8:50 ` [PATCH 3/3] arm64: module: Use text-poke for late PLT/veneer emission Rui Qi 2026-10-15 16:57 ` [PATCH 2/3] arm64: patching: Fix instruction byte order in aarch64_insn_set() Catalin Marinas
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.