Commit dd0eb50e authored by Mark Rutland's avatar Mark Rutland Committed by Catalin Marinas
Browse files

arm64: probes: Cleanup kprobes endianness conversions



The core kprobes code uses kprobe_opcode_t for the in-memory
representation of an instruction, using 'kprobe_opcode_t *' for XOL
slots. As arm64 instructions are always little-endian 32-bit values,
kprobes_opcode_t should be __le32, but at the moment kprobe_opcode_t
is typedef'd to u32.

Today there is no functional issue as we convert values via
cpu_to_le32() and le32_to_cpu() where necessary, but these conversions
are inconsistent with the types used, causing sparse warnings:

|   CHECK   arch/arm64/kernel/probes/kprobes.c
| arch/arm64/kernel/probes/kprobes.c:102:21: warning: cast to restricted __le32
|   CHECK   arch/arm64/kernel/probes/decode-insn.c
| arch/arm64/kernel/probes/decode-insn.c:122:46: warning: cast to restricted __le32
| arch/arm64/kernel/probes/decode-insn.c:124:50: warning: cast to restricted __le32
| arch/arm64/kernel/probes/decode-insn.c:136:31: warning: cast to restricted __le32

Improve this by making kprobes_opcode_t a typedef for __le32 and
consistently using this for pointers to executable instructions. With
this change we can rely on the type system to tell us where conversions
are necessary.

Since kprobe::opcode is changed from u32 to __le32, the existing
le32_to_cpu() converion moves from the point this is initialized (in
arch_prepare_kprobe()) to the points this is consumed when passed to
a handler or text patching function. As kprobe::opcode isn't altered or
consumed elsewhere, this shouldn't result in a functional change.

Signed-off-by: default avatarMark Rutland <mark.rutland@arm.com>
Cc: Will Deacon <will@kernel.org>
Link: https://lore.kernel.org/r/20241008155851.801546-6-mark.rutland@arm.com


Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent 6105c5d4
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -16,10 +16,10 @@ struct arch_probe_insn {
	probes_handler_t *handler;
};
#ifdef CONFIG_KPROBES
typedef u32 kprobe_opcode_t;
typedef __le32 kprobe_opcode_t;
struct arch_specific_insn {
	struct arch_probe_insn api;
	probe_opcode_t *xol_insn;
	kprobe_opcode_t *xol_insn;
	/* restore address after step xol */
	unsigned long xol_restore;
};
+1 −1
Original line number Diff line number Diff line
@@ -134,7 +134,7 @@ arm_kprobe_decode_insn(kprobe_opcode_t *addr, struct arch_specific_insn *asi)
{
	enum probe_insn decoded;
	probe_opcode_t insn = le32_to_cpu(*addr);
	probe_opcode_t *scan_end = NULL;
	kprobe_opcode_t *scan_end = NULL;
	unsigned long size = 0, offset = 0;
	struct arch_probe_insn *api = &asi->api;

+5 −4
Original line number Diff line number Diff line
@@ -64,7 +64,7 @@ static void __kprobes arch_prepare_ss_slot(struct kprobe *p)
	 * the BRK exception handler, so it is unnecessary to generate
	 * Contex-Synchronization-Event via ISB again.
	 */
	aarch64_insn_patch_text_nosync(addr, p->opcode);
	aarch64_insn_patch_text_nosync(addr, le32_to_cpu(p->opcode));
	aarch64_insn_patch_text_nosync(addr + 1, BRK64_OPCODE_KPROBES_SS);

	/*
@@ -85,7 +85,7 @@ static void __kprobes arch_simulate_insn(struct kprobe *p, struct pt_regs *regs)
	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();

	if (p->ainsn.api.handler)
		p->ainsn.api.handler((u32)p->opcode, (long)p->addr, regs);
		p->ainsn.api.handler(le32_to_cpu(p->opcode), (long)p->addr, regs);

	/* single step simulated, now go for post processing */
	post_kprobe_handler(p, kcb, regs);
@@ -99,7 +99,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
		return -EINVAL;

	/* copy instruction */
	p->opcode = le32_to_cpu(*p->addr);
	p->opcode = *p->addr;

	if (search_exception_tables(probe_addr))
		return -EINVAL;
@@ -142,8 +142,9 @@ void __kprobes arch_arm_kprobe(struct kprobe *p)
void __kprobes arch_disarm_kprobe(struct kprobe *p)
{
	void *addr = p->addr;
	u32 insn = le32_to_cpu(p->opcode);

	aarch64_insn_patch_text(&addr, &p->opcode, 1);
	aarch64_insn_patch_text(&addr, &insn, 1);
}

void __kprobes arch_remove_kprobe(struct kprobe *p)