Removed wrong kfree() call
[otst.git] / otst.c
blob9cd24ec554a1cc97d777889dcb9075e6283e4ab0
1 /*
2 * otst: one-time stacktrace module
3 * Copyright (C) 2011 Daniel Borkmann <borkmann@iogearbox.net>
4 * Emmanuel Roullit <emmanuel@netsniff-ng.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * cat /proc/driver/otst ... to show currently traced syms
17 * echo -n "netif_rx" > /proc/driver/otst ... to add a symbol for trace
20 #include <linux/kernel.h>
21 #include <linux/module.h>
22 #include <linux/kprobes.h>
23 #include <linux/proc_fs.h>
24 #include <linux/seq_file.h>
25 #include <linux/uaccess.h>
26 #include <linux/rcupdate.h>
27 #include <linux/list.h>
28 #include <linux/slab.h>
29 #include <linux/spinlock.h>
30 #include <linux/kallsyms.h>
32 #define MODULE_NAME "otst"
33 #define MODULE_PROC "driver/"MODULE_NAME
34 #define MODULE_DESC "one-time stacktrace driver"
36 struct otst_kprobes_elem {
37 char symname[256];
38 struct kprobe probe;
39 struct list_head list;
42 static LIST_HEAD(otst_kprobes);
43 static DEFINE_SPINLOCK(otst_kprobes_lock);
45 static int otst_handler(struct kprobe *kp, struct pt_regs *regs)
47 printk(KERN_INFO "%s: triggered stacktrace for symbol %s at 0x%p:\n",
48 MODULE_NAME, kp->symbol_name, kp->addr);
49 dump_stack();
50 return 0;
53 static void otst_handler_post_work(struct kprobe *kp, struct pt_regs *regs,
54 unsigned long flags)
56 disable_kprobe(kp);
59 static void otst_collect_garbage(void)
61 int found;
62 struct otst_kprobes_elem *elem;
64 do {
65 found = 0;
66 rcu_read_lock();
67 list_for_each_entry_rcu(elem, &otst_kprobes, list) {
68 if (kprobe_disabled(&elem->probe)) {
69 found = 1;
70 unregister_kprobe(&elem->probe);
71 break;
74 rcu_read_unlock();
75 if (found) {
76 spin_lock(&otst_kprobes_lock);
77 list_del_rcu(&elem->list);
78 spin_unlock(&otst_kprobes_lock);
79 synchronize_rcu();
80 printk(KERN_INFO
81 "%s: symbol %s unregistered!\n",
82 MODULE_NAME, elem->symname);
83 kfree(elem);
85 } while (found);
88 static int otst_proc_show(struct seq_file *m, void *v)
90 struct otst_kprobes_elem *elem;
91 rcu_read_lock();
92 list_for_each_entry_rcu(elem, &otst_kprobes, list) {
93 seq_printf(m, "%s\n", elem->probe.symbol_name);
95 rcu_read_unlock();
96 return 0;
99 static int otst_proc_open(struct inode *inode, struct file *file)
101 return single_open(file, otst_proc_show, NULL);
104 static ssize_t otst_proc_write(struct file *file, const char __user * buffer,
105 size_t count, loff_t * pos)
107 int ret = 0;
108 size_t len = 0;
109 struct otst_kprobes_elem *elem = NULL;
111 otst_collect_garbage();
113 elem = kzalloc(sizeof(*elem), GFP_KERNEL);
114 if (!elem) {
115 ret = -ENOMEM;
116 goto out;
119 len =
120 strncpy_from_user(elem->symname, buffer,
121 min(count, sizeof(elem->symname) - 1));
123 if (len < 0) {
124 ret = -EFAULT;
125 goto out;
128 elem->symname[len] = '\0';
130 elem->probe.pre_handler = otst_handler;
131 elem->probe.post_handler = otst_handler_post_work;
132 elem->probe.symbol_name = elem->symname;
134 if (!kallsyms_lookup_name(elem->probe.symbol_name)) {
135 printk(KERN_INFO "%s: %s is no symbol!\n",
136 MODULE_NAME, elem->probe.symbol_name);
137 ret = -EINVAL;
138 goto out;
140 ret = register_kprobe(&elem->probe);
141 if (ret < 0) {
142 printk(KERN_INFO "%s: register_kprobe for %s failed "
143 "with %d\n", MODULE_NAME, elem->probe.symbol_name, ret);
144 goto out;
145 } else {
146 printk(KERN_INFO "%s: symbol %s registered!\n",
147 MODULE_NAME, elem->probe.symbol_name);
150 spin_lock(&otst_kprobes_lock);
151 list_add_rcu(&elem->list, &otst_kprobes);
152 spin_unlock(&otst_kprobes_lock);
154 out:
155 if (ret) {
156 kfree(elem);
159 return ret ? ret : count;
162 static const struct file_operations otst_fops = {
163 .owner = THIS_MODULE,
164 .open = otst_proc_open,
165 .read = seq_read,
166 .llseek = seq_lseek,
167 .write = otst_proc_write,
168 .release = single_release,
171 static int __init otst_init(void)
173 if (!proc_create(MODULE_PROC, S_IWUSR | S_IRUSR, NULL, &otst_fops))
174 return -ENOMEM;
176 printk(KERN_INFO "%s: %s loaded!\n", MODULE_NAME, MODULE_DESC);
177 return 0;
180 static void __exit otst_exit(void)
182 otst_collect_garbage();
183 remove_proc_entry(MODULE_PROC, NULL);
184 printk(KERN_INFO "%s: removed!\n", MODULE_NAME);
187 module_init(otst_init);
188 module_exit(otst_exit);
190 MODULE_LICENSE("GPL");
191 MODULE_DESCRIPTION(MODULE_DESC);
192 MODULE_AUTHOR("Daniel Borkmann <borkmann@iogearbox.net>");
193 MODULE_AUTHOR("Emmanuel Roullit <emmanuel@netsniff-ng.org>");