Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a95b0644 authored by Catalin Marinas's avatar Catalin Marinas
Browse files

Merge branch 'for-next/kprobes' into for-next/core

* kprobes:
  arm64: kprobes: Add KASAN instrumentation around stack accesses
  arm64: kprobes: Cleanup jprobe_return
  arm64: kprobes: Fix overflow when saving stack
  arm64: kprobes: WARN if attempting to step with PSTATE.D=1
  kprobes: Add arm64 case in kprobe example module
  arm64: Add kernel return probes support (kretprobes)
  arm64: Add trampoline code for kretprobes
  arm64: kprobes instruction simulation support
  arm64: Treat all entry code as non-kprobe-able
  arm64: Blacklist non-kprobe-able symbol
  arm64: Kprobes with single stepping support
  arm64: add conditional instruction simulation support
  arm64: Add more test functions to insn.c
  arm64: Add HAVE_REGS_AND_STACK_ACCESS_API feature
parents e75118a7 f7e35c5b
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -121,7 +121,6 @@ extern unsigned long profile_pc(struct pt_regs *regs);
#define MAX_REG_OFFSET (offsetof(struct pt_regs, ARM_ORIG_r0))

extern int regs_query_register_offset(const char *name);
extern const char *regs_query_register_name(unsigned int offset);
extern bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr);
extern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
					       unsigned int n);
+3 −0
Original line number Diff line number Diff line
@@ -86,8 +86,11 @@ config ARM64
	select HAVE_PERF_EVENTS
	select HAVE_PERF_REGS
	select HAVE_PERF_USER_STACK_DUMP
	select HAVE_REGS_AND_STACK_ACCESS_API
	select HAVE_RCU_TABLE_FREE
	select HAVE_SYSCALL_TRACEPOINTS
	select HAVE_KPROBES
	select HAVE_KRETPROBES if HAVE_KPROBES
	select IOMMU_DMA if IOMMU_SUPPORT
	select IRQ_DOMAIN
	select IRQ_FORCED_THREADING
+5 −0
Original line number Diff line number Diff line
@@ -66,6 +66,11 @@

#define CACHE_FLUSH_IS_SAFE		1

/* kprobes BRK opcodes with ESR encoding  */
#define BRK64_ESR_MASK		0xFFFF
#define BRK64_ESR_KPROBES	0x0004
#define BRK64_OPCODE_KPROBES	(AARCH64_BREAK_MON | (BRK64_ESR_KPROBES << 5))

/* AArch32 */
#define DBG_ESR_EVT_BKPT	0x4
#define DBG_ESR_EVT_VECC	0x5
+41 −0
Original line number Diff line number Diff line
@@ -120,6 +120,29 @@ enum aarch64_insn_register {
	AARCH64_INSN_REG_SP = 31  /* Stack pointer: as load/store base reg */
};

enum aarch64_insn_special_register {
	AARCH64_INSN_SPCLREG_SPSR_EL1	= 0xC200,
	AARCH64_INSN_SPCLREG_ELR_EL1	= 0xC201,
	AARCH64_INSN_SPCLREG_SP_EL0	= 0xC208,
	AARCH64_INSN_SPCLREG_SPSEL	= 0xC210,
	AARCH64_INSN_SPCLREG_CURRENTEL	= 0xC212,
	AARCH64_INSN_SPCLREG_DAIF	= 0xDA11,
	AARCH64_INSN_SPCLREG_NZCV	= 0xDA10,
	AARCH64_INSN_SPCLREG_FPCR	= 0xDA20,
	AARCH64_INSN_SPCLREG_DSPSR_EL0	= 0xDA28,
	AARCH64_INSN_SPCLREG_DLR_EL0	= 0xDA29,
	AARCH64_INSN_SPCLREG_SPSR_EL2	= 0xE200,
	AARCH64_INSN_SPCLREG_ELR_EL2	= 0xE201,
	AARCH64_INSN_SPCLREG_SP_EL1	= 0xE208,
	AARCH64_INSN_SPCLREG_SPSR_INQ	= 0xE218,
	AARCH64_INSN_SPCLREG_SPSR_ABT	= 0xE219,
	AARCH64_INSN_SPCLREG_SPSR_UND	= 0xE21A,
	AARCH64_INSN_SPCLREG_SPSR_FIQ	= 0xE21B,
	AARCH64_INSN_SPCLREG_SPSR_EL3	= 0xF200,
	AARCH64_INSN_SPCLREG_ELR_EL3	= 0xF201,
	AARCH64_INSN_SPCLREG_SP_EL2	= 0xF210
};

