aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnanth N Mavinakayanahalli <ananth@in.ibm.com>2007-05-08 03:34:16 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-08 14:15:19 -0400
commitbf8f6e5b3e51ee0c64c2d1350c70198ddc8ad3f7 (patch)
treec48ebb92f836cfac58465eacc9658fbc2bac4783
parent4c4308cb93450989846ac49faeb6dab943e7657e (diff)
Kprobes: The ON/OFF knob thru debugfs
This patch provides a debugfs knob to turn kprobes on/off o A new file /debug/kprobes/enabled indicates if kprobes is enabled or not (default enabled) o Echoing 0 to this file will disarm all installed probes o Any new probe registration when disabled will register the probe but not arm it. A message will be printed out in such a case. o When a value 1 is echoed to the file, all probes (including ones registered in the intervening period) will be enabled o Unregistration will happen irrespective of whether probes are globally enabled or not. o Update Documentation/kprobes.txt to reflect these changes. While there also update the doc to make it current. We are also looking at providing sysrq key support to tie to the disabling feature provided by this patch. [akpm@linux-foundation.org: Use bool like a bool!] [akpm@linux-foundation.org: add printk facility levels] [cornelia.huck@de.ibm.com: Add the missing arch_trampoline_kprobe() for s390] Signed-off-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com> Signed-off-by: Srinivasa DS <srinivasa@in.ibm.com> Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--Documentation/kprobes.txt34
-rw-r--r--arch/i386/kernel/kprobes.c5
-rw-r--r--arch/ia64/kernel/kprobes.c9
-rw-r--r--arch/powerpc/kernel/kprobes.c8
-rw-r--r--arch/s390/kernel/kprobes.c7
-rw-r--r--arch/x86_64/kernel/kprobes.c8
-rw-r--r--include/linux/kprobes.h5
-rw-r--r--kernel/kprobes.c156
8 files changed, 222 insertions, 10 deletions
diff --git a/Documentation/kprobes.txt b/Documentation/kprobes.txt
index d71fafffce90..da5404ab7569 100644
--- a/Documentation/kprobes.txt
+++ b/Documentation/kprobes.txt
@@ -14,6 +14,7 @@ CONTENTS
148. Kprobes Example 148. Kprobes Example
159. Jprobes Example 159. Jprobes Example
1610. Kretprobes Example 1610. Kretprobes Example
17Appendix A: The kprobes debugfs interface
17 18
181. Concepts: Kprobes, Jprobes, Return Probes 191. Concepts: Kprobes, Jprobes, Return Probes
19 20
@@ -349,9 +350,12 @@ for instrumentation and error reporting.)
349 350
350If the number of times a function is called does not match the number 351If the number of times a function is called does not match the number
351of times it returns, registering a return probe on that function may 352of times it returns, registering a return probe on that function may
352produce undesirable results. We have the do_exit() case covered. 353produce undesirable results. In such a case, a line:
353do_execve() and do_fork() are not an issue. We're unaware of other 354kretprobe BUG!: Processing kretprobe d000000000041aa8 @ c00000000004f48c
354specific cases where this could be a problem. 355gets printed. With this information, one will be able to correlate the
356exact instance of the kretprobe that caused the problem. We have the
357do_exit() case covered. do_execve() and do_fork() are not an issue.
358We're unaware of other specific cases where this could be a problem.
355 359
356If, upon entry to or exit from a function, the CPU is running on 360If, upon entry to or exit from a function, the CPU is running on
357a stack other than that of the current task, registering a return 361a stack other than that of the current task, registering a return
@@ -614,3 +618,27 @@ http://www-106.ibm.com/developerworks/library/l-kprobes.html?ca=dgr-lnxw42Kprobe
614http://www.redhat.com/magazine/005mar05/features/kprobes/ 618http://www.redhat.com/magazine/005mar05/features/kprobes/
615http://www-users.cs.umn.edu/~boutcher/kprobes/ 619http://www-users.cs.umn.edu/~boutcher/kprobes/
616http://www.linuxsymposium.org/2006/linuxsymposium_procv2.pdf (pages 101-115) 620http://www.linuxsymposium.org/2006/linuxsymposium_procv2.pdf (pages 101-115)
621
622
623Appendix A: The kprobes debugfs interface
624
625With recent kernels (> 2.6.20) the list of registered kprobes is visible
626under the /debug/kprobes/ directory (assuming debugfs is mounted at /debug).
627
628/debug/kprobes/list: Lists all registered probes on the system
629
630c015d71a k vfs_read+0x0
631c011a316 j do_fork+0x0
632c03dedc5 r tcp_v4_rcv+0x0
633
634The first column provides the kernel address where the probe is inserted.
635The second column identifies the type of probe (k - kprobe, r - kretprobe
636and j - jprobe), while the third column specifies the symbol+offset of
637the probe. If the probed function belongs to a module, the module name
638is also specified.
639
640/debug/kprobes/enabled: Turn kprobes ON/OFF
641
642Provides a knob to globally turn registered kprobes ON or OFF. By default,
643all kprobes are enabled. By echoing "0" to this file, all registered probes
644will be disarmed, till such time a "1" is echoed to this file.
diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c
index b6a9d64c2251..dde828a333c3 100644
--- a/arch/i386/kernel/kprobes.c
+++ b/arch/i386/kernel/kprobes.c
@@ -743,6 +743,11 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
743 return 0; 743 return 0;
744} 744}
745 745
746int __kprobes arch_trampoline_kprobe(struct kprobe *p)
747{
748 return 0;
749}
750
746int __init arch_init_kprobes(void) 751int __init arch_init_kprobes(void)
747{ 752{
748 return 0; 753 return 0;
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
index 0b72f0f94192..4f5fd0960ba7 100644
--- a/arch/ia64/kernel/kprobes.c
+++ b/arch/ia64/kernel/kprobes.c
@@ -1012,3 +1012,12 @@ int __init arch_init_kprobes(void)
1012 (kprobe_opcode_t *)((struct fnptr *)kretprobe_trampoline)->ip; 1012 (kprobe_opcode_t *)((struct fnptr *)kretprobe_trampoline)->ip;
1013 return register_kprobe(&trampoline_p); 1013 return register_kprobe(&trampoline_p);
1014} 1014}
1015
1016int __kprobes arch_trampoline_kprobe(struct kprobe *p)
1017{
1018 if (p->addr ==
1019 (kprobe_opcode_t *)((struct fnptr *)kretprobe_trampoline)->ip)
1020 return 1;
1021
1022 return 0;
1023}
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
index aed58e1cb91f..088b8c6defa0 100644
--- a/arch/powerpc/kernel/kprobes.c
+++ b/arch/powerpc/kernel/kprobes.c
@@ -550,3 +550,11 @@ int __init arch_init_kprobes(void)
550{ 550{
551 return register_kprobe(&trampoline_p); 551 return register_kprobe(&trampoline_p);
552} 552}
553
554int __kprobes arch_trampoline_kprobe(struct kprobe *p)
555{
556 if (p->addr == (kprobe_opcode_t *)&kretprobe_trampoline)
557 return 1;
558
559 return 0;
560}
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c
index 9d0f0d09d473..e39333ae0fcf 100644
--- a/arch/s390/kernel/kprobes.c
+++ b/arch/s390/kernel/kprobes.c
@@ -661,3 +661,10 @@ int __init arch_init_kprobes(void)
661{ 661{
662 return register_kprobe(&trampoline_p); 662 return register_kprobe(&trampoline_p);
663} 663}
664
665int __kprobes arch_trampoline_kprobe(struct kprobe *p)
666{
667 if (p->addr == (kprobe_opcode_t *) & kretprobe_trampoline)
668 return 1;
669 return 0;
670}
diff --git a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes.c
index f995bea6e2c1..d4a0d0ac9935 100644
--- a/arch/x86_64/kernel/kprobes.c
+++ b/arch/x86_64/kernel/kprobes.c
@@ -743,3 +743,11 @@ int __init arch_init_kprobes(void)
743{ 743{
744 return register_kprobe(&trampoline_p); 744 return register_kprobe(&trampoline_p);
745} 745}
746
747int __kprobes arch_trampoline_kprobe(struct kprobe *p)
748{
749 if (p->addr == (kprobe_opcode_t *)&kretprobe_trampoline)
750 return 1;
751
752 return 0;
753}
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
index 6fc623e41fd8..23adf6075ae4 100644
--- a/include/linux/kprobes.h
+++ b/include/linux/kprobes.h
@@ -125,11 +125,16 @@ DECLARE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
125#ifdef ARCH_SUPPORTS_KRETPROBES 125#ifdef ARCH_SUPPORTS_KRETPROBES
126extern void arch_prepare_kretprobe(struct kretprobe_instance *ri, 126extern void arch_prepare_kretprobe(struct kretprobe_instance *ri,
127 struct pt_regs *regs); 127 struct pt_regs *regs);
128extern int arch_trampoline_kprobe(struct kprobe *p);
128#else /* ARCH_SUPPORTS_KRETPROBES */ 129#else /* ARCH_SUPPORTS_KRETPROBES */
129static inline void arch_prepare_kretprobe(struct kretprobe *rp, 130static inline void arch_prepare_kretprobe(struct kretprobe *rp,
130 struct pt_regs *regs) 131 struct pt_regs *regs)
131{ 132{
132} 133}
134static inline int arch_trampoline_kprobe(struct kprobe *p)
135{
136 return 0;
137}
133#endif /* ARCH_SUPPORTS_KRETPROBES */ 138#endif /* ARCH_SUPPORTS_KRETPROBES */
134/* 139/*
135 * Function-return probe - 140 * Function-return probe -
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index f58f171bd65f..9e47d8c493f3 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -43,9 +43,11 @@
43#include <linux/seq_file.h> 43#include <linux/seq_file.h>
44#include <linux/debugfs.h> 44#include <linux/debugfs.h>
45#include <linux/kdebug.h> 45#include <linux/kdebug.h>
46
46#include <asm-generic/sections.h> 47#include <asm-generic/sections.h>
47#include <asm/cacheflush.h> 48#include <asm/cacheflush.h>
48#include <asm/errno.h> 49#include <asm/errno.h>
50#include <asm/uaccess.h>
49 51
50#define KPROBE_HASH_BITS 6 52#define KPROBE_HASH_BITS 6
51#define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS) 53#define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS)
@@ -64,6 +66,9 @@ static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
64static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE]; 66static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE];
65static atomic_t kprobe_count; 67static atomic_t kprobe_count;
66 68
69/* NOTE: change this value only with kprobe_mutex held */
70static bool kprobe_enabled;
71
67DEFINE_MUTEX(kprobe_mutex); /* Protects kprobe_table */ 72DEFINE_MUTEX(kprobe_mutex); /* Protects kprobe_table */
68DEFINE_SPINLOCK(kretprobe_lock); /* Protects kretprobe_inst_table */ 73DEFINE_SPINLOCK(kretprobe_lock); /* Protects kretprobe_inst_table */
69static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL; 74static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL;
@@ -564,12 +569,13 @@ static int __kprobes __register_kprobe(struct kprobe *p,
564 hlist_add_head_rcu(&p->hlist, 569 hlist_add_head_rcu(&p->hlist,
565 &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]); 570 &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]);
566 571
567 if (atomic_add_return(1, &kprobe_count) == \ 572 if (kprobe_enabled) {
573 if (atomic_add_return(1, &kprobe_count) == \
568 (ARCH_INACTIVE_KPROBE_COUNT + 1)) 574 (ARCH_INACTIVE_KPROBE_COUNT + 1))
569 register_page_fault_notifier(&kprobe_page_fault_nb); 575 register_page_fault_notifier(&kprobe_page_fault_nb);
570
571 arch_arm_kprobe(p);
572 576
577 arch_arm_kprobe(p);
578 }
573out: 579out:
574 mutex_unlock(&kprobe_mutex); 580 mutex_unlock(&kprobe_mutex);
575 581
@@ -607,8 +613,13 @@ valid_p:
607 if (old_p == p || 613 if (old_p == p ||
608 (old_p->pre_handler == aggr_pre_handler && 614 (old_p->pre_handler == aggr_pre_handler &&
609 p->list.next == &old_p->list && p->list.prev == &old_p->list)) { 615 p->list.next == &old_p->list && p->list.prev == &old_p->list)) {
610 /* Only probe on the hash list */ 616 /*
611 arch_disarm_kprobe(p); 617 * Only probe on the hash list. Disarm only if kprobes are
618 * enabled - otherwise, the breakpoint would already have
619 * been removed. We save on flushing icache.
620 */
621 if (kprobe_enabled)
622 arch_disarm_kprobe(p);
612 hlist_del_rcu(&old_p->hlist); 623 hlist_del_rcu(&old_p->hlist);
613 cleanup_p = 1; 624 cleanup_p = 1;
614 } else { 625 } else {
@@ -797,6 +808,9 @@ static int __init init_kprobes(void)
797 } 808 }
798 atomic_set(&kprobe_count, 0); 809 atomic_set(&kprobe_count, 0);
799 810
811 /* By default, kprobes are enabled */
812 kprobe_enabled = true;
813
800 err = arch_init_kprobes(); 814 err = arch_init_kprobes();
801 if (!err) 815 if (!err)
802 err = register_die_notifier(&kprobe_exceptions_nb); 816 err = register_die_notifier(&kprobe_exceptions_nb);
@@ -806,7 +820,7 @@ static int __init init_kprobes(void)
806 820
807#ifdef CONFIG_DEBUG_FS 821#ifdef CONFIG_DEBUG_FS
808static void __kprobes report_probe(struct seq_file *pi, struct kprobe *p, 822static void __kprobes report_probe(struct seq_file *pi, struct kprobe *p,
809 const char *sym, int offset,char *modname) 823 const char *sym, int offset,char *modname)
810{ 824{
811 char *kprobe_type; 825 char *kprobe_type;
812 826
@@ -885,9 +899,130 @@ static struct file_operations debugfs_kprobes_operations = {
885 .release = seq_release, 899 .release = seq_release,
886}; 900};
887 901
902static void __kprobes enable_all_kprobes(void)
903{
904 struct hlist_head *head;
905 struct hlist_node *node;
906 struct kprobe *p;
907 unsigned int i;
908
909 mutex_lock(&kprobe_mutex);
910
911 /* If kprobes are already enabled, just return */
912 if (kprobe_enabled)
913 goto already_enabled;
914
915 /*
916 * Re-register the page fault notifier only if there are any
917 * active probes at the time of enabling kprobes globally
918 */
919 if (atomic_read(&kprobe_count) > ARCH_INACTIVE_KPROBE_COUNT)
920 register_page_fault_notifier(&kprobe_page_fault_nb);
921
922 for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
923 head = &kprobe_table[i];
924 hlist_for_each_entry_rcu(p, node, head, hlist)
925 arch_arm_kprobe(p);
926 }
927
928 kprobe_enabled = true;
929 printk(KERN_INFO "Kprobes globally enabled\n");
930
931already_enabled:
932 mutex_unlock(&kprobe_mutex);
933 return;
934}
935
936static void __kprobes disable_all_kprobes(void)
937{
938 struct hlist_head *head;
939 struct hlist_node *node;
940 struct kprobe *p;
941 unsigned int i;
942
943 mutex_lock(&kprobe_mutex);
944
945 /* If kprobes are already disabled, just return */
946 if (!kprobe_enabled)
947 goto already_disabled;
948
949 kprobe_enabled = false;
950 printk(KERN_INFO "Kprobes globally disabled\n");
951 for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
952 head = &kprobe_table[i];
953 hlist_for_each_entry_rcu(p, node, head, hlist) {
954 if (!arch_trampoline_kprobe(p))
955 arch_disarm_kprobe(p);
956 }
957 }
958
959 mutex_unlock(&kprobe_mutex);
960 /* Allow all currently running kprobes to complete */
961 synchronize_sched();
962
963 mutex_lock(&kprobe_mutex);
964 /* Unconditionally unregister the page_fault notifier */
965 unregister_page_fault_notifier(&kprobe_page_fault_nb);
966
967already_disabled:
968 mutex_unlock(&kprobe_mutex);
969 return;
970}
971
972/*
973 * XXX: The debugfs bool file interface doesn't allow for callbacks
974 * when the bool state is switched. We can reuse that facility when
975 * available
976 */
977static ssize_t read_enabled_file_bool(struct file *file,
978 char __user *user_buf, size_t count, loff_t *ppos)
979{
980 char buf[3];
981
982 if (kprobe_enabled)
983 buf[0] = '1';
984 else
985 buf[0] = '0';
986 buf[1] = '\n';
987 buf[2] = 0x00;
988 return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
989}
990
991static ssize_t write_enabled_file_bool(struct file *file,
992 const char __user *user_buf, size_t count, loff_t *ppos)
993{
994 char buf[32];
995 int buf_size;
996
997 buf_size = min(count, (sizeof(buf)-1));
998 if (copy_from_user(buf, user_buf, buf_size))
999 return -EFAULT;
1000
1001 switch (buf[0]) {
1002 case 'y':
1003 case 'Y':
1004 case '1':
1005 enable_all_kprobes();
1006 break;
1007 case 'n':
1008 case 'N':
1009 case '0':
1010 disable_all_kprobes();
1011 break;
1012 }
1013
1014 return count;
1015}
1016
1017static struct file_operations fops_kp = {
1018 .read = read_enabled_file_bool,
1019 .write = write_enabled_file_bool,
1020};
1021
888static int __kprobes debugfs_kprobe_init(void) 1022static int __kprobes debugfs_kprobe_init(void)
889{ 1023{
890 struct dentry *dir, *file; 1024 struct dentry *dir, *file;
1025 unsigned int value = 1;
891 1026
892 dir = debugfs_create_dir("kprobes", NULL); 1027 dir = debugfs_create_dir("kprobes", NULL);
893 if (!dir) 1028 if (!dir)
@@ -900,6 +1035,13 @@ static int __kprobes debugfs_kprobe_init(void)
900 return -ENOMEM; 1035 return -ENOMEM;
901 } 1036 }
902 1037
1038 file = debugfs_create_file("enabled", 0600, dir,
1039 &value, &fops_kp);
1040 if (!file) {
1041 debugfs_remove(dir);
1042 return -ENOMEM;
1043 }
1044
903 return 0; 1045 return 0;
904} 1046}
905 1047