Skip to content

Commit

Permalink
ARM: kprobes: Decode 32-bit Thumb load/store single data item instruc…
Browse files Browse the repository at this point in the history
…tions

We will reject probing of unprivileged load and store instructions.
These rarely occur and writing test cases for them is difficult.

Signed-off-by: Jon Medhurst <tixy@yxit.co.uk>
Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
  • Loading branch information
Jon Medhurst authored and Tixy committed Jul 13, 2011
1 parent 46009cc commit d691023
Showing 1 changed file with 153 additions and 0 deletions.
153 changes: 153 additions & 0 deletions arch/arm/kernel/kprobes-thumb.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,44 @@ t32_simulate_branch(struct kprobe *p, struct pt_regs *regs)
regs->ARM_pc = pc + (offset * 2);
}

static void __kprobes
t32_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs)
{
kprobe_opcode_t insn = p->opcode;
unsigned long addr = thumb_probe_pc(p) & ~3;
int rt = (insn >> 12) & 0xf;
unsigned long rtv;

long offset = insn & 0xfff;
if (insn & 0x00800000)
addr += offset;
else
addr -= offset;

if (insn & 0x00400000) {
/* LDR */
rtv = *(unsigned long *)addr;
if (rt == 15) {
bx_write_pc(rtv, regs);
return;
}
} else if (insn & 0x00200000) {
/* LDRH */
if (insn & 0x01000000)
rtv = *(s16 *)addr;
else
rtv = *(u16 *)addr;
} else {
/* LDRB */
if (insn & 0x01000000)
rtv = *(s8 *)addr;
else
rtv = *(u8 *)addr;
}

regs->uregs[rt] = rtv;
}

static enum kprobe_insn __kprobes
t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi)
{
Expand Down Expand Up @@ -158,6 +196,32 @@ t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs)
regs->uregs[rt2] = rt2v;
}

static void __kprobes
t32_emulate_ldrstr(struct kprobe *p, struct pt_regs *regs)
{
kprobe_opcode_t insn = p->opcode;
int rt = (insn >> 12) & 0xf;
int rn = (insn >> 16) & 0xf;
int rm = insn & 0xf;

register unsigned long rtv asm("r0") = regs->uregs[rt];
register unsigned long rnv asm("r2") = regs->uregs[rn];
register unsigned long rmv asm("r3") = regs->uregs[rm];

__asm__ __volatile__ (
"blx %[fn]"
: "=r" (rtv), "=r" (rnv)
: "0" (rtv), "1" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn)
: "lr", "memory", "cc"
);

regs->uregs[rn] = rnv; /* Writeback base register */
if (rt == 15) /* Can't be true for a STR as they aren't allowed */
bx_write_pc(rtv, regs);
else
regs->uregs[rt] = rtv;
}

static void __kprobes
t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs)
{
Expand Down Expand Up @@ -516,6 +580,87 @@ static const union decode_item t32_table_1111_100x_x0x1__1111[] = {
DECODE_END
};

static const union decode_item t32_table_1111_100x[] = {
/* Store/Load single data item */

/* ??? 1111 100x x11x xxxx xxxx xxxx xxxx xxxx */
DECODE_REJECT (0xfe600000, 0xf8600000),

/* ??? 1111 1001 0101 xxxx xxxx xxxx xxxx xxxx */
DECODE_REJECT (0xfff00000, 0xf9500000),

/* ??? 1111 100x 0xxx xxxx xxxx 10x0 xxxx xxxx */
DECODE_REJECT (0xfe800d00, 0xf8000800),

/* STRBT 1111 1000 0000 xxxx xxxx 1110 xxxx xxxx */
/* STRHT 1111 1000 0010 xxxx xxxx 1110 xxxx xxxx */
/* STRT 1111 1000 0100 xxxx xxxx 1110 xxxx xxxx */
/* LDRBT 1111 1000 0001 xxxx xxxx 1110 xxxx xxxx */
/* LDRSBT 1111 1001 0001 xxxx xxxx 1110 xxxx xxxx */
/* LDRHT 1111 1000 0011 xxxx xxxx 1110 xxxx xxxx */
/* LDRSHT 1111 1001 0011 xxxx xxxx 1110 xxxx xxxx */
/* LDRT 1111 1000 0101 xxxx xxxx 1110 xxxx xxxx */
DECODE_REJECT (0xfe800f00, 0xf8000e00),

/* STR{,B,H} Rn,[PC...] 1111 1000 xxx0 1111 xxxx xxxx xxxx xxxx */
DECODE_REJECT (0xff1f0000, 0xf80f0000),

/* STR{,B,H} PC,[Rn...] 1111 1000 xxx0 xxxx 1111 xxxx xxxx xxxx */
DECODE_REJECT (0xff10f000, 0xf800f000),

/* LDR (literal) 1111 1000 x101 1111 xxxx xxxx xxxx xxxx */
DECODE_SIMULATEX(0xff7f0000, 0xf85f0000, t32_simulate_ldr_literal,
REGS(PC, ANY, 0, 0, 0)),

/* STR (immediate) 1111 1000 0100 xxxx xxxx 1xxx xxxx xxxx */
/* LDR (immediate) 1111 1000 0101 xxxx xxxx 1xxx xxxx xxxx */
DECODE_OR (0xffe00800, 0xf8400800),
/* STR (immediate) 1111 1000 1100 xxxx xxxx xxxx xxxx xxxx */
/* LDR (immediate) 1111 1000 1101 xxxx xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0xffe00000, 0xf8c00000, t32_emulate_ldrstr,
REGS(NOPCX, ANY, 0, 0, 0)),

/* STR (register) 1111 1000 0100 xxxx xxxx 0000 00xx xxxx */
/* LDR (register) 1111 1000 0101 xxxx xxxx 0000 00xx xxxx */
DECODE_EMULATEX (0xffe00fc0, 0xf8400000, t32_emulate_ldrstr,
REGS(NOPCX, ANY, 0, 0, NOSPPC)),

/* LDRB (literal) 1111 1000 x001 1111 xxxx xxxx xxxx xxxx */
/* LDRSB (literal) 1111 1001 x001 1111 xxxx xxxx xxxx xxxx */
/* LDRH (literal) 1111 1000 x011 1111 xxxx xxxx xxxx xxxx */
/* LDRSH (literal) 1111 1001 x011 1111 xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0xfe5f0000, 0xf81f0000, t32_simulate_ldr_literal,
REGS(PC, NOSPPCX, 0, 0, 0)),

/* STRB (immediate) 1111 1000 0000 xxxx xxxx 1xxx xxxx xxxx */
/* STRH (immediate) 1111 1000 0010 xxxx xxxx 1xxx xxxx xxxx */
/* LDRB (immediate) 1111 1000 0001 xxxx xxxx 1xxx xxxx xxxx */
/* LDRSB (immediate) 1111 1001 0001 xxxx xxxx 1xxx xxxx xxxx */
/* LDRH (immediate) 1111 1000 0011 xxxx xxxx 1xxx xxxx xxxx */
/* LDRSH (immediate) 1111 1001 0011 xxxx xxxx 1xxx xxxx xxxx */
DECODE_OR (0xfec00800, 0xf8000800),
/* STRB (immediate) 1111 1000 1000 xxxx xxxx xxxx xxxx xxxx */
/* STRH (immediate) 1111 1000 1010 xxxx xxxx xxxx xxxx xxxx */
/* LDRB (immediate) 1111 1000 1001 xxxx xxxx xxxx xxxx xxxx */
/* LDRSB (immediate) 1111 1001 1001 xxxx xxxx xxxx xxxx xxxx */
/* LDRH (immediate) 1111 1000 1011 xxxx xxxx xxxx xxxx xxxx */
/* LDRSH (immediate) 1111 1001 1011 xxxx xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0xfec00000, 0xf8800000, t32_emulate_ldrstr,
REGS(NOPCX, NOSPPCX, 0, 0, 0)),

/* STRB (register) 1111 1000 0000 xxxx xxxx 0000 00xx xxxx */
/* STRH (register) 1111 1000 0010 xxxx xxxx 0000 00xx xxxx */
/* LDRB (register) 1111 1000 0001 xxxx xxxx 0000 00xx xxxx */
/* LDRSB (register) 1111 1001 0001 xxxx xxxx 0000 00xx xxxx */
/* LDRH (register) 1111 1000 0011 xxxx xxxx 0000 00xx xxxx */
/* LDRSH (register) 1111 1001 0011 xxxx xxxx 0000 00xx xxxx */
DECODE_EMULATEX (0xfe800fc0, 0xf8000000, t32_emulate_ldrstr,
REGS(NOPCX, NOSPPCX, 0, 0, NOSPPC)),

/* Other unallocated instructions... */
DECODE_END
};

const union decode_item kprobe_decode_thumb32_table[] = {

/*
Expand Down Expand Up @@ -572,6 +717,14 @@ const union decode_item kprobe_decode_thumb32_table[] = {
*/
DECODE_TABLE (0xfe50f000, 0xf810f000, t32_table_1111_100x_x0x1__1111),

/*
* Store single data item
* 1111 1000 xxx0 xxxx xxxx xxxx xxxx xxxx
* Load single data items
* 1111 100x xxx1 xxxx xxxx xxxx xxxx xxxx
*/
DECODE_TABLE (0xfe000000, 0xf8000000, t32_table_1111_100x),

/*
* Coprocessor instructions
* 1111 11xx xxxx xxxx xxxx xxxx xxxx xxxx
Expand Down

0 comments on commit d691023

Please sign in to comment.