enum aarch64_insn_variant {
	AARCH64_INSN_VARIANT_32BIT,
	AARCH64_INSN_VARIANT_64BIT
@@ -223,8 +246,15 @@ static __always_inline bool aarch64_insn_is_##abbr(u32 code) \
static __always_inline u32 aarch64_insn_get_##abbr##_value(void) \
{ return (val); }

__AARCH64_INSN_FUNCS(adr_adrp,	0x1F000000, 0x10000000)
__AARCH64_INSN_FUNCS(prfm_lit,	0xFF000000, 0xD8000000)
__AARCH64_INSN_FUNCS(str_reg,	0x3FE0EC00, 0x38206800)
__AARCH64_INSN_FUNCS(ldr_reg,	0x3FE0EC00, 0x38606800)
__AARCH64_INSN_FUNCS(ldr_lit,	0xBF000000, 0x18000000)
__AARCH64_INSN_FUNCS(ldrsw_lit,	0xFF000000, 0x98000000)
__AARCH64_INSN_FUNCS(exclusive,	0x3F800000, 0x08000000)
__AARCH64_INSN_FUNCS(load_ex,	0x3F400000, 0x08400000)
__AARCH64_INSN_FUNCS(store_ex,	0x3F400000, 0x08000000)
__AARCH64_INSN_FUNCS(stp_post,	0x7FC00000, 0x28800000)
__AARCH64_INSN_FUNCS(ldp_post,	0x7FC00000, 0x28C00000)
__AARCH64_INSN_FUNCS(stp_pre,	0x7FC00000, 0x29800000)
@@ -273,10 +303,15 @@ __AARCH64_INSN_FUNCS(svc, 0xFFE0001F, 0xD4000001)
__AARCH64_INSN_FUNCS(hvc,	0xFFE0001F, 0xD4000002)
__AARCH64_INSN_FUNCS(smc,	0xFFE0001F, 0xD4000003)
__AARCH64_INSN_FUNCS(brk,	0xFFE0001F, 0xD4200000)
__AARCH64_INSN_FUNCS(exception,	0xFF000000, 0xD4000000)
__AARCH64_INSN_FUNCS(hint,	0xFFFFF01F, 0xD503201F)
__AARCH64_INSN_FUNCS(br,	0xFFFFFC1F, 0xD61F0000)
__AARCH64_INSN_FUNCS(blr,	0xFFFFFC1F, 0xD63F0000)
__AARCH64_INSN_FUNCS(ret,	0xFFFFFC1F, 0xD65F0000)
__AARCH64_INSN_FUNCS(eret,	0xFFFFFFFF, 0xD69F03E0)
__AARCH64_INSN_FUNCS(mrs,	0xFFF00000, 0xD5300000)
__AARCH64_INSN_FUNCS(msr_imm,	0xFFF8F01F, 0xD500401F)
__AARCH64_INSN_FUNCS(msr_reg,	0xFFF00000, 0xD5100000)

#undef	__AARCH64_INSN_FUNCS

@@ -286,6 +321,8 @@ bool aarch64_insn_is_branch_imm(u32 insn);
int aarch64_insn_read(void *addr, u32 *insnp);
int aarch64_insn_write(void *addr, u32 insn);
enum aarch64_insn_encoding_class aarch64_get_insn_class(u32 insn);
bool aarch64_insn_uses_literal(u32 insn);
bool aarch64_insn_is_branch(u32 insn);
u64 aarch64_insn_decode_immediate(enum aarch64_insn_imm_type type, u32 insn);
u32 aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type,
				  u32 insn, u64 imm);
@@ -367,9 +404,13 @@ bool aarch32_insn_is_wide(u32 insn);
#define A32_RT_OFFSET	12
#define A32_RT2_OFFSET	 0

u32 aarch64_insn_extract_system_reg(u32 insn);
u32 aarch32_insn_extract_reg_num(u32 insn, int offset);
u32 aarch32_insn_mcr_extract_opc2(u32 insn);
u32 aarch32_insn_mcr_extract_crm(u32 insn);

typedef bool (pstate_check_t)(unsigned long);
extern pstate_check_t * const aarch32_opcode_cond_checks[16];
#endif /* __ASSEMBLY__ */

#endif	/* __ASM_INSN_H */
+62 −0
Original line number Diff line number Diff line
/*
 * arch/arm64/include/asm/kprobes.h
 *
 * Copyright (C) 2013 Linaro Limited
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 */

#ifndef _ARM_KPROBES_H
#define _ARM_KPROBES_H

#include <linux/types.h>
#include <linux/ptrace.h>
#include <linux/percpu.h>

#define __ARCH_WANT_KPROBES_INSN_SLOT
#define MAX_INSN_SIZE			1
#define MAX_STACK_SIZE			128

#define flush_insn_slot(p)		do { } while (0)
#define kretprobe_blacklist_size	0

#include <asm/probes.h>

struct prev_kprobe {
	struct kprobe *kp;
	unsigned int status;
};

/* Single step context for kprobe */
struct kprobe_step_ctx {
	unsigned long ss_pending;
	unsigned long match_addr;
};

/* per-cpu kprobe control block */
struct kprobe_ctlblk {
	unsigned int kprobe_status;
	unsigned long saved_irqflag;
	struct prev_kprobe prev_kprobe;
	struct kprobe_step_ctx ss_ctx;
	struct pt_regs jprobe_saved_regs;
	char jprobes_stack[MAX_STACK_SIZE];
};

void arch_remove_kprobe(struct kprobe *);
int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr);
int kprobe_exceptions_notify(struct notifier_block *self,
			     unsigned long val, void *data);
int kprobe_breakpoint_handler(struct pt_regs *regs, unsigned int esr);
int kprobe_single_step_handler(struct pt_regs *regs, unsigned int esr);
void kretprobe_trampoline(void);
void __kprobes *trampoline_probe_handler(struct pt_regs *regs);

#endif /* _ARM_KPROBES_H */
Loading