Merge commit '9cc656e464' into kernel
[kernel/swap-modules.git] / us_manager / helper.c
1 #include <dbi_kprobes.h>
2 #include <dbi_kprobes_deps.h>
3 #include <ksyms.h>
4 #include "us_proc_inst.h"
5 #include "us_slot_manager.h"
6 #include "storage.h"
7 #include "sspt/sspt.h"
8 #include "helper.h"
9
10 struct task_struct;
11
12 struct task_struct *check_task(struct task_struct *task);
13
14 /*
15  ******************************************************************************
16  *                               do_page_fault()                              *
17  ******************************************************************************
18  */
19
20 struct pf_data {
21         unsigned long addr;
22 };
23
24 static int entry_handler_pf(struct kretprobe_instance *ri, struct pt_regs *regs)
25 {
26         struct pf_data *data = (struct pf_data *)ri->data;
27
28 #if defined(CONFIG_X86)
29         data->addr = read_cr2();
30 #elif defined(CONFIG_ARM)
31         data->addr = regs->ARM_r0;
32 #else
33 #error this architecture is not supported
34 #endif
35
36         return 0;
37 }
38
39 /* Detects when IPs are really loaded into phy mem and installs probes. */
40 static int ret_handler_pf(struct kretprobe_instance *ri, struct pt_regs *regs)
41 {
42         struct task_struct *task;
43         unsigned long page_addr;
44
45         task = current->group_leader;
46         if (is_kthread(task))
47                 return 0;
48
49         page_addr = ((struct pf_data *)ri->data)->addr & PAGE_MASK;
50         call_page_fault(task, page_addr);
51
52         return 0;
53 }
54
55 static struct kretprobe pf_kretprobe = {
56         .entry_handler = entry_handler_pf,
57         .handler = ret_handler_pf,
58         .data_size = sizeof(struct pf_data)
59 };
60
61
62
63 /*
64  ******************************************************************************
65  *                              copy_process()                                *
66  ******************************************************************************
67  */
68
69 static void recover_child(struct task_struct *child_task, struct sspt_proc *proc)
70 {
71         sspt_proc_uninstall(proc, child_task, US_DISARM);
72         dbi_disarm_urp_inst_for_task(current, child_task);
73 }
74
75 static void rm_uprobes_child(struct task_struct *task)
76 {
77         struct sspt_proc *proc = sspt_proc_get_by_task(current);
78         if(proc) {
79                 recover_child(task, proc);
80         }
81 }
82
83 /* Delete uprobs in children at fork */
84 static int ret_handler_cp(struct kretprobe_instance *ri, struct pt_regs *regs)
85 {
86         struct task_struct *task = (struct task_struct *)regs_return_value(regs);
87
88         if(!task || IS_ERR(task))
89                 goto out;
90
91         if(task->mm != current->mm) {   /* check flags CLONE_VM */
92                 rm_uprobes_child(task);
93
94                 /*
95                  * Ignoring page_addr, because it is
96                  * first calling call_page_fault()
97                  */
98                 call_page_fault(task, 0xbadc0de);
99         }
100 out:
101         return 0;
102 }
103
104 static struct kretprobe cp_kretprobe = {
105         .handler = ret_handler_cp,
106 };
107
108
109
110 /*
111  ******************************************************************************
112  *                                mm_release()                                *
113  ******************************************************************************
114  */
115
116 /* Detects when target process removes IPs. */
117 static int mr_pre_handler(struct kprobe *p, struct pt_regs *regs)
118 {
119         struct sspt_proc *proc = NULL;
120         struct task_struct *task;
121
122 #if defined(CONFIG_X86)
123         task = (struct task_struct *)regs->EREG(ax);
124 #elif defined(CONFIG_ARM)
125         task = (struct task_struct *)regs->ARM_r0;
126 #else
127 #error this architecture is not supported
128 #endif
129
130         if (is_kthread(task))
131                 goto out;
132
133         if (task->tgid != task->pid) {
134                 goto out;
135         }
136
137         call_mm_release(task);
138 out:
139         return 0;
140 }
141
142 static struct kprobe mr_kprobe = {
143         .pre_handler = mr_pre_handler
144 };
145
146
147
148 /*
149  ******************************************************************************
150  *                                 do_munmap()                                *
151  ******************************************************************************
152  */
153
154 static int remove_unmap_probes(struct task_struct *task, struct sspt_proc *proc, unsigned long start, size_t len)
155 {
156         struct mm_struct *mm = task->mm;
157         struct vm_area_struct *vma;
158
159         /* FIXME: not implemented */
160         return 0;
161
162         if ((start & ~PAGE_MASK) || start > TASK_SIZE || len > TASK_SIZE - start) {
163                 return -EINVAL;
164         }
165
166         if ((len = PAGE_ALIGN(len)) == 0) {
167                 return -EINVAL;
168         }
169
170         vma = find_vma(mm, start);
171         if (vma && check_vma(vma)) {
172                 struct sspt_file *file;
173                 unsigned long end = start + len;
174                 struct dentry *dentry = vma->vm_file->f_dentry;
175
176                 file = sspt_proc_find_file(proc, dentry);
177                 if (file) {
178                         if (vma->vm_start == start || vma->vm_end == end) {
179                                 sspt_file_uninstall(file, task, US_UNREGS_PROBE);
180                                 file->loaded = 0;
181                         } else {
182                                 unsigned long page_addr;
183                                 struct sspt_page *page;
184
185                                 for (page_addr = vma->vm_start; page_addr < vma->vm_end; page_addr += PAGE_SIZE) {
186                                         page = sspt_find_page_mapped(file, page_addr);
187                                         if (page) {
188                                                 sspt_unregister_page(page, US_UNREGS_PROBE, task);
189                                         }
190                                 }
191
192                                 if (sspt_file_check_install_pages(file)) {
193                                         file->loaded = 0;
194                                 }
195                         }
196                 }
197         }
198
199         return 0;
200 }
201
202 /* Detects when target removes IPs. */
203 static int unmap_pre_handler(struct kprobe *p, struct pt_regs *regs)
204 {
205         /* for ARM */
206         struct mm_struct *mm;
207         unsigned long start;
208         size_t len;
209
210 #if defined(CONFIG_X86)
211         mm = (struct mm_struct *)regs->EREG(ax);
212         start = regs->EREG(dx);
213         len = (size_t)regs->EREG(cx);
214 #elif defined(CONFIG_ARM)
215         mm = (struct mm_struct *)regs->ARM_r0;
216         start = regs->ARM_r1;
217         len = (size_t)regs->ARM_r2;
218 #else
219 #error this architecture is not supported
220 #endif
221
222         struct sspt_proc *proc = NULL;
223         struct task_struct *task = current;
224
225         if (is_kthread(task))
226                 goto out;
227
228         proc = sspt_proc_get_by_task(task);
229         if (proc) {
230                 if (remove_unmap_probes(task, proc, start, len)) {
231                         printk("ERROR do_munmap: start=%lx, len=%x\n", start, len);
232                 }
233         }
234
235 out:
236         return 0;
237 }
238
239 static struct kprobe unmap_kprobe = {
240         .pre_handler = unmap_pre_handler
241 };
242
243
244
245 int register_helper(void)
246 {
247         int ret = 0;
248
249         /* install kprobe on 'do_munmap' to detect when for remove user space probes */
250         ret = dbi_register_kprobe(&unmap_kprobe);
251         if (ret) {
252                 printk("dbi_register_kprobe(do_munmap) result=%d!\n", ret);
253                 return ret;
254         }
255
256         /* install kprobe on 'mm_release' to detect when for remove user space probes */
257         ret = dbi_register_kprobe(&mr_kprobe);
258         if (ret != 0) {
259                 printk("dbi_register_kprobe(mm_release) result=%d!\n", ret);
260                 goto unregister_unmap;
261         }
262
263
264         /* install kretprobe on 'copy_process' */
265         ret = dbi_register_kretprobe(&cp_kretprobe);
266         if (ret) {
267                 printk("dbi_register_kretprobe(copy_process) result=%d!\n", ret);
268                 goto unregister_mr;
269         }
270
271         /* install kretprobe on 'do_page_fault' to detect when they will be loaded */
272         ret = dbi_register_kretprobe(&pf_kretprobe);
273         if (ret) {
274                 printk("dbi_register_kretprobe(do_page_fault) result=%d!\n", ret);
275                 goto unregister_cp;
276         }
277
278         return ret;
279
280 unregister_cp:
281         dbi_unregister_kretprobe(&cp_kretprobe);
282
283 unregister_mr:
284         dbi_unregister_kprobe(&mr_kprobe, NULL);
285
286 unregister_unmap:
287         dbi_unregister_kprobe(&unmap_kprobe, NULL);
288
289         return ret;
290 }
291
292 void unregister_helper(void)
293 {
294         /* uninstall kretprobe with 'do_page_fault' */
295         dbi_unregister_kretprobe(&pf_kretprobe);
296
297         /* uninstall kretprobe with 'copy_process' */
298         dbi_unregister_kretprobe(&cp_kretprobe);
299
300         /* uninstall kprobe with 'mm_release' */
301         dbi_unregister_kprobe(&mr_kprobe, NULL);
302
303         /* uninstall kprobe with 'do_munmap' */
304         dbi_unregister_kprobe(&unmap_kprobe, NULL);
305 }
306
307 int init_helper(void)
308 {
309         unsigned long addr;
310         addr = swap_ksyms("do_page_fault");
311         if (addr == 0) {
312                 printk("Cannot find address for page fault function!\n");
313                 return -EINVAL;
314         }
315         pf_kretprobe.kp.addr = (kprobe_opcode_t *)addr;
316
317         addr = swap_ksyms("copy_process");
318         if (addr == 0) {
319                 printk("Cannot find address for copy_process function!\n");
320                 return -EINVAL;
321         }
322         cp_kretprobe.kp.addr = (kprobe_opcode_t *)addr;
323
324         addr = swap_ksyms("mm_release");
325         if (addr == 0) {
326                 printk("Cannot find address for mm_release function!\n");
327                 return -EINVAL;
328         }
329         mr_kprobe.addr = (kprobe_opcode_t *)addr;
330
331         addr = swap_ksyms("do_munmap");
332         if (addr == 0) {
333                 printk("Cannot find address for do_munmap function!\n");
334                 return -EINVAL;
335         }
336         unmap_kprobe.addr = (kprobe_opcode_t *)addr;
337
338         return 0;
339 }
340
341 void uninit_helper(void)
342 {
343 }