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