cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

actions-arm.c (10484B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * arch/arm/probes/kprobes/actions-arm.c
      4 *
      5 * Copyright (C) 2006, 2007 Motorola Inc.
      6 */
      7
      8/*
      9 * We do not have hardware single-stepping on ARM, This
     10 * effort is further complicated by the ARM not having a
     11 * "next PC" register.  Instructions that change the PC
     12 * can't be safely single-stepped in a MP environment, so
     13 * we have a lot of work to do:
     14 *
     15 * In the prepare phase:
     16 *   *) If it is an instruction that does anything
     17 *      with the CPU mode, we reject it for a kprobe.
     18 *      (This is out of laziness rather than need.  The
     19 *      instructions could be simulated.)
     20 *
     21 *   *) Otherwise, decode the instruction rewriting its
     22 *      registers to take fixed, ordered registers and
     23 *      setting a handler for it to run the instruction.
     24 *
     25 * In the execution phase by an instruction's handler:
     26 *
     27 *   *) If the PC is written to by the instruction, the
     28 *      instruction must be fully simulated in software.
     29 *
     30 *   *) Otherwise, a modified form of the instruction is
     31 *      directly executed.  Its handler calls the
     32 *      instruction in insn[0].  In insn[1] is a
     33 *      "mov pc, lr" to return.
     34 *
     35 *      Before calling, load up the reordered registers
     36 *      from the original instruction's registers.  If one
     37 *      of the original input registers is the PC, compute
     38 *      and adjust the appropriate input register.
     39 *
     40 *	After call completes, copy the output registers to
     41 *      the original instruction's original registers.
     42 *
     43 * We don't use a real breakpoint instruction since that
     44 * would have us in the kernel go from SVC mode to SVC
     45 * mode losing the link register.  Instead we use an
     46 * undefined instruction.  To simplify processing, the
     47 * undefined instruction used for kprobes must be reserved
     48 * exclusively for kprobes use.
     49 *
     50 * TODO: ifdef out some instruction decoding based on architecture.
     51 */
     52
     53#include <linux/kernel.h>
     54#include <linux/kprobes.h>
     55#include <linux/ptrace.h>
     56
     57#include "../decode-arm.h"
     58#include "core.h"
     59#include "checkers.h"
     60
     61#if  __LINUX_ARM_ARCH__ >= 6
     62#define BLX(reg)	"blx	"reg"		\n\t"
     63#else
     64#define BLX(reg)	"mov	lr, pc		\n\t"	\
     65			"mov	pc, "reg"	\n\t"
     66#endif
     67
     68static void __kprobes
     69emulate_ldrdstrd(probes_opcode_t insn,
     70	struct arch_probes_insn *asi, struct pt_regs *regs)
     71{
     72	unsigned long pc = regs->ARM_pc + 4;
     73	int rt = (insn >> 12) & 0xf;
     74	int rn = (insn >> 16) & 0xf;
     75	int rm = insn & 0xf;
     76
     77	register unsigned long rtv asm("r0") = regs->uregs[rt];
     78	register unsigned long rt2v asm("r1") = regs->uregs[rt+1];
     79	register unsigned long rnv asm("r2") = (rn == 15) ? pc
     80							  : regs->uregs[rn];
     81	register unsigned long rmv asm("r3") = regs->uregs[rm];
     82
     83	__asm__ __volatile__ (
     84		BLX("%[fn]")
     85		: "=r" (rtv), "=r" (rt2v), "=r" (rnv)
     86		: "0" (rtv), "1" (rt2v), "2" (rnv), "r" (rmv),
     87		  [fn] "r" (asi->insn_fn)
     88		: "lr", "memory", "cc"
     89	);
     90
     91	regs->uregs[rt] = rtv;
     92	regs->uregs[rt+1] = rt2v;
     93	if (is_writeback(insn))
     94		regs->uregs[rn] = rnv;
     95}
     96
     97static void __kprobes
     98emulate_ldr(probes_opcode_t insn,
     99	struct arch_probes_insn *asi, struct pt_regs *regs)
    100{
    101	unsigned long pc = regs->ARM_pc + 4;
    102	int rt = (insn >> 12) & 0xf;
    103	int rn = (insn >> 16) & 0xf;
    104	int rm = insn & 0xf;
    105
    106	register unsigned long rtv asm("r0");
    107	register unsigned long rnv asm("r2") = (rn == 15) ? pc
    108							  : regs->uregs[rn];
    109	register unsigned long rmv asm("r3") = regs->uregs[rm];
    110
    111	__asm__ __volatile__ (
    112		BLX("%[fn]")
    113		: "=r" (rtv), "=r" (rnv)
    114		: "1" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
    115		: "lr", "memory", "cc"
    116	);
    117
    118	if (rt == 15)
    119		load_write_pc(rtv, regs);
    120	else
    121		regs->uregs[rt] = rtv;
    122
    123	if (is_writeback(insn))
    124		regs->uregs[rn] = rnv;
    125}
    126
    127static void __kprobes
    128emulate_str(probes_opcode_t insn,
    129	struct arch_probes_insn *asi, struct pt_regs *regs)
    130{
    131	unsigned long rtpc = regs->ARM_pc - 4 + str_pc_offset;
    132	unsigned long rnpc = regs->ARM_pc + 4;
    133	int rt = (insn >> 12) & 0xf;
    134	int rn = (insn >> 16) & 0xf;
    135	int rm = insn & 0xf;
    136
    137	register unsigned long rtv asm("r0") = (rt == 15) ? rtpc
    138							  : regs->uregs[rt];
    139	register unsigned long rnv asm("r2") = (rn == 15) ? rnpc
    140							  : regs->uregs[rn];
    141	register unsigned long rmv asm("r3") = regs->uregs[rm];
    142
    143	__asm__ __volatile__ (
    144		BLX("%[fn]")
    145		: "=r" (rnv)
    146		: "r" (rtv), "0" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
    147		: "lr", "memory", "cc"
    148	);
    149
    150	if (is_writeback(insn))
    151		regs->uregs[rn] = rnv;
    152}
    153
    154static void __kprobes
    155emulate_rd12rn16rm0rs8_rwflags(probes_opcode_t insn,
    156	struct arch_probes_insn *asi, struct pt_regs *regs)
    157{
    158	unsigned long pc = regs->ARM_pc + 4;
    159	int rd = (insn >> 12) & 0xf;
    160	int rn = (insn >> 16) & 0xf;
    161	int rm = insn & 0xf;
    162	int rs = (insn >> 8) & 0xf;
    163
    164	register unsigned long rdv asm("r0") = regs->uregs[rd];
    165	register unsigned long rnv asm("r2") = (rn == 15) ? pc
    166							  : regs->uregs[rn];
    167	register unsigned long rmv asm("r3") = (rm == 15) ? pc
    168							  : regs->uregs[rm];
    169	register unsigned long rsv asm("r1") = regs->uregs[rs];
    170	unsigned long cpsr = regs->ARM_cpsr;
    171
    172	__asm__ __volatile__ (
    173		"msr	cpsr_fs, %[cpsr]	\n\t"
    174		BLX("%[fn]")
    175		"mrs	%[cpsr], cpsr		\n\t"
    176		: "=r" (rdv), [cpsr] "=r" (cpsr)
    177		: "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv),
    178		  "1" (cpsr), [fn] "r" (asi->insn_fn)
    179		: "lr", "memory", "cc"
    180	);
    181
    182	if (rd == 15)
    183		alu_write_pc(rdv, regs);
    184	else
    185		regs->uregs[rd] = rdv;
    186	regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
    187}
    188
    189static void __kprobes
    190emulate_rd12rn16rm0_rwflags_nopc(probes_opcode_t insn,
    191	struct arch_probes_insn *asi, struct pt_regs *regs)
    192{
    193	int rd = (insn >> 12) & 0xf;
    194	int rn = (insn >> 16) & 0xf;
    195	int rm = insn & 0xf;
    196
    197	register unsigned long rdv asm("r0") = regs->uregs[rd];
    198	register unsigned long rnv asm("r2") = regs->uregs[rn];
    199	register unsigned long rmv asm("r3") = regs->uregs[rm];
    200	unsigned long cpsr = regs->ARM_cpsr;
    201
    202	__asm__ __volatile__ (
    203		"msr	cpsr_fs, %[cpsr]	\n\t"
    204		BLX("%[fn]")
    205		"mrs	%[cpsr], cpsr		\n\t"
    206		: "=r" (rdv), [cpsr] "=r" (cpsr)
    207		: "0" (rdv), "r" (rnv), "r" (rmv),
    208		  "1" (cpsr), [fn] "r" (asi->insn_fn)
    209		: "lr", "memory", "cc"
    210	);
    211
    212	regs->uregs[rd] = rdv;
    213	regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
    214}
    215
    216static void __kprobes
    217emulate_rd16rn12rm0rs8_rwflags_nopc(probes_opcode_t insn,
    218	struct arch_probes_insn *asi,
    219	struct pt_regs *regs)
    220{
    221	int rd = (insn >> 16) & 0xf;
    222	int rn = (insn >> 12) & 0xf;
    223	int rm = insn & 0xf;
    224	int rs = (insn >> 8) & 0xf;
    225
    226	register unsigned long rdv asm("r2") = regs->uregs[rd];
    227	register unsigned long rnv asm("r0") = regs->uregs[rn];
    228	register unsigned long rmv asm("r3") = regs->uregs[rm];
    229	register unsigned long rsv asm("r1") = regs->uregs[rs];
    230	unsigned long cpsr = regs->ARM_cpsr;
    231
    232	__asm__ __volatile__ (
    233		"msr	cpsr_fs, %[cpsr]	\n\t"
    234		BLX("%[fn]")
    235		"mrs	%[cpsr], cpsr		\n\t"
    236		: "=r" (rdv), [cpsr] "=r" (cpsr)
    237		: "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv),
    238		  "1" (cpsr), [fn] "r" (asi->insn_fn)
    239		: "lr", "memory", "cc"
    240	);
    241
    242	regs->uregs[rd] = rdv;
    243	regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
    244}
    245
    246static void __kprobes
    247emulate_rd12rm0_noflags_nopc(probes_opcode_t insn,
    248	struct arch_probes_insn *asi, struct pt_regs *regs)
    249{
    250	int rd = (insn >> 12) & 0xf;
    251	int rm = insn & 0xf;
    252
    253	register unsigned long rdv asm("r0") = regs->uregs[rd];
    254	register unsigned long rmv asm("r3") = regs->uregs[rm];
    255
    256	__asm__ __volatile__ (
    257		BLX("%[fn]")
    258		: "=r" (rdv)
    259		: "0" (rdv), "r" (rmv), [fn] "r" (asi->insn_fn)
    260		: "lr", "memory", "cc"
    261	);
    262
    263	regs->uregs[rd] = rdv;
    264}
    265
    266static void __kprobes
    267emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn,
    268	struct arch_probes_insn *asi,
    269	struct pt_regs *regs)
    270{
    271	int rdlo = (insn >> 12) & 0xf;
    272	int rdhi = (insn >> 16) & 0xf;
    273	int rn = insn & 0xf;
    274	int rm = (insn >> 8) & 0xf;
    275
    276	register unsigned long rdlov asm("r0") = regs->uregs[rdlo];
    277	register unsigned long rdhiv asm("r2") = regs->uregs[rdhi];
    278	register unsigned long rnv asm("r3") = regs->uregs[rn];
    279	register unsigned long rmv asm("r1") = regs->uregs[rm];
    280	unsigned long cpsr = regs->ARM_cpsr;
    281
    282	__asm__ __volatile__ (
    283		"msr	cpsr_fs, %[cpsr]	\n\t"
    284		BLX("%[fn]")
    285		"mrs	%[cpsr], cpsr		\n\t"
    286		: "=r" (rdlov), "=r" (rdhiv), [cpsr] "=r" (cpsr)
    287		: "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv),
    288		  "2" (cpsr), [fn] "r" (asi->insn_fn)
    289		: "lr", "memory", "cc"
    290	);
    291
    292	regs->uregs[rdlo] = rdlov;
    293	regs->uregs[rdhi] = rdhiv;
    294	regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
    295}
    296
    297const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = {
    298	[PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop},
    299	[PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop},
    300	[PROBES_BRANCH_IMM] = {.handler = simulate_blx1},
    301	[PROBES_MRS] = {.handler = simulate_mrs},
    302	[PROBES_BRANCH_REG] = {.handler = simulate_blx2bx},
    303	[PROBES_CLZ] = {.handler = emulate_rd12rm0_noflags_nopc},
    304	[PROBES_SATURATING_ARITHMETIC] = {
    305		.handler = emulate_rd12rn16rm0_rwflags_nopc},
    306	[PROBES_MUL1] = {.handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc},
    307	[PROBES_MUL2] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc},
    308	[PROBES_SWP] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
    309	[PROBES_LDRSTRD] = {.handler = emulate_ldrdstrd},
    310	[PROBES_LOAD_EXTRA] = {.handler = emulate_ldr},
    311	[PROBES_LOAD] = {.handler = emulate_ldr},
    312	[PROBES_STORE_EXTRA] = {.handler = emulate_str},
    313	[PROBES_STORE] = {.handler = emulate_str},
    314	[PROBES_MOV_IP_SP] = {.handler = simulate_mov_ipsp},
    315	[PROBES_DATA_PROCESSING_REG] = {
    316		.handler = emulate_rd12rn16rm0rs8_rwflags},
    317	[PROBES_DATA_PROCESSING_IMM] = {
    318		.handler = emulate_rd12rn16rm0rs8_rwflags},
    319	[PROBES_MOV_HALFWORD] = {.handler = emulate_rd12rm0_noflags_nopc},
    320	[PROBES_SEV] = {.handler = probes_emulate_none},
    321	[PROBES_WFE] = {.handler = probes_simulate_nop},
    322	[PROBES_SATURATE] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
    323	[PROBES_REV] = {.handler = emulate_rd12rm0_noflags_nopc},
    324	[PROBES_MMI] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
    325	[PROBES_PACK] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
    326	[PROBES_EXTEND] = {.handler = emulate_rd12rm0_noflags_nopc},
    327	[PROBES_EXTEND_ADD] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
    328	[PROBES_MUL_ADD_LONG] = {
    329		.handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc},
    330	[PROBES_MUL_ADD] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc},
    331	[PROBES_BITFIELD] = {.handler = emulate_rd12rm0_noflags_nopc},
    332	[PROBES_BRANCH] = {.handler = simulate_bbl},
    333	[PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm}
    334};
    335
    336const struct decode_checker *kprobes_arm_checkers[] = {arm_stack_checker, arm_regs_checker, NULL};