-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdynamic_dump_stack.c
More file actions
216 lines (169 loc) · 5.76 KB
/
dynamic_dump_stack.c
File metadata and controls
216 lines (169 loc) · 5.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#include<linux/kernel.h>
#include<linux/init.h>
#include<linux/sched.h>
#include<linux/syscalls.h>
#include<linux/string.h>
#include<linux/kprobes.h>
#include<linux/kallsyms.h>
#include<linux/module.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/dynamic_dump_stack.h>
#define MAX_SYMBOL_LEN 40
int dumpstackid;
struct list_head dump_stack_list = LIST_HEAD_INIT(dump_stack_list);
struct dump_stack_struct *node;
// structure to store the info of all the dynamic dump stack probes
struct dump_stack_struct{
int dumpstackid; // id of the dump stack
char symbol_name[40];
struct kprobe p;
pid_t pid; // owner pid
pid_t threadgid; // thread group id
int dumpstackmode; // mode
struct list_head dlist;
};
// to store the temporary list of all the kprobes added by the exiting process
struct delete_node {
struct list_head listnode;
struct list_head* address;
};
/*
Method to remove the kprobes added by the process
Gets called before existing the process
process id is passed
*/
int remove_krpobes(pid_t pid) {
struct list_head* iter = NULL;
struct dump_stack_struct* struct_iter = NULL;
struct delete_node *delList, *temp = NULL;
struct list_head nodes_to_delete = LIST_HEAD_INIT(nodes_to_delete);
pr_info("PROCESS %d IS EXITED. REMOVING THE KRPOBES\n", pid);
// find all the kprobes added by the process
list_for_each(iter, &dump_stack_list) {
struct_iter = list_entry(iter, struct dump_stack_struct, dlist);
//pr_info("PROBES - symbol %s pid %d\n", struct_iter->symbol_name, struct_iter->pid);
if(struct_iter->pid == pid) {
unregister_kprobe(&struct_iter->p); // unregister the kprobes
delList = kmalloc(sizeof(struct delete_node), GFP_KERNEL);
memset(delList, 0, sizeof(struct delete_node));
delList->address = iter;
list_add(&delList->listnode, &nodes_to_delete);
}
}
// delete entries from the global list
list_for_each(iter, &nodes_to_delete) {
temp = list_entry(iter, struct delete_node, listnode);
list_del(temp->address);
}
pr_info("REMOVED THE KRPOBES\n");
return 1;
}
int Pre_Handler(struct kprobe *probe, struct pt_regs *regs){
struct dump_stack_struct *current_struct;
struct task_struct* task = current;
pid_t tgid;
pid_t pid;
tgid = task->tgid;
pid = task->pid;
current_struct = container_of(probe, struct dump_stack_struct, p);
// If mode >1
// do dump stack for all the processs
if(current_struct->dumpstackmode > 1){
dump_stack();
}
// If mode = 0
// do dump stack for the parent process only
else if(current_struct->dumpstackmode == 0 && pid == current_struct->pid){
dump_stack();
}
// If mode = 1
// do dump stack for all the processs who has parent pid as owner process id
// and shares the same address space as parent process
else if(current_struct->dumpstackmode == 1 && (pid == current_struct->pid || tgid == current_struct->threadgid)){
dump_stack();
}
return 0;
}
SYSCALL_DEFINE1(rmdump, int, dumpid){
#ifdef CONFIG_DYNAMIC_DUMP_STACK
struct list_head* iter = NULL;
bool dump_stack_id_exists = false;
struct dump_stack_struct* struct_iter = NULL;
struct task_struct* task = current;
pid_t pid = task->pid;
pr_info("IN THE SYSCALL RMDUMP\n");
// find the kprobe with the given dumpstack id
list_for_each(iter, &dump_stack_list) {
struct_iter = list_entry(iter, struct dump_stack_struct, dlist);
if(struct_iter->dumpstackid == dumpid && struct_iter->pid == pid) {
// ensure that current process id is same as the owner process id
dump_stack_id_exists = true;
break;
}
}
if(dump_stack_id_exists){
printk(KERN_INFO "DUMPSTACK FOUND!! REMOVING\n");
// unregister the krpobe
// delete the entry from the global table
unregister_kprobe(&struct_iter->p);
list_del(iter);
}else{
printk(KERN_INFO "DUMPSTACK NOT FOUND\n");
return -EINVAL;
}
return 1;
#else
return 0;
#endif
}
SYSCALL_DEFINE2(insdump,const char __user *, symbolname, struct dumpmode_t __user *, dumpmode)
{
#ifdef CONFIG_DYNAMIC_DUMP_STACK
unsigned long address;
char *symbol_name;
struct task_struct* task;
struct dumpmode_t input_mode;
pid_t tgid;
pid_t pid;
task = current;
tgid = task->tgid;
pid = task->pid;
pr_info("IN THE SYSCALL INSDUMP\n");
symbol_name = kmalloc(sizeof(char)*MAX_SYMBOL_LEN, GFP_KERNEL);
strncpy_from_user((char *)symbol_name,
symbolname, MAX_SYMBOL_LEN);
address = kallsyms_lookup_name(symbol_name); // find the address of the symbol
if(address == 0/* && is_kernel_text(address)*/){ // validate the address
printk(KERN_INFO "SYMBOL NOT FOUND\n");
return -EINVAL;
}
printk(KERN_INFO "SYMOBOL FOUND! ADDING THE KRPOBE\n");
node = (struct dump_stack_struct *)kmalloc(sizeof(struct dump_stack_struct), GFP_KERNEL);
memset(node, 0, sizeof(struct dump_stack_struct));
if (copy_from_user(&input_mode, dumpmode,sizeof(input_mode))){
return -EFAULT;
}
printk(KERN_INFO "DUMPSTACK MODE IS - %d\n", input_mode.mode);
node->pid = pid;
node->threadgid = tgid;
node->dumpstackmode = input_mode.mode;
snprintf(node->symbol_name, sizeof(char)*MAX_SYMBOL_LEN, "%s", symbol_name);
//node->p = (struct kprobe*)kmalloc(sizeof(struct kprobe), GFP_KERNEL);
memset(&node->p, 0, sizeof(struct kprobe));
node->p.pre_handler = Pre_Handler;
node->p.addr = (kprobe_opcode_t *)address;
node->dumpstackid = dumpstackid++;
// register the krpobe
if(register_kprobe(&node->p)){
printk(KERN_INFO "Error while setting kprobe on address %p\n", (void*)(address));\
return -EINVAL;
}
// add entry to the global list
list_add(&node->dlist, &dump_stack_list);
printk(KERN_INFO "KPROBE INSERTED\n");
return node->dumpstackid;
#else
return 0;
#endif
}