Skip to content

Commit bf8f6e5

Browse files
Ananth N MavinakayanahalliLinus Torvalds
authored andcommitted
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. [[email protected]: Use bool like a bool!] [[email protected]: add printk facility levels] [[email protected]: Add the missing arch_trampoline_kprobe() for s390] Signed-off-by: Ananth N Mavinakayanahalli <[email protected]> Signed-off-by: Srinivasa DS <[email protected]> Signed-off-by: Cornelia Huck <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 4c4308c commit bf8f6e5

File tree

8 files changed

+222
-10
lines changed

8 files changed

+222
-10
lines changed

Documentation/kprobes.txt

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ CONTENTS
1414
8. Kprobes Example
1515
9. Jprobes Example
1616
10. Kretprobes Example
17+
Appendix A: The kprobes debugfs interface
1718

1819
1. Concepts: Kprobes, Jprobes, Return Probes
1920

@@ -349,9 +350,12 @@ for instrumentation and error reporting.)
349350

350351
If the number of times a function is called does not match the number
351352
of times it returns, registering a return probe on that function may
352-
produce undesirable results. We have the do_exit() case covered.
353-
do_execve() and do_fork() are not an issue. We're unaware of other
354-
specific cases where this could be a problem.
353+
produce undesirable results. In such a case, a line:
354+
kretprobe BUG!: Processing kretprobe d000000000041aa8 @ c00000000004f48c
355+
gets printed. With this information, one will be able to correlate the
356+
exact instance of the kretprobe that caused the problem. We have the
357+
do_exit() case covered. do_execve() and do_fork() are not an issue.
358+
We're unaware of other specific cases where this could be a problem.
355359

356360
If, upon entry to or exit from a function, the CPU is running on
357361
a 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
614618
http://www.redhat.com/magazine/005mar05/features/kprobes/
615619
http://www-users.cs.umn.edu/~boutcher/kprobes/
616620
http://www.linuxsymposium.org/2006/linuxsymposium_procv2.pdf (pages 101-115)
621+
622+
623+
Appendix A: The kprobes debugfs interface
624+
625+
With recent kernels (> 2.6.20) the list of registered kprobes is visible
626+
under the /debug/kprobes/ directory (assuming debugfs is mounted at /debug).
627+
628+
/debug/kprobes/list: Lists all registered probes on the system
629+
630+
c015d71a k vfs_read+0x0
631+
c011a316 j do_fork+0x0
632+
c03dedc5 r tcp_v4_rcv+0x0
633+
634+
The first column provides the kernel address where the probe is inserted.
635+
The second column identifies the type of probe (k - kprobe, r - kretprobe
636+
and j - jprobe), while the third column specifies the symbol+offset of
637+
the probe. If the probed function belongs to a module, the module name
638+
is also specified.
639+
640+
/debug/kprobes/enabled: Turn kprobes ON/OFF
641+
642+
Provides a knob to globally turn registered kprobes ON or OFF. By default,
643+
all kprobes are enabled. By echoing "0" to this file, all registered probes
644+
will be disarmed, till such time a "1" is echoed to this file.

arch/i386/kernel/kprobes.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,11 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
743743
return 0;
744744
}
745745

746+
int __kprobes arch_trampoline_kprobe(struct kprobe *p)
747+
{
748+
return 0;
749+
}
750+
746751
int __init arch_init_kprobes(void)
747752
{
748753
return 0;

arch/ia64/kernel/kprobes.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,3 +1012,12 @@ int __init arch_init_kprobes(void)
10121012
(kprobe_opcode_t *)((struct fnptr *)kretprobe_trampoline)->ip;
10131013
return register_kprobe(&trampoline_p);
10141014
}
1015+
1016+
int __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+
}

arch/powerpc/kernel/kprobes.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,3 +550,11 @@ int __init arch_init_kprobes(void)
550550
{
551551
return register_kprobe(&trampoline_p);
552552
}
553+
554+
int __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+
}

arch/s390/kernel/kprobes.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,3 +661,10 @@ int __init arch_init_kprobes(void)
661661
{
662662
return register_kprobe(&trampoline_p);
663663
}
664+
665+
int __kprobes arch_trampoline_kprobe(struct kprobe *p)
666+
{
667+
if (p->addr == (kprobe_opcode_t *) & kretprobe_trampoline)
668+
return 1;
669+
return 0;
670+
}

arch/x86_64/kernel/kprobes.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,3 +743,11 @@ int __init arch_init_kprobes(void)
743743
{
744744
return register_kprobe(&trampoline_p);
745745
}
746+
747+
int __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+
}

include/linux/kprobes.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,16 @@ DECLARE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
125125
#ifdef ARCH_SUPPORTS_KRETPROBES
126126
extern void arch_prepare_kretprobe(struct kretprobe_instance *ri,
127127
struct pt_regs *regs);
128+
extern int arch_trampoline_kprobe(struct kprobe *p);
128129
#else /* ARCH_SUPPORTS_KRETPROBES */
129130
static inline void arch_prepare_kretprobe(struct kretprobe *rp,
130131
struct pt_regs *regs)
131132
{
132133
}
134+
static inline int arch_trampoline_kprobe(struct kprobe *p)
135+
{
136+
return 0;
137+
}
133138
#endif /* ARCH_SUPPORTS_KRETPROBES */
134139
/*
135140
* Function-return probe -

kernel/kprobes.c

Lines changed: 149 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,11 @@
4343
#include <linux/seq_file.h>
4444
#include <linux/debugfs.h>
4545
#include <linux/kdebug.h>
46+
4647
#include <asm-generic/sections.h>
4748
#include <asm/cacheflush.h>
4849
#include <asm/errno.h>
50+
#include <asm/uaccess.h>
4951

5052
#define KPROBE_HASH_BITS 6
5153
#define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS)
@@ -64,6 +66,9 @@ static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
6466
static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE];
6567
static atomic_t kprobe_count;
6668

69+
/* NOTE: change this value only with kprobe_mutex held */
70+
static bool kprobe_enabled;
71+
6772
DEFINE_MUTEX(kprobe_mutex); /* Protects kprobe_table */
6873
DEFINE_SPINLOCK(kretprobe_lock); /* Protects kretprobe_inst_table */
6974
static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL;
@@ -564,12 +569,13 @@ static int __kprobes __register_kprobe(struct kprobe *p,
564569
hlist_add_head_rcu(&p->hlist,
565570
&kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]);
566571

567-
if (atomic_add_return(1, &kprobe_count) == \
572+
if (kprobe_enabled) {
573+
if (atomic_add_return(1, &kprobe_count) == \
568574
(ARCH_INACTIVE_KPROBE_COUNT + 1))
569-
register_page_fault_notifier(&kprobe_page_fault_nb);
570-
571-
arch_arm_kprobe(p);
575+
register_page_fault_notifier(&kprobe_page_fault_nb);
572576

577+
arch_arm_kprobe(p);
578+
}
573579
out:
574580
mutex_unlock(&kprobe_mutex);
575581

@@ -607,8 +613,13 @@ void __kprobes unregister_kprobe(struct kprobe *p)
607613
if (old_p == p ||
608614
(old_p->pre_handler == aggr_pre_handler &&
609615
p->list.next == &old_p->list && p->list.prev == &old_p->list)) {
610-
/* Only probe on the hash list */
611-
arch_disarm_kprobe(p);
616+
/*
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);
612623
hlist_del_rcu(&old_p->hlist);
613624
cleanup_p = 1;
614625
} else {
@@ -797,6 +808,9 @@ static int __init init_kprobes(void)
797808
}
798809
atomic_set(&kprobe_count, 0);
799810

811+
/* By default, kprobes are enabled */
812+
kprobe_enabled = true;
813+
800814
err = arch_init_kprobes();
801815
if (!err)
802816
err = register_die_notifier(&kprobe_exceptions_nb);
@@ -806,7 +820,7 @@ static int __init init_kprobes(void)
806820

807821
#ifdef CONFIG_DEBUG_FS
808822
static 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)
810824
{
811825
char *kprobe_type;
812826

@@ -885,9 +899,130 @@ static struct file_operations debugfs_kprobes_operations = {
885899
.release = seq_release,
886900
};
887901

902+
static 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+
931+
already_enabled:
932+
mutex_unlock(&kprobe_mutex);
933+
return;
934+
}
935+
936+
static 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+
967+
already_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+
*/
977+
static 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+
991+
static 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+
1017+
static struct file_operations fops_kp = {
1018+
.read = read_enabled_file_bool,
1019+
.write = write_enabled_file_bool,
1020+
};
1021+
8881022
static int __kprobes debugfs_kprobe_init(void)
8891023
{
8901024
struct dentry *dir, *file;
1025+
unsigned int value = 1;
8911026

8921027
dir = debugfs_create_dir("kprobes", NULL);
8931028
if (!dir)
@@ -900,6 +1035,13 @@ static int __kprobes debugfs_kprobe_init(void)
9001035
return -ENOMEM;
9011036
}
9021037

1038+
file = debugfs_create_file("enabled", 0600, dir,
1039+
&value, &fops_kp);
1040+
if (!file) {
1041+
debugfs_remove(dir);
1042+
return -ENOMEM;
1043+
}
1044+
9031045
return 0;
9041046
}
9051047

0 commit comments

Comments
 (0)