[FIX] Skip fixup do_page_fault for x86
[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 "us_slot_manager.h"
31 #include "sspt/sspt.h"
32 #include "sspt/sspt_filter.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         struct pt_regs *pf_regs;
52         unsigned long save_pc;
53 };
54
55 static int entry_handler_pf(struct kretprobe_instance *ri, struct pt_regs *regs)
56 {
57         struct pf_data *data = (struct pf_data *)ri->data;
58
59 #if defined(CONFIG_ARM)
60         data->addr = swap_get_karg(regs, 0);
61         data->pf_regs = (struct pt_regs *)swap_get_karg(regs, 2);
62         data->save_pc = data->pf_regs->ARM_pc;
63 #elif defined(CONFIG_X86_32)
64         data->addr = read_cr2();
65         data->pf_regs = (struct pt_regs *)swap_get_karg(regs, 0);
66         data->save_pc = data->pf_regs->ip;
67 #else
68         #error "this architecture is not supported"
69 #endif /* CONFIG_arch */
70
71         if (data->addr) {
72                 int ret = 0;
73                 struct sspt_proc *proc;
74
75                 proc = sspt_proc_get_by_task(current);
76                 if (proc) {
77                         if (proc->r_state_addr == data->addr) {
78                                 /* skip ret_handler_pf() for current task */
79                                 ret = 1;
80                         }
81
82                         sspt_proc_put(proc);
83                 }
84
85                 return ret;
86         }
87
88         return 0;
89 }
90
91 static unsigned long cb_pf(void *data)
92 {
93         unsigned long page_addr = *(unsigned long *)data;
94
95         call_page_fault(current, page_addr);
96
97         return 0;
98 }
99
100 /* Detects when IPs are really loaded into phy mem and installs probes. */
101 static int ret_handler_pf(struct kretprobe_instance *ri, struct pt_regs *regs)
102 {
103         struct task_struct *task = current;
104         struct pf_data *data = (struct pf_data *)ri->data;
105         unsigned long page_addr;
106         int ret;
107
108         if (is_kthread(task))
109                 return 0;
110
111         /* skip fixup page_fault */
112 #if defined(CONFIG_ARM)
113         if (data->save_pc != data->pf_regs->ARM_pc)
114                 return 0;
115 #elif defined(CONFIG_X86_32)
116         if (data->save_pc != data->pf_regs->ip)
117                 return 0;
118 #endif /* CONFIG_arch */
119
120         /* TODO: check return value */
121         page_addr = data->addr & PAGE_MASK;
122         ret = set_jump_cb((unsigned long)ri->ret_addr, regs, cb_pf,
123                           &page_addr, sizeof(page_addr));
124
125         if (ret == 0)
126                 ri->ret_addr = (unsigned long *)get_jump_addr();
127
128         return 0;
129 }
130
131 static struct kretprobe mf_kretprobe = {
132         .entry_handler = entry_handler_pf,
133         .handler = ret_handler_pf,
134         .data_size = sizeof(struct pf_data)
135 };
136
137 static int register_mf(void)
138 {
139         int ret;
140
141         ret = swap_register_kretprobe(&mf_kretprobe);
142         if (ret)
143                 printk(KERN_INFO "swap_register_kretprobe(handle_mm_fault) ret=%d!\n",
144                        ret);
145
146         return ret;
147 }
148
149 static void unregister_mf(void)
150 {
151         swap_unregister_kretprobe(&mf_kretprobe);
152 }
153
154
155
156
157
158 /*
159  ******************************************************************************
160  *                              copy_process()                                *
161  ******************************************************************************
162  */
163 static void disarm_ip(struct sspt_ip *ip, void *data)
164 {
165         struct task_struct *child = (struct task_struct *)data;
166         struct uprobe *up;
167
168         up = probe_info_get_uprobe(ip->desc->type, ip);
169         if (up)
170                 disarm_uprobe(up, child);
171 }
172
173 static atomic_t rm_uprobes_child_cnt = ATOMIC_INIT(0);
174
175 static unsigned long cb_clean_child(void *data)
176 {
177         struct task_struct *parent = current;
178         struct sspt_proc *proc;
179
180         proc = sspt_proc_get_by_task(parent);
181         if (proc) {
182                 struct task_struct *child = *(struct task_struct **)data;
183
184                 /* disarm up for child */
185                 sspt_proc_on_each_ip(proc, disarm_ip, (void *)child);
186
187                 /* disarm urp for child */
188                 swap_uretprobe_free_task(parent, child, false);
189
190                 sspt_proc_put(proc);
191         }
192
193         atomic_dec(&rm_uprobes_child_cnt);
194         return 0;
195 }
196 static void rm_uprobes_child(struct kretprobe_instance *ri,
197                              struct pt_regs *regs, struct task_struct *child)
198 {
199         int ret;
200
201         if (!sspt_proc_by_task(current))
202                 return;
203
204         /* set jumper */
205         ret = set_jump_cb((unsigned long)ri->ret_addr, regs,
206                           cb_clean_child, &child, sizeof(child));
207         if (ret == 0) {
208                 atomic_inc(&rm_uprobes_child_cnt);
209                 ri->ret_addr = (unsigned long *)get_jump_addr();
210         } else {
211                 WARN_ON(1);
212         }
213 }
214
215
216 static int pre_handler_cp(struct kprobe *p, struct pt_regs *regs)
217 {
218         if (is_kthread(current))
219                 goto out;
220
221         if (atomic_read(&stop_flag))
222                 call_mm_release(current);
223
224 out:
225         return 0;
226 }
227
228
229 static atomic_t copy_process_cnt = ATOMIC_INIT(0);
230
231 static int entry_handler_cp(struct kretprobe_instance *ri, struct pt_regs *regs)
232 {
233         atomic_inc(&copy_process_cnt);
234
235         return 0;
236 }
237
238 /* Delete uprobs in children at fork */
239 static int ret_handler_cp(struct kretprobe_instance *ri, struct pt_regs *regs)
240 {
241         struct task_struct *task =
242                 (struct task_struct *)regs_return_value(regs);
243
244         if (!task || IS_ERR(task))
245                 goto out;
246
247         if (task->mm != current->mm) {  /* check flags CLONE_VM */
248                 rm_uprobes_child(ri, regs, task);
249         }
250 out:
251         atomic_dec(&copy_process_cnt);
252
253         return 0;
254 }
255
256 static struct kretprobe cp_kretprobe = {
257         .entry_handler = entry_handler_cp,
258         .handler = ret_handler_cp,
259 };
260
261 static struct kprobe cp_kprobe = {
262         .pre_handler = pre_handler_cp
263 };
264
265 static int register_cp(void)
266 {
267         int ret;
268
269
270         ret = swap_register_kprobe(&cp_kprobe);
271         if (ret)
272                 pr_err("swap_register_kprobe(copy_process) ret=%d!\n", ret);
273
274         ret = swap_register_kretprobe(&cp_kretprobe);
275         if (ret) {
276                 pr_err("swap_register_kretprobe(copy_process) ret=%d!\n", ret);
277                 swap_unregister_kprobe(&cp_kprobe);
278         }
279
280         return ret;
281 }
282
283 static void unregister_cp(void)
284 {
285         swap_unregister_kretprobe_top(&cp_kretprobe, 0);
286         do {
287                 synchronize_sched();
288         } while (atomic_read(&copy_process_cnt));
289         swap_unregister_kretprobe_bottom(&cp_kretprobe);
290         swap_unregister_kprobe(&cp_kprobe);
291
292         do {
293                 synchronize_sched();
294         } while (atomic_read(&rm_uprobes_child_cnt));
295 }
296
297
298
299
300
301 /*
302  ******************************************************************************
303  *                                mm_release()                                *
304  ******************************************************************************
305  */
306 static void mr_handler(struct task_struct *task)
307 {
308         struct mm_struct *mm = task->mm;
309
310         if (mm == NULL) {
311                 pr_err("mm is NULL\n");
312                 return;
313         }
314
315         /* TODO: this lock for synchronizing to disarm urp */
316         down_write(&mm->mmap_sem);
317         if (task != task->group_leader) {
318                 struct sspt_proc *proc;
319
320                 if (task != current) {
321                         pr_err("call mm_release in isn't current context\n");
322                         return;
323                 }
324
325                 /* if the thread is killed we need to discard pending
326                  * uretprobe instances which have not triggered yet */
327                 proc = sspt_proc_by_task(task);
328                 if (proc)
329                         swap_uretprobe_free_task(task, task, true);
330         } else {
331                 call_mm_release(task);
332         }
333         up_write(&mm->mmap_sem);
334 }
335
336 /* Detects when target process removes IPs. */
337 static int mr_pre_handler(struct kprobe *p, struct pt_regs *regs)
338 {
339         struct task_struct *task = (struct task_struct *)swap_get_karg(regs, 0);
340
341         if (is_kthread(task))
342                 goto out;
343
344         mr_handler(task);
345
346 out:
347         return 0;
348 }
349
350 static struct kprobe mr_kprobe = {
351         .pre_handler = mr_pre_handler
352 };
353
354 static int register_mr(void)
355 {
356         int ret;
357
358         ret = swap_register_kprobe(&mr_kprobe);
359         if (ret)
360                 printk(KERN_INFO
361                        "swap_register_kprobe(mm_release) ret=%d!\n", ret);
362
363         return ret;
364 }
365
366 static void unregister_mr(void)
367 {
368         swap_unregister_kprobe(&mr_kprobe);
369 }
370
371
372
373
374
375 /*
376  ******************************************************************************
377  *                                 do_munmap()                                *
378  ******************************************************************************
379  */
380 struct unmap_data {
381         unsigned long start;
382         size_t len;
383 };
384
385 static atomic_t unmap_cnt = ATOMIC_INIT(0);
386
387 struct msg_unmap_data {
388         unsigned long start;
389         unsigned long end;
390 };
391
392 static void msg_unmap(struct sspt_filter *f, void *data)
393 {
394         if (f->pfg_is_inst) {
395                 struct pfg_msg_cb *cb = pfg_msg_cb_get(f->pfg);
396
397                 if (cb && cb->msg_unmap) {
398                         struct msg_unmap_data *msg_data;
399
400                         msg_data = (struct msg_unmap_data *)data;
401                         cb->msg_unmap(msg_data->start, msg_data->end);
402                 }
403         }
404 }
405
406 static void __remove_unmap_probes(struct sspt_proc *proc,
407                                   struct unmap_data *umd)
408 {
409         unsigned long start = umd->start;
410         size_t len = umd->len;
411         LIST_HEAD(head);
412
413         if (sspt_proc_get_files_by_region(proc, &head, start, len)) {
414                 struct sspt_file *file, *n;
415                 unsigned long end = start + len;
416                 struct task_struct *task = proc->leader;
417
418                 list_for_each_entry_safe(file, n, &head, list) {
419                         if (file->vm_start >= end)
420                                 continue;
421
422                         if (file->vm_start >= start)
423                                 sspt_file_uninstall(file, task, US_UNINSTALL);
424                         /* TODO: else: uninstall pages: * start..file->vm_end */
425                 }
426
427                 sspt_proc_insert_files(proc, &head);
428         }
429 }
430
431 static unsigned long cb_munmap(void *data)
432 {
433         struct sspt_proc *proc;
434         struct unmap_data *umd = (struct unmap_data *)data;
435
436         proc = sspt_proc_get_by_task(current);
437         if (proc) {
438                 struct msg_unmap_data msg_data = {
439                         .start = umd->start,
440                         .end = umd->start + umd->len,
441                 };
442
443                 __remove_unmap_probes(proc, umd);
444
445                 /* send unmap region */
446                 sspt_proc_on_each_filter(proc, msg_unmap, (void *)&msg_data);
447
448                 sspt_proc_put(proc);
449         }
450
451         atomic_dec(&unmap_cnt);
452         return 0;
453 }
454
455 static int entry_handler_unmap(struct kretprobe_instance *ri,
456                                struct pt_regs *regs)
457 {
458         struct unmap_data *data = (struct unmap_data *)ri->data;
459
460         data->start = swap_get_karg(regs, 1);
461         data->len = (size_t)PAGE_ALIGN(swap_get_karg(regs, 2));
462
463         atomic_inc(&unmap_cnt);
464         return 0;
465 }
466
467 static int ret_handler_unmap(struct kretprobe_instance *ri,
468                              struct pt_regs *regs)
469 {
470         int ret;
471
472         if (regs_return_value(regs)) {
473                 atomic_dec(&unmap_cnt);
474                 return 0;
475         }
476
477         ret = set_jump_cb((unsigned long)ri->ret_addr, regs, cb_munmap,
478                           (struct unmap_data *)ri->data,
479                           sizeof(struct unmap_data));
480         if (ret == 0) {
481                 ri->ret_addr = (unsigned long *)get_jump_addr();
482         } else {
483                 WARN_ON(1);
484                 atomic_dec(&unmap_cnt);
485         }
486
487         return 0;
488 }
489
490 static struct kretprobe unmap_kretprobe = {
491         .entry_handler = entry_handler_unmap,
492         .handler = ret_handler_unmap,
493         .data_size = sizeof(struct unmap_data)
494 };
495
496 static int register_unmap(void)
497 {
498         int ret;
499
500         ret = swap_register_kretprobe(&unmap_kretprobe);
501         if (ret)
502                 printk(KERN_INFO "swap_register_kprobe(do_munmap) ret=%d!\n",
503                        ret);
504
505         return ret;
506 }
507
508 static void unregister_unmap(void)
509 {
510         swap_unregister_kretprobe_top(&unmap_kretprobe, 0);
511         do {
512                 synchronize_sched();
513         } while (atomic_read(&unmap_cnt));
514         swap_unregister_kretprobe_bottom(&unmap_kretprobe);
515 }
516
517
518
519
520
521 /*
522  ******************************************************************************
523  *                               do_mmap_pgoff()                              *
524  ******************************************************************************
525  */
526 static void msg_map(struct sspt_filter *f, void *data)
527 {
528         if (f->pfg_is_inst) {
529                 struct pfg_msg_cb *cb = pfg_msg_cb_get(f->pfg);
530
531                 if (cb && cb->msg_map)
532                         cb->msg_map((struct vm_area_struct *)data);
533         }
534 }
535
536 static int ret_handler_mmap(struct kretprobe_instance *ri,
537                             struct pt_regs *regs)
538 {
539         struct sspt_proc *proc;
540         struct task_struct *task;
541         unsigned long start_addr;
542         struct vm_area_struct *vma;
543
544         task = current->group_leader;
545         if (is_kthread(task))
546                 return 0;
547
548         start_addr = regs_return_value(regs);
549         if (IS_ERR_VALUE(start_addr))
550                 return 0;
551
552         proc = sspt_proc_get_by_task(task);
553         if (proc == NULL)
554                 return 0;
555
556         vma = find_vma_intersection(task->mm, start_addr, start_addr + 1);
557         if (vma && check_vma(vma))
558                 sspt_proc_on_each_filter(proc, msg_map, (void *)vma);
559
560         sspt_proc_put(proc);
561         return 0;
562 }
563
564 static struct kretprobe mmap_kretprobe = {
565         .handler = ret_handler_mmap
566 };
567
568 static int register_mmap(void)
569 {
570         int ret;
571
572         ret = swap_register_kretprobe(&mmap_kretprobe);
573         if (ret)
574                 printk(KERN_INFO "swap_register_kretprobe(do_mmap_pgoff) ret=%d!\n",
575                        ret);
576
577         return ret;
578 }
579
580 static void unregister_mmap(void)
581 {
582         swap_unregister_kretprobe(&mmap_kretprobe);
583 }
584
585
586
587
588
589 /*
590  ******************************************************************************
591  *                               set_task_comm()                              *
592  ******************************************************************************
593  */
594 struct comm_data {
595         struct task_struct *task;
596 };
597
598 static unsigned long cb_check_and_install(void *data)
599 {
600         check_task_and_install(current);
601
602         return 0;
603 }
604
605 static int entry_handler_comm(struct kretprobe_instance *ri,
606                               struct pt_regs *regs)
607 {
608         struct comm_data *data = (struct comm_data *)ri->data;
609
610         data->task = (struct task_struct *)swap_get_karg(regs, 0);
611
612         return 0;
613 }
614
615 static int ret_handler_comm(struct kretprobe_instance *ri, struct pt_regs *regs)
616 {
617         struct task_struct *task;
618         int ret;
619
620         if (is_kthread(current))
621                 return 0;
622
623         task = ((struct comm_data *)ri->data)->task;
624         if (task != current)
625                 return 0;
626
627         ret = set_jump_cb((unsigned long)ri->ret_addr, regs,
628                           cb_check_and_install, NULL, 0);
629         if (ret == 0)
630                 ri->ret_addr = (unsigned long *)get_jump_addr();
631
632         return 0;
633 }
634
635 static struct kretprobe comm_kretprobe = {
636         .entry_handler = entry_handler_comm,
637         .handler = ret_handler_comm,
638         .data_size = sizeof(struct comm_data)
639 };
640
641 static int register_comm(void)
642 {
643         int ret;
644
645         ret = swap_register_kretprobe(&comm_kretprobe);
646         if (ret)
647                 printk(KERN_INFO "swap_register_kretprobe(set_task_comm) ret=%d!\n",
648                        ret);
649
650         return ret;
651 }
652
653 static void unregister_comm(void)
654 {
655         swap_unregister_kretprobe(&comm_kretprobe);
656 }
657
658
659
660
661 /*
662  ******************************************************************************
663  *                               release_task()                               *
664  ******************************************************************************
665  */
666 static int release_task_h(struct kprobe *p, struct pt_regs *regs)
667 {
668         struct task_struct *task = (struct task_struct *)swap_get_karg(regs, 0);
669         struct task_struct *cur = current;
670
671         if (cur->flags & PF_KTHREAD)
672                 return 0;
673
674         /* EXEC: change group leader */
675         if (cur != task && task->pid == cur->pid)
676                 sspt_change_leader(task, cur);
677
678         return 0;
679 }
680
681 struct kprobe release_task_kp = {
682         .pre_handler = release_task_h,
683 };
684
685 static int reg_release_task(void)
686 {
687         return swap_register_kprobe(&release_task_kp);
688 }
689
690 static void unreg_release_task(void)
691 {
692         swap_unregister_kprobe(&release_task_kp);
693 }
694
695
696
697
698
699 /**
700  * @brief Registration of helper
701  *
702  * @return Error code
703  */
704 int register_helper(void)
705 {
706         int ret = 0;
707
708         atomic_set(&stop_flag, 0);
709
710         /* tracking group leader changing */
711         ret = reg_release_task();
712         if (ret)
713                 return ret;
714
715         /*
716          * install probe on 'set_task_comm' to detect when field comm struct
717          * task_struct changes
718          */
719         ret = register_comm();
720         if (ret)
721                 goto unreg_rel_task;
722
723         /* install probe on 'do_munmap' to detect when for remove US probes */
724         ret = register_unmap();
725         if (ret)
726                 goto unreg_comm;
727
728         /* install probe on 'mm_release' to detect when for remove US probes */
729         ret = register_mr();
730         if (ret)
731                 goto unreg_unmap;
732
733         /* install probe on 'copy_process' to disarm children process */
734         ret = register_cp();
735         if (ret)
736                 goto unreg_mr;
737
738         /* install probe on 'do_mmap_pgoff' to detect when mapping file */
739         ret = register_mmap();
740         if (ret)
741                 goto unreg_cp;
742
743         /*
744          * install probe on 'handle_mm_fault' to detect when US pages will be
745          * loaded
746          */
747         ret = register_mf();
748         if (ret)
749                 goto unreg_mmap;
750
751         return ret;
752
753 unreg_mmap:
754         unregister_mmap();
755
756 unreg_cp:
757         unregister_cp();
758
759 unreg_mr:
760         unregister_mr();
761
762 unreg_unmap:
763         unregister_unmap();
764
765 unreg_comm:
766         unregister_comm();
767
768 unreg_rel_task:
769         unreg_release_task();
770
771         return ret;
772 }
773
774 /**
775  * @brief Unegistration of helper bottom
776  *
777  * @return Void
778  */
779 void unregister_helper_top(void)
780 {
781         unregister_mf();
782         atomic_set(&stop_flag, 1);
783 }
784
785 /**
786  * @brief Unegistration of helper top
787  *
788  * @return Void
789  */
790 void unregister_helper_bottom(void)
791 {
792         unregister_mmap();
793         unregister_cp();
794         unregister_mr();
795         unregister_unmap();
796         unregister_comm();
797         unreg_release_task();
798 }
799
800 /**
801  * @brief Initialization of helper
802  *
803  * @return Error code
804  */
805 int once_helper(void)
806 {
807         const char *sym;
808
809         sym = "do_page_fault";
810         mf_kretprobe.kp.addr = swap_ksyms(sym);
811         if (mf_kretprobe.kp.addr == 0)
812                 goto not_found;
813
814         sym = "copy_process";
815         cp_kretprobe.kp.addr = swap_ksyms_substr(sym);
816         if (cp_kretprobe.kp.addr == 0)
817                 goto not_found;
818         cp_kprobe.addr = cp_kretprobe.kp.addr;
819
820         sym = "mm_release";
821         mr_kprobe.addr = swap_ksyms(sym);
822         if (mr_kprobe.addr == 0)
823                 goto not_found;
824
825         sym = "do_munmap";
826         unmap_kretprobe.kp.addr = swap_ksyms(sym);
827         if (unmap_kretprobe.kp.addr == 0)
828                 goto not_found;
829
830         sym = "do_mmap_pgoff";
831         mmap_kretprobe.kp.addr = swap_ksyms(sym);
832         if (mmap_kretprobe.kp.addr == 0)
833                 goto not_found;
834
835         sym = "set_task_comm";
836         comm_kretprobe.kp.addr = swap_ksyms(sym);
837         if (comm_kretprobe.kp.addr == 0)
838                 goto not_found;
839
840         sym = "release_task";
841         release_task_kp.addr = swap_ksyms(sym);
842         if (release_task_kp.addr == 0)
843                 goto not_found;
844
845         return 0;
846
847 not_found:
848         printk(KERN_INFO "ERROR: symbol '%s' not found\n", sym);
849         return -ESRCH;
850 }