* [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:58 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox