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"
56 #include <linux/version.h>
57 #if defined(ENABLE_LINUX_SYSCALL_PROBING)
58 #include <linux/module.h> /* early to avoid printf->printk mapping */
59 #include <scsi/scsi.h> /* for scsi_command_size */
60 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26)
61 /* Slightly kludgy, but too bad */
62 #define scsi_command_size scsi_command_size_tbl
64 #ifndef OSI_PROBE_STANDALONE
65 # include "afs/sysincludes.h"
66 # include "afsincludes.h"
68 #include <linux/sched.h>
69 #ifdef HAVE_LINUX_CONFIG_H
70 # include <linux/config.h>
72 #include <linux/linkage.h>
73 #include <linux/init.h>
74 #include <linux/unistd.h>
77 #if defined(AFS_PPC64_LINUX26_ENV)
78 # include <asm/abs_addr.h>
81 #ifdef AFS_AMD64_LINUX20_ENV
82 # include <asm/ia32_unistd.h>
85 /* number of syscalls */
86 /* NB: on MIPS we care about the 4xxx range */
88 #define NR_syscalls 222
91 /* lower bound of valid kernel text pointers */
92 #ifdef AFS_IA64_LINUX20_ENV
93 #define ktxt_lower_bound (((unsigned long)&kernel_thread ) & 0xfff00000L)
94 #elif defined(AFS_PPC64_LINUX20_ENV)
95 #define ktxt_lower_bound (KERNELBASE)
97 #define ktxt_lower_bound (((unsigned long)&kernel_thread ) & ~0xfffffL)
100 /* On SPARC64 and S390X, sys_call_table contains 32-bit entries
101 * even though pointers are 64 bit quantities.
103 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390X_LINUX24_ENV)
104 #define SYSCALLTYPE unsigned int
105 #define PROBETYPE int
107 #define SYSCALLTYPE void *
108 #define PROBETYPE long
111 #if defined(AFS_S390X_LINUX20_ENV) && !defined(AFS_S390X_LINUX26_ENV)
112 #define _SS(x) ((x) << 1)
113 #define _SX(x) ((x) &~ 1)
119 /* Older Linux doesn't have __user. The sys_read prototype needs it. */
124 /* Allow the user to specify sys_call_table addresses */
125 static unsigned long sys_call_table_addr
[4] = { 0,0,0,0 };
126 #if defined(module_param_array) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
127 module_param_array(sys_call_table_addr
, long, NULL
, 0);
129 MODULE_PARM(sys_call_table_addr
, "1-4l");
131 MODULE_PARM_DESC(sys_call_table_addr
, "Location of system call tables");
133 /* If this is set, we are more careful about avoiding duplicate matches */
134 static int probe_carefully
= 1;
135 #if defined(module_param) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
136 module_param(probe_carefully
, int, 0);
138 MODULE_PARM(probe_carefully
, "i");
140 MODULE_PARM_DESC(probe_carefully
, "Probe for system call tables carefully");
142 static int probe_ignore_syscalls
[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
143 #if defined(module_param_array) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
144 module_param_array(probe_ignore_syscalls
, int, NULL
, 0);
146 MODULE_PARM(probe_ignore_syscalls
, "1-8i");
148 MODULE_PARM_DESC(probe_ignore_syscalls
, "Syscalls to ignore in table checks");
150 #ifdef OSI_PROBE_DEBUG
153 * 0x0001 - General debugging
154 * 0x0002 - detail - try
155 * 0x0004 - detail - try_harder
156 * 0x0008 - detail - check_table
157 * 0x0010 - detail - check_harder
158 * 0x0020 - detail - check_harder/zapped
159 * 0x0040 - automatically ignore setgroups and afs_syscall
160 * 0x0080 - detail - check_table_readable
162 static int probe_debug
= 0x41;
163 #if defined(module_param) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
164 module_param(probe_debug
, int, 0);
166 MODULE_PARM(probe_debug
, "i");
168 MODULE_PARM_DESC(probe_debug
, "Debugging level");
170 static unsigned long probe_debug_addr
[4] = { 0,0,0,0 };
171 #if defined(module_param_array) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
172 module_param_array(probe_debug_addr
, long, NULL
, 0);
174 MODULE_PARM(probe_debug_addr
, "1-4l");
176 MODULE_PARM_DESC(probe_debug_addr
, "Debug range starting locations");
178 static unsigned long probe_debug_range
= 0;
179 #if defined(module_param) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
180 module_param(probe_debug_range
, long, 0);
182 MODULE_PARM(probe_debug_range
, "l");
184 MODULE_PARM_DESC(probe_debug_range
, "Debug range length");
186 static unsigned long probe_debug_tag
= 0;
187 #if defined(module_param) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
188 module_param(probe_debug_tag
, long, 0);
190 MODULE_PARM(probe_debug_tag
, "l");
192 MODULE_PARM_DESC(probe_debug_tag
, "Debugging output start tag");
196 /* Weak references are our friends. They are supported by the in-kernel
197 * linker in Linux 2.6 and by all versions of modutils back to 2.2pre1.
198 * A weak reference not satisified by the kernel will have value zero.
200 * Unfortunately, weak references to functions don't work right on
201 * IA64; specifically, if you actually try to make a call through
202 * such a reference, and the symbol doesn't exist in the kernel, then
203 * the module relocation code will oops. A workaround for this is
204 * probably possible, but the use of kallsyms_* is of limited value,
205 * so I'm not bothing with the effort for now.
206 * -- jhutz, 10-Feb-2005
208 #ifdef OSI_PROBE_KALLSYMS
209 extern int kallsyms_symbol_to_address(char *name
, unsigned long *token
,
211 unsigned long *mod_start
,
212 unsigned long *mod_end
,
214 unsigned long *sec_start
,
215 unsigned long *sec_end
,
217 unsigned long *sym_start
,
218 unsigned long *sym_end
219 ) __attribute__((weak
));
221 extern int kallsyms_address_to_symbol(unsigned long address
,
223 unsigned long *mod_start
,
224 unsigned long *mod_end
,
226 unsigned long *sec_start
,
227 unsigned long *sec_end
,
229 unsigned long *sym_start
,
230 unsigned long *sym_end
231 ) __attribute__((weak
));
234 extern SYSCALLTYPE sys_call_table
[] __attribute__((weak
));
235 extern SYSCALLTYPE ia32_sys_call_table
[] __attribute__((weak
));
236 extern SYSCALLTYPE sys_call_table32
[] __attribute__((weak
));
237 extern SYSCALLTYPE sys_call_table_emu
[] __attribute__((weak
));
239 extern asmlinkage ssize_t
sys_read(unsigned int fd
, char __user
* buf
, size_t count
) __attribute__((weak
));
240 extern asmlinkage
long sys_close(unsigned int) __attribute__((weak
));
241 #if defined(EXPORTED_SYS_CHDIR)
242 extern asmlinkage
long sys_chdir(const char *) __attribute__((weak
));
244 extern asmlinkage ssize_t
sys_write(unsigned int, const char *, size_t) __attribute__((weak
));
245 extern asmlinkage
long sys_wait4(pid_t
, int *, int, struct rusage
*) __attribute__((weak
));
246 extern asmlinkage
long sys_exit (int) __attribute__((weak
));
247 #if defined(EXPORTED_SYS_OPEN)
248 extern asmlinkage
long sys_open (const char *, int, int) __attribute__((weak
));
250 extern asmlinkage
long sys_ioctl(unsigned int, unsigned int, unsigned long) __attribute__((weak
));
253 /* Structures used to control probing. We put all the details of which
254 * symbols we're interested in, what syscall functions to look for, etc
255 * into tables, so we can then have a single copy of the functions that
256 * actually do the work.
269 char *symbol
; /* symbol name */
270 char *desc
; /* description for messages */
271 int offset
; /* first syscall number in table */
273 void *weak_answer
; /* weak symbol ref */
274 void *parm_answer
; /* module parameter answer */
275 void *debug_answer
; /* module parameter answer */
276 unsigned long given_answer
; /* compiled-in answer, if any */
278 tryctl
*trylist
; /* array of combinations to try */
280 unsigned long try_sect_sym
; /* symbol in section to try scanning */
281 unsigned long try_base
; /* default base address for scan */
282 unsigned long try_base_mask
; /* base address bits to force to zero */
283 unsigned long try_length
; /* default length for scan */
285 unsigned long alt_try_sect_sym
; /* symbol in section to try scanning */
286 unsigned long alt_try_base
; /* default base address for scan */
287 unsigned long alt_try_base_mask
; /* base address bits to force to zero */
288 unsigned long alt_try_length
; /* default length for scan */
290 int n_zapped_syscalls
; /* number of unimplemented system calls */
291 int *zapped_syscalls
; /* list of unimplemented system calls */
293 int n_unique_syscalls
; /* number of unique system calls */
294 int *unique_syscalls
; /* list of unimplemented system calls */
296 int verifyNR
; /* syscall number to verify match */
297 void *verify_fn
; /* syscall pointer to verify match */
299 int debug_ignore_NR
[4]; /* syscalls to ignore for debugging */
302 #if defined(AFS_I386_LINUX26_ENV) || defined(AFS_AMD64_LINUX26_ENV)
303 static int check_access(unsigned long, int);
304 static int check_table_readable(probectl
*, PROBETYPE
*);
308 /********** Probing Configuration: sys_call_table **********/
310 /* syscall pairs/triplets to probe */
311 /* On PPC64 and SPARC64, we need to omit the ones that might match both tables */
312 static tryctl main_try
[] = {
313 #if !defined(AFS_PPC64_LINUX20_ENV) && !defined(AFS_SPARC64_LINUX20_ENV)
314 #if defined(EXPORTED_SYS_CHDIR)
315 { "scan: close+chdir+write", __NR_close
, &sys_close
, __NR_chdir
, &sys_chdir
, __NR_write
, &sys_write
},
318 { "scan: close+wait4", __NR_close
, &sys_close
, __NR_wait4
, &sys_wait4
, -1, 0 },
319 #if !defined(AFS_PPC64_LINUX20_ENV) && !defined(AFS_SPARC64_LINUX20_ENV)
320 #if defined(EXPORTED_SYS_CHDIR)
321 { "scan: close+chdir", __NR_close
, &sys_close
, __NR_chdir
, &sys_chdir
, -1, 0 },
324 { "scan: close+ioctl", __NR_close
, &sys_close
, __NR_ioctl
, &sys_ioctl
, -1, 0 },
325 #if defined(EXPORTED_SYS_OPEN)
326 { "scan: exit+open", __NR_exit
, &sys_exit
, __NR_open
, &sys_open
, -1, 0 },
331 /* zapped syscalls for try_harder */
332 /* this list is based on the table in 'zapped_syscalls' */
334 static int main_zapped_syscalls
[] = {
336 * SPARC-Linux uses syscall number mappings chosen to be compatible
337 * with SunOS. So, it doesn't have any of the traditional calls or
338 * the new STREAMS ones. However, there are a number of syscalls
339 * which are SunOS-specific (not implemented on Linux), i386-specific
340 * (not implemented on SPARC-Linux), or implemented only on one of
341 * sparc32 or sparc64. Of course, there are no __NR macros for most
344 * Note that the calls we list here are implemented by sys_nis_syscall,
345 * not by sys_ni_syscall. That means we have to exclude all of the
346 * other entries, or we might get a sys_ni_syscall into the list and
347 * the test would no longer work.
349 #if defined(AFS_SPARC64_LINUX20_ENV)
350 /* mmap2, fstat64, getmsg, putmsg, modify_ldt */
351 56, 63, 151, 152, 218,
352 #elif defined(AFS_SPARC_LINUX20_ENV)
353 /* memory_ordering, getmsg, putmsg, unimplemented, modify_ldt */
354 52, 151, 152, 164, 218,
355 #else /* !AFS_SPARC_LINUX20_ENV */
358 * These 7 syscalls are present in the syscall table on most "older"
359 * platforms that use the traditional syscall number mappings. They
360 * are not implemented on any platform.
384 * On s390 and arm (but not arm26), the seven traditional unimplemented
385 * system calls are indeed present and unimplemented. However, the
386 * corresponding __NR macros are not defined, so the tests above fail.
387 * Instead, we just have to know the numbers for these.
389 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
390 /* break, stty, gtty, ftime, prof, lock, mpx */
391 17, 31, 32, 35, 44, 53, 56,
395 * Sadly, some newer platforms like IA64, amd64, and PA-RISC don't have
396 * the traditional numbers, so the list above are not helpful. They
397 * do have entries for getpmsg/putpmsg, which are always unimplemented.
407 * The module-loading mechanism changed in Linux 2.6, and insmod's
408 * loss is our gain: three new unimplemented system calls!
413 #ifdef __NR_query_module
416 #ifdef __NR_get_kernel_syms
417 __NR_get_kernel_syms
,
421 * On IA64, the old module-loading calls are indeed present and
422 * unimplemented, but the __NR macros are not defined. Again,
423 * we simply have to know their numbers.
425 #ifdef AFS_IA64_LINUX26_ENV
426 /* create_module, query_module, get_kernel_sysms */
430 /* And the same deal for arm (not arm26), if we ever support that. */
432 /* create_module, query_module, get_kernel_sysms */
437 * Alpha-Linux uses syscall number mappings chosen to be compatible
438 * with OSF/1. So, it doesn't have any of the traditional calls or
439 * the new STREAMS ones, but it does have several OSF/1-specific
440 * syscalls which are not implemented on Linux. These don't exist on
441 * any other platform.
443 #ifdef __NR_osf_syscall
446 #ifdef __NR_osf_profil
449 #ifdef __NR_osf_reboot
452 #ifdef __NR_osf_kmodcall
455 #ifdef __NR_osf_old_vtrace
460 * On PPC64, we need a couple more entries to distinguish the two
461 * tables, since the system call numbers are the same and the sets of
462 * unimplemented calls are very similar.
463 * mmap2 and fstat64 are implemented only for 32-bit calls
465 #ifdef AFS_PPC64_LINUX20_ENV
466 /* _mmap2, _fstat64 */
468 #endif /* AFS_PPC64_LINUX20_ENV */
470 /* Similarly for S390X, with lcown16 and fstat64 */
471 #ifdef AFS_S390X_LINUX20_ENV
472 /* lchown16, fstat64 */
475 #endif /* !AFS_SPARC_LINUX20_ENV */
479 /* unique syscalls for try_harder */
480 static int main_unique_syscalls
[] = {
481 #if defined(AFS_SPARC64_LINUX24_ENV) || defined(AFS_SPARC_LINUX24_ENV)
483 * On SPARC, we need some additional unique calls to make sure
484 * we don't match the SunOS-compatibility table.
486 __NR_sgetmask
, __NR_ssetmask
,
488 __NR_exit
, __NR_mount
, __NR_read
, __NR_write
,
489 __NR_open
, __NR_close
, __NR_unlink
492 /* probe control structure */
493 static probectl main_probe
= {
494 /* symbol name and description */
498 /* syscall number of first entry in table */
499 #ifdef AFS_IA64_LINUX20_ENV
505 sys_call_table
, /* weak symbol ref */
506 0, 0, /* module parameter answers */
507 #ifdef AFS_LINUX_sys_call_table
508 AFS_LINUX_sys_call_table
, /* compiled-in answer, if any */
513 main_try
, /* array of combinations to try */
515 /* symbol in section to try scanning */
516 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
517 (unsigned long)&sys_close
,
518 #elif defined(AFS_AMD64_LINUX26_ENV)
519 /* On this platform, it's in a different section! */
520 (unsigned long)&generic_ro_fops
,
522 (unsigned long)&init_mm
,
525 /* default base address for scan */
526 /* base address bits to force to zero */
527 /* default length for scan */
528 #if defined(AFS_SPARC64_LINUX20_ENV)
529 (unsigned long)(&sys_close
),
532 #elif defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
533 /* bleah; this is so suboptimal */
534 (unsigned long)(&sys_close
),
537 #elif defined(AFS_IA64_LINUX20_ENV)
538 (unsigned long)(&init_mm
),
541 #elif defined(AFS_AMD64_LINUX26_ENV)
542 (unsigned long)(&generic_ro_fops
) - 0x30000,
545 #elif defined(AFS_PPC64_LINUX26_ENV)
546 (unsigned long)(&do_signal
),
550 (unsigned long)&init_mm
,
555 (unsigned long)scsi_command_size
,
556 (unsigned long)scsi_command_size
- 0x10000,
560 /* number and list of unimplemented system calls */
561 ((sizeof(main_zapped_syscalls
)/sizeof(main_zapped_syscalls
[0])) - 1),
562 main_zapped_syscalls
,
564 /* number and list of unique system calls */
565 (sizeof(main_unique_syscalls
)/sizeof(main_unique_syscalls
[0])),
566 main_unique_syscalls
,
568 /* syscall number and pointer to verify match */
569 __NR_close
, &sys_close
,
571 /* syscalls to ignore for debugging */
573 #if defined(AFS_ALPHA_LINUX20_ENV)
575 #elif defined(AFS_AMD64_LINUX20_ENV)
577 #elif defined(AFS_IA64_LINUX20_ENV)
579 #elif defined(AFS_SPARC_LINUX20_ENV) || defined(AFS_SPARC64_LINUX20_ENV)
585 #ifdef __NR_setgroups32
595 /********** Probing Configuration: amd64 ia32_sys_call_table **********/
596 #if defined(AFS_AMD64_LINUX20_ENV)
598 /* syscall pairs/triplets to probe */
599 static tryctl ia32_try
[] = {
600 #if defined(EXPORTED_SYS_CHDIR)
601 { "scan: close+chdir+write", __NR_ia32_close
, &sys_close
, __NR_ia32_chdir
, &sys_chdir
, __NR_ia32_write
, &sys_write
},
602 { "scan: close+chdir", __NR_ia32_close
, &sys_close
, __NR_ia32_chdir
, &sys_chdir
, -1, 0 },
607 /* zapped syscalls for try_harder */
608 static int ia32_zapped_syscalls
[] = {
609 __NR_ia32_break
, __NR_ia32_stty
, __NR_ia32_gtty
, __NR_ia32_ftime
,
610 __NR_ia32_prof
, __NR_ia32_lock
, __NR_ia32_mpx
,
614 /* unique syscalls for try_harder */
615 static int ia32_unique_syscalls
[] = {
616 __NR_ia32_exit
, __NR_ia32_mount
, __NR_ia32_read
, __NR_ia32_write
,
617 __NR_ia32_open
, __NR_ia32_close
, __NR_ia32_unlink
620 /* probe control structure */
621 static probectl ia32_probe
= {
622 /* symbol name and description */
623 "ia32_sys_call_table",
624 "32-bit system call table",
626 /* syscall number of first entry in table */
629 ia32_sys_call_table
, /* weak symbol ref */
630 0, 0, /* module parameter answers */
631 #ifdef AFS_LINUX_ia32_sys_call_table
632 AFS_LINUX_ia32_sys_call_table
,/* compiled-in answer, if any */
637 ia32_try
, /* array of combinations to try */
639 /* symbol in section to try scanning */
640 (unsigned long)&init_mm
,
642 /* default base address for scan */
643 /* base address bits to force to zero */
644 /* default length for scan */
645 (unsigned long)&init_mm
,
647 (0x180000 / sizeof(unsigned long *)),
649 (unsigned long)scsi_command_size
,
650 (unsigned long)scsi_command_size
- 0x10000,
655 /* number and list of unimplemented system calls */
656 ((sizeof(ia32_zapped_syscalls
)/sizeof(ia32_zapped_syscalls
[0])) - 1),
657 ia32_zapped_syscalls
,
659 /* number and list of unique system calls */
660 (sizeof(ia32_unique_syscalls
)/sizeof(ia32_unique_syscalls
[0])),
661 ia32_unique_syscalls
,
663 /* syscall number and pointer to verify match */
664 __NR_ia32_close
, &sys_close
,
666 /* syscalls to ignore for debugging */
670 __NR_ia32_setgroups32
,
675 static probectl
*probe_list
[] = {
676 &main_probe
, &ia32_probe
680 /********** Probing Configuration: IA64 **********/
681 #elif defined(AFS_IA64_LINUX20_ENV)
687 /* no 32-bit support on IA64 for now */
688 static probectl
*probe_list
[] = {
693 /********** Probing Configuration: ppc64, sparc64 sys_call_table32 **********/
694 #elif defined(AFS_PPC64_LINUX20_ENV) || defined(AFS_SPARC64_LINUX20_ENV)
701 * syscall pairs/triplets to probe
702 * This has to be empty, because anything that would work will
703 * also match the main table, and that's no good.
705 static tryctl sct32_try
[] = {
709 /* zapped syscalls for try_harder */
710 static int sct32_zapped_syscalls
[] = {
711 #ifdef AFS_PPC64_LINUX20_ENV
712 /* These should be sufficient */
713 __NR_break
, __NR_stty
, __NR_gtty
, __NR_ftime
,
714 __NR_prof
, __NR_lock
, __NR_mpx
,
716 #ifdef AFS_SPARC64_LINUX20_ENV
717 /* memory_ordering, getmsg, putmsg, unimplemented, modify_ldt */
718 52, 151, 152, 164, 218,
723 /* unique syscalls for try_harder */
724 /* mmap2 and fstat64 are implemented only for 32-bit calls */
725 static int sct32_unique_syscalls
[] = {
726 #ifdef AFS_PPC64_LINUX20_ENV
727 /* _mmap2, _fstat64 */
730 #ifdef AFS_SPARC64_LINUX24_ENV
732 * On SPARC, we need some additional unique calls to make sure
733 * we don't match the SunOS-compatibility table.
735 __NR_sgetmask
, __NR_ssetmask
,
737 __NR_exit
, __NR_mount
, __NR_read
, __NR_write
,
738 __NR_open
, __NR_close
, __NR_unlink
741 /* probe control structure */
742 static probectl sct32_probe
= {
743 /* symbol name and description */
745 "32-bit system call table",
747 /* syscall number of first entry in table */
750 sys_call_table32
, /* weak symbol ref */
751 0, 0, /* module parameter answers */
752 #ifdef AFS_LINUX_sys_call_table32
753 AFS_LINUX_sys_call_table32
, /* compiled-in answer, if any */
758 sct32_try
, /* array of combinations to try */
760 /* symbol in section to try scanning */
761 #if defined(AFS_SPARC64_LINUX20_ENV)
762 (unsigned long)&sys_close
,
764 (unsigned long)&init_mm
,
767 /* default base address for scan */
768 /* base address bits to force to zero */
769 /* default length for scan */
770 #if defined(AFS_SPARC64_LINUX20_ENV)
771 (unsigned long)(&sys_close
),
774 #elif defined(AFS_PPC64_LINUX26_ENV)
775 (unsigned long)(&do_signal
),
779 (unsigned long)&init_mm
,
784 (unsigned long)scsi_command_size
,
785 (unsigned long)scsi_command_size
- 0x10000,
789 /* number and list of unimplemented system calls */
790 ((sizeof(sct32_zapped_syscalls
)/sizeof(sct32_zapped_syscalls
[0])) - 1),
791 sct32_zapped_syscalls
,
793 /* number and list of unique system calls */
794 (sizeof(sct32_unique_syscalls
)/sizeof(sct32_unique_syscalls
[0])),
795 sct32_unique_syscalls
,
797 /* syscall number and pointer to verify match */
798 __NR_close
, &sys_close
,
800 /* syscalls to ignore for debugging */
802 #if defined(AFS_SPARC64_LINUX20_ENV)
813 static probectl
*probe_list
[] = {
814 &main_probe
, &sct32_probe
818 /********** Probing Configuration: s390x sys_call_table_emu **********/
819 /* We only actually need to do this on s390x_linux26 and later.
820 * On earlier versions, the two tables were interleaved and so
821 * have related base addresses.
823 #elif defined(AFS_S390X_LINUX26_ENV)
825 /* syscall pairs/triplets to probe */
826 /* nothing worthwhile is exported, so this is empty */
827 static tryctl emu_try
[] = {
831 /* zapped syscalls for try_harder */
832 static int emu_zapped_syscalls
[] = {
833 /* break, stty, gtty, ftime, prof, lock, mpx */
834 17, 31, 32, 35, 44, 53, 56,
838 /* unique syscalls for try_harder */
839 static int emu_unique_syscalls
[] = {
840 /* lchown16, fstat64 */
842 __NR_exit
, __NR_mount
, __NR_read
, __NR_write
,
843 __NR_open
, __NR_close
, __NR_unlink
846 /* probe control structure */
847 static probectl emu_probe
= {
848 /* symbol name and description */
849 "sys_call_table_emu",
850 "32-bit system call table",
852 /* syscall number of first entry in table */
855 sys_call_table_emu
, /* weak symbol ref */
856 0, 0, /* module parameter answers */
857 #ifdef AFS_LINUX_sys_call_table_emu
858 AFS_LINUX_sys_call_table_emu
, /* compiled-in answer, if any */
863 emu_try
, /* array of combinations to try */
865 /* symbol in section to try scanning */
866 (unsigned long)&sys_close
,
868 /* default base address for scan */
869 /* base address bits to force to zero */
870 /* default length for scan */
871 (unsigned long)&sys_close
,
875 (unsigned long)scsi_command_size
,
876 (unsigned long)scsi_command_size
- 0x10000,
880 /* number and list of unimplemented system calls */
881 ((sizeof(emu_zapped_syscalls
)/sizeof(emu_zapped_syscalls
[0])) - 1),
884 /* number and list of unique system calls */
885 (sizeof(emu_unique_syscalls
)/sizeof(emu_unique_syscalls
[0])),
888 /* syscall number and pointer to verify match */
889 __NR_close
, &sys_close
,
891 /* syscalls to ignore for debugging */
900 static probectl
*probe_list
[] = {
901 &main_probe
, &emu_probe
905 /********** End of Probing Configuration **********/
907 #else /* no per-platform probe control, so use the default list */
908 static probectl
*probe_list
[] = {
913 #define N_PROBE_LIST (sizeof(probe_list) / sizeof(*probe_list))
914 #define DEBUG_IN_RANGE(P,x) (!probe_debug_range || \
915 (P->debug_answer && \
916 (unsigned long)(x) >= (unsigned long)P->debug_answer && \
917 (unsigned long)(x) < (unsigned long)P->debug_answer + probe_debug_range))
921 static int check_table(probectl
*P
, PROBETYPE
*ptr
)
926 #if defined(AFS_I386_LINUX26_ENV) || defined(AFS_AMD64_LINUX26_ENV)
927 i
= check_table_readable(P
, ptr
);
928 if (i
>= 0) return i
;
931 for (x
= ptr
, i
= 0; i
< _SS(NR_syscalls
); i
++, x
++) {
932 #ifdef OSI_PROBE_DEBUG
933 if (probe_debug
& 0x0040) {
934 for (j
= 0; j
< 4; j
++) {
935 if (_SS(P
->debug_ignore_NR
[j
]) == _SX(i
+ P
->offset
)) break;
940 for (j
= 0; j
< 8; j
++) {
941 if (_SS(probe_ignore_syscalls
[j
]) == _SX(i
) + P
->offset
) break;
944 if (*x
<= ktxt_lower_bound
) {
945 #ifdef OSI_PROBE_DEBUG
946 if ((probe_debug
& 0x0008) && DEBUG_IN_RANGE(P
,ptr
))
947 printk("<7>check 0x%lx -> %d [0x%lx]\n",
948 (unsigned long)ptr
, i
, (unsigned long)*x
);
953 #ifdef OSI_PROBE_DEBUG
954 if ((probe_debug
& 0x0008) && DEBUG_IN_RANGE(P
,ptr
))
955 printk("<7>check 0x%lx -> ok\n", (unsigned long)ptr
);
960 static void *try(probectl
*P
, tryctl
*T
, PROBETYPE
*aptr
,
961 unsigned long datalen
)
963 #ifdef OSI_PROBE_KALLSYMS
964 char *mod_name
, *sec_name
, *sym_name
;
965 unsigned long mod_start
, mod_end
;
966 unsigned long sec_start
, sec_end
;
967 unsigned long sym_start
, sym_end
;
969 unsigned long offset
, ip1
, ip2
, ip3
;
973 #if defined(AFS_IA64_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV)
974 ip1
= T
->fn1
? (unsigned long)((struct fptr
*)T
->fn1
)->ip
: 0;
975 ip2
= T
->fn2
? (unsigned long)((struct fptr
*)T
->fn2
)->ip
: 0;
976 ip3
= T
->fn3
? (unsigned long)((struct fptr
*)T
->fn3
)->ip
: 0;
978 ip1
= (unsigned long)T
->fn1
;
979 ip2
= (unsigned long)T
->fn2
;
980 ip3
= (unsigned long)T
->fn3
;
983 #ifdef OSI_PROBE_DEBUG
984 if (probe_debug
& 0x0001)
985 printk("<7>osi_probe: %s %s (%d->0x%lx, %d->0x%lx, %d->0x%lx)\n",
986 P
->symbol
, T
->name
, T
->NR1
, ip1
, T
->NR2
, ip2
, T
->NR3
, ip3
);
989 if (!ip1
|| !ip2
|| (T
->NR3
>= 0 && !ip3
))
992 for (offset
= 0; offset
< datalen
; offset
++, aptr
++) {
993 #if defined(AFS_PPC64_LINUX20_ENV)
994 ptr
= (PROBETYPE
*)(*aptr
);
995 if ((unsigned long)ptr
<= KERNELBASE
) {
1001 if ((unsigned long)ptr
< init_mm
.start_code
||
1002 #if defined(AFS_AMD64_LINUX20_ENV)
1003 (unsigned long)ptr
> init_mm
.brk
)
1005 (unsigned long)ptr
> init_mm
.end_data
)
1008 /* printk("address 0x%lx (from 0x%lx %d) is out of range in check_table. wtf?\n", (unsigned long)x, (unsigned long)ptr, i);*/
1012 ret
= check_table(P
, ptr
);
1014 /* return value is number of entries to skip */
1020 #ifdef OSI_PROBE_DEBUG
1021 if ((probe_debug
& 0x0002) && DEBUG_IN_RANGE(P
,ptr
))
1022 printk("<7>try 0x%lx\n", (unsigned long)ptr
);
1024 if (ptr
[_SS(T
->NR1
- P
->offset
)] != ip1
) continue;
1025 if (ptr
[_SS(T
->NR2
- P
->offset
)] != ip2
) continue;
1026 if (ip3
&& ptr
[_SS(T
->NR3
- P
->offset
)] != ip3
) continue;
1028 #ifdef OSI_PROBE_DEBUG
1029 if (probe_debug
& 0x0002)
1030 printk("<7>try found 0x%lx\n", (unsigned long)ptr
);
1032 #ifdef OSI_PROBE_KALLSYMS
1033 if (kallsyms_address_to_symbol
) {
1034 ret
= kallsyms_address_to_symbol((unsigned long)ptr
,
1035 &mod_name
, &mod_start
, &mod_end
,
1036 &sec_name
, &sec_start
, &sec_end
,
1037 &sym_name
, &sym_start
, &sym_end
);
1038 if (!ret
|| strcmp(sym_name
, P
->symbol
)) continue;
1041 /* XXX should we make sure there is only one match? */
1048 static int check_harder(probectl
*P
, PROBETYPE
*p
)
1053 #if defined(AFS_I386_LINUX26_ENV) || defined(AFS_AMD64_LINUX26_ENV)
1054 i
= check_table_readable(P
, p
);
1055 if (i
>= 0) return 0;
1058 /* Check zapped syscalls */
1059 for (i
= 1; i
< P
->n_zapped_syscalls
; i
++) {
1060 if (p
[_SS(P
->zapped_syscalls
[i
])] != p
[_SS(P
->zapped_syscalls
[0])]) {
1061 #ifdef OSI_PROBE_DEBUG
1062 if ((probe_debug
& 0x0020) && DEBUG_IN_RANGE(P
,p
))
1063 printk("<7>check_harder 0x%lx zapped failed i=%d\n", (unsigned long)p
, i
);
1069 /* Check unique syscalls */
1070 for (i
= 0; i
< P
->n_unique_syscalls
; i
++) {
1071 for (s
= 0; s
< NR_syscalls
; s
++) {
1072 if (p
[_SS(s
)] == p
[_SS(P
->unique_syscalls
[i
])]
1073 && s
!= P
->unique_syscalls
[i
]) {
1074 #ifdef OSI_PROBE_DEBUG
1075 if ((probe_debug
& 0x0010) && DEBUG_IN_RANGE(P
,p
))
1076 printk("<7>check_harder 0x%lx unique failed i=%d s=%d\n", (unsigned long)p
, i
, s
);
1083 #if defined(AFS_IA64_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV)
1084 ip1
= P
->verify_fn
? (unsigned long)((struct fptr
*)(P
->verify_fn
))->ip
: 0;
1086 ip1
= (unsigned long)(P
->verify_fn
);
1089 if (ip1
&& p
[_SS(P
->verifyNR
- P
->offset
)] != ip1
) {
1090 #ifdef OSI_PROBE_DEBUG
1091 if ((probe_debug
& 0x0010) && DEBUG_IN_RANGE(P
,p
))
1092 printk("<7>check_harder 0x%lx verify failed\n", (unsigned long)p
);
1097 #ifdef OSI_PROBE_DEBUG
1098 if ((probe_debug
& 0x0010) && DEBUG_IN_RANGE(P
,p
))
1099 printk("<7>check_harder 0x%lx success!\n", (unsigned long)p
);
1104 static void *try_harder(probectl
*P
, PROBETYPE
*ptr
, unsigned long datalen
)
1106 #ifdef OSI_PROBE_KALLSYMS
1107 char *mod_name
, *sec_name
, *sym_name
;
1108 unsigned long mod_start
, mod_end
;
1109 unsigned long sec_start
, sec_end
;
1110 unsigned long sym_start
, sym_end
;
1112 unsigned long offset
;
1116 #ifdef OSI_PROBE_DEBUG
1117 if (probe_debug
& 0x0001)
1118 printk("<7>osi_probe: %s try_harder\n", P
->symbol
);
1120 for (offset
= 0; offset
< datalen
; offset
++, ptr
++) {
1121 if ((unsigned long)ptr
< init_mm
.start_code
||
1122 #if defined(AFS_AMD64_LINUX20_ENV)
1123 (unsigned long)ptr
> init_mm
.brk
)
1125 (unsigned long)ptr
> init_mm
.end_data
)
1128 /* printk("address 0x%lx (from 0x%lx %d) is out of range in check_table. wtf?\n", (unsigned long)x, (unsigned long)ptr, i);*/
1131 ret
= check_table(P
, ptr
);
1133 /* return value is number of entries to skip */
1139 #ifdef OSI_PROBE_DEBUG
1140 if ((probe_debug
& 0x0004) && DEBUG_IN_RANGE(P
,ptr
))
1141 printk("<7>try_harder 0x%lx\n", (unsigned long)ptr
);
1143 if (!check_harder(P
, ptr
))
1146 #ifdef OSI_PROBE_DEBUG
1147 if (probe_debug
& 0x0004)
1148 printk("<7>try_harder found 0x%lx\n", (unsigned long)ptr
);
1151 #ifdef OSI_PROBE_KALLSYMS
1152 if (kallsyms_address_to_symbol
) {
1153 ret
= kallsyms_address_to_symbol((unsigned long)ptr
,
1154 &mod_name
, &mod_start
, &mod_end
,
1155 &sec_name
, &sec_start
, &sec_end
,
1156 &sym_name
, &sym_start
, &sym_end
);
1157 if (!ret
|| strcmp(sym_name
, P
->symbol
)) continue;
1162 #ifdef OSI_PROBE_DEBUG
1163 if (probe_debug
& 0x0005)
1164 printk("<7>%s: try_harder found multiple matches!\n", P
->symbol
);
1169 match
= (void *)ptr
;
1170 if (!probe_carefully
)
1177 #ifdef OSI_PROBE_DEBUG
1178 #define check_result(x,m) do { \
1179 if (probe_debug & 0x0001) { \
1180 printk("<7>osi_probe: %s = 0x%016lx %s\n", P->symbol, (unsigned long)(x), (m)); \
1182 if ((x) && ((int)(x)) != -ENOENT) { \
1184 final_answer = (void *)(x); \
1188 #define check_result(x,m) do { \
1189 if ((x) && ((int)(x)) != -ENOENT) { \
1191 return (void *)(x); \
1195 static void *scan_for_syscall_table(probectl
*P
, PROBETYPE
*B
, unsigned long L
)
1199 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
1202 #ifdef OSI_PROBE_DEBUG
1203 void *final_answer
= 0;
1205 #ifdef OSI_PROBE_DEBUG
1206 if (probe_debug
& 0x0007)
1207 printk("<7>osi_probe: %s base=0x%lx, len=0x%lx\n",
1208 P
->symbol
, (unsigned long)B
, L
);
1209 if (probe_debug
& 0x0009) {
1210 printk("<7>osi_probe: %s ktxt_lower_bound=0x%lx\n",
1211 P
->symbol
, ktxt_lower_bound
);
1212 printk("<7>osi_probe: %s NR_syscalls=%d\n",
1213 P
->symbol
, NR_syscalls
);
1217 for (T
= P
->trylist
; T
->name
; T
++) {
1218 answer
= try(P
, T
, B
, L
);
1219 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
1220 answer2
= try(P
, T
, (PROBETYPE
*)(2 + (void *)B
), L
);
1221 #ifdef OSI_PROBE_DEBUG
1222 if (probe_debug
& 0x0003) {
1223 printk("<7>osi_probe: %s = 0x%016lx %s (even)\n",
1224 P
->symbol
, (unsigned long)(answer
), T
->name
);
1225 printk("<7>osi_probe: %s = 0x%016lx %s (odd)\n",
1226 P
->symbol
, (unsigned long)(answer2
), T
->name
);
1229 if (answer
&& answer2
) answer
= 0;
1230 else if (answer2
) answer
= answer2
;
1236 /* XXX more checks here */
1238 answer
= try_harder(P
, B
, L
);
1239 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
1240 answer2
= try_harder(P
, (PROBETYPE
*)(2 + (void *)B
), L
);
1241 #ifdef OSI_PROBE_DEBUG
1242 if (probe_debug
& 0x0005) {
1243 printk("<7>osi_probe: %s = 0x%016lx pattern scan (even)\n",
1244 P
->symbol
, (unsigned long)(answer
));
1245 printk("<7>osi_probe: %s = 0x%016lx pattern scan (odd)\n",
1246 P
->symbol
, (unsigned long)(answer2
));
1249 if (answer
&& answer2
) answer
= 0;
1250 else if (answer2
) answer
= answer2
;
1255 static void *do_find_syscall_table(probectl
*P
, char **method
)
1257 #ifdef OSI_PROBE_KALLSYMS
1258 char *mod_name
, *sec_name
, *sym_name
;
1259 unsigned long mod_start
, mod_end
;
1260 unsigned long sec_start
, sec_end
;
1261 unsigned long sym_start
, sym_end
;
1262 unsigned long token
;
1268 #ifdef OSI_PROBE_DEBUG
1269 void *final_answer
= 0;
1272 *method
= "not found";
1274 /* if it's exported, there's nothing to do */
1275 check_result(P
->weak_answer
, "exported");
1277 /* ask the kernel to do the name lookup, if it's willing */
1278 #ifdef OSI_PROBE_KALLSYMS
1279 if (kallsyms_symbol_to_address
) {
1283 ret
= kallsyms_symbol_to_address(P
->symbol
, &token
,
1284 &mod_name
, &mod_start
, &mod_end
,
1285 &sec_name
, &sec_start
, &sec_end
,
1286 &sym_name
, &sym_start
, &sym_end
);
1287 if (ret
&& !strcmp(mod_name
, "kernel") && sym_start
)
1291 check_result(sym_start
, "kallsyms_symbol_to_address");
1295 /* Maybe a little birdie told us */
1296 check_result(P
->parm_answer
, "module parameter");
1297 check_result(P
->given_answer
, "compiled-in");
1299 /* OK, so we have to scan. */
1300 B
= (PROBETYPE
*)((P
->try_base
) & ~(P
->try_base_mask
));
1302 /* Now, see if the kernel will tell us something better than the default */
1303 #ifdef OSI_PROBE_KALLSYMS
1304 if (kallsyms_address_to_symbol
) {
1305 ret
= kallsyms_address_to_symbol(P
->try_sect_sym
,
1306 &mod_name
, &mod_start
, &mod_end
,
1307 &sec_name
, &sec_start
, &sec_end
,
1308 &sym_name
, &sym_start
, &sym_end
);
1310 B
= (PROBETYPE
*)sec_start
;
1311 L
= (sec_end
- sec_start
) / sizeof(unsigned long);
1316 answer
= scan_for_syscall_table(P
, B
, L
);
1317 check_result(answer
, "pattern scan");
1318 B
= (PROBETYPE
*)((P
->alt_try_base
) & ~(P
->alt_try_base_mask
));
1319 L
= P
->alt_try_length
;
1320 /* Now, see if the kernel will tell us something better than the default */
1321 #ifdef OSI_PROBE_KALLSYMS
1322 if (kallsyms_address_to_symbol
&& P
->alt_try_sect_sym
) {
1323 ret
= kallsyms_address_to_symbol(P
->alt_try_sect_sym
,
1324 &mod_name
, &mod_start
, &mod_end
,
1325 &sec_name
, &sec_start
, &sec_end
,
1326 &sym_name
, &sym_start
, &sym_end
);
1328 B
= (PROBETYPE
*)sec_start
;
1329 L
= (sec_end
- sec_start
) / sizeof(unsigned long);
1334 answer
= scan_for_syscall_table(P
, B
, L
);
1335 check_result(answer
, "pattern scan");
1337 #ifdef OSI_PROBE_DEBUG
1338 return final_answer
;
1344 #if defined(AFS_I386_LINUX26_ENV) || defined(AFS_AMD64_LINUX26_ENV)
1345 static int check_access(unsigned long address
, int mode
)
1347 pgd_t
*pgd
= pgd_offset_k(address
);
1357 pud
= pud_offset(pgd
, address
);
1360 pmd
= pmd_offset(pud
, address
);
1362 pmd
= pmd_offset(pgd
, address
);
1366 if (pmd_large(*pmd
))
1369 pte
= pte_offset_kernel(pmd
, address
);
1370 if (pte_none(*pte
) || !pte_present(*pte
))
1372 if (mode
&& !pte_write(*pte
))
1377 static int check_table_readable(probectl
*P
, PROBETYPE
*ptr
)
1379 PROBETYPE
*next_page
;
1382 while (i
< _SS(NR_syscalls
)) {
1383 next_page
= (PROBETYPE
*)PAGE_ALIGN((unsigned long)(ptr
+1));
1384 delta
= next_page
- ptr
;
1385 if (!check_access((unsigned long)ptr
, 0)) {
1386 #ifdef OSI_PROBE_DEBUG
1387 if (probe_debug
& 0x0080)
1388 printk("<7>osi_probe: %s 0x%016lx not readable; delta=0x%lx\n",
1389 P
->symbol
, (unsigned long)ptr
, delta
);
1400 void *osi_find_syscall_table(int which
)
1406 if (which
< 0 || which
>= N_PROBE_LIST
) {
1407 printk("error - afs_find_syscall_table called with invalid index!\n");
1410 P
= probe_list
[which
];
1412 P
->parm_answer
= (void *)sys_call_table_addr
[which
];
1413 #ifdef OSI_PROBE_DEBUG
1414 P
->debug_answer
= (void *)probe_debug_addr
[which
];
1417 answer
= do_find_syscall_table(P
, &method
);
1419 printk("Warning: failed to find address of %s\n", P
->desc
);
1420 printk("System call hooks will not be installed; proceeding anyway\n");
1423 printk("Found %s at 0x%lx (%s)\n", P
->desc
, (unsigned long)answer
, method
);
1424 #if defined(AFS_I386_LINUX26_ENV) || defined(AFS_AMD64_LINUX26_ENV)
1425 if (!check_access((unsigned long)answer
, 1)) {
1426 printk("Address 0x%lx is not writable.\n", (unsigned long)answer
);
1427 printk("System call hooks will not be installed; proceeding anyway\n");
1435 #ifdef OSI_PROBE_STANDALONE
1436 int __init
osi_probe_init(void)
1440 if (!probe_debug_tag
) probe_debug_tag
= jiffies
;
1441 printk("*** osi_probe %ld debug = 0x%04x ***\n",
1442 probe_debug_tag
, probe_debug
);
1443 for (i
= 0; i
< N_PROBE_LIST
; i
++)
1444 (void)osi_find_syscall_table(i
);
1448 void osi_probe_exit(void) { }
1450 module_init(osi_probe_init
);
1451 module_exit(osi_probe_exit
);
1455 void *osi_find_syscall_table(int which
)
1459 #endif /* EXPORTED_INIT_MM */