[REFACTOR] remove arch code for obtain arguments
[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 <writer/kernel_operations.h>
30 #include <writer/swap_writer_module.h>
31 #include "us_slot_manager.h"
32 #include "sspt/sspt.h"
33 #include "helper.h"
34
35 struct task_struct;
36
37 struct task_struct *check_task(struct task_struct *task);
38
39 /*
40  ******************************************************************************
41  *                               do_page_fault()                              *
42  ******************************************************************************
43  */
44
45 struct pf_data {
46         unsigned long addr;
47 };
48
49 static int entry_handler_mf(struct kretprobe_instance *ri, struct pt_regs *regs)
50 {
51         struct pf_data *data = (struct pf_data *)ri->data;
52
53         data->addr = swap_get_karg(regs, 2);
54
55         return 0;
56 }
57
58 /* Detects when IPs are really loaded into phy mem and installs probes. */
59 static int ret_handler_mf(struct kretprobe_instance *ri, struct pt_regs *regs)
60 {
61         struct task_struct *task;
62         unsigned long page_addr;
63
64         task = current->group_leader;
65         if (is_kthread(task))
66                 return 0;
67
68         /* TODO: check return value */
69         page_addr = ((struct pf_data *)ri->data)->addr & PAGE_MASK;
70         call_page_fault(task, page_addr);
71
72         return 0;
73 }
74
75 static struct kretprobe mf_kretprobe = {
76         .entry_handler = entry_handler_mf,
77         .handler = ret_handler_mf,
78         .data_size = sizeof(struct pf_data)
79 };
80
81
82
83 /*
84  ******************************************************************************
85  *                              copy_process()                                *
86  ******************************************************************************
87  */
88
89 static void recover_child(struct task_struct *child_task, struct sspt_proc *proc)
90 {
91         sspt_proc_uninstall(proc, child_task, US_DISARM);
92         dbi_disarm_urp_inst_for_task(current, child_task);
93 }
94
95 static void rm_uprobes_child(struct task_struct *task)
96 {
97         struct sspt_proc *proc = sspt_proc_get_by_task(current);
98         if(proc) {
99                 recover_child(task, proc);
100         }
101 }
102
103 /* Delete uprobs in children at fork */
104 static int ret_handler_cp(struct kretprobe_instance *ri, struct pt_regs *regs)
105 {
106         struct task_struct *task = (struct task_struct *)regs_return_value(regs);
107
108         if(!task || IS_ERR(task))
109                 goto out;
110
111         if(task->mm != current->mm) {   /* check flags CLONE_VM */
112                 rm_uprobes_child(task);
113         }
114 out:
115         return 0;
116 }
117
118 static struct kretprobe cp_kretprobe = {
119         .handler = ret_handler_cp,
120 };
121
122
123
124 /*
125  ******************************************************************************
126  *                                mm_release()                                *
127  ******************************************************************************
128  */
129
130 /* Detects when target process removes IPs. */
131 static int mr_pre_handler(struct kprobe *p, struct pt_regs *regs)
132 {
133         struct task_struct *task = (struct task_struct *)swap_get_karg(regs, 0);
134
135         if (is_kthread(task))
136                 goto out;
137
138         if (task->tgid != task->pid) {
139                 goto out;
140         }
141
142         call_mm_release(task);
143 out:
144         return 0;
145 }
146
147 static struct kprobe mr_kprobe = {
148         .pre_handler = mr_pre_handler
149 };
150
151
152
153 /*
154  ******************************************************************************
155  *                                 do_munmap()                                *
156  ******************************************************************************
157  */
158 struct unmap_data {
159         unsigned long start;
160         size_t len;
161 };
162
163 static void remove_unmap_probes(struct sspt_proc *proc, struct unmap_data *umd)
164 {
165         struct task_struct *task = proc->task;
166         unsigned long start = umd->start;
167         size_t len = PAGE_ALIGN(umd->len);
168         LIST_HEAD(head);
169
170         if (sspt_proc_get_files_by_region(proc, &head, start, len)) {
171                 struct sspt_file *file, *n;
172                 unsigned long end = start + len;
173
174                 list_for_each_entry_safe(file, n, &head, list) {
175                         if (file->vm_start >= end)
176                                 continue;
177
178                         if (file->vm_start >= start) {
179                                 sspt_file_uninstall(file, task, US_UNINSTALL);
180                         } else {
181                                 /* TODO: uninstall pages: start..file->vm_end */
182                         }
183                 }
184
185                 sspt_proc_insert_files(proc, &head);
186
187                 proc_unmap_msg(start, end);
188         }
189 }
190
191
192 static int entry_handler_unmap(struct kretprobe_instance *ri,
193                                struct pt_regs *regs)
194 {
195         struct unmap_data *data = (struct unmap_data *)ri->data;
196
197         data->start = swap_get_karg(regs, 1);
198         data->len = (size_t)swap_get_karg(regs, 2);
199
200         return 0;
201 }
202
203 static int ret_handler_unmap(struct kretprobe_instance *ri,
204                              struct pt_regs *regs)
205 {
206         struct task_struct *task;
207         struct sspt_proc *proc;
208
209         task = current->group_leader;
210         if (is_kthread(task) ||
211             get_regs_ret_val(regs))
212                 return 0;
213
214         proc = sspt_proc_get_by_task(task);
215         if (proc)
216                 remove_unmap_probes(proc, (struct unmap_data *)ri->data);
217
218         return 0;
219 }
220
221 static struct kretprobe unmap_kretprobe = {
222         .entry_handler = entry_handler_unmap,
223         .handler = ret_handler_unmap,
224         .data_size = sizeof(struct unmap_data)
225 };
226
227
228
229 /*
230  ******************************************************************************
231  *                               do_mmap_pgoff()                              *
232  ******************************************************************************
233  */
234 static int ret_handler_mmap(struct kretprobe_instance *ri,
235                             struct pt_regs *regs)
236 {
237         struct sspt_proc *proc;
238         struct task_struct *task;
239         unsigned long start_addr;
240         struct vm_area_struct *vma;
241
242         task = current->group_leader;
243         if (is_kthread(task))
244                 return 0;
245
246         start_addr = (unsigned long)get_regs_ret_val(regs);
247         if (IS_ERR_VALUE(start_addr))
248                 return 0;
249
250         proc = sspt_proc_get_by_task(task);
251         if (proc == NULL)
252                 return 0;
253
254         vma = find_vma_intersection(task->mm, start_addr, start_addr + 1);
255         if (vma && check_vma(vma))
256                 pcoc_map_msg(vma);
257
258         return 0;
259 }
260
261 static struct kretprobe mmap_kretprobe = {
262         .handler = ret_handler_mmap
263 };
264
265
266
267 int register_helper(void)
268 {
269         int ret = 0;
270
271         /* install kprobe on 'do_munmap' to detect when for remove user space probes */
272         ret = dbi_register_kretprobe(&unmap_kretprobe);
273         if (ret) {
274                 printk("dbi_register_kprobe(do_munmap) result=%d!\n", ret);
275                 return ret;
276         }
277
278         /* install kprobe on 'mm_release' to detect when for remove user space probes */
279         ret = dbi_register_kprobe(&mr_kprobe);
280         if (ret != 0) {
281                 printk("dbi_register_kprobe(mm_release) result=%d!\n", ret);
282                 goto unregister_unmap;
283         }
284
285
286         /* install kretprobe on 'copy_process' */
287         ret = dbi_register_kretprobe(&cp_kretprobe);
288         if (ret) {
289                 printk("dbi_register_kretprobe(copy_process) result=%d!\n", ret);
290                 goto unregister_mr;
291         }
292
293         /* install kretprobe on 'do_mmap_pgoff' to detect when mapping file */
294         ret = dbi_register_kretprobe(&mmap_kretprobe);
295         if (ret) {
296                 printk("dbi_register_kretprobe(do_mmap_pgoff) result=%d!\n", ret);
297                 goto unregister_cp;
298         }
299
300         /* install kretprobe on 'handle_mm_fault' to detect when they will be loaded */
301         ret = dbi_register_kretprobe(&mf_kretprobe);
302         if (ret) {
303                 printk("dbi_register_kretprobe(do_page_fault) result=%d!\n", ret);
304                 goto unregister_mmap;
305         }
306
307         return ret;
308
309
310 unregister_mmap:
311         dbi_unregister_kretprobe(&mmap_kretprobe);
312
313 unregister_cp:
314         dbi_unregister_kretprobe(&cp_kretprobe);
315
316 unregister_mr:
317         dbi_unregister_kprobe(&mr_kprobe);
318
319 unregister_unmap:
320         dbi_unregister_kretprobe(&unmap_kretprobe);
321
322         return ret;
323 }
324
325 void unregister_helper(void)
326 {
327         /* uninstall kretprobe with 'handle_mm_fault' */
328         dbi_unregister_kretprobe(&mf_kretprobe);
329
330         /* uninstall kretprobe with 'do_mmap_pgoff' */
331         dbi_unregister_kretprobe(&mmap_kretprobe);
332
333         /* uninstall kretprobe with 'copy_process' */
334         dbi_unregister_kretprobe(&cp_kretprobe);
335
336         /* uninstall kprobe with 'mm_release' */
337         dbi_unregister_kprobe(&mr_kprobe);
338
339         /* uninstall kretprobe with 'do_munmap' */
340         dbi_unregister_kretprobe(&unmap_kretprobe);
341 }
342
343 int init_helper(void)
344 {
345         unsigned long addr;
346         addr = swap_ksyms("handle_mm_fault");
347         if (addr == 0) {
348                 printk("Cannot find address for handle_mm_fault function!\n");
349                 return -EINVAL;
350         }
351         mf_kretprobe.kp.addr = (kprobe_opcode_t *)addr;
352
353         addr = swap_ksyms("copy_process");
354         if (addr == 0) {
355                 printk("Cannot find address for copy_process function!\n");
356                 return -EINVAL;
357         }
358         cp_kretprobe.kp.addr = (kprobe_opcode_t *)addr;
359
360         addr = swap_ksyms("mm_release");
361         if (addr == 0) {
362                 printk("Cannot find address for mm_release function!\n");
363                 return -EINVAL;
364         }
365         mr_kprobe.addr = (kprobe_opcode_t *)addr;
366
367         addr = swap_ksyms("do_munmap");
368         if (addr == 0) {
369                 printk("Cannot find address for do_munmap function!\n");
370                 return -EINVAL;
371         }
372         unmap_kretprobe.kp.addr = (kprobe_opcode_t *)addr;
373
374         addr = swap_ksyms("do_mmap_pgoff");
375         if (addr == 0) {
376                 printk("Cannot find address for do_mmap_pgoff function!\n");
377                 return -EINVAL;
378         }
379         mmap_kretprobe.kp.addr = (kprobe_opcode_t *)addr;
380
381         return 0;
382 }
383
384 void uninit_helper(void)
385 {
386 }