2 * vi:set cin noet sw=4 tw=70:
3 * Copyright 2004, International Business Machines Corporation and others.
6 * This software has been released under the terms of the IBM Public
7 * License. For details, see the LICENSE file in the top-level source
8 * directory or online at http://www.openafs.org/dl/license10.html
10 * Portions of this code borrowed from arla under the following terms:
11 * Copyright (c) 2003-2004 Kungliga Tekniska Högskolan
12 * (Royal Institute of Technology, Stockholm, Sweden).
13 * All rights reserved.
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution.
26 * 3. Neither the name of the Institute nor the names of its contributors
27 * may be used to endorse or promote products derived from this software
28 * without specific prior written permission.
30 * Alternatively, this software may be distributed under the terms of the
31 * GNU General Public License ("GPL").
33 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
37 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 /* Code to find the Linux syscall table */
48 #ifdef OSI_PROBE_STANDALONE
49 #define OSI_PROBE_DEBUG
51 #ifndef OSI_PROBE_STANDALONE
52 #include <afsconfig.h>
53 #include "afs/param.h"
55 #if defined(ENABLE_LINUX_SYSCALL_PROBING)
56 #ifdef AFS_LINUX24_ENV
57 #include <linux/module.h> /* early to avoid printf->printk mapping */
58 #ifndef OSI_PROBE_STANDALONE
59 #include "afs/sysincludes.h"
60 #include "afsincludes.h"
62 #include <linux/version.h>
63 #include <linux/sched.h>
64 #ifdef HAVE_LINUX_CONFIG_H
65 #include <linux/config.h>
67 #include <linux/linkage.h>
68 #include <linux/init.h>
69 #include <linux/unistd.h>
72 #ifdef AFS_AMD64_LINUX20_ENV
73 #include <asm/ia32_unistd.h>
76 /* number of syscalls */
77 /* NB: on MIPS we care about the 4xxx range */
79 #define NR_syscalls 222
82 /* lower bound of valid kernel text pointers */
83 #ifdef AFS_IA64_LINUX20_ENV
84 #define ktxt_lower_bound (((unsigned long)&kernel_thread ) & 0xfff00000L)
85 #elif defined(AFS_PPC64_LINUX20_ENV)
86 #define ktxt_lower_bound (KERNELBASE)
88 #define ktxt_lower_bound (((unsigned long)&kernel_thread ) & ~0xfffffL)
91 /* On SPARC64 and S390X, sys_call_table contains 32-bit entries
92 * even though pointers are 64 bit quantities.
94 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390X_LINUX24_ENV)
95 #define SYSCALLTYPE unsigned int
98 #define SYSCALLTYPE void *
99 #define PROBETYPE long
102 #if defined(AFS_S390X_LINUX20_ENV)
103 #define _SS(x) ((x) << 1)
104 #define _SX(x) ((x) &~ 1)
110 /* Older Linux doesn't have __user. The sys_read prototype needs it. */
115 /* Allow the user to specify sys_call_table addresses */
116 static unsigned long sys_call_table_addr[4] = { 0,0,0,0 };
117 #if defined(module_param_array) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
118 module_param_array(sys_call_table_addr, long, NULL, 0);
120 MODULE_PARM(sys_call_table_addr, "1-4l");
122 MODULE_PARM_DESC(sys_call_table_addr, "Location of system call tables");
124 /* If this is set, we are more careful about avoiding duplicate matches */
125 static int probe_carefully = 1;
126 #if defined(module_param) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
127 module_param(probe_carefully, int, 0);
129 MODULE_PARM(probe_carefully, "i");
131 MODULE_PARM_DESC(probe_carefully, "Probe for system call tables carefully");
133 static int probe_ignore_syscalls[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
134 #if defined(module_param_array) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
135 module_param_array(probe_ignore_syscalls, int, NULL, 0);
137 MODULE_PARM(probe_ignore_syscalls, "1-8i");
139 MODULE_PARM_DESC(probe_ignore_syscalls, "Syscalls to ignore in table checks");
141 #ifdef OSI_PROBE_DEBUG
144 * 0x0001 - General debugging
145 * 0x0002 - detail - try
146 * 0x0004 - detail - try_harder
147 * 0x0008 - detail - check_table
148 * 0x0010 - detail - check_harder
149 * 0x0020 - detail - check_harder/zapped
150 * 0x0040 - automatically ignore setgroups and afs_syscall
151 * 0x0080 - detail - check_table_readable
153 static int probe_debug = 0x41;
154 #if defined(module_param) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
155 module_param(probe_debug, int, 0);
157 MODULE_PARM(probe_debug, "i");
159 MODULE_PARM_DESC(probe_debug, "Debugging level");
161 static unsigned long probe_debug_addr[4] = { 0,0,0,0 };
162 #if defined(module_param_array) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
163 module_param_array(probe_debug_addr, long, NULL, 0);
165 MODULE_PARM(probe_debug_addr, "1-4l");
167 MODULE_PARM_DESC(probe_debug_addr, "Debug range starting locations");
169 static unsigned long probe_debug_range = 0;
170 #if defined(module_param) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
171 module_param(probe_debug_range, long, 0);
173 MODULE_PARM(probe_debug_range, "l");
175 MODULE_PARM_DESC(probe_debug_range, "Debug range length");
177 static unsigned long probe_debug_tag = 0;
178 #if defined(module_param) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
179 module_param(probe_debug_tag, long, 0);
181 MODULE_PARM(probe_debug_tag, "l");
183 MODULE_PARM_DESC(probe_debug_tag, "Debugging output start tag");
187 /* Weak references are our friends. They are supported by the in-kernel
188 * linker in Linux 2.6 and by all versions of modutils back to 2.2pre1.
189 * A weak reference not satisified by the kernel will have value zero.
191 * Unfortunately, weak references to functions don't work right on
192 * IA64; specifically, if you actually try to make a call through
193 * such a reference, and the symbol doesn't exist in the kernel, then
194 * the module relocation code will oops. A workaround for this is
195 * probably possible, but the use of kallsyms_* is of limited value,
196 * so I'm not bothing with the effort for now.
197 * -- jhutz, 10-Feb-2005
199 #ifdef OSI_PROBE_KALLSYMS
200 extern int kallsyms_symbol_to_address(char *name, unsigned long *token,
202 unsigned long *mod_start,
203 unsigned long *mod_end,
205 unsigned long *sec_start,
206 unsigned long *sec_end,
208 unsigned long *sym_start,
209 unsigned long *sym_end
210 ) __attribute__((weak));
212 extern int kallsyms_address_to_symbol(unsigned long address,
214 unsigned long *mod_start,
215 unsigned long *mod_end,
217 unsigned long *sec_start,
218 unsigned long *sec_end,
220 unsigned long *sym_start,
221 unsigned long *sym_end
222 ) __attribute__((weak));
225 extern SYSCALLTYPE sys_call_table[] __attribute__((weak));
226 extern SYSCALLTYPE ia32_sys_call_table[] __attribute__((weak));
227 extern SYSCALLTYPE sys_call_table32[] __attribute__((weak));
228 extern SYSCALLTYPE sys_call_table_emu[] __attribute__((weak));
230 extern asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count) __attribute__((weak));
231 extern asmlinkage long sys_close(unsigned int) __attribute__((weak));
232 #if defined(EXPORTED_SYS_CHDIR)
233 extern asmlinkage long sys_chdir(const char *) __attribute__((weak));
235 extern asmlinkage ssize_t sys_write(unsigned int, const char *, size_t) __attribute__((weak));
236 extern asmlinkage long sys_wait4(pid_t, unsigned int *, int, struct rusage *) __attribute__((weak));
237 extern asmlinkage long sys_exit (int) __attribute__((weak));
238 #if defined(EXPORTED_SYS_OPEN)
239 extern asmlinkage long sys_open (const char *, int, int) __attribute__((weak));
241 extern asmlinkage long sys_ioctl(unsigned int, unsigned int, unsigned long) __attribute__((weak));
244 /* Structures used to control probing. We put all the details of which
245 * symbols we're interested in, what syscall functions to look for, etc
246 * into tables, so we can then have a single copy of the functions that
247 * actually do the work.
260 char *symbol; /* symbol name */
261 char *desc; /* description for messages */
262 int offset; /* first syscall number in table */
264 void *weak_answer; /* weak symbol ref */
265 void *parm_answer; /* module parameter answer */
266 void *debug_answer; /* module parameter answer */
267 unsigned long given_answer; /* compiled-in answer, if any */
269 tryctl *trylist; /* array of combinations to try */
271 unsigned long try_sect_sym; /* symbol in section to try scanning */
272 unsigned long try_base; /* default base address for scan */
273 unsigned long try_base_mask; /* base address bits to force to zero */
274 unsigned long try_length; /* default length for scan */
276 unsigned long alt_try_sect_sym; /* symbol in section to try scanning */
277 unsigned long alt_try_base; /* default base address for scan */
278 unsigned long alt_try_base_mask; /* base address bits to force to zero */
279 unsigned long alt_try_length; /* default length for scan */
281 int n_zapped_syscalls; /* number of unimplemented system calls */
282 int *zapped_syscalls; /* list of unimplemented system calls */
284 int n_unique_syscalls; /* number of unique system calls */
285 int *unique_syscalls; /* list of unimplemented system calls */
287 int verifyNR; /* syscall number to verify match */
288 void *verify_fn; /* syscall pointer to verify match */
290 int debug_ignore_NR[4]; /* syscalls to ignore for debugging */
293 /********** Probing Configuration: sys_call_table **********/
295 /* syscall pairs/triplets to probe */
296 /* On PPC64 and SPARC64, we need to omit the ones that might match both tables */
297 static tryctl main_try[] = {
298 #if !defined(AFS_PPC64_LINUX20_ENV) && !defined(AFS_SPARC64_LINUX20_ENV)
299 #if defined(EXPORTED_SYS_CHDIR)
300 { "scan: close+chdir+write", __NR_close, &sys_close, __NR_chdir, &sys_chdir, __NR_write, &sys_write },
303 { "scan: close+wait4", __NR_close, &sys_close, __NR_wait4, &sys_wait4, -1, 0 },
304 #if !defined(AFS_PPC64_LINUX20_ENV) && !defined(AFS_SPARC64_LINUX20_ENV)
305 #if defined(EXPORTED_SYS_CHDIR)
306 { "scan: close+chdir", __NR_close, &sys_close, __NR_chdir, &sys_chdir, -1, 0 },
309 { "scan: close+ioctl", __NR_close, &sys_close, __NR_ioctl, &sys_ioctl, -1, 0 },
310 #if defined(EXPORTED_SYS_OPEN)
311 { "scan: exit+open", __NR_exit, &sys_exit, __NR_open, &sys_open, -1, 0 },
316 /* zapped syscalls for try_harder */
317 /* this list is based on the table in 'zapped_syscalls' */
319 static int main_zapped_syscalls[] = {
321 * SPARC-Linux uses syscall number mappings chosen to be compatible
322 * with SunOS. So, it doesn't have any of the traditional calls or
323 * the new STREAMS ones. However, there are a number of syscalls
324 * which are SunOS-specific (not implemented on Linux), i386-specific
325 * (not implemented on SPARC-Linux), or implemented only on one of
326 * sparc32 or sparc64. Of course, there are no __NR macros for most
329 * Note that the calls we list here are implemented by sys_nis_syscall,
330 * not by sys_ni_syscall. That means we have to exclude all of the
331 * other entries, or we might get a sys_ni_syscall into the list and
332 * the test would no longer work.
334 #if defined(AFS_SPARC64_LINUX20_ENV)
335 /* mmap2, fstat64, getmsg, putmsg, modify_ldt */
336 56, 63, 151, 152, 218,
337 #elif defined(AFS_SPARC_LINUX20_ENV)
338 /* memory_ordering, getmsg, putmsg, unimplemented, modify_ldt */
339 52, 151, 152, 164, 218,
340 #else /* !AFS_SPARC_LINUX20_ENV */
343 * These 7 syscalls are present in the syscall table on most "older"
344 * platforms that use the traditional syscall number mappings. They
345 * are not implemented on any platform.
369 * On s390 and arm (but not arm26), the seven traditional unimplemented
370 * system calls are indeed present and unimplemented. However, the
371 * corresponding __NR macros are not defined, so the tests above fail.
372 * Instead, we just have to know the numbers for these.
374 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
375 /* break, stty, gtty, ftime, prof, lock, mpx */
376 17, 31, 32, 35, 44, 53, 56,
380 * Sadly, some newer platforms like IA64, amd64, and PA-RISC don't have
381 * the traditional numbers, so the list above are not helpful. They
382 * do have entries for getpmsg/putpmsg, which are always unimplemented.
392 * Alpha-Linux uses syscall number mappings chosen to be compatible
393 * with OSF/1. So, it doesn't have any of the traditional calls or
394 * the new STREAMS ones, but it does have several OSF/1-specific
395 * syscalls which are not implemented on Linux. These don't exist on
396 * any other platform.
398 #ifdef __NR_osf_syscall
401 #ifdef __NR_osf_profil
404 #ifdef __NR_osf_reboot
407 #ifdef __NR_osf_kmodcall
410 #ifdef __NR_osf_old_vtrace
415 * On PPC64, we need a couple more entries to distinguish the two
416 * tables, since the system call numbers are the same and the sets of
417 * unimplemented calls are very similar.
418 * mmap2 and fstat64 are implemented only for 32-bit calls
420 #ifdef AFS_PPC64_LINUX20_ENV
421 /* _mmap2, _fstat64 */
423 #endif /* AFS_PPC64_LINUX20_ENV */
425 /* Similarly for S390X, with lcown16 and fstat64 */
426 #ifdef AFS_S390X_LINUX20_ENV
427 /* lchown16, fstat64 */
430 #endif /* !AFS_SPARC_LINUX20_ENV */
434 /* unique syscalls for try_harder */
435 static int main_unique_syscalls[] = {
436 #if defined(AFS_SPARC64_LINUX24_ENV) || defined(AFS_SPARC_LINUX24_ENV)
438 * On SPARC, we need some additional unique calls to make sure
439 * we don't match the SunOS-compatibility table.
441 __NR_sgetmask, __NR_ssetmask,
443 __NR_exit, __NR_mount, __NR_read, __NR_write,
444 __NR_open, __NR_close, __NR_unlink
447 /* probe control structure */
448 static probectl main_probe = {
449 /* symbol name and description */
453 /* syscall number of first entry in table */
454 #ifdef AFS_IA64_LINUX20_ENV
460 sys_call_table, /* weak symbol ref */
461 0, 0, /* module parameter answers */
462 #ifdef AFS_LINUX_sys_call_table
463 AFS_LINUX_sys_call_table, /* compiled-in answer, if any */
468 main_try, /* array of combinations to try */
470 /* symbol in section to try scanning */
471 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
472 (unsigned long)&sys_close,
473 #elif defined(AFS_AMD64_LINUX20_ENV)
474 /* On this platform, it's in a different section! */
475 (unsigned long)&tasklist_lock,
477 (unsigned long)&init_mm,
480 /* default base address for scan */
481 /* base address bits to force to zero */
482 /* default length for scan */
483 #if defined(AFS_SPARC64_LINUX20_ENV)
484 (unsigned long)(&sys_close),
487 #elif defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
488 /* bleah; this is so suboptimal */
489 (unsigned long)(&sys_close),
492 #elif defined(AFS_IA64_LINUX20_ENV)
493 (unsigned long)(&init_mm),
496 #elif defined(AFS_AMD64_LINUX20_ENV)
497 (unsigned long)(&tasklist_lock) - 0x30000,
500 #elif defined(AFS_PPC_LINUX20_ENV) || defined(AFS_PPC_LINUX20_ENV)
501 (unsigned long)&init_mm,
505 (unsigned long)&init_mm,
512 /* number and list of unimplemented system calls */
513 ((sizeof(main_zapped_syscalls)/sizeof(main_zapped_syscalls[0])) - 1),
514 main_zapped_syscalls,
516 /* number and list of unique system calls */
517 (sizeof(main_unique_syscalls)/sizeof(main_unique_syscalls[0])),
518 main_unique_syscalls,
520 /* syscall number and pointer to verify match */
521 __NR_close, &sys_close,
523 /* syscalls to ignore for debugging */
525 #if defined(AFS_ALPHA_LINUX20_ENV)
527 #elif defined(AFS_AMD64_LINUX20_ENV)
529 #elif defined(AFS_IA64_LINUX20_ENV)
531 #elif defined(AFS_SPARC_LINUX20_ENV) || defined(AFS_SPARC64_LINUX20_ENV)
537 #ifdef __NR_setgroups32
547 /********** Probing Configuration: amd64 ia32_sys_call_table **********/
548 #if defined(AFS_AMD64_LINUX20_ENV)
550 /* syscall pairs/triplets to probe */
551 static tryctl ia32_try[] = {
552 #if defined(EXPORTED_SYS_CHDIR)
553 { "scan: close+chdir+write", __NR_ia32_close, &sys_close, __NR_ia32_chdir, &sys_chdir, __NR_ia32_write, &sys_write },
554 { "scan: close+chdir", __NR_ia32_close, &sys_close, __NR_ia32_chdir, &sys_chdir, -1, 0 },
559 /* zapped syscalls for try_harder */
560 static int ia32_zapped_syscalls[] = {
561 __NR_ia32_break, __NR_ia32_stty, __NR_ia32_gtty, __NR_ia32_ftime,
562 __NR_ia32_prof, __NR_ia32_lock, __NR_ia32_mpx,
566 /* unique syscalls for try_harder */
567 static int ia32_unique_syscalls[] = {
568 __NR_ia32_exit, __NR_ia32_mount, __NR_ia32_read, __NR_ia32_write,
569 __NR_ia32_open, __NR_ia32_close, __NR_ia32_unlink
572 /* probe control structure */
573 static probectl ia32_probe = {
574 /* symbol name and description */
575 "ia32_sys_call_table",
576 "32-bit system call table",
578 /* syscall number of first entry in table */
581 ia32_sys_call_table, /* weak symbol ref */
582 0, 0, /* module parameter answers */
583 #ifdef AFS_LINUX_ia32_sys_call_table
584 AFS_LINUX_ia32_sys_call_table,/* compiled-in answer, if any */
589 ia32_try, /* array of combinations to try */
591 /* symbol in section to try scanning */
592 (unsigned long)&init_mm,
594 /* default base address for scan */
595 /* base address bits to force to zero */
596 /* default length for scan */
597 (unsigned long)&init_mm,
599 (0x180000 / sizeof(unsigned long *)),
604 /* number and list of unimplemented system calls */
605 ((sizeof(ia32_zapped_syscalls)/sizeof(ia32_zapped_syscalls[0])) - 1),
606 ia32_zapped_syscalls,
608 /* number and list of unique system calls */
609 (sizeof(ia32_unique_syscalls)/sizeof(ia32_unique_syscalls[0])),
610 ia32_unique_syscalls,
612 /* syscall number and pointer to verify match */
613 __NR_ia32_close, &sys_close,
615 /* syscalls to ignore for debugging */
619 __NR_ia32_setgroups32,
624 static probectl *probe_list[] = {
625 &main_probe, &ia32_probe
629 /********** Probing Configuration: IA64 **********/
630 #elif defined(AFS_IA64_LINUX20_ENV)
636 /* no 32-bit support on IA64 for now */
637 static probectl *probe_list[] = {
642 /********** Probing Configuration: ppc64, sparc64 sys_call_table32 **********/
643 #elif defined(AFS_PPC64_LINUX20_ENV) || defined(AFS_SPARC64_LINUX20_ENV)
650 * syscall pairs/triplets to probe
651 * This has to be empty, because anything that would work will
652 * also match the main table, and that's no good.
654 static tryctl sct32_try[] = {
658 /* zapped syscalls for try_harder */
659 static int sct32_zapped_syscalls[] = {
660 #ifdef AFS_PPC64_LINUX20_ENV
661 /* These should be sufficient */
662 __NR_break, __NR_stty, __NR_gtty, __NR_ftime,
663 __NR_prof, __NR_lock, __NR_mpx,
665 #ifdef AFS_SPARC64_LINUX20_ENV
666 /* memory_ordering, getmsg, putmsg, unimplemented, modify_ldt */
667 52, 151, 152, 164, 218,
672 /* unique syscalls for try_harder */
673 /* mmap2 and fstat64 are implemented only for 32-bit calls */
674 static int sct32_unique_syscalls[] = {
675 #ifdef AFS_PPC64_LINUX20_ENV
676 /* _mmap2, _fstat64 */
679 #ifdef AFS_SPARC64_LINUX24_ENV
681 * On SPARC, we need some additional unique calls to make sure
682 * we don't match the SunOS-compatibility table.
684 __NR_sgetmask, __NR_ssetmask,
686 __NR_exit, __NR_mount, __NR_read, __NR_write,
687 __NR_open, __NR_close, __NR_unlink
690 /* probe control structure */
691 static probectl sct32_probe = {
692 /* symbol name and description */
694 "32-bit system call table",
696 /* syscall number of first entry in table */
699 sys_call_table32, /* weak symbol ref */
700 0, 0, /* module parameter answers */
701 #ifdef AFS_LINUX_sys_call_table32
702 AFS_LINUX_sys_call_table32, /* compiled-in answer, if any */
707 sct32_try, /* array of combinations to try */
709 /* symbol in section to try scanning */
710 #if defined(AFS_SPARC64_LINUX20_ENV)
711 (unsigned long)&sys_close,
713 (unsigned long)&init_mm,
716 /* default base address for scan */
717 /* base address bits to force to zero */
718 /* default length for scan */
719 #if defined(AFS_SPARC64_LINUX20_ENV)
720 (unsigned long)(&sys_close),
724 (unsigned long)&init_mm,
731 /* number and list of unimplemented system calls */
732 ((sizeof(sct32_zapped_syscalls)/sizeof(sct32_zapped_syscalls[0])) - 1),
733 sct32_zapped_syscalls,
735 /* number and list of unique system calls */
736 (sizeof(sct32_unique_syscalls)/sizeof(sct32_unique_syscalls[0])),
737 sct32_unique_syscalls,
739 /* syscall number and pointer to verify match */
740 __NR_close, &sys_close,
742 /* syscalls to ignore for debugging */
744 #if defined(AFS_SPARC64_LINUX20_ENV)
755 static probectl *probe_list[] = {
756 &main_probe, &sct32_probe
760 /********** End of Probing Configuration **********/
762 #else /* no per-platform probe control, so use the default list */
763 static probectl *probe_list[] = {
768 #define N_PROBE_LIST (sizeof(probe_list) / sizeof(*probe_list))
769 #define DEBUG_IN_RANGE(P,x) (!probe_debug_range || \
770 (P->debug_answer && \
771 (unsigned long)(x) >= (unsigned long)P->debug_answer && \
772 (unsigned long)(x) < (unsigned long)P->debug_answer + probe_debug_range))
776 static int check_table(probectl *P, PROBETYPE *ptr)
781 for (x = ptr, i = 0; i < _SS(NR_syscalls); i++, x++) {
782 #ifdef OSI_PROBE_DEBUG
783 if (probe_debug & 0x0040) {
784 for (j = 0; j < 4; j++) {
785 if (_SS(P->debug_ignore_NR[j]) == _SX(i + P->offset)) break;
790 for (j = 0; j < 8; j++) {
791 if (_SS(probe_ignore_syscalls[j]) == _SX(i) + P->offset) break;
794 if (*x <= ktxt_lower_bound) {
795 #ifdef OSI_PROBE_DEBUG
796 if ((probe_debug & 0x0008) && DEBUG_IN_RANGE(P,ptr))
797 printk("<7>check 0x%lx -> %d [0x%lx]\n",
798 (unsigned long)ptr, i, (unsigned long)*x);
803 #ifdef OSI_PROBE_DEBUG
804 if ((probe_debug & 0x0008) && DEBUG_IN_RANGE(P,ptr))
805 printk("<7>check 0x%lx -> ok\n", (unsigned long)ptr);
810 static void *try(probectl *P, tryctl *T, PROBETYPE *aptr,
811 unsigned long datalen)
813 #ifdef OSI_PROBE_KALLSYMS
814 char *mod_name, *sec_name, *sym_name;
815 unsigned long mod_start, mod_end;
816 unsigned long sec_start, sec_end;
817 unsigned long sym_start, sym_end;
819 unsigned long offset, ip1, ip2, ip3;
823 #if defined(AFS_IA64_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV)
824 ip1 = T->fn1 ? (unsigned long)((struct fptr *)T->fn1)->ip : 0;
825 ip2 = T->fn2 ? (unsigned long)((struct fptr *)T->fn2)->ip : 0;
826 ip3 = T->fn3 ? (unsigned long)((struct fptr *)T->fn3)->ip : 0;
828 ip1 = (unsigned long)T->fn1;
829 ip2 = (unsigned long)T->fn2;
830 ip3 = (unsigned long)T->fn3;
833 #ifdef OSI_PROBE_DEBUG
834 if (probe_debug & 0x0001)
835 printk("<7>osi_probe: %s %s (%d->0x%lx, %d->0x%lx, %d->0x%lx)\n",
836 P->symbol, T->name, T->NR1, ip1, T->NR2, ip2, T->NR3, ip3);
839 if (!ip1 || !ip2 || (T->NR3 >= 0 && !ip3))
842 for (offset = 0; offset < datalen; offset++, aptr++) {
843 #if defined(AFS_PPC64_LINUX20_ENV)
844 ptr = (PROBETYPE*)(*aptr);
845 if ((unsigned long)ptr <= KERNELBASE) {
851 if ((unsigned long)ptr < init_mm.start_code ||
852 #if defined(AFS_AMD64_LINUX20_ENV)
853 (unsigned long)ptr > init_mm.brk)
855 (unsigned long)ptr > init_mm.end_data)
858 /* printk("address 0x%lx (from 0x%lx %d) is out of range in check_table. wtf?\n", (unsigned long)x, (unsigned long)ptr, i);*/
862 ret = check_table(P, ptr);
864 /* return value is number of entries to skip */
870 #ifdef OSI_PROBE_DEBUG
871 if ((probe_debug & 0x0002) && DEBUG_IN_RANGE(P,ptr))
872 printk("<7>try 0x%lx\n", (unsigned long)ptr);
874 if (ptr[_SS(T->NR1 - P->offset)] != ip1) continue;
875 if (ptr[_SS(T->NR2 - P->offset)] != ip2) continue;
876 if (ip3 && ptr[_SS(T->NR3 - P->offset)] != ip3) continue;
878 #ifdef OSI_PROBE_DEBUG
879 if (probe_debug & 0x0002)
880 printk("<7>try found 0x%lx\n", (unsigned long)ptr);
882 #ifdef OSI_PROBE_KALLSYMS
883 if (kallsyms_address_to_symbol) {
884 ret = kallsyms_address_to_symbol((unsigned long)ptr,
885 &mod_name, &mod_start, &mod_end,
886 &sec_name, &sec_start, &sec_end,
887 &sym_name, &sym_start, &sym_end);
888 if (!ret || strcmp(sym_name, P->symbol)) continue;
891 /* XXX should we make sure there is only one match? */
898 static int check_harder(probectl *P, PROBETYPE *p)
903 /* Check zapped syscalls */
904 for (i = 1; i < P->n_zapped_syscalls; i++) {
905 if (p[_SS(P->zapped_syscalls[i])] != p[_SS(P->zapped_syscalls[0])]) {
906 #ifdef OSI_PROBE_DEBUG
907 if ((probe_debug & 0x0020) && DEBUG_IN_RANGE(P,p))
908 printk("<7>check_harder 0x%lx zapped failed i=%d\n", (unsigned long)p, i);
914 /* Check unique syscalls */
915 for (i = 0; i < P->n_unique_syscalls; i++) {
916 for (s = 0; s < NR_syscalls; s++) {
917 if (p[_SS(s)] == p[_SS(P->unique_syscalls[i])]
918 && s != P->unique_syscalls[i]) {
919 #ifdef OSI_PROBE_DEBUG
920 if ((probe_debug & 0x0010) && DEBUG_IN_RANGE(P,p))
921 printk("<7>check_harder 0x%lx unique failed i=%d s=%d\n", (unsigned long)p, i, s);
928 #if defined(AFS_IA64_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV)
929 ip1 = P->verify_fn ? (unsigned long)((struct fptr *)(P->verify_fn))->ip : 0;
931 ip1 = (unsigned long)(P->verify_fn);
934 if (ip1 && p[_SS(P->verifyNR - P->offset)] != ip1) {
935 #ifdef OSI_PROBE_DEBUG
936 if ((probe_debug & 0x0010) && DEBUG_IN_RANGE(P,p))
937 printk("<7>check_harder 0x%lx verify failed\n", (unsigned long)p);
942 #ifdef OSI_PROBE_DEBUG
943 if ((probe_debug & 0x0010) && DEBUG_IN_RANGE(P,p))
944 printk("<7>check_harder 0x%lx success!\n", (unsigned long)p);
949 static void *try_harder(probectl *P, PROBETYPE *ptr, unsigned long datalen)
951 #ifdef OSI_PROBE_KALLSYMS
952 char *mod_name, *sec_name, *sym_name;
953 unsigned long mod_start, mod_end;
954 unsigned long sec_start, sec_end;
955 unsigned long sym_start, sym_end;
957 unsigned long offset;
961 #ifdef OSI_PROBE_DEBUG
962 if (probe_debug & 0x0001)
963 printk("<7>osi_probe: %s try_harder\n", P->symbol);
965 for (offset = 0; offset < datalen; offset++, ptr++) {
966 if ((unsigned long)ptr < init_mm.start_code ||
967 #if defined(AFS_AMD64_LINUX20_ENV)
968 (unsigned long)ptr > init_mm.brk)
970 (unsigned long)ptr > init_mm.end_data)
973 /* printk("address 0x%lx (from 0x%lx %d) is out of range in check_table. wtf?\n", (unsigned long)x, (unsigned long)ptr, i);*/
976 ret = check_table(P, ptr);
978 /* return value is number of entries to skip */
984 #ifdef OSI_PROBE_DEBUG
985 if ((probe_debug & 0x0004) && DEBUG_IN_RANGE(P,ptr))
986 printk("<7>try_harder 0x%lx\n", (unsigned long)ptr);
988 if (!check_harder(P, ptr))
991 #ifdef OSI_PROBE_DEBUG
992 if (probe_debug & 0x0004)
993 printk("<7>try_harder found 0x%lx\n", (unsigned long)ptr);
996 #ifdef OSI_PROBE_KALLSYMS
997 if (kallsyms_address_to_symbol) {
998 ret = kallsyms_address_to_symbol((unsigned long)ptr,
999 &mod_name, &mod_start, &mod_end,
1000 &sec_name, &sec_start, &sec_end,
1001 &sym_name, &sym_start, &sym_end);
1002 if (!ret || strcmp(sym_name, P->symbol)) continue;
1007 #ifdef OSI_PROBE_DEBUG
1008 if (probe_debug & 0x0005)
1009 printk("<7>%s: try_harder found multiple matches!\n", P->symbol);
1014 match = (void *)ptr;
1015 if (!probe_carefully)
1022 #ifdef OSI_PROBE_DEBUG
1023 #define check_result(x,m) do { \
1024 if (probe_debug & 0x0001) { \
1025 printk("<7>osi_probe: %s = 0x%016lx %s\n", P->symbol, (unsigned long)(x), (m)); \
1027 if ((x) && ((int)(x)) != -ENOENT) { \
1029 final_answer = (void *)(x); \
1033 #define check_result(x,m) do { \
1034 if ((x) && ((int)(x)) != -ENOENT) { \
1036 return (void *)(x); \
1040 static void *scan_for_syscall_table(probectl *P, PROBETYPE *B, unsigned long L)
1044 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
1047 #ifdef OSI_PROBE_DEBUG
1048 void *final_answer = 0;
1050 #ifdef OSI_PROBE_DEBUG
1051 if (probe_debug & 0x0007)
1052 printk("<7>osi_probe: %s base=0x%lx, len=0x%lx\n",
1053 P->symbol, (unsigned long)B, L);
1054 if (probe_debug & 0x0009) {
1055 printk("<7>osi_probe: %s ktxt_lower_bound=0x%lx\n",
1056 P->symbol, ktxt_lower_bound);
1057 printk("<7>osi_probe: %s NR_syscalls=%d\n",
1058 P->symbol, NR_syscalls);
1062 for (T = P->trylist; T->name; T++) {
1063 answer = try(P, T, B, L);
1064 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
1065 answer2 = try(P, T, (PROBETYPE *)(2 + (void *)B), L);
1066 #ifdef OSI_PROBE_DEBUG
1067 if (probe_debug & 0x0003) {
1068 printk("<7>osi_probe: %s = 0x%016lx %s (even)\n",
1069 P->symbol, (unsigned long)(answer), T->name);
1070 printk("<7>osi_probe: %s = 0x%016lx %s (odd)\n",
1071 P->symbol, (unsigned long)(answer2), T->name);
1074 if (answer && answer2) answer = 0;
1075 else if (answer2) answer = answer2;
1081 /* XXX more checks here */
1083 answer = try_harder(P, B, L);
1084 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
1085 answer2 = try_harder(P, (PROBETYPE *)(2 + (void *)B), L);
1086 #ifdef OSI_PROBE_DEBUG
1087 if (probe_debug & 0x0005) {
1088 printk("<7>osi_probe: %s = 0x%016lx pattern scan (even)\n",
1089 P->symbol, (unsigned long)(answer));
1090 printk("<7>osi_probe: %s = 0x%016lx pattern scan (odd)\n",
1091 P->symbol, (unsigned long)(answer2));
1094 if (answer && answer2) answer = 0;
1095 else if (answer2) answer = answer2;
1100 static void *do_find_syscall_table(probectl *P, char **method)
1102 #ifdef OSI_PROBE_KALLSYMS
1103 char *mod_name, *sec_name, *sym_name;
1104 unsigned long mod_start, mod_end;
1105 unsigned long sec_start, sec_end;
1106 unsigned long sym_start, sym_end;
1107 unsigned long token;
1113 #ifdef OSI_PROBE_DEBUG
1114 void *final_answer = 0;
1117 *method = "not found";
1119 /* if it's exported, there's nothing to do */
1120 check_result(P->weak_answer, "exported");
1122 /* ask the kernel to do the name lookup, if it's willing */
1123 #ifdef OSI_PROBE_KALLSYMS
1124 if (kallsyms_symbol_to_address) {
1128 ret = kallsyms_symbol_to_address(P->symbol, &token,
1129 &mod_name, &mod_start, &mod_end,
1130 &sec_name, &sec_start, &sec_end,
1131 &sym_name, &sym_start, &sym_end);
1132 if (ret && !strcmp(mod_name, "kernel") && sym_start)
1136 check_result(sym_start, "kallsyms_symbol_to_address");
1140 /* Maybe a little birdie told us */
1141 check_result(P->parm_answer, "module parameter");
1142 check_result(P->given_answer, "compiled-in");
1144 /* OK, so we have to scan. */
1145 B = (PROBETYPE *)((P->try_base) & ~(P->try_base_mask));
1147 /* Now, see if the kernel will tell us something better than the default */
1148 #ifdef OSI_PROBE_KALLSYMS
1149 if (kallsyms_address_to_symbol) {
1150 ret = kallsyms_address_to_symbol(P->try_sect_sym,
1151 &mod_name, &mod_start, &mod_end,
1152 &sec_name, &sec_start, &sec_end,
1153 &sym_name, &sym_start, &sym_end);
1155 B = (PROBETYPE *)sec_start;
1156 L = (sec_end - sec_start) / sizeof(unsigned long);
1161 answer = scan_for_syscall_table(P, B, L);
1162 check_result(answer, "pattern scan");
1163 B = (PROBETYPE *)((P->alt_try_base) & ~(P->alt_try_base_mask));
1164 L = P->alt_try_length;
1165 /* Now, see if the kernel will tell us something better than the default */
1166 #ifdef OSI_PROBE_KALLSYMS
1167 if (kallsyms_address_to_symbol && P->alt_try_sect_sym) {
1168 ret = kallsyms_address_to_symbol(P->alt_try_sect_sym,
1169 &mod_name, &mod_start, &mod_end,
1170 &sec_name, &sec_start, &sec_end,
1171 &sym_name, &sym_start, &sym_end);
1173 B = (PROBETYPE *)sec_start;
1174 L = (sec_end - sec_start) / sizeof(unsigned long);
1179 answer = scan_for_syscall_table(P, B, L);
1180 check_result(answer, "pattern scan");
1182 #ifdef OSI_PROBE_DEBUG
1183 return final_answer;
1189 void *osi_find_syscall_table(int which)
1195 if (which < 0 || which >= N_PROBE_LIST) {
1196 printk("error - afs_find_syscall_table called with invalid index!\n");
1199 P = probe_list[which];
1201 P->parm_answer = (void *)sys_call_table_addr[which];
1202 #ifdef OSI_PROBE_DEBUG
1203 P->debug_answer = (void *)probe_debug_addr[which];
1206 answer = do_find_syscall_table(P, &method);
1208 printk("Warning: failed to find address of %s\n", P->desc);
1209 printk("System call hooks will not be installed; proceeding anyway\n");
1212 printk("Found %s at 0x%lx (%s)\n", P->desc, (unsigned long)answer, method);
1217 #ifdef OSI_PROBE_STANDALONE
1218 int __init osi_probe_init(void)
1222 if (!probe_debug_tag) probe_debug_tag = jiffies;
1223 printk("*** osi_probe %ld debug = 0x%04x ***\n",
1224 probe_debug_tag, probe_debug);
1225 for (i = 0; i < N_PROBE_LIST; i++)
1226 (void)osi_find_syscall_table(i);
1230 void osi_probe_exit(void) { }
1232 module_init(osi_probe_init);
1233 module_exit(osi_probe_exit);
1237 void *osi_find_syscall_table(int which)
1241 #endif /* EXPORTED_INIT_MM */