[FEATURE] create call_mm_release()
[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         struct sspt_proc *proc;
44
45         call_page_fault(((struct pf_data *)ri->data)->addr);
46         return 0;
47
48         /*
49          * Because process threads have same address space
50          * we instrument only group_leader of all this threads
51          */
52         task = current->group_leader;
53         if (is_kthread(task))
54                 return 0;
55
56         proc = sspt_proc_get_by_task(task);
57         if (proc)
58                 goto install_proc;
59
60         task = check_task(task);
61         if (task) {
62                 proc = sspt_proc_get_new(task);
63                 goto install_proc;
64         }
65
66         return 0;
67
68 install_proc:
69         if (proc->first_install) {
70                 unsigned long page;
71                 page = ((struct pf_data *)ri->data)->addr & PAGE_MASK;
72                 sspt_proc_install_page(proc, page);
73         } else {
74                 sspt_proc_install(proc);
75         }
76
77         return 0;
78 }
79
80 static struct kretprobe pf_kretprobe = {
81         .entry_handler = entry_handler_pf,
82         .handler = ret_handler_pf,
83         .data_size = sizeof(struct pf_data)
84 };
85
86
87
88 /*
89  ******************************************************************************
90  *                              copy_process()                                *
91  ******************************************************************************
92  */
93
94 static void recover_child(struct task_struct *child_task, struct sspt_proc *proc)
95 {
96         sspt_proc_uninstall(proc, child_task, US_DISARM);
97         dbi_disarm_urp_inst_for_task(current, child_task);
98 }
99
100 static void rm_uprobes_child(struct task_struct *task)
101 {
102         struct sspt_proc *proc = sspt_proc_get_by_task(current);
103         if(proc) {
104                 recover_child(task, proc);
105         }
106 }
107
108 /* Delete uprobs in children at fork */
109 static int ret_handler_cp(struct kretprobe_instance *ri, struct pt_regs *regs)
110 {
111         struct task_struct *task = (struct task_struct *)regs_return_value(regs);
112
113         return 0;
114
115         if(!task || IS_ERR(task))
116                 goto out;
117
118         if(task->mm != current->mm) {   /* check flags CLONE_VM */
119                 rm_uprobes_child(task);
120
121                 if (check_task(current)) {
122                         struct sspt_proc *proc;
123
124                         proc = sspt_proc_get_new(task);
125                         sspt_proc_install(proc);
126                 }
127         }
128 out:
129         return 0;
130 }
131
132 static struct kretprobe cp_kretprobe = {
133         .handler = ret_handler_cp,
134 };
135
136
137
138 /*
139  ******************************************************************************
140  *                                mm_release()                                *
141  ******************************************************************************
142  */
143
144 /* Detects when target process removes IPs. */
145 static int mr_pre_handler(struct kprobe *p, struct pt_regs *regs)
146 {
147         struct sspt_proc *proc = NULL;
148         struct task_struct *task;
149
150 #if defined(CONFIG_X86)
151         task = (struct task_struct *)regs->EREG(ax);
152 #elif defined(CONFIG_ARM)
153         task = (struct task_struct *)regs->ARM_r0;
154 #else
155 #error this architecture is not supported
156 #endif
157
158         if (is_kthread(task))
159                 goto out;
160
161         if (task->tgid != task->pid) {
162                 goto out;
163         }
164
165         call_mm_release(task);
166         return 0;
167
168         proc = sspt_proc_get_by_task(task);
169         if (proc) {
170                 int ret = sspt_proc_uninstall(proc, task, US_UNREGS_PROBE);
171                 if (ret != 0) {
172                         printk("failed to uninstall IPs (%d)!\n", ret);
173                 }
174
175                 dbi_unregister_all_uprobes(task);
176         }
177
178 out:
179         return 0;
180 }
181
182 static struct kprobe mr_kprobe = {
183         .pre_handler = mr_pre_handler
184 };
185
186
187
188 /*
189  ******************************************************************************
190  *                                 do_munmap()                                *
191  ******************************************************************************
192  */
193
194 static int remove_unmap_probes(struct task_struct *task, struct sspt_proc *proc, unsigned long start, size_t len)
195 {
196         struct mm_struct *mm = task->mm;
197         struct vm_area_struct *vma;
198
199         return 0;
200
201         if ((start & ~PAGE_MASK) || start > TASK_SIZE || len > TASK_SIZE - start) {
202                 return -EINVAL;
203         }
204
205         if ((len = PAGE_ALIGN(len)) == 0) {
206                 return -EINVAL;
207         }
208
209         vma = find_vma(mm, start);
210         if (vma && check_vma(vma)) {
211                 struct sspt_file *file;
212                 unsigned long end = start + len;
213                 struct dentry *dentry = vma->vm_file->f_dentry;
214
215                 file = sspt_proc_find_file(proc, dentry);
216                 if (file) {
217                         if (vma->vm_start == start || vma->vm_end == end) {
218                                 sspt_file_uninstall(file, task, US_UNREGS_PROBE);
219                                 file->loaded = 0;
220                         } else {
221                                 unsigned long page_addr;
222                                 struct sspt_page *page;
223
224                                 for (page_addr = vma->vm_start; page_addr < vma->vm_end; page_addr += PAGE_SIZE) {
225                                         page = sspt_find_page_mapped(file, page_addr);
226                                         if (page) {
227                                                 sspt_unregister_page(page, US_UNREGS_PROBE, task);
228                                         }
229                                 }
230
231                                 if (sspt_file_check_install_pages(file)) {
232                                         file->loaded = 0;
233                                 }
234                         }
235                 }
236         }
237
238         return 0;
239 }
240
241 /* Detects when target removes IPs. */
242 static int unmap_pre_handler(struct kprobe *p, struct pt_regs *regs)
243 {
244         /* for ARM */
245         struct mm_struct *mm;
246         unsigned long start;
247         size_t len;
248
249 #if defined(CONFIG_X86)
250         mm = (struct mm_struct *)regs->EREG(ax);
251         start = regs->EREG(dx);
252         len = (size_t)regs->EREG(cx);
253 #elif defined(CONFIG_ARM)
254         mm = (struct mm_struct *)regs->ARM_r0;
255         start = regs->ARM_r1;
256         len = (size_t)regs->ARM_r2;
257 #else
258 #error this architecture is not supported
259 #endif
260
261         struct sspt_proc *proc = NULL;
262         struct task_struct *task = current;
263
264         if (is_kthread(task))
265                 goto out;
266
267         proc = sspt_proc_get_by_task(task);
268         if (proc) {
269                 if (remove_unmap_probes(task, proc, start, len)) {
270                         printk("ERROR do_munmap: start=%lx, len=%x\n", start, len);
271                 }
272         }
273
274 out:
275         return 0;
276 }
277
278 static struct kprobe unmap_kprobe = {
279         .pre_handler = unmap_pre_handler
280 };
281
282
283
284 int register_helper(void)
285 {
286         int ret = 0;
287
288         /* install kprobe on 'do_munmap' to detect when for remove user space probes */
289         ret = dbi_register_kprobe(&unmap_kprobe);
290         if (ret) {
291                 printk("dbi_register_kprobe(do_munmap) result=%d!\n", ret);
292                 return ret;
293         }
294
295         /* install kprobe on 'mm_release' to detect when for remove user space probes */
296         ret = dbi_register_kprobe(&mr_kprobe);
297         if (ret != 0) {
298                 printk("dbi_register_kprobe(mm_release) result=%d!\n", ret);
299                 goto unregister_unmap;
300         }
301
302
303         /* install kretprobe on 'copy_process' */
304         ret = dbi_register_kretprobe(&cp_kretprobe);
305         if (ret) {
306                 printk("dbi_register_kretprobe(copy_process) result=%d!\n", ret);
307                 goto unregister_mr;
308         }
309
310         /* install kretprobe on 'do_page_fault' to detect when they will be loaded */
311         ret = dbi_register_kretprobe(&pf_kretprobe);
312         if (ret) {
313                 printk("dbi_register_kretprobe(do_page_fault) result=%d!\n", ret);
314                 goto unregister_cp;
315         }
316
317         return ret;
318
319 unregister_cp:
320         dbi_unregister_kretprobe(&cp_kretprobe);
321
322 unregister_mr:
323         dbi_unregister_kprobe(&mr_kprobe, NULL);
324
325 unregister_unmap:
326         dbi_unregister_kprobe(&unmap_kprobe, NULL);
327
328         return ret;
329 }
330
331 void unregister_helper(void)
332 {
333         /* uninstall kretprobe with 'do_page_fault' */
334         dbi_unregister_kretprobe(&pf_kretprobe);
335
336         /* uninstall kretprobe with 'copy_process' */
337         dbi_unregister_kretprobe(&cp_kretprobe);
338
339         /* uninstall kprobe with 'mm_release' */
340         dbi_unregister_kprobe(&mr_kprobe, NULL);
341
342         /* uninstall kprobe with 'do_munmap' */
343         dbi_unregister_kprobe(&unmap_kprobe, NULL);
344 }
345
346 int init_helper(void)
347 {
348         unsigned long addr;
349         addr = swap_ksyms("do_page_fault");
350         if (addr == 0) {
351                 printk("Cannot find address for page fault function!\n");
352                 return -EINVAL;
353         }
354         pf_kretprobe.kp.addr = (kprobe_opcode_t *)addr;
355
356         addr = swap_ksyms("copy_process");
357         if (addr == 0) {
358                 printk("Cannot find address for copy_process function!\n");
359                 return -EINVAL;
360         }
361         cp_kretprobe.kp.addr = (kprobe_opcode_t *)addr;
362
363         addr = swap_ksyms("mm_release");
364         if (addr == 0) {
365                 printk("Cannot find address for mm_release function!\n");
366                 return -EINVAL;
367         }
368         mr_kprobe.addr = (kprobe_opcode_t *)addr;
369
370         addr = swap_ksyms("do_munmap");
371         if (addr == 0) {
372                 printk("Cannot find address for do_munmap function!\n");
373                 return -EINVAL;
374         }
375         unmap_kprobe.addr = (kprobe_opcode_t *)addr;
376
377         return 0;
378 }
379
380 void uninit_helper(void)
381 {
382 }