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