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