diff options
author | Jon Medhurst <tixy@yxit.co.uk> | 2011-07-03 10:04:26 -0400 |
---|---|---|
committer | Tixy <tixy@medhuaa1.miniserver.com> | 2011-07-13 13:32:47 -0400 |
commit | d691023b62bdf33ed84023330f4d2c77d2325b01 (patch) | |
tree | fbe9813708414f82dc62d271140d41fd08e6788a | |
parent | 46009cc5c59e0acdf165ed8a9d1ccc43baf44800 (diff) |
ARM: kprobes: Decode 32-bit Thumb load/store single data item instructions
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>
-rw-r--r-- | arch/arm/kernel/kprobes-thumb.c | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c index bf1113c89b15..9be8bea2990c 100644 --- a/arch/arm/kernel/kprobes-thumb.c +++ b/arch/arm/kernel/kprobes-thumb.c | |||
@@ -118,6 +118,44 @@ t32_simulate_branch(struct kprobe *p, struct pt_regs *regs) | |||
118 | regs->ARM_pc = pc + (offset * 2); | 118 | regs->ARM_pc = pc + (offset * 2); |
119 | } | 119 | } |
120 | 120 | ||
121 | static void __kprobes | ||
122 | t32_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) | ||
123 | { | ||
124 | kprobe_opcode_t insn = p->opcode; | ||
125 | unsigned long addr = thumb_probe_pc(p) & ~3; | ||
126 | int rt = (insn >> 12) & 0xf; | ||
127 | unsigned long rtv; | ||
128 | |||
129 | long offset = insn & 0xfff; | ||
130 | if (insn & 0x00800000) | ||
131 | addr += offset; | ||
132 | else | ||
133 | addr -= offset; | ||
134 | |||
135 | if (insn & 0x00400000) { | ||
136 | /* LDR */ | ||
137 | rtv = *(unsigned long *)addr; | ||
138 | if (rt == 15) { | ||
139 | bx_write_pc(rtv, regs); | ||
140 | return; | ||
141 | } | ||
142 | } else if (insn & 0x00200000) { | ||
143 | /* LDRH */ | ||
144 | if (insn & 0x01000000) | ||
145 | rtv = *(s16 *)addr; | ||
146 | else | ||
147 | rtv = *(u16 *)addr; | ||
148 | } else { | ||
149 | /* LDRB */ | ||
150 | if (insn & 0x01000000) | ||
151 | rtv = *(s8 *)addr; | ||
152 | else | ||
153 | rtv = *(u8 *)addr; | ||
154 | } | ||
155 | |||
156 | regs->uregs[rt] = rtv; | ||
157 | } | ||
158 | |||
121 | static enum kprobe_insn __kprobes | 159 | static enum kprobe_insn __kprobes |
122 | t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) | 160 | t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) |
123 | { | 161 | { |
@@ -159,6 +197,32 @@ t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) | |||
159 | } | 197 | } |
160 | 198 | ||
161 | static void __kprobes | 199 | static void __kprobes |
200 | t32_emulate_ldrstr(struct kprobe *p, struct pt_regs *regs) | ||
201 | { | ||
202 | kprobe_opcode_t insn = p->opcode; | ||
203 | int rt = (insn >> 12) & 0xf; | ||
204 | int rn = (insn >> 16) & 0xf; | ||
205 | int rm = insn & 0xf; | ||
206 | |||
207 | register unsigned long rtv asm("r0") = regs->uregs[rt]; | ||
208 | register unsigned long rnv asm("r2") = regs->uregs[rn]; | ||
209 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
210 | |||
211 | __asm__ __volatile__ ( | ||
212 | "blx %[fn]" | ||
213 | : "=r" (rtv), "=r" (rnv) | ||
214 | : "0" (rtv), "1" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn) | ||
215 | : "lr", "memory", "cc" | ||
216 | ); | ||
217 | |||
218 | regs->uregs[rn] = rnv; /* Writeback base register */ | ||
219 | if (rt == 15) /* Can't be true for a STR as they aren't allowed */ | ||
220 | bx_write_pc(rtv, regs); | ||
221 | else | ||
222 | regs->uregs[rt] = rtv; | ||
223 | } | ||
224 | |||
225 | static void __kprobes | ||
162 | t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) | 226 | t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) |
163 | { | 227 | { |
164 | kprobe_opcode_t insn = p->opcode; | 228 | kprobe_opcode_t insn = p->opcode; |
@@ -516,6 +580,87 @@ static const union decode_item t32_table_1111_100x_x0x1__1111[] = { | |||
516 | DECODE_END | 580 | DECODE_END |
517 | }; | 581 | }; |
518 | 582 | ||
583 | static const union decode_item t32_table_1111_100x[] = { | ||
584 | /* Store/Load single data item */ | ||
585 | |||
586 | /* ??? 1111 100x x11x xxxx xxxx xxxx xxxx xxxx */ | ||
587 | DECODE_REJECT (0xfe600000, 0xf8600000), | ||
588 | |||
589 | /* ??? 1111 1001 0101 xxxx xxxx xxxx xxxx xxxx */ | ||
590 | DECODE_REJECT (0xfff00000, 0xf9500000), | ||
591 | |||
592 | /* ??? 1111 100x 0xxx xxxx xxxx 10x0 xxxx xxxx */ | ||
593 | DECODE_REJECT (0xfe800d00, 0xf8000800), | ||
594 | |||
595 | /* STRBT 1111 1000 0000 xxxx xxxx 1110 xxxx xxxx */ | ||
596 | /* STRHT 1111 1000 0010 xxxx xxxx 1110 xxxx xxxx */ | ||
597 | /* STRT 1111 1000 0100 xxxx xxxx 1110 xxxx xxxx */ | ||
598 | /* LDRBT 1111 1000 0001 xxxx xxxx 1110 xxxx xxxx */ | ||
599 | /* LDRSBT 1111 1001 0001 xxxx xxxx 1110 xxxx xxxx */ | ||
600 | /* LDRHT 1111 1000 0011 xxxx xxxx 1110 xxxx xxxx */ | ||
601 | /* LDRSHT 1111 1001 0011 xxxx xxxx 1110 xxxx xxxx */ | ||
602 | /* LDRT 1111 1000 0101 xxxx xxxx 1110 xxxx xxxx */ | ||
603 | DECODE_REJECT (0xfe800f00, 0xf8000e00), | ||
604 | |||
605 | /* STR{,B,H} Rn,[PC...] 1111 1000 xxx0 1111 xxxx xxxx xxxx xxxx */ | ||
606 | DECODE_REJECT (0xff1f0000, 0xf80f0000), | ||
607 | |||
608 | /* STR{,B,H} PC,[Rn...] 1111 1000 xxx0 xxxx 1111 xxxx xxxx xxxx */ | ||
609 | DECODE_REJECT (0xff10f000, 0xf800f000), | ||
610 | |||
611 | /* LDR (literal) 1111 1000 x101 1111 xxxx xxxx xxxx xxxx */ | ||
612 | DECODE_SIMULATEX(0xff7f0000, 0xf85f0000, t32_simulate_ldr_literal, | ||
613 | REGS(PC, ANY, 0, 0, 0)), | ||
614 | |||
615 | /* STR (immediate) 1111 1000 0100 xxxx xxxx 1xxx xxxx xxxx */ | ||
616 | /* LDR (immediate) 1111 1000 0101 xxxx xxxx 1xxx xxxx xxxx */ | ||
617 | DECODE_OR (0xffe00800, 0xf8400800), | ||
618 | /* STR (immediate) 1111 1000 1100 xxxx xxxx xxxx xxxx xxxx */ | ||
619 | /* LDR (immediate) 1111 1000 1101 xxxx xxxx xxxx xxxx xxxx */ | ||
620 | DECODE_EMULATEX (0xffe00000, 0xf8c00000, t32_emulate_ldrstr, | ||
621 | REGS(NOPCX, ANY, 0, 0, 0)), | ||
622 | |||
623 | /* STR (register) 1111 1000 0100 xxxx xxxx 0000 00xx xxxx */ | ||
624 | /* LDR (register) 1111 1000 0101 xxxx xxxx 0000 00xx xxxx */ | ||
625 | DECODE_EMULATEX (0xffe00fc0, 0xf8400000, t32_emulate_ldrstr, | ||
626 | REGS(NOPCX, ANY, 0, 0, NOSPPC)), | ||
627 | |||
628 | /* LDRB (literal) 1111 1000 x001 1111 xxxx xxxx xxxx xxxx */ | ||
629 | /* LDRSB (literal) 1111 1001 x001 1111 xxxx xxxx xxxx xxxx */ | ||
630 | /* LDRH (literal) 1111 1000 x011 1111 xxxx xxxx xxxx xxxx */ | ||
631 | /* LDRSH (literal) 1111 1001 x011 1111 xxxx xxxx xxxx xxxx */ | ||
632 | DECODE_EMULATEX (0xfe5f0000, 0xf81f0000, t32_simulate_ldr_literal, | ||
633 | REGS(PC, NOSPPCX, 0, 0, 0)), | ||
634 | |||
635 | /* STRB (immediate) 1111 1000 0000 xxxx xxxx 1xxx xxxx xxxx */ | ||
636 | /* STRH (immediate) 1111 1000 0010 xxxx xxxx 1xxx xxxx xxxx */ | ||
637 | /* LDRB (immediate) 1111 1000 0001 xxxx xxxx 1xxx xxxx xxxx */ | ||
638 | /* LDRSB (immediate) 1111 1001 0001 xxxx xxxx 1xxx xxxx xxxx */ | ||
639 | /* LDRH (immediate) 1111 1000 0011 xxxx xxxx 1xxx xxxx xxxx */ | ||
640 | /* LDRSH (immediate) 1111 1001 0011 xxxx xxxx 1xxx xxxx xxxx */ | ||
641 | DECODE_OR (0xfec00800, 0xf8000800), | ||
642 | /* STRB (immediate) 1111 1000 1000 xxxx xxxx xxxx xxxx xxxx */ | ||
643 | /* STRH (immediate) 1111 1000 1010 xxxx xxxx xxxx xxxx xxxx */ | ||
644 | /* LDRB (immediate) 1111 1000 1001 xxxx xxxx xxxx xxxx xxxx */ | ||
645 | /* LDRSB (immediate) 1111 1001 1001 xxxx xxxx xxxx xxxx xxxx */ | ||
646 | /* LDRH (immediate) 1111 1000 1011 xxxx xxxx xxxx xxxx xxxx */ | ||
647 | /* LDRSH (immediate) 1111 1001 1011 xxxx xxxx xxxx xxxx xxxx */ | ||
648 | DECODE_EMULATEX (0xfec00000, 0xf8800000, t32_emulate_ldrstr, | ||
649 | REGS(NOPCX, NOSPPCX, 0, 0, 0)), | ||
650 | |||
651 | /* STRB (register) 1111 1000 0000 xxxx xxxx 0000 00xx xxxx */ | ||
652 | /* STRH (register) 1111 1000 0010 xxxx xxxx 0000 00xx xxxx */ | ||
653 | /* LDRB (register) 1111 1000 0001 xxxx xxxx 0000 00xx xxxx */ | ||
654 | /* LDRSB (register) 1111 1001 0001 xxxx xxxx 0000 00xx xxxx */ | ||
655 | /* LDRH (register) 1111 1000 0011 xxxx xxxx 0000 00xx xxxx */ | ||
656 | /* LDRSH (register) 1111 1001 0011 xxxx xxxx 0000 00xx xxxx */ | ||
657 | DECODE_EMULATEX (0xfe800fc0, 0xf8000000, t32_emulate_ldrstr, | ||
658 | REGS(NOPCX, NOSPPCX, 0, 0, NOSPPC)), | ||
659 | |||
660 | /* Other unallocated instructions... */ | ||
661 | DECODE_END | ||
662 | }; | ||
663 | |||
519 | const union decode_item kprobe_decode_thumb32_table[] = { | 664 | const union decode_item kprobe_decode_thumb32_table[] = { |
520 | 665 | ||
521 | /* | 666 | /* |
@@ -573,6 +718,14 @@ const union decode_item kprobe_decode_thumb32_table[] = { | |||
573 | DECODE_TABLE (0xfe50f000, 0xf810f000, t32_table_1111_100x_x0x1__1111), | 718 | DECODE_TABLE (0xfe50f000, 0xf810f000, t32_table_1111_100x_x0x1__1111), |
574 | 719 | ||
575 | /* | 720 | /* |
721 | * Store single data item | ||
722 | * 1111 1000 xxx0 xxxx xxxx xxxx xxxx xxxx | ||
723 | * Load single data items | ||
724 | * 1111 100x xxx1 xxxx xxxx xxxx xxxx xxxx | ||
725 | */ | ||
726 | DECODE_TABLE (0xfe000000, 0xf8000000, t32_table_1111_100x), | ||
727 | |||
728 | /* | ||
576 | * Coprocessor instructions | 729 | * Coprocessor instructions |
577 | * 1111 11xx xxxx xxxx xxxx xxxx xxxx xxxx | 730 | * 1111 11xx xxxx xxxx xxxx xxxx xxxx xxxx |
578 | */ | 731 | */ |