aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel
diff options
context:
space:
mode:
authorJon Medhurst <tixy@yxit.co.uk>2011-07-01 12:32:06 -0400
committerTixy <tixy@medhuaa1.miniserver.com>2011-07-13 13:32:48 -0400
commitdf4fa1f8dde23db25f50e49535d2c7db0005f9ad (patch)
treeafd56bec1275665bcd429e0dbe91352596436152 /arch/arm/kernel
parent9a5c1284a3ec76c15a8bc51b2badc29e42fc5d92 (diff)
ARM: kprobes: Add alu_write_pc()
This writes a new value to PC which was obtained as the result of an ARM ALU instruction. For ARMv7 and later this performs interworking. On ARM kernels we shouldn't encounter any ALU instructions trying to switch to Thumb mode so support for this isn't strictly necessary. However, the approach taken in all other instruction decoding is for us to avoid unpredictable modification of the PC for security reasons. This is usually achieved by rejecting insertion of probes on problematic instruction, but for ALU instructions we can't do this as it depends on the contents of the CPU registers at the time the probe is hit. So, as we require some form of run-time checking to trap undesirable PC modification, we may as well simulate the instructions correctly, i.e. in the way they would behave in the absence of a probe. Signed-off-by: Jon Medhurst <tixy@yxit.co.uk> Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/kprobes-common.c15
-rw-r--r--arch/arm/kernel/kprobes.h28
2 files changed, 43 insertions, 0 deletions
diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c
index 32bb0f236684..a5394fb4e4e0 100644
--- a/arch/arm/kernel/kprobes-common.c
+++ b/arch/arm/kernel/kprobes-common.c
@@ -59,10 +59,25 @@ void __init test_load_write_pc_interworking(void)
59#endif /* !test_load_write_pc_interworking */ 59#endif /* !test_load_write_pc_interworking */
60 60
61 61
62#ifndef test_alu_write_pc_interworking
63
64bool alu_write_pc_interworks;
65
66void __init test_alu_write_pc_interworking(void)
67{
68 int arch = cpu_architecture();
69 BUG_ON(arch == CPU_ARCH_UNKNOWN);
70 alu_write_pc_interworks = arch >= CPU_ARCH_ARMv7;
71}
72
73#endif /* !test_alu_write_pc_interworking */
74
75
62void __init arm_kprobe_decode_init(void) 76void __init arm_kprobe_decode_init(void)
63{ 77{
64 find_str_pc_offset(); 78 find_str_pc_offset();
65 test_load_write_pc_interworking(); 79 test_load_write_pc_interworking();
80 test_alu_write_pc_interworking();
66} 81}
67 82
68 83
diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h
index c442852e65e4..a6aeda0a6c7f 100644
--- a/arch/arm/kernel/kprobes.h
+++ b/arch/arm/kernel/kprobes.h
@@ -133,6 +133,34 @@ static inline void __kprobes load_write_pc(long pcv, struct pt_regs *regs)
133} 133}
134 134
135 135
136#if __LINUX_ARM_ARCH__ >= 7
137
138#define alu_write_pc_interworks true
139#define test_alu_write_pc_interworking()
140
141#elif __LINUX_ARM_ARCH__ <= 5
142
143/* Kernels built for <= ARMv5 should never run on >= ARMv6 hardware, so... */
144#define alu_write_pc_interworks false
145#define test_alu_write_pc_interworking()
146
147#else /* __LINUX_ARM_ARCH__ == 6 */
148
149/* We could be an ARMv6 binary on ARMv7 hardware so we need a run-time check. */
150extern bool alu_write_pc_interworks;
151void __init test_alu_write_pc_interworking(void);
152
153#endif /* __LINUX_ARM_ARCH__ == 6 */
154
155static inline void __kprobes alu_write_pc(long pcv, struct pt_regs *regs)
156{
157 if (alu_write_pc_interworks)
158 bx_write_pc(pcv, regs);
159 else
160 regs->ARM_pc = pcv;
161}
162
163
136void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs); 164void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs);
137void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs); 165void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs);
138 166