[FIX] race condition on probes disarming (at stop)
[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 <kprobe/dbi_kprobes.h>
27 #include <kprobe/dbi_kprobes_deps.h>
28 #include <ksyms/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 static atomic_t stop_flag = ATOMIC_INIT(0);
40
41
42 /*
43  ******************************************************************************
44  *                               do_page_fault()                              *
45  ******************************************************************************
46  */
47
48 struct pf_data {
49         unsigned long addr;
50 };
51
52 static int entry_handler_mf(struct kretprobe_instance *ri, struct pt_regs *regs)
53 {
54         struct pf_data *data = (struct pf_data *)ri->data;
55
56 #ifdef CONFIG_ARM
57         data->addr = swap_get_karg(regs, 0);
58 #else /* CONFIG_ARM */
59         data->addr = swap_get_karg(regs, 2);
60 #endif /* CONFIG_ARM */
61
62         return 0;
63 }
64
65 #ifdef CONFIG_ARM
66 static unsigned long cb_pf(void *data)
67 {
68         unsigned long page_addr = *(unsigned long *)data;
69
70         call_page_fault(current, page_addr);
71
72         return 0;
73 }
74 #endif /* CONFIG_ARM */
75
76 /* Detects when IPs are really loaded into phy mem and installs probes. */
77 static int ret_handler_mf(struct kretprobe_instance *ri, struct pt_regs *regs)
78 {
79         struct task_struct *task = current;
80         unsigned long page_addr;
81
82         if (is_kthread(task))
83                 return 0;
84
85         /* TODO: check return value */
86         page_addr = ((struct pf_data *)ri->data)->addr & PAGE_MASK;
87
88 #ifdef CONFIG_ARM
89         set_jump_cb((unsigned long)ri->ret_addr, regs, cb_pf,
90                     &page_addr, sizeof(page_addr));
91         ri->ret_addr = (unsigned long *)get_jump_addr();
92 #else /* CONFIG_ARM */
93         call_page_fault(task, page_addr);
94 #endif /* CONFIG_ARM */
95
96         return 0;
97 }
98
99 static struct kretprobe mf_kretprobe = {
100         .entry_handler = entry_handler_mf,
101         .handler = ret_handler_mf,
102         .data_size = sizeof(struct pf_data)
103 };
104
105 static int register_mf(void)
106 {
107         int ret;
108
109         ret = dbi_register_kretprobe(&mf_kretprobe);
110         if (ret)
111                 printk("dbi_register_kretprobe(handle_mm_fault) ret=%d!\n",
112                        ret);
113
114         return ret;
115 }
116
117 static void unregister_mf(void)
118 {
119         dbi_unregister_kretprobe(&mf_kretprobe);
120 }
121
122
123
124
125
126 #ifdef CONFIG_ARM
127 /*
128  ******************************************************************************
129  *                       workaround for already running                       *
130  ******************************************************************************
131  */
132 static int ctx_task_pre_handler(struct kprobe *p, struct pt_regs *regs)
133 {
134         struct sspt_proc *proc;
135         unsigned long page_addr;
136         struct task_struct *task = current;
137
138         if (is_kthread(task) || check_task_on_filters(task) == 0)
139                 return 0;
140
141         proc = sspt_proc_get_by_task(task);
142         if (proc && proc->first_install)
143                 return 0;
144
145         page_addr = 0;
146         set_kjump_cb((unsigned long)p->ainsn.insn, regs, cb_pf,
147                      &page_addr, sizeof(page_addr));
148
149         /* set kjumper */
150         p->ss_addr[smp_processor_id()] = (unsigned long *)get_kjump_addr();
151
152         return 0;
153 }
154
155 static struct kprobe ctx_task_kprobe = {
156         .pre_handler = ctx_task_pre_handler,
157 };
158
159 static int register_ctx_task(void)
160 {
161         int ret = 0;
162
163         ret = dbi_register_kprobe(&ctx_task_kprobe);
164         if (ret)
165                 printk("dbi_register_kprobe(workaround) ret=%d!\n", ret);
166
167         return ret;
168 }
169
170 static void unregister_ctx_task(void)
171 {
172         dbi_unregister_kprobe(&ctx_task_kprobe);
173 }
174 #endif /* CONFIG_ARM */
175
176
177
178
179
180 /*
181  ******************************************************************************
182  *                              copy_process()                                *
183  ******************************************************************************
184  */
185 static atomic_t copy_process_cnt = ATOMIC_INIT(0);
186
187 static void recover_child(struct task_struct *child_task, struct sspt_proc *proc)
188 {
189         sspt_proc_uninstall(proc, child_task, US_DISARM);
190         dbi_disarm_urp_inst_for_task(current, child_task);
191 }
192
193 static void rm_uprobes_child(struct task_struct *task)
194 {
195         struct sspt_proc *proc;
196
197         sspt_proc_write_lock();
198
199         proc = sspt_proc_get_by_task(current);
200         if (proc)
201                 recover_child(task, proc);
202
203         sspt_proc_write_unlock();
204 }
205
206 static int entry_handler_cp(struct kretprobe_instance *ri, struct pt_regs *regs)
207 {
208         atomic_inc(&copy_process_cnt);
209
210         if (atomic_read(&stop_flag))
211                 call_mm_release(current);
212
213         return 0;
214 }
215
216 /* Delete uprobs in children at fork */
217 static int ret_handler_cp(struct kretprobe_instance *ri, struct pt_regs *regs)
218 {
219         struct task_struct *task = (struct task_struct *)regs_return_value(regs);
220
221         if(!task || IS_ERR(task))
222                 goto out;
223
224         if(task->mm != current->mm) {   /* check flags CLONE_VM */
225                 rm_uprobes_child(task);
226         }
227 out:
228         atomic_dec(&copy_process_cnt);
229
230         return 0;
231 }
232
233 static struct kretprobe cp_kretprobe = {
234         .entry_handler = entry_handler_cp,
235         .handler = ret_handler_cp,
236 };
237
238 static int register_cp(void)
239 {
240         int ret;
241
242         ret = dbi_register_kretprobe(&cp_kretprobe);
243         if (ret)
244                 printk("dbi_register_kretprobe(copy_process) ret=%d!\n", ret);
245
246         return ret;
247 }
248
249 static void unregister_cp(void)
250 {
251         dbi_unregister_kretprobe_top(&cp_kretprobe, 0);
252         do {
253                 synchronize_sched();
254         } while (atomic_read(&copy_process_cnt));
255         dbi_unregister_kretprobe_bottom(&cp_kretprobe);
256 }
257
258
259
260
261
262 /*
263  ******************************************************************************
264  *                                mm_release()                                *
265  ******************************************************************************
266  */
267
268 /* Detects when target process removes IPs. */
269 static int mr_pre_handler(struct kprobe *p, struct pt_regs *regs)
270 {
271         struct task_struct *task = (struct task_struct *)swap_get_karg(regs, 0);
272
273         if (is_kthread(task))
274                 goto out;
275
276         if (task->tgid != task->pid) {
277                 /* if the thread is killed we need to discard pending
278                  * uretprobe instances which have not triggered yet */
279                 dbi_discard_pending_uretprobes(task);
280                 goto out;
281         }
282
283         call_mm_release(task);
284 out:
285         return 0;
286 }
287
288 static struct kprobe mr_kprobe = {
289         .pre_handler = mr_pre_handler
290 };
291
292 static int register_mr(void)
293 {
294         int ret;
295
296         ret = dbi_register_kprobe(&mr_kprobe);
297         if (ret)
298                 printk("dbi_register_kprobe(mm_release) ret=%d!\n", ret);
299
300         return ret;
301 }
302
303 static void unregister_mr(void)
304 {
305         dbi_unregister_kprobe(&mr_kprobe);
306 }
307
308
309
310
311
312 /*
313  ******************************************************************************
314  *                                 do_munmap()                                *
315  ******************************************************************************
316  */
317 struct unmap_data {
318         unsigned long start;
319         size_t len;
320 };
321
322 static atomic_t unmap_cnt = ATOMIC_INIT(0);
323
324 static void __remove_unmap_probes(struct sspt_proc *proc,
325                                   struct unmap_data *umd)
326 {
327         struct task_struct *task = proc->task;
328         unsigned long start = umd->start;
329         size_t len = PAGE_ALIGN(umd->len);
330         LIST_HEAD(head);
331
332         if (sspt_proc_get_files_by_region(proc, &head, start, len)) {
333                 struct sspt_file *file, *n;
334                 unsigned long end = start + len;
335
336                 list_for_each_entry_safe(file, n, &head, list) {
337                         if (file->vm_start >= end)
338                                 continue;
339
340                         if (file->vm_start >= start) {
341                                 sspt_file_uninstall(file, task, US_UNINSTALL);
342                         } else {
343                                 /* TODO: uninstall pages: start..file->vm_end */
344                         }
345                 }
346
347                 sspt_proc_insert_files(proc, &head);
348
349                 proc_unmap_msg(start, end);
350         }
351 }
352
353 static void remove_unmap_probes(struct task_struct *task,
354                                 struct unmap_data *umd)
355 {
356         struct sspt_proc *proc;
357
358         sspt_proc_write_lock();
359
360         proc = sspt_proc_get_by_task(task);
361         if (proc)
362                 __remove_unmap_probes(proc, umd);
363
364         sspt_proc_write_unlock();
365 }
366
367 static int entry_handler_unmap(struct kretprobe_instance *ri,
368                                struct pt_regs *regs)
369 {
370         struct unmap_data *data = (struct unmap_data *)ri->data;
371         struct task_struct *task = current->group_leader;
372
373         atomic_inc(&unmap_cnt);
374
375         data->start = swap_get_karg(regs, 1);
376         data->len = (size_t)swap_get_karg(regs, 2);
377
378         if (!is_kthread(task) && atomic_read(&stop_flag))
379                 remove_unmap_probes(task, data);
380
381         return 0;
382 }
383
384 static int ret_handler_unmap(struct kretprobe_instance *ri,
385                              struct pt_regs *regs)
386 {
387         struct task_struct *task;
388
389         task = current->group_leader;
390         if (is_kthread(task) ||
391             get_regs_ret_val(regs))
392                 return 0;
393
394         remove_unmap_probes(task, (struct unmap_data *)ri->data);
395
396         atomic_dec(&unmap_cnt);
397
398         return 0;
399 }
400
401 static struct kretprobe unmap_kretprobe = {
402         .entry_handler = entry_handler_unmap,
403         .handler = ret_handler_unmap,
404         .data_size = sizeof(struct unmap_data)
405 };
406
407 static int register_unmap(void)
408 {
409         int ret;
410
411         ret = dbi_register_kretprobe(&unmap_kretprobe);
412         if (ret)
413                 printk("dbi_register_kprobe(do_munmap) ret=%d!\n", ret);
414
415         return ret;
416 }
417
418 static void unregister_unmap(void)
419 {
420         dbi_unregister_kretprobe_top(&unmap_kretprobe, 0);
421         do {
422                 synchronize_sched();
423         } while (atomic_read(&unmap_cnt));
424         dbi_unregister_kretprobe_bottom(&unmap_kretprobe);
425 }
426
427
428
429
430
431 /*
432  ******************************************************************************
433  *                               do_mmap_pgoff()                              *
434  ******************************************************************************
435  */
436 static int ret_handler_mmap(struct kretprobe_instance *ri,
437                             struct pt_regs *regs)
438 {
439         struct sspt_proc *proc;
440         struct task_struct *task;
441         unsigned long start_addr;
442         struct vm_area_struct *vma;
443
444         task = current->group_leader;
445         if (is_kthread(task))
446                 return 0;
447
448         start_addr = (unsigned long)get_regs_ret_val(regs);
449         if (IS_ERR_VALUE(start_addr))
450                 return 0;
451
452         proc = sspt_proc_get_by_task(task);
453         if (proc == NULL)
454                 return 0;
455
456         vma = find_vma_intersection(task->mm, start_addr, start_addr + 1);
457         if (vma && check_vma(vma))
458                 pcoc_map_msg(vma);
459
460         return 0;
461 }
462
463 static struct kretprobe mmap_kretprobe = {
464         .handler = ret_handler_mmap
465 };
466
467 static int register_mmap(void)
468 {
469         int ret;
470
471         ret = dbi_register_kretprobe(&mmap_kretprobe);
472         if (ret)
473                 printk("dbi_register_kretprobe(do_mmap_pgoff) ret=%d!\n", ret);
474
475         return ret;
476 }
477
478 static void unregister_mmap(void)
479 {
480         dbi_unregister_kretprobe(&mmap_kretprobe);
481 }
482
483
484
485
486
487 int register_helper(void)
488 {
489         int ret = 0;
490
491         atomic_set(&stop_flag, 0);
492
493         /* install probe on 'do_munmap' to detect when for remove US probes */
494         ret = register_unmap();
495         if (ret)
496                 return ret;
497
498         /* install probe on 'mm_release' to detect when for remove US probes */
499         ret = register_mr();
500         if (ret)
501                 goto unreg_unmap;
502
503         /* install probe on 'copy_process' to disarm children process */
504         ret = register_cp();
505         if (ret)
506                 goto unreg_mr;
507
508         /* install probe on 'do_mmap_pgoff' to detect when mapping file */
509         ret = register_mmap();
510         if (ret)
511                 goto unreg_cp;
512
513         /*
514          * install probe on 'handle_mm_fault' to detect when US pages will be
515          * loaded
516          */
517         ret = register_mf();
518         if (ret)
519                 goto unreg_mmap;
520
521 #ifdef CONFIG_ARM
522         /* install probe to detect already running process */
523         ret = register_ctx_task();
524         if (ret)
525                 goto unreg_mf;
526 #endif /* CONFIG_ARM */
527
528         return ret;
529
530 #ifdef CONFIG_ARM
531 unreg_mf:
532         unregister_mf();
533 #endif /* CONFIG_ARM */
534
535 unreg_mmap:
536         unregister_mmap();
537
538 unreg_cp:
539         unregister_cp();
540
541 unreg_mr:
542         unregister_mr();
543
544 unreg_unmap:
545         unregister_unmap();
546
547         return ret;
548 }
549
550 void unregister_helper_top(void)
551 {
552 #ifdef CONFIG_ARM
553         unregister_ctx_task();
554 #endif /* CONFIG_ARM */
555         unregister_mf();
556         atomic_set(&stop_flag, 1);
557 }
558
559 void unregister_helper_bottom(void)
560 {
561         unregister_mmap();
562         unregister_cp();
563         unregister_mr();
564         unregister_unmap();
565 }
566
567 int init_helper(void)
568 {
569         unsigned long addr;
570
571 #ifdef CONFIG_ARM
572         addr = swap_ksyms("do_page_fault");
573 #else /* CONFIG_ARM */
574         addr = swap_ksyms("handle_mm_fault");
575 #endif /* CONFIG_ARM */
576
577         if (addr == 0) {
578                 printk("Cannot find address for handle_mm_fault function!\n");
579                 return -EINVAL;
580         }
581         mf_kretprobe.kp.addr = (kprobe_opcode_t *)addr;
582
583         addr = swap_ksyms_substr("copy_process");
584         if (addr == 0) {
585                 printk("Cannot find address for copy_process function!\n");
586                 return -EINVAL;
587         }
588         cp_kretprobe.kp.addr = (kprobe_opcode_t *)addr;
589
590         addr = swap_ksyms("mm_release");
591         if (addr == 0) {
592                 printk("Cannot find address for mm_release function!\n");
593                 return -EINVAL;
594         }
595         mr_kprobe.addr = (kprobe_opcode_t *)addr;
596
597         addr = swap_ksyms("do_munmap");
598         if (addr == 0) {
599                 printk("Cannot find address for do_munmap function!\n");
600                 return -EINVAL;
601         }
602         unmap_kretprobe.kp.addr = (kprobe_opcode_t *)addr;
603
604         addr = swap_ksyms("do_mmap_pgoff");
605         if (addr == 0) {
606                 printk("Cannot find address for do_mmap_pgoff function!\n");
607                 return -EINVAL;
608         }
609         mmap_kretprobe.kp.addr = (kprobe_opcode_t *)addr;
610
611 #ifdef CONFIG_ARM
612         addr = swap_ksyms("ret_to_user");
613         if (addr == 0) {
614                 printk("Cannot find address for ret_to_user function!\n");
615                 return -EINVAL;
616         }
617         ctx_task_kprobe.addr = (kprobe_opcode_t *)addr;
618 #endif /* CONFIG_ARM */
619
620         return 0;
621 }
622
623 void uninit_helper(void)
624 {
625 }