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