aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/asm-generic/sections.h1
-rw-r--r--include/asm-generic/vmlinux.lds.h6
-rw-r--r--include/linux/kprobes.h3
-rw-r--r--include/linux/linkage.h7
-rw-r--r--kernel/kprobes.c72
5 files changed, 60 insertions, 29 deletions
diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h
index 450eae22c39a..886dbd116899 100644
--- a/include/asm-generic/sections.h
+++ b/include/asm-generic/sections.h
@@ -12,5 +12,6 @@ extern char _sextratext[] __attribute__((weak));
12extern char _eextratext[] __attribute__((weak)); 12extern char _eextratext[] __attribute__((weak));
13extern char _end[]; 13extern char _end[];
14extern char __per_cpu_start[], __per_cpu_end[]; 14extern char __per_cpu_start[], __per_cpu_end[];
15extern char __kprobes_text_start[], __kprobes_text_end[];
15 16
16#endif /* _ASM_GENERIC_SECTIONS_H_ */ 17#endif /* _ASM_GENERIC_SECTIONS_H_ */
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 3fa94288aa93..6f857be2b644 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -97,3 +97,9 @@
97 VMLINUX_SYMBOL(__lock_text_start) = .; \ 97 VMLINUX_SYMBOL(__lock_text_start) = .; \
98 *(.spinlock.text) \ 98 *(.spinlock.text) \
99 VMLINUX_SYMBOL(__lock_text_end) = .; 99 VMLINUX_SYMBOL(__lock_text_end) = .;
100
101#define KPROBES_TEXT \
102 ALIGN_FUNCTION(); \
103 VMLINUX_SYMBOL(__kprobes_text_start) = .; \
104 *(.kprobes.text) \
105 VMLINUX_SYMBOL(__kprobes_text_end) = .;
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
index e050fc2d4c26..e30afdca7917 100644
--- a/include/linux/kprobes.h
+++ b/include/linux/kprobes.h
@@ -42,6 +42,9 @@
42#define KPROBE_REENTER 0x00000004 42#define KPROBE_REENTER 0x00000004
43#define KPROBE_HIT_SSDONE 0x00000008 43#define KPROBE_HIT_SSDONE 0x00000008
44 44
45/* Attach to insert probes on any functions which should be ignored*/
46#define __kprobes __attribute__((__section__(".kprobes.text")))
47
45struct kprobe; 48struct kprobe;
46struct pt_regs; 49struct pt_regs;
47struct kretprobe; 50struct kretprobe;
diff --git a/include/linux/linkage.h b/include/linux/linkage.h
index 338f7795d8a0..147eb01e0d4b 100644
--- a/include/linux/linkage.h
+++ b/include/linux/linkage.h
@@ -33,6 +33,13 @@
33 ALIGN; \ 33 ALIGN; \
34 name: 34 name:
35 35
36#define KPROBE_ENTRY(name) \
37 .section .kprobes.text, "ax"; \
38 .globl name; \
39 ALIGN; \
40 name:
41
42
36#endif 43#endif
37 44
38#define NORET_TYPE /**/ 45#define NORET_TYPE /**/
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index b0237122b24e..3b7653f2e7ae 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -37,6 +37,7 @@
37#include <linux/init.h> 37#include <linux/init.h>
38#include <linux/module.h> 38#include <linux/module.h>
39#include <linux/moduleloader.h> 39#include <linux/moduleloader.h>
40#include <asm-generic/sections.h>
40#include <asm/cacheflush.h> 41#include <asm/cacheflush.h>
41#include <asm/errno.h> 42#include <asm/errno.h>
42#include <asm/kdebug.h> 43#include <asm/kdebug.h>
@@ -72,7 +73,7 @@ static struct hlist_head kprobe_insn_pages;
72 * get_insn_slot() - Find a slot on an executable page for an instruction. 73 * get_insn_slot() - Find a slot on an executable page for an instruction.
73 * We allocate an executable page if there's no room on existing ones. 74 * We allocate an executable page if there's no room on existing ones.
74 */ 75 */
75kprobe_opcode_t *get_insn_slot(void) 76kprobe_opcode_t __kprobes *get_insn_slot(void)
76{ 77{
77 struct kprobe_insn_page *kip; 78 struct kprobe_insn_page *kip;
78 struct hlist_node *pos; 79 struct hlist_node *pos;
@@ -117,7 +118,7 @@ kprobe_opcode_t *get_insn_slot(void)
117 return kip->insns; 118 return kip->insns;
118} 119}
119 120
120void free_insn_slot(kprobe_opcode_t *slot) 121void __kprobes free_insn_slot(kprobe_opcode_t *slot)
121{ 122{
122 struct kprobe_insn_page *kip; 123 struct kprobe_insn_page *kip;
123 struct hlist_node *pos; 124 struct hlist_node *pos;
@@ -152,20 +153,20 @@ void free_insn_slot(kprobe_opcode_t *slot)
152} 153}
153 154
154/* Locks kprobe: irqs must be disabled */ 155/* Locks kprobe: irqs must be disabled */
155void lock_kprobes(void) 156void __kprobes lock_kprobes(void)
156{ 157{
157 spin_lock(&kprobe_lock); 158 spin_lock(&kprobe_lock);
158 kprobe_cpu = smp_processor_id(); 159 kprobe_cpu = smp_processor_id();
159} 160}
160 161
161void unlock_kprobes(void) 162void __kprobes unlock_kprobes(void)
162{ 163{
163 kprobe_cpu = NR_CPUS; 164 kprobe_cpu = NR_CPUS;
164 spin_unlock(&kprobe_lock); 165 spin_unlock(&kprobe_lock);
165} 166}
166 167
167/* You have to be holding the kprobe_lock */ 168/* You have to be holding the kprobe_lock */
168struct kprobe *get_kprobe(void *addr) 169struct kprobe __kprobes *get_kprobe(void *addr)
169{ 170{
170 struct hlist_head *head; 171 struct hlist_head *head;
171 struct hlist_node *node; 172 struct hlist_node *node;
@@ -183,7 +184,7 @@ struct kprobe *get_kprobe(void *addr)
183 * Aggregate handlers for multiple kprobes support - these handlers 184 * Aggregate handlers for multiple kprobes support - these handlers
184 * take care of invoking the individual kprobe handlers on p->list 185 * take care of invoking the individual kprobe handlers on p->list
185 */ 186 */
186static int aggr_pre_handler(struct kprobe *p, struct pt_regs *regs) 187static int __kprobes aggr_pre_handler(struct kprobe *p, struct pt_regs *regs)
187{ 188{
188 struct kprobe *kp; 189 struct kprobe *kp;
189 190
@@ -198,8 +199,8 @@ static int aggr_pre_handler(struct kprobe *p, struct pt_regs *regs)
198 return 0; 199 return 0;
199} 200}
200 201
201static void aggr_post_handler(struct kprobe *p, struct pt_regs *regs, 202static void __kprobes aggr_post_handler(struct kprobe *p, struct pt_regs *regs,
202 unsigned long flags) 203 unsigned long flags)
203{ 204{
204 struct kprobe *kp; 205 struct kprobe *kp;
205 206
@@ -213,8 +214,8 @@ static void aggr_post_handler(struct kprobe *p, struct pt_regs *regs,
213 return; 214 return;
214} 215}
215 216
216static int aggr_fault_handler(struct kprobe *p, struct pt_regs *regs, 217static int __kprobes aggr_fault_handler(struct kprobe *p, struct pt_regs *regs,
217 int trapnr) 218 int trapnr)
218{ 219{
219 /* 220 /*
220 * if we faulted "during" the execution of a user specified 221 * if we faulted "during" the execution of a user specified
@@ -227,7 +228,7 @@ static int aggr_fault_handler(struct kprobe *p, struct pt_regs *regs,
227 return 0; 228 return 0;
228} 229}
229 230
230static int aggr_break_handler(struct kprobe *p, struct pt_regs *regs) 231static int __kprobes aggr_break_handler(struct kprobe *p, struct pt_regs *regs)
231{ 232{
232 struct kprobe *kp = curr_kprobe; 233 struct kprobe *kp = curr_kprobe;
233 if (curr_kprobe && kp->break_handler) { 234 if (curr_kprobe && kp->break_handler) {
@@ -240,7 +241,7 @@ static int aggr_break_handler(struct kprobe *p, struct pt_regs *regs)
240 return 0; 241 return 0;
241} 242}
242 243
243struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp) 244struct kretprobe_instance __kprobes *get_free_rp_inst(struct kretprobe *rp)
244{ 245{
245 struct hlist_node *node; 246 struct hlist_node *node;
246 struct kretprobe_instance *ri; 247 struct kretprobe_instance *ri;
@@ -249,7 +250,8 @@ struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp)
249 return NULL; 250 return NULL;
250} 251}
251 252
252static struct kretprobe_instance *get_used_rp_inst(struct kretprobe *rp) 253static struct kretprobe_instance __kprobes *get_used_rp_inst(struct kretprobe
254 *rp)
253{ 255{
254 struct hlist_node *node; 256 struct hlist_node *node;
255 struct kretprobe_instance *ri; 257 struct kretprobe_instance *ri;
@@ -258,7 +260,7 @@ static struct kretprobe_instance *get_used_rp_inst(struct kretprobe *rp)
258 return NULL; 260 return NULL;
259} 261}
260 262
261void add_rp_inst(struct kretprobe_instance *ri) 263void __kprobes add_rp_inst(struct kretprobe_instance *ri)
262{ 264{
263 /* 265 /*
264 * Remove rp inst off the free list - 266 * Remove rp inst off the free list -
@@ -276,7 +278,7 @@ void add_rp_inst(struct kretprobe_instance *ri)
276 hlist_add_head(&ri->uflist, &ri->rp->used_instances); 278 hlist_add_head(&ri->uflist, &ri->rp->used_instances);
277} 279}
278 280
279void recycle_rp_inst(struct kretprobe_instance *ri) 281void __kprobes recycle_rp_inst(struct kretprobe_instance *ri)
280{ 282{
281 /* remove rp inst off the rprobe_inst_table */ 283 /* remove rp inst off the rprobe_inst_table */
282 hlist_del(&ri->hlist); 284 hlist_del(&ri->hlist);
@@ -291,7 +293,7 @@ void recycle_rp_inst(struct kretprobe_instance *ri)
291 kfree(ri); 293 kfree(ri);
292} 294}
293 295
294struct hlist_head * kretprobe_inst_table_head(struct task_struct *tsk) 296struct hlist_head __kprobes *kretprobe_inst_table_head(struct task_struct *tsk)
295{ 297{
296 return &kretprobe_inst_table[hash_ptr(tsk, KPROBE_HASH_BITS)]; 298 return &kretprobe_inst_table[hash_ptr(tsk, KPROBE_HASH_BITS)];
297} 299}
@@ -302,7 +304,7 @@ struct hlist_head * kretprobe_inst_table_head(struct task_struct *tsk)
302 * instances associated with this task. These left over instances represent 304 * instances associated with this task. These left over instances represent
303 * probed functions that have been called but will never return. 305 * probed functions that have been called but will never return.
304 */ 306 */
305void kprobe_flush_task(struct task_struct *tk) 307void __kprobes kprobe_flush_task(struct task_struct *tk)
306{ 308{
307 struct kretprobe_instance *ri; 309 struct kretprobe_instance *ri;
308 struct hlist_head *head; 310 struct hlist_head *head;
@@ -322,7 +324,8 @@ void kprobe_flush_task(struct task_struct *tk)
322 * This kprobe pre_handler is registered with every kretprobe. When probe 324 * This kprobe pre_handler is registered with every kretprobe. When probe
323 * hits it will set up the return probe. 325 * hits it will set up the return probe.
324 */ 326 */
325static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs) 327static int __kprobes pre_handler_kretprobe(struct kprobe *p,
328 struct pt_regs *regs)
326{ 329{
327 struct kretprobe *rp = container_of(p, struct kretprobe, kp); 330 struct kretprobe *rp = container_of(p, struct kretprobe, kp);
328 331
@@ -353,7 +356,7 @@ static inline void copy_kprobe(struct kprobe *old_p, struct kprobe *p)
353* Add the new probe to old_p->list. Fail if this is the 356* Add the new probe to old_p->list. Fail if this is the
354* second jprobe at the address - two jprobes can't coexist 357* second jprobe at the address - two jprobes can't coexist
355*/ 358*/
356static int add_new_kprobe(struct kprobe *old_p, struct kprobe *p) 359static int __kprobes add_new_kprobe(struct kprobe *old_p, struct kprobe *p)
357{ 360{
358 struct kprobe *kp; 361 struct kprobe *kp;
359 362
@@ -395,7 +398,8 @@ static inline void add_aggr_kprobe(struct kprobe *ap, struct kprobe *p)
395 * the intricacies 398 * the intricacies
396 * TODO: Move kcalloc outside the spinlock 399 * TODO: Move kcalloc outside the spinlock
397 */ 400 */
398static int register_aggr_kprobe(struct kprobe *old_p, struct kprobe *p) 401static int __kprobes register_aggr_kprobe(struct kprobe *old_p,
402 struct kprobe *p)
399{ 403{
400 int ret = 0; 404 int ret = 0;
401 struct kprobe *ap; 405 struct kprobe *ap;
@@ -434,15 +438,25 @@ static inline void cleanup_aggr_kprobe(struct kprobe *old_p,
434 spin_unlock_irqrestore(&kprobe_lock, flags); 438 spin_unlock_irqrestore(&kprobe_lock, flags);
435} 439}
436 440
437int register_kprobe(struct kprobe *p) 441static int __kprobes in_kprobes_functions(unsigned long addr)
442{
443 if (addr >= (unsigned long)__kprobes_text_start
444 && addr < (unsigned long)__kprobes_text_end)
445 return -EINVAL;
446 return 0;
447}
448
449int __kprobes register_kprobe(struct kprobe *p)
438{ 450{
439 int ret = 0; 451 int ret = 0;
440 unsigned long flags = 0; 452 unsigned long flags = 0;
441 struct kprobe *old_p; 453 struct kprobe *old_p;
442 454
443 if ((ret = arch_prepare_kprobe(p)) != 0) { 455 if ((ret = in_kprobes_functions((unsigned long) p->addr)) != 0)
456 return ret;
457 if ((ret = arch_prepare_kprobe(p)) != 0)
444 goto rm_kprobe; 458 goto rm_kprobe;
445 } 459
446 spin_lock_irqsave(&kprobe_lock, flags); 460 spin_lock_irqsave(&kprobe_lock, flags);
447 old_p = get_kprobe(p->addr); 461 old_p = get_kprobe(p->addr);
448 p->nmissed = 0; 462 p->nmissed = 0;
@@ -466,7 +480,7 @@ rm_kprobe:
466 return ret; 480 return ret;
467} 481}
468 482
469void unregister_kprobe(struct kprobe *p) 483void __kprobes unregister_kprobe(struct kprobe *p)
470{ 484{
471 unsigned long flags; 485 unsigned long flags;
472 struct kprobe *old_p; 486 struct kprobe *old_p;
@@ -487,7 +501,7 @@ static struct notifier_block kprobe_exceptions_nb = {
487 .priority = 0x7fffffff /* we need to notified first */ 501 .priority = 0x7fffffff /* we need to notified first */
488}; 502};
489 503
490int register_jprobe(struct jprobe *jp) 504int __kprobes register_jprobe(struct jprobe *jp)
491{ 505{
492 /* Todo: Verify probepoint is a function entry point */ 506 /* Todo: Verify probepoint is a function entry point */
493 jp->kp.pre_handler = setjmp_pre_handler; 507 jp->kp.pre_handler = setjmp_pre_handler;
@@ -496,14 +510,14 @@ int register_jprobe(struct jprobe *jp)
496 return register_kprobe(&jp->kp); 510 return register_kprobe(&jp->kp);
497} 511}
498 512
499void unregister_jprobe(struct jprobe *jp) 513void __kprobes unregister_jprobe(struct jprobe *jp)
500{ 514{
501 unregister_kprobe(&jp->kp); 515 unregister_kprobe(&jp->kp);
502} 516}
503 517
504#ifdef ARCH_SUPPORTS_KRETPROBES 518#ifdef ARCH_SUPPORTS_KRETPROBES
505 519
506int register_kretprobe(struct kretprobe *rp) 520int __kprobes register_kretprobe(struct kretprobe *rp)
507{ 521{
508 int ret = 0; 522 int ret = 0;
509 struct kretprobe_instance *inst; 523 struct kretprobe_instance *inst;
@@ -540,14 +554,14 @@ int register_kretprobe(struct kretprobe *rp)
540 554
541#else /* ARCH_SUPPORTS_KRETPROBES */ 555#else /* ARCH_SUPPORTS_KRETPROBES */
542 556
543int register_kretprobe(struct kretprobe *rp) 557int __kprobes register_kretprobe(struct kretprobe *rp)
544{ 558{
545 return -ENOSYS; 559 return -ENOSYS;
546} 560}
547 561
548#endif /* ARCH_SUPPORTS_KRETPROBES */ 562#endif /* ARCH_SUPPORTS_KRETPROBES */
549 563
550void unregister_kretprobe(struct kretprobe *rp) 564void __kprobes unregister_kretprobe(struct kretprobe *rp)
551{ 565{
552 unsigned long flags; 566 unsigned long flags;
553 struct kretprobe_instance *ri; 567 struct kretprobe_instance *ri;