5f87b709e3a7a6f469151324c7adddbd3aa16269
[openafs.git] / src / afs / LINUX / osi_probe.c
1 /*
2  * vi:set cin noet sw=4 tw=70:
3  * Copyright 2004, International Business Machines Corporation and others.
4  * All Rights Reserved.
5  * 
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
9  *
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.
14  * 
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions
17  * are met:
18  * 
19  * 1. Redistributions of source code must retain the above copyright
20  *    notice, this list of conditions and the following disclaimer.
21  * 
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.
25  * 
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.
29  * 
30  * Alternatively, this software may be distributed under the terms of the
31  * GNU General Public License ("GPL").
32  * 
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
43  * SUCH DAMAGE.
44  */
45
46 /* Code to find the Linux syscall table */
47
48 #ifdef OSI_PROBE_STANDALONE
49 # define OSI_PROBE_DEBUG
50 #endif
51 #ifndef OSI_PROBE_STANDALONE
52 # include <afsconfig.h>
53 # include "afs/param.h"
54 #endif
55
56 #if defined(ENABLE_LINUX_SYSCALL_PROBING) && defined(EXPORTED_INIT_MM)
57 #include <linux/module.h> /* early to avoid printf->printk mapping */
58 #include <scsi/scsi.h> /* for scsi_command_size */
59 #ifndef OSI_PROBE_STANDALONE
60 # include "afs/sysincludes.h"
61 # include "afsincludes.h"
62 #endif
63 #include <linux/version.h>
64 #include <linux/sched.h>
65 #ifdef HAVE_LINUX_CONFIG_H
66 # include <linux/config.h>
67 #endif
68 #include <linux/linkage.h>
69 #include <linux/init.h>
70 #include <linux/unistd.h>
71 #include <linux/mm.h>
72
73 #if defined(AFS_PPC64_LINUX26_ENV)
74 # include <asm/abs_addr.h>
75 #endif
76
77 #ifdef AFS_AMD64_LINUX20_ENV
78 # include <asm/ia32_unistd.h>
79 #endif
80
81 /* number of syscalls */
82 /* NB: on MIPS we care about the 4xxx range */
83 #ifndef NR_syscalls
84 #define NR_syscalls 222
85 #endif
86
87 /* lower bound of valid kernel text pointers */
88 #ifdef AFS_IA64_LINUX20_ENV
89 #define ktxt_lower_bound (((unsigned long)&kernel_thread )  & 0xfff00000L)
90 #elif defined(AFS_PPC64_LINUX20_ENV)
91 #define ktxt_lower_bound (KERNELBASE)
92 #else
93 #define ktxt_lower_bound (((unsigned long)&kernel_thread )  & ~0xfffffL)
94 #endif
95
96 /* On SPARC64 and S390X, sys_call_table contains 32-bit entries
97  * even though pointers are 64 bit quantities.
98  */
99 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390X_LINUX24_ENV)
100 #define SYSCALLTYPE unsigned int
101 #define PROBETYPE int
102 #else
103 #define SYSCALLTYPE void *
104 #define PROBETYPE long
105 #endif
106
107 #if defined(AFS_S390X_LINUX20_ENV) && !defined(AFS_S390X_LINUX26_ENV) 
108 #define _SS(x) ((x) << 1)
109 #define _SX(x) ((x) &~ 1)
110 #else
111 #define _SS(x) (x)
112 #define _SX(x) (x)
113 #endif
114
115 /* Older Linux doesn't have __user. The sys_read prototype needs it. */
116 #ifndef __user
117 #define __user
118 #endif
119
120 /* Allow the user to specify sys_call_table addresses */
121 static unsigned long sys_call_table_addr[4] = { 0,0,0,0 };
122 #if defined(module_param_array) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
123 module_param_array(sys_call_table_addr, long, NULL, 0);
124 #else
125 MODULE_PARM(sys_call_table_addr, "1-4l");
126 #endif
127 MODULE_PARM_DESC(sys_call_table_addr, "Location of system call tables");
128
129 /* If this is set, we are more careful about avoiding duplicate matches */
130 static int probe_carefully = 1;
131 #if defined(module_param) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
132 module_param(probe_carefully, int, 0);
133 #else
134 MODULE_PARM(probe_carefully, "i");
135 #endif
136 MODULE_PARM_DESC(probe_carefully, "Probe for system call tables carefully");
137
138 static int probe_ignore_syscalls[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
139 #if defined(module_param_array) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
140 module_param_array(probe_ignore_syscalls, int, NULL, 0);
141 #else
142 MODULE_PARM(probe_ignore_syscalls, "1-8i");
143 #endif
144 MODULE_PARM_DESC(probe_ignore_syscalls, "Syscalls to ignore in table checks");
145
146 #ifdef OSI_PROBE_DEBUG
147 /* 
148  * Debugging flags:
149  * 0x0001 - General debugging
150  * 0x0002 - detail - try
151  * 0x0004 - detail - try_harder
152  * 0x0008 - detail - check_table
153  * 0x0010 - detail - check_harder
154  * 0x0020 - detail - check_harder/zapped
155  * 0x0040 - automatically ignore setgroups and afs_syscall
156  * 0x0080 - detail - check_table_readable
157  */
158 static int probe_debug = 0x41;
159 #if defined(module_param) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
160 module_param(probe_debug, int, 0);
161 #else
162 MODULE_PARM(probe_debug, "i");
163 #endif
164 MODULE_PARM_DESC(probe_debug, "Debugging level");
165
166 static unsigned long probe_debug_addr[4] = { 0,0,0,0 };
167 #if defined(module_param_array) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
168 module_param_array(probe_debug_addr, long, NULL, 0);
169 #else
170 MODULE_PARM(probe_debug_addr, "1-4l");
171 #endif
172 MODULE_PARM_DESC(probe_debug_addr, "Debug range starting locations");
173
174 static unsigned long probe_debug_range = 0;
175 #if defined(module_param) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
176 module_param(probe_debug_range, long, 0);
177 #else
178 MODULE_PARM(probe_debug_range, "l");
179 #endif
180 MODULE_PARM_DESC(probe_debug_range, "Debug range length");
181
182 static unsigned long probe_debug_tag = 0;
183 #if defined(module_param) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
184 module_param(probe_debug_tag, long, 0);
185 #else
186 MODULE_PARM(probe_debug_tag, "l");
187 #endif
188 MODULE_PARM_DESC(probe_debug_tag, "Debugging output start tag");
189 #endif
190
191
192 /* Weak references are our friends.  They are supported by the in-kernel
193  * linker in Linux 2.6 and by all versions of modutils back to 2.2pre1.
194  * A weak reference not satisified by the kernel will have value zero.
195  *
196  * Unfortunately, weak references to functions don't work right on
197  * IA64; specifically, if you actually try to make a call through
198  * such a reference, and the symbol doesn't exist in the kernel, then
199  * the module relocation code will oops.  A workaround for this is
200  * probably possible, but the use of kallsyms_* is of limited value,
201  * so I'm not bothing with the effort for now.
202  * -- jhutz, 10-Feb-2005
203  */
204 #ifdef OSI_PROBE_KALLSYMS
205 extern int kallsyms_symbol_to_address(char *name, unsigned long *token,
206                                       char **mod_name,
207                                       unsigned long *mod_start,
208                                       unsigned long *mod_end,
209                                       char **sec_name,
210                                       unsigned long *sec_start,
211                                       unsigned long *sec_end,
212                                       char **sym_name,
213                                       unsigned long *sym_start,
214                                       unsigned long *sym_end
215                                      ) __attribute__((weak));
216
217 extern int kallsyms_address_to_symbol(unsigned long address,
218                                       char **mod_name,
219                                       unsigned long *mod_start,
220                                       unsigned long *mod_end,
221                                       char **sec_name,
222                                       unsigned long *sec_start,
223                                       unsigned long *sec_end,
224                                       char **sym_name,
225                                       unsigned long *sym_start,
226                                       unsigned long *sym_end
227                                      ) __attribute__((weak));
228 #endif
229
230 extern SYSCALLTYPE sys_call_table[] __attribute__((weak));
231 extern SYSCALLTYPE ia32_sys_call_table[] __attribute__((weak));
232 extern SYSCALLTYPE sys_call_table32[] __attribute__((weak));
233 extern SYSCALLTYPE sys_call_table_emu[] __attribute__((weak));
234
235 extern asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count) __attribute__((weak));
236 extern asmlinkage long sys_close(unsigned int) __attribute__((weak));
237 #if defined(EXPORTED_SYS_CHDIR)
238 extern asmlinkage long sys_chdir(const char *) __attribute__((weak));
239 #endif
240 extern asmlinkage ssize_t sys_write(unsigned int, const char *, size_t) __attribute__((weak));
241 extern asmlinkage long sys_wait4(pid_t, int *, int, struct rusage *) __attribute__((weak));
242 extern asmlinkage long sys_exit (int) __attribute__((weak));
243 #if defined(EXPORTED_SYS_OPEN)
244 extern asmlinkage long sys_open (const char *, int, int) __attribute__((weak));
245 #endif
246 extern asmlinkage long sys_ioctl(unsigned int, unsigned int, unsigned long) __attribute__((weak));
247
248
249 /* Structures used to control probing.  We put all the details of which
250  * symbols we're interested in, what syscall functions to look for, etc
251  * into tables, so we can then have a single copy of the functions that
252  * actually do the work.
253  */
254 typedef struct {
255     char *name;
256     int NR1;
257     void *fn1;
258     int NR2;
259     void *fn2;
260     int NR3;
261     void *fn3;
262 } tryctl;
263
264 typedef struct {
265     char *symbol;                   /* symbol name */
266     char *desc;                     /* description for messages */
267     int offset;                     /* first syscall number in table */
268
269     void *weak_answer;              /* weak symbol ref */
270     void *parm_answer;              /* module parameter answer */
271     void *debug_answer;             /* module parameter answer */
272     unsigned long given_answer;     /* compiled-in answer, if any */
273
274     tryctl *trylist;                /* array of combinations to try */
275
276     unsigned long try_sect_sym;     /* symbol in section to try scanning */
277     unsigned long try_base;         /* default base address for scan */
278     unsigned long try_base_mask;    /* base address bits to force to zero */
279     unsigned long try_length;       /* default length for scan */
280
281     unsigned long alt_try_sect_sym;     /* symbol in section to try scanning */
282     unsigned long alt_try_base;         /* default base address for scan */
283     unsigned long alt_try_base_mask;    /* base address bits to force to zero */
284     unsigned long alt_try_length;       /* default length for scan */
285
286     int n_zapped_syscalls;          /* number of unimplemented system calls */
287     int *zapped_syscalls;           /* list of unimplemented system calls */
288
289     int n_unique_syscalls;          /* number of unique system calls */
290     int *unique_syscalls;           /* list of unimplemented system calls */
291
292     int verifyNR;                   /* syscall number to verify match */
293     void *verify_fn;                /* syscall pointer to verify match */
294
295     int debug_ignore_NR[4];         /* syscalls to ignore for debugging */
296 } probectl;
297
298 #if defined(AFS_I386_LINUX26_ENV) || defined(AFS_AMD64_LINUX26_ENV)
299 static int check_access(unsigned long, int);
300 static int check_table_readable(probectl *, PROBETYPE *);
301 #endif
302
303
304 /********** Probing Configuration: sys_call_table **********/
305
306 /* syscall pairs/triplets to probe */
307 /* On PPC64 and SPARC64, we need to omit the ones that might match both tables */
308 static tryctl main_try[] = {
309 #if !defined(AFS_PPC64_LINUX20_ENV) && !defined(AFS_SPARC64_LINUX20_ENV)
310 #if defined(EXPORTED_SYS_CHDIR)
311     { "scan: close+chdir+write", __NR_close, &sys_close, __NR_chdir, &sys_chdir, __NR_write, &sys_write },
312 #endif
313 #endif
314     { "scan: close+wait4",       __NR_close, &sys_close, __NR_wait4, &sys_wait4, -1,         0          },
315 #if !defined(AFS_PPC64_LINUX20_ENV) && !defined(AFS_SPARC64_LINUX20_ENV)
316 #if defined(EXPORTED_SYS_CHDIR)
317     { "scan: close+chdir",       __NR_close, &sys_close, __NR_chdir, &sys_chdir, -1,         0          },
318 #endif
319 #endif
320     { "scan: close+ioctl",       __NR_close, &sys_close, __NR_ioctl, &sys_ioctl, -1,         0          },
321 #if defined(EXPORTED_SYS_OPEN)
322     { "scan: exit+open",         __NR_exit,  &sys_exit,  __NR_open,  &sys_open,  -1,         0          },
323 #endif
324     { 0 }
325 };
326
327 /* zapped syscalls for try_harder */
328 /* this list is based on the table in 'zapped_syscalls' */
329
330 static int main_zapped_syscalls[] = {
331 /* 
332  * SPARC-Linux uses syscall number mappings chosen to be compatible
333  * with SunOS.  So, it doesn't have any of the traditional calls or
334  * the new STREAMS ones.  However, there are a number of syscalls
335  * which are SunOS-specific (not implemented on Linux), i386-specific
336  * (not implemented on SPARC-Linux), or implemented only on one of
337  * sparc32 or sparc64.  Of course, there are no __NR macros for most
338  * of these.
339  * 
340  * Note that the calls we list here are implemented by sys_nis_syscall,
341  * not by sys_ni_syscall.  That means we have to exclude all of the
342  * other entries, or we might get a sys_ni_syscall into the list and
343  * the test would no longer work.
344  */
345 #if defined(AFS_SPARC64_LINUX20_ENV)
346     /* mmap2, fstat64, getmsg, putmsg, modify_ldt */
347     56, 63, 151, 152, 218,
348 #elif defined(AFS_SPARC_LINUX20_ENV)
349     /* memory_ordering, getmsg, putmsg, unimplemented, modify_ldt */
350     52, 151, 152, 164, 218,
351 #else /* !AFS_SPARC_LINUX20_ENV */
352
353 /* 
354  * These 7 syscalls are present in the syscall table on most "older"
355  * platforms that use the traditional syscall number mappings.  They
356  * are not implemented on any platform.
357  */
358 #ifdef __NR_break
359     __NR_break,
360 #endif
361 #ifdef __NR_stty
362     __NR_stty,
363 #endif
364 #ifdef __NR_gtty
365     __NR_gtty,
366 #endif
367 #ifdef __NR_ftime
368     __NR_ftime,
369 #endif
370 #ifdef __NR_prof
371     __NR_prof,
372 #endif
373 #ifdef __NR_lock
374     __NR_lock,
375 #endif
376 #ifdef __NR_mpx
377     __NR_mpx,
378 #endif
379 /* 
380  * On s390 and arm (but not arm26), the seven traditional unimplemented
381  * system calls are indeed present and unimplemented.  However, the
382  * corresponding __NR macros are not defined, so the tests above fail.
383  * Instead, we just have to know the numbers for these.
384  */
385 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
386     /* break, stty, gtty, ftime, prof, lock, mpx */
387     17, 31, 32, 35, 44, 53, 56,
388 #endif
389
390 /* 
391  * Sadly, some newer platforms like IA64, amd64, and PA-RISC don't have
392  * the traditional numbers, so the list above are not helpful.  They
393  * do have entries for getpmsg/putpmsg, which are always unimplemented.
394  */
395 #ifdef __NR_getpmsg
396     __NR_getpmsg,
397 #endif
398 #ifdef __NR_putpmsg
399     __NR_putpmsg,
400 #endif
401
402 /* 
403  * The module-loading mechanism changed in Linux 2.6, and insmod's
404  * loss is our gain: three new unimplemented system calls! 
405  */
406 #ifdef __NR_
407     __NR_create_module,
408 #endif
409 #ifdef __NR_query_module
410     __NR_query_module,
411 #endif
412 #ifdef __NR_get_kernel_syms
413     __NR_get_kernel_syms,
414 #endif
415
416 /* 
417  * On IA64, the old module-loading calls are indeed present and
418  * unimplemented, but the __NR macros are not defined.  Again,
419  * we simply have to know their numbers.
420  */
421 #ifdef AFS_IA64_LINUX26_ENV
422     /* create_module, query_module, get_kernel_sysms */
423     1132, 1136, 1135,
424 #endif
425
426 /* And the same deal for arm (not arm26), if we ever support that. */
427 #if 0
428     /* create_module, query_module, get_kernel_sysms */
429     127, 167, 130,
430 #endif
431
432 /*
433  * Alpha-Linux uses syscall number mappings chosen to be compatible
434  * with OSF/1.  So, it doesn't have any of the traditional calls or
435  * the new STREAMS ones, but it does have several OSF/1-specific
436  * syscalls which are not implemented on Linux.  These don't exist on
437  * any other platform.
438  */
439 #ifdef __NR_osf_syscall
440     __NR_osf_syscall,
441 #endif
442 #ifdef __NR_osf_profil
443     __NR_osf_profil,
444 #endif
445 #ifdef __NR_osf_reboot
446     __NR_osf_reboot,
447 #endif
448 #ifdef __NR_osf_kmodcall
449     __NR_osf_kmodcall,
450 #endif
451 #ifdef __NR_osf_old_vtrace
452     __NR_osf_old_vtrace,
453 #endif
454
455 /*
456  * On PPC64, we need a couple more entries to distinguish the two
457  * tables, since the system call numbers are the same and the sets of
458  * unimplemented calls are very similar.
459  * mmap2 and fstat64 are implemented only for 32-bit calls
460  */
461 #ifdef AFS_PPC64_LINUX20_ENV
462     /* _mmap2, _fstat64 */
463     192, 197,
464 #endif /* AFS_PPC64_LINUX20_ENV */
465
466 /* Similarly for S390X, with lcown16 and fstat64 */
467 #ifdef AFS_S390X_LINUX20_ENV
468     /* lchown16, fstat64 */
469     16, 197,
470 #endif
471 #endif /* !AFS_SPARC_LINUX20_ENV */
472     0
473 };
474
475 /* unique syscalls for try_harder */
476 static int main_unique_syscalls[] = {
477 #if defined(AFS_SPARC64_LINUX24_ENV) || defined(AFS_SPARC_LINUX24_ENV)
478     /* 
479      * On SPARC, we need some additional unique calls to make sure
480      * we don't match the SunOS-compatibility table.
481      */
482     __NR_sgetmask, __NR_ssetmask,
483 #endif
484     __NR_exit, __NR_mount, __NR_read, __NR_write,
485     __NR_open, __NR_close, __NR_unlink
486 };
487
488 /* probe control structure */
489 static probectl main_probe = {
490     /* symbol name and description */
491     "sys_call_table",
492     "system call table",
493
494     /* syscall number of first entry in table */
495 #ifdef AFS_IA64_LINUX20_ENV
496     1024,
497 #else
498     0,
499 #endif
500
501     sys_call_table,               /* weak symbol ref */
502     0, 0,                         /* module parameter answers */
503 #ifdef AFS_LINUX_sys_call_table
504     AFS_LINUX_sys_call_table,     /* compiled-in answer, if any */
505 #else
506     0,
507 #endif
508
509     main_try,                     /* array of combinations to try */
510
511     /* symbol in section to try scanning */
512 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
513     (unsigned long)&sys_close,
514 #elif defined(AFS_AMD64_LINUX26_ENV)
515     /* On this platform, it's in a different section! */
516     (unsigned long)&generic_ro_fops,
517 #else
518     (unsigned long)&init_mm,
519 #endif
520
521     /* default base address for scan */
522     /* base address bits to force to zero */
523     /* default length for scan */
524 #if   defined(AFS_SPARC64_LINUX20_ENV)
525     (unsigned long)(&sys_close),
526     0xfffff,
527     0x10000,
528 #elif   defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
529     /* bleah; this is so suboptimal */
530     (unsigned long)(&sys_close),
531     0xfffff,
532     0x20000,
533 #elif   defined(AFS_IA64_LINUX20_ENV)
534     (unsigned long)(&init_mm),
535     0x1fffff,
536     0x30000,
537 #elif defined(AFS_AMD64_LINUX26_ENV)
538     (unsigned long)(&generic_ro_fops) - 0x30000,
539     0,
540     0x6000,
541 #elif defined(AFS_PPC64_LINUX26_ENV)
542     (unsigned long)(&do_signal),
543     0xfff,
544     0x400,
545 #else
546     (unsigned long)&init_mm,
547     0,
548     16384,
549 #endif
550
551     (unsigned long)scsi_command_size,
552     (unsigned long)scsi_command_size - 0x10000,
553     0x3ffff,
554     0x40000,
555
556     /* number and list of unimplemented system calls */
557     ((sizeof(main_zapped_syscalls)/sizeof(main_zapped_syscalls[0])) - 1),
558     main_zapped_syscalls,
559
560     /* number and list of unique system calls */
561     (sizeof(main_unique_syscalls)/sizeof(main_unique_syscalls[0])),
562     main_unique_syscalls,
563
564     /* syscall number and pointer to verify match */
565     __NR_close, &sys_close,
566
567     /* syscalls to ignore for debugging */
568     {
569 #if   defined(AFS_ALPHA_LINUX20_ENV)
570         338,
571 #elif defined(AFS_AMD64_LINUX20_ENV)
572         183,
573 #elif defined(AFS_IA64_LINUX20_ENV)
574         1141,
575 #elif defined(AFS_SPARC_LINUX20_ENV) || defined(AFS_SPARC64_LINUX20_ENV)
576         227,
577 #else
578         137,
579 #endif
580         __NR_setgroups,
581 #ifdef __NR_setgroups32
582         __NR_setgroups32,
583 #else
584         -1,
585 #endif
586         -1,
587     }
588 };
589
590
591 /********** Probing Configuration: amd64 ia32_sys_call_table **********/
592 #if defined(AFS_AMD64_LINUX20_ENV)
593
594 /* syscall pairs/triplets to probe */
595 static tryctl ia32_try[] = {
596 #if defined(EXPORTED_SYS_CHDIR)
597     { "scan: close+chdir+write", __NR_ia32_close, &sys_close, __NR_ia32_chdir, &sys_chdir,        __NR_ia32_write, &sys_write },
598     { "scan: close+chdir",       __NR_ia32_close, &sys_close, __NR_ia32_chdir, &sys_chdir,        -1,              0          },
599 #endif
600     { 0 }
601 };
602
603 /* zapped syscalls for try_harder */
604 static int ia32_zapped_syscalls[] = {
605     __NR_ia32_break, __NR_ia32_stty, __NR_ia32_gtty, __NR_ia32_ftime,
606     __NR_ia32_prof,  __NR_ia32_lock, __NR_ia32_mpx,
607     0
608 };
609
610 /* unique syscalls for try_harder */
611 static int ia32_unique_syscalls[] = {
612     __NR_ia32_exit, __NR_ia32_mount, __NR_ia32_read, __NR_ia32_write,
613     __NR_ia32_open, __NR_ia32_close, __NR_ia32_unlink
614 };
615
616 /* probe control structure */
617 static probectl ia32_probe = {
618     /* symbol name and description */
619     "ia32_sys_call_table",
620     "32-bit system call table",
621
622     /* syscall number of first entry in table */
623     0,
624
625     ia32_sys_call_table,          /* weak symbol ref */
626     0, 0,                         /* module parameter answers */
627 #ifdef AFS_LINUX_ia32_sys_call_table
628     AFS_LINUX_ia32_sys_call_table,/* compiled-in answer, if any */
629 #else
630     0,
631 #endif
632
633     ia32_try,                     /* array of combinations to try */
634
635     /* symbol in section to try scanning */
636     (unsigned long)&init_mm,
637
638     /* default base address for scan */
639     /* base address bits to force to zero */
640     /* default length for scan */
641     (unsigned long)&init_mm,
642     0,
643     (0x180000 / sizeof(unsigned long *)),
644
645     (unsigned long)scsi_command_size,
646     (unsigned long)scsi_command_size - 0x10000,
647     0x3ffff,
648     0x40000,
649
650
651     /* number and list of unimplemented system calls */
652     ((sizeof(ia32_zapped_syscalls)/sizeof(ia32_zapped_syscalls[0])) - 1),
653     ia32_zapped_syscalls,
654
655     /* number and list of unique system calls */
656     (sizeof(ia32_unique_syscalls)/sizeof(ia32_unique_syscalls[0])),
657     ia32_unique_syscalls,
658
659     /* syscall number and pointer to verify match */
660     __NR_ia32_close, &sys_close,
661
662     /* syscalls to ignore for debugging */
663     {
664         137,
665         __NR_ia32_setgroups,
666         __NR_ia32_setgroups32,
667         -1,
668     }
669 };
670
671 static probectl *probe_list[] = {
672     &main_probe, &ia32_probe
673 };
674
675
676 /********** Probing Configuration: IA64 **********/
677 #elif defined(AFS_IA64_LINUX20_ENV)
678 struct fptr {
679     void *ip;
680     unsigned long gp;
681 };
682
683 /* no 32-bit support on IA64 for now */
684 static probectl *probe_list[] = {
685     &main_probe
686 };
687
688
689 /********** Probing Configuration: ppc64, sparc64 sys_call_table32 **********/
690 #elif defined(AFS_PPC64_LINUX20_ENV) || defined(AFS_SPARC64_LINUX20_ENV)
691 struct fptr {
692     void *ip;
693     unsigned long gp;
694 };
695
696 /* 
697  * syscall pairs/triplets to probe
698  * This has to be empty, because anything that would work will
699  * also match the main table, and that's no good.
700  */
701 static tryctl sct32_try[] = {
702     { 0 }
703 };
704
705 /* zapped syscalls for try_harder */
706 static int sct32_zapped_syscalls[] = {
707 #ifdef AFS_PPC64_LINUX20_ENV
708     /* These should be sufficient */
709     __NR_break, __NR_stty, __NR_gtty, __NR_ftime,
710     __NR_prof, __NR_lock, __NR_mpx,
711 #endif
712 #ifdef AFS_SPARC64_LINUX20_ENV
713     /* memory_ordering, getmsg, putmsg, unimplemented, modify_ldt */
714     52, 151, 152, 164, 218,
715 #endif
716     0
717 };
718
719 /* unique syscalls for try_harder */
720 /* mmap2 and fstat64 are implemented only for 32-bit calls */
721 static int sct32_unique_syscalls[] = {
722 #ifdef AFS_PPC64_LINUX20_ENV
723     /* _mmap2, _fstat64 */
724     192, 197,
725 #endif
726 #ifdef AFS_SPARC64_LINUX24_ENV
727     /* 
728      * On SPARC, we need some additional unique calls to make sure
729      * we don't match the SunOS-compatibility table.
730      */
731     __NR_sgetmask, __NR_ssetmask,
732 #endif
733     __NR_exit, __NR_mount, __NR_read, __NR_write,
734     __NR_open, __NR_close, __NR_unlink
735 };
736
737 /* probe control structure */
738 static probectl sct32_probe = {
739     /* symbol name and description */
740     "sys_call_table32",
741     "32-bit system call table",
742
743     /* syscall number of first entry in table */
744     0,
745
746     sys_call_table32,             /* weak symbol ref */
747     0, 0,                         /* module parameter answers */
748 #ifdef AFS_LINUX_sys_call_table32
749     AFS_LINUX_sys_call_table32,   /* compiled-in answer, if any */
750 #else
751     0,
752 #endif
753
754     sct32_try,                   /* array of combinations to try */
755
756     /* symbol in section to try scanning */
757 #if defined(AFS_SPARC64_LINUX20_ENV)
758     (unsigned long)&sys_close,
759 #else
760     (unsigned long)&init_mm,
761 #endif
762
763     /* default base address for scan */
764     /* base address bits to force to zero */
765     /* default length for scan */
766 #if   defined(AFS_SPARC64_LINUX20_ENV)
767     (unsigned long)(&sys_close),
768     0xfffff,
769     0x10000,
770 #elif defined(AFS_PPC64_LINUX26_ENV)
771     (unsigned long)(&do_signal),
772     0xfff,
773     0x400,
774 #else
775     (unsigned long)&init_mm,
776     0,
777     16384,
778 #endif
779
780     (unsigned long)scsi_command_size,
781     (unsigned long)scsi_command_size - 0x10000,
782     0x3ffff,
783     0x40000,
784
785     /* number and list of unimplemented system calls */
786     ((sizeof(sct32_zapped_syscalls)/sizeof(sct32_zapped_syscalls[0])) - 1),
787     sct32_zapped_syscalls,
788
789     /* number and list of unique system calls */
790     (sizeof(sct32_unique_syscalls)/sizeof(sct32_unique_syscalls[0])),
791     sct32_unique_syscalls,
792
793     /* syscall number and pointer to verify match */
794     __NR_close, &sys_close,
795
796     /* syscalls to ignore for debugging */
797     {
798 #if defined(AFS_SPARC64_LINUX20_ENV)
799         227,
800 #else
801         137,
802 #endif
803         __NR_setgroups,
804         -1,
805         -1,
806     }
807 };
808
809 static probectl *probe_list[] = {
810     &main_probe, &sct32_probe
811 };
812
813
814 /********** Probing Configuration: s390x sys_call_table_emu **********/
815 /* We only actually need to do this on s390x_linux26 and later.
816  * On earlier versions, the two tables were interleaved and so
817  * have related base addresses.
818  */
819 #elif defined(AFS_S390X_LINUX26_ENV)
820
821 /* syscall pairs/triplets to probe */
822 /* nothing worthwhile is exported, so this is empty */
823 static tryctl emu_try[] = {
824     { 0 }
825 };
826
827 /* zapped syscalls for try_harder */
828 static int emu_zapped_syscalls[] = {
829     /* break, stty, gtty, ftime, prof, lock, mpx */
830     17, 31, 32, 35, 44, 53, 56,
831     0
832 };
833
834 /* unique syscalls for try_harder */
835 static int emu_unique_syscalls[] = {
836     /* lchown16, fstat64 */
837     16, 197,
838     __NR_exit, __NR_mount, __NR_read, __NR_write,
839     __NR_open, __NR_close, __NR_unlink
840 };
841
842 /* probe control structure */
843 static probectl emu_probe = {
844     /* symbol name and description */
845     "sys_call_table_emu",
846     "32-bit system call table",
847
848     /* syscall number of first entry in table */
849     0,
850
851     sys_call_table_emu,           /* weak symbol ref */
852     0, 0,                         /* module parameter answers */
853 #ifdef AFS_LINUX_sys_call_table_emu
854     AFS_LINUX_sys_call_table_emu, /* compiled-in answer, if any */
855 #else
856     0,
857 #endif
858
859     emu_try,                      /* array of combinations to try */
860
861     /* symbol in section to try scanning */
862     (unsigned long)&sys_close,
863
864     /* default base address for scan */
865     /* base address bits to force to zero */
866     /* default length for scan */
867     (unsigned long)&sys_close,
868     0xfffff,
869     0x20000,
870
871     (unsigned long)scsi_command_size,
872     (unsigned long)scsi_command_size - 0x10000,
873     0x3ffff,
874     0x40000,
875
876     /* number and list of unimplemented system calls */
877     ((sizeof(emu_zapped_syscalls)/sizeof(emu_zapped_syscalls[0])) - 1),
878     emu_zapped_syscalls,
879
880     /* number and list of unique system calls */
881     (sizeof(emu_unique_syscalls)/sizeof(emu_unique_syscalls[0])),
882     emu_unique_syscalls,
883
884     /* syscall number and pointer to verify match */
885     __NR_close, &sys_close,
886
887     /* syscalls to ignore for debugging */
888     {
889         137,
890         __NR_setgroups,
891         -1,
892         -1,
893     }
894 };
895
896 static probectl *probe_list[] = {
897     &main_probe, &emu_probe
898 };
899
900
901 /********** End of Probing Configuration **********/
902
903 #else /* no per-platform probe control, so use the default list */
904 static probectl *probe_list[] = {
905     &main_probe
906 };
907 #endif
908
909 #define N_PROBE_LIST (sizeof(probe_list) / sizeof(*probe_list))
910 #define DEBUG_IN_RANGE(P,x) (!probe_debug_range ||                             \
911   (P->debug_answer &&                                                          \
912    (unsigned long)(x) >= (unsigned long)P->debug_answer &&                     \
913    (unsigned long)(x) <  (unsigned long)P->debug_answer + probe_debug_range))
914
915
916
917 static int check_table(probectl *P, PROBETYPE *ptr)
918 {
919     PROBETYPE *x;
920     int i, j;
921
922 #if defined(AFS_I386_LINUX26_ENV) || defined(AFS_AMD64_LINUX26_ENV)
923     i = check_table_readable(P, ptr);
924     if (i >= 0) return i;
925 #endif
926
927     for (x = ptr, i = 0; i < _SS(NR_syscalls); i++, x++) {
928 #ifdef OSI_PROBE_DEBUG
929         if (probe_debug & 0x0040) {
930             for (j = 0; j < 4; j++) {
931                 if (_SS(P->debug_ignore_NR[j]) == _SX(i + P->offset)) break;
932             }
933             if (j < 4) continue;
934         }
935 #endif
936         for (j = 0; j < 8; j++) {
937             if (_SS(probe_ignore_syscalls[j]) == _SX(i) + P->offset) break;
938         }
939         if (j < 8) continue;
940         if (*x <= ktxt_lower_bound) {
941 #ifdef OSI_PROBE_DEBUG
942             if ((probe_debug & 0x0008) && DEBUG_IN_RANGE(P,ptr))
943                 printk("<7>check 0x%lx -> %d [0x%lx]\n",
944                        (unsigned long)ptr, i, (unsigned long)*x);
945 #endif
946             return i;
947         }
948     }
949 #ifdef OSI_PROBE_DEBUG
950     if ((probe_debug & 0x0008) && DEBUG_IN_RANGE(P,ptr))
951         printk("<7>check 0x%lx -> ok\n", (unsigned long)ptr);
952 #endif
953     return -1;
954 }
955
956 static void *try(probectl *P, tryctl *T, PROBETYPE *aptr,
957                  unsigned long datalen)
958 {
959 #ifdef OSI_PROBE_KALLSYMS
960     char *mod_name, *sec_name, *sym_name;
961     unsigned long mod_start, mod_end;
962     unsigned long sec_start, sec_end;
963     unsigned long sym_start, sym_end;
964 #endif
965     unsigned long offset, ip1, ip2, ip3;
966     int ret;
967     PROBETYPE *ptr;
968
969 #if defined(AFS_IA64_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV)
970     ip1 = T->fn1 ? (unsigned long)((struct fptr *)T->fn1)->ip : 0;
971     ip2 = T->fn2 ? (unsigned long)((struct fptr *)T->fn2)->ip : 0;
972     ip3 = T->fn3 ? (unsigned long)((struct fptr *)T->fn3)->ip : 0;
973 #else
974     ip1 = (unsigned long)T->fn1;
975     ip2 = (unsigned long)T->fn2;
976     ip3 = (unsigned long)T->fn3;
977 #endif
978
979 #ifdef OSI_PROBE_DEBUG
980     if (probe_debug & 0x0001)
981         printk("<7>osi_probe: %s                      %s (%d->0x%lx, %d->0x%lx, %d->0x%lx)\n",
982                P->symbol, T->name, T->NR1, ip1, T->NR2, ip2, T->NR3, ip3);
983 #endif
984
985     if (!ip1 || !ip2 || (T->NR3 >= 0 && !ip3))
986         return 0;
987
988     for (offset = 0; offset < datalen; offset++, aptr++) {
989 #if defined(AFS_PPC64_LINUX20_ENV)
990         ptr = (PROBETYPE*)(*aptr);
991         if ((unsigned long)ptr <= KERNELBASE) {
992                 continue;
993         }
994 #else
995         ptr = aptr;
996 #endif
997         if ((unsigned long)ptr < init_mm.start_code ||
998 #if defined(AFS_AMD64_LINUX20_ENV)
999                 (unsigned long)ptr > init_mm.brk)
1000 #else
1001                 (unsigned long)ptr > init_mm.end_data)
1002 #endif
1003         {
1004 /*           printk("address 0x%lx (from 0x%lx %d) is out of range in check_table. wtf?\n", (unsigned long)x, (unsigned long)ptr, i);*/
1005              continue;
1006         }
1007
1008         ret = check_table(P, ptr);
1009         if (ret >= 0) {
1010             /* return value is number of entries to skip */
1011             aptr    += ret;
1012             offset += ret;
1013             continue;
1014         }
1015
1016 #ifdef OSI_PROBE_DEBUG
1017         if ((probe_debug & 0x0002) && DEBUG_IN_RANGE(P,ptr))
1018             printk("<7>try 0x%lx\n", (unsigned long)ptr);
1019 #endif
1020         if (ptr[_SS(T->NR1 - P->offset)] != ip1)        continue;
1021         if (ptr[_SS(T->NR2 - P->offset)] != ip2)        continue;
1022         if (ip3 && ptr[_SS(T->NR3 - P->offset)] != ip3) continue;
1023
1024 #ifdef OSI_PROBE_DEBUG
1025         if (probe_debug & 0x0002)
1026             printk("<7>try found 0x%lx\n", (unsigned long)ptr);
1027 #endif
1028 #ifdef OSI_PROBE_KALLSYMS
1029         if (kallsyms_address_to_symbol) {
1030             ret = kallsyms_address_to_symbol((unsigned long)ptr,
1031                                              &mod_name, &mod_start, &mod_end,
1032                                              &sec_name, &sec_start, &sec_end,
1033                                              &sym_name, &sym_start, &sym_end);
1034             if (!ret || strcmp(sym_name, P->symbol)) continue;
1035         }
1036 #endif
1037         /* XXX should we make sure there is only one match? */
1038         return (void *)ptr;
1039     }
1040     return 0;
1041 }
1042
1043
1044 static int check_harder(probectl *P, PROBETYPE *p)
1045 {
1046     unsigned long ip1;
1047     int i, s;
1048
1049 #if defined(AFS_I386_LINUX26_ENV) || defined(AFS_AMD64_LINUX26_ENV)
1050     i = check_table_readable(P, p);
1051     if (i >= 0) return 0;
1052 #endif
1053
1054     /* Check zapped syscalls */
1055     for (i = 1; i < P->n_zapped_syscalls; i++) {
1056         if (p[_SS(P->zapped_syscalls[i])] != p[_SS(P->zapped_syscalls[0])]) {
1057 #ifdef OSI_PROBE_DEBUG
1058             if ((probe_debug & 0x0020) && DEBUG_IN_RANGE(P,p))
1059                 printk("<7>check_harder 0x%lx zapped failed i=%d\n", (unsigned long)p, i);
1060 #endif
1061             return 0;
1062         }
1063     }
1064
1065     /* Check unique syscalls */
1066     for (i = 0; i < P->n_unique_syscalls; i++) {
1067         for (s = 0; s < NR_syscalls; s++) {
1068             if (p[_SS(s)] == p[_SS(P->unique_syscalls[i])]
1069                 && s != P->unique_syscalls[i]) {
1070 #ifdef OSI_PROBE_DEBUG
1071                 if ((probe_debug & 0x0010) && DEBUG_IN_RANGE(P,p))
1072                     printk("<7>check_harder 0x%lx unique failed i=%d s=%d\n", (unsigned long)p, i, s);
1073 #endif
1074                 return 0;
1075             }
1076         }
1077     }
1078
1079 #if defined(AFS_IA64_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV)
1080     ip1 = P->verify_fn ? (unsigned long)((struct fptr *)(P->verify_fn))->ip : 0;
1081 #else
1082     ip1 = (unsigned long)(P->verify_fn);
1083 #endif
1084
1085     if (ip1 && p[_SS(P->verifyNR - P->offset)] != ip1) {
1086 #ifdef OSI_PROBE_DEBUG
1087         if ((probe_debug & 0x0010) && DEBUG_IN_RANGE(P,p))
1088             printk("<7>check_harder 0x%lx verify failed\n", (unsigned long)p);
1089 #endif
1090         return 0;
1091     }
1092
1093 #ifdef OSI_PROBE_DEBUG
1094     if ((probe_debug & 0x0010) && DEBUG_IN_RANGE(P,p))
1095         printk("<7>check_harder 0x%lx success!\n", (unsigned long)p);
1096 #endif
1097     return 1;
1098 }
1099
1100 static void *try_harder(probectl *P, PROBETYPE *ptr, unsigned long datalen)
1101 {
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 #endif
1108     unsigned long offset;
1109     void *match = 0;
1110     int ret;
1111
1112 #ifdef OSI_PROBE_DEBUG
1113     if (probe_debug & 0x0001)
1114         printk("<7>osi_probe: %s                      try_harder\n", P->symbol);
1115 #endif
1116     for (offset = 0; offset < datalen; offset++, ptr++) {
1117          if ((unsigned long)ptr < init_mm.start_code ||
1118 #if defined(AFS_AMD64_LINUX20_ENV)
1119                 (unsigned long)ptr > init_mm.brk)
1120 #else
1121                 (unsigned long)ptr > init_mm.end_data)
1122 #endif
1123         {
1124 /*           printk("address 0x%lx (from 0x%lx %d) is out of range in check_table. wtf?\n", (unsigned long)x, (unsigned long)ptr, i);*/
1125              continue;
1126         }
1127         ret = check_table(P, ptr);
1128         if (ret >= 0) {
1129             /* return value is number of entries to skip */
1130             ptr    += ret;
1131             offset += ret;
1132             continue;
1133         }
1134
1135 #ifdef OSI_PROBE_DEBUG
1136         if ((probe_debug & 0x0004) && DEBUG_IN_RANGE(P,ptr))
1137             printk("<7>try_harder 0x%lx\n", (unsigned long)ptr);
1138 #endif
1139         if (!check_harder(P, ptr))
1140             continue;
1141
1142 #ifdef OSI_PROBE_DEBUG
1143         if (probe_debug & 0x0004)
1144             printk("<7>try_harder found 0x%lx\n", (unsigned long)ptr);
1145 #endif
1146
1147 #ifdef OSI_PROBE_KALLSYMS
1148         if (kallsyms_address_to_symbol) {
1149             ret = kallsyms_address_to_symbol((unsigned long)ptr,
1150                                              &mod_name, &mod_start, &mod_end,
1151                                              &sec_name, &sec_start, &sec_end,
1152                                              &sym_name, &sym_start, &sym_end);
1153             if (!ret || strcmp(sym_name, P->symbol)) continue;
1154         }
1155 #endif
1156
1157         if (match) {
1158 #ifdef OSI_PROBE_DEBUG
1159             if (probe_debug & 0x0005)
1160                 printk("<7>%s: try_harder found multiple matches!\n", P->symbol);
1161 #endif
1162             return 0;
1163         }
1164
1165         match = (void *)ptr;
1166         if (!probe_carefully)
1167             break;
1168     }
1169     return match;
1170 }
1171
1172
1173 #ifdef OSI_PROBE_DEBUG
1174 #define check_result(x,m) do {                                                             \
1175     if (probe_debug & 0x0001) {                                                              \
1176         printk("<7>osi_probe: %s = 0x%016lx %s\n", P->symbol, (unsigned long)(x), (m)); \
1177     }                                                                                      \
1178     if ((x) && ((int)(x)) != -ENOENT) {                                                    \
1179         *method = (m);                                                                     \
1180         final_answer = (void *)(x);                                                        \
1181     }                                                                                      \
1182 } while (0)
1183 #else
1184 #define check_result(x,m) do {  \
1185     if ((x) && ((int)(x)) != -ENOENT) { \
1186         *method = (m);          \
1187         return (void *)(x);     \
1188     }                           \
1189 } while (0)
1190 #endif
1191 static void *scan_for_syscall_table(probectl *P, PROBETYPE *B, unsigned long L)
1192 {
1193     tryctl *T;
1194     void *answer;
1195 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
1196     void *answer2;
1197 #endif
1198 #ifdef OSI_PROBE_DEBUG
1199     void *final_answer = 0;
1200 #endif
1201 #ifdef OSI_PROBE_DEBUG
1202     if (probe_debug & 0x0007)
1203         printk("<7>osi_probe: %s                      base=0x%lx, len=0x%lx\n",
1204                P->symbol, (unsigned long)B, L);
1205     if (probe_debug & 0x0009) {
1206         printk("<7>osi_probe: %s                      ktxt_lower_bound=0x%lx\n",
1207                P->symbol, ktxt_lower_bound);
1208         printk("<7>osi_probe: %s                      NR_syscalls=%d\n",
1209                P->symbol, NR_syscalls);
1210     }
1211 #endif
1212
1213     for (T = P->trylist; T->name; T++) {
1214         answer = try(P, T, B, L);
1215 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
1216         answer2 = try(P, T, (PROBETYPE *)(2 + (void *)B), L);
1217 #ifdef OSI_PROBE_DEBUG
1218         if (probe_debug & 0x0003) {
1219             printk("<7>osi_probe: %s = 0x%016lx %s (even)\n",
1220                    P->symbol, (unsigned long)(answer), T->name);
1221             printk("<7>osi_probe: %s = 0x%016lx %s (odd)\n",
1222                    P->symbol, (unsigned long)(answer2), T->name);
1223         }
1224 #endif
1225         if (answer && answer2) answer = 0;
1226         else if (answer2) answer = answer2;
1227 #endif
1228         if (answer)
1229             return answer;
1230     }
1231
1232     /* XXX more checks here */
1233
1234     answer = try_harder(P, B, L);
1235 #if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
1236     answer2 = try_harder(P, (PROBETYPE *)(2 + (void *)B), L);
1237 #ifdef OSI_PROBE_DEBUG
1238     if (probe_debug & 0x0005) {
1239         printk("<7>osi_probe: %s = 0x%016lx pattern scan (even)\n",
1240                P->symbol, (unsigned long)(answer));
1241         printk("<7>osi_probe: %s = 0x%016lx pattern scan (odd)\n",
1242                P->symbol, (unsigned long)(answer2));
1243     }
1244 #endif
1245     if (answer && answer2) answer = 0;
1246     else if (answer2) answer = answer2;
1247 #endif
1248     return answer;
1249 }
1250
1251 static void *do_find_syscall_table(probectl *P, char **method)
1252 {
1253 #ifdef OSI_PROBE_KALLSYMS
1254     char *mod_name, *sec_name, *sym_name;
1255     unsigned long mod_start, mod_end;
1256     unsigned long sec_start, sec_end;
1257     unsigned long sym_start, sym_end;
1258     unsigned long token;
1259     int ret;
1260 #endif
1261     PROBETYPE *B;
1262     unsigned long L;
1263     void *answer;
1264 #ifdef OSI_PROBE_DEBUG
1265     void *final_answer = 0;
1266 #endif
1267
1268     *method = "not found";
1269
1270     /* if it's exported, there's nothing to do */
1271     check_result(P->weak_answer, "exported");
1272
1273     /* ask the kernel to do the name lookup, if it's willing */
1274 #ifdef OSI_PROBE_KALLSYMS
1275     if (kallsyms_symbol_to_address) {
1276         token = 0;
1277         sym_start = 0;
1278         do {
1279             ret = kallsyms_symbol_to_address(P->symbol, &token,
1280                                              &mod_name, &mod_start, &mod_end,
1281                                              &sec_name, &sec_start, &sec_end,
1282                                              &sym_name, &sym_start, &sym_end);
1283             if (ret && !strcmp(mod_name, "kernel") && sym_start)
1284                 break;
1285             sym_start = 0;
1286         } while (ret);
1287         check_result(sym_start, "kallsyms_symbol_to_address");
1288     }
1289 #endif
1290
1291     /* Maybe a little birdie told us */
1292     check_result(P->parm_answer,  "module parameter");
1293     check_result(P->given_answer, "compiled-in");
1294
1295     /* OK, so we have to scan. */
1296     B = (PROBETYPE *)((P->try_base) & ~(P->try_base_mask));
1297     L = P->try_length;
1298     /* Now, see if the kernel will tell us something better than the default */
1299 #ifdef OSI_PROBE_KALLSYMS
1300     if (kallsyms_address_to_symbol) {
1301         ret = kallsyms_address_to_symbol(P->try_sect_sym,
1302                                          &mod_name, &mod_start, &mod_end,
1303                                          &sec_name, &sec_start, &sec_end,
1304                                          &sym_name, &sym_start, &sym_end);
1305         if (ret) {
1306             B = (PROBETYPE *)sec_start;
1307             L = (sec_end - sec_start) / sizeof(unsigned long);
1308         }
1309     }
1310 #endif
1311    
1312     answer = scan_for_syscall_table(P, B, L);
1313     check_result(answer, "pattern scan");
1314     B = (PROBETYPE *)((P->alt_try_base) & ~(P->alt_try_base_mask));
1315     L = P->alt_try_length;
1316     /* Now, see if the kernel will tell us something better than the default */
1317 #ifdef OSI_PROBE_KALLSYMS
1318     if (kallsyms_address_to_symbol && P->alt_try_sect_sym) {
1319         ret = kallsyms_address_to_symbol(P->alt_try_sect_sym,
1320                                          &mod_name, &mod_start, &mod_end,
1321                                          &sec_name, &sec_start, &sec_end,
1322                                          &sym_name, &sym_start, &sym_end);
1323         if (ret) {
1324             B = (PROBETYPE *)sec_start;
1325             L = (sec_end - sec_start) / sizeof(unsigned long);
1326         }
1327     }
1328 #endif
1329     if (B && L) {
1330         answer = scan_for_syscall_table(P, B, L);
1331         check_result(answer, "pattern scan");
1332     }
1333 #ifdef OSI_PROBE_DEBUG
1334     return final_answer;
1335 #else
1336     return 0;
1337 #endif
1338 }
1339
1340 #if defined(AFS_I386_LINUX26_ENV) || defined(AFS_AMD64_LINUX26_ENV)
1341 static int check_access(unsigned long address, int mode) 
1342
1343     pgd_t *pgd = pgd_offset_k(address);
1344 #ifdef PUD_SIZE
1345     pud_t *pud;
1346 #endif
1347     pmd_t *pmd;
1348     pte_t *pte;
1349
1350     if (pgd_none(*pgd))
1351         return 0;
1352 #ifdef PUD_SIZE
1353     pud = pud_offset(pgd, address);
1354     if (pud_none(*pud))
1355         return 0;
1356     pmd = pmd_offset(pud, address);
1357 #else
1358     pmd = pmd_offset(pgd, address);
1359 #endif
1360     if (pmd_none(*pmd))
1361         return 0;
1362     if (pmd_large(*pmd))
1363         pte = (pte_t *)pmd;
1364     else
1365         pte = pte_offset_kernel(pmd, address);
1366     if (pte_none(*pte) || !pte_present(*pte))
1367         return 0;
1368     if (mode && !pte_write(*pte))
1369         return 0;
1370     return 1;
1371 }
1372
1373 static int check_table_readable(probectl *P, PROBETYPE *ptr)
1374 {
1375     PROBETYPE *next_page;
1376     int i = 0, delta;
1377
1378     while (i < _SS(NR_syscalls)) {
1379         next_page = (PROBETYPE *)PAGE_ALIGN((unsigned long)(ptr+1));
1380         delta = next_page - ptr;
1381         if (!check_access((unsigned long)ptr, 0)) {
1382 #ifdef OSI_PROBE_DEBUG
1383             if (probe_debug & 0x0080)
1384                 printk("<7>osi_probe: %s                      0x%016lx not readable; delta=0x%lx\n",
1385                        P->symbol, (unsigned long)ptr, delta);
1386 #endif
1387             return delta - 1;
1388         }
1389         ptr += delta;
1390         i += delta;
1391     }
1392     return -1;
1393 }
1394 #endif
1395
1396 void *osi_find_syscall_table(int which)
1397 {
1398     probectl *P;
1399     void *answer;
1400     char *method;
1401
1402     if (which < 0 || which >= N_PROBE_LIST) {
1403         printk("error - afs_find_syscall_table called with invalid index!\n");
1404         return 0;
1405     }
1406     P = probe_list[which];
1407     if (which < 4) {
1408         P->parm_answer = (void *)sys_call_table_addr[which];
1409 #ifdef OSI_PROBE_DEBUG
1410         P->debug_answer = (void *)probe_debug_addr[which];
1411 #endif
1412     }
1413     answer = do_find_syscall_table(P, &method);
1414     if (!answer) {
1415         printk("Warning: failed to find address of %s\n", P->desc);
1416         printk("System call hooks will not be installed; proceeding anyway\n");
1417         return 0;
1418     }
1419     printk("Found %s at 0x%lx (%s)\n", P->desc, (unsigned long)answer, method);
1420 #if defined(AFS_I386_LINUX26_ENV) || defined(AFS_AMD64_LINUX26_ENV)
1421     if (!check_access((unsigned long)answer, 1)) {
1422         printk("Address 0x%lx is not writable.\n", (unsigned long)answer);
1423         printk("System call hooks will not be installed; proceeding anyway\n");
1424         return 0;
1425     }
1426 #endif
1427     return answer;
1428 }
1429
1430
1431 #ifdef OSI_PROBE_STANDALONE
1432 int __init osi_probe_init(void)
1433 {
1434     int i;
1435
1436     if (!probe_debug_tag) probe_debug_tag = jiffies;
1437     printk("*** osi_probe %ld debug = 0x%04x ***\n",
1438            probe_debug_tag, probe_debug);
1439     for (i = 0; i < N_PROBE_LIST; i++)
1440         (void)osi_find_syscall_table(i);
1441     return 0;
1442 }
1443
1444 void osi_probe_exit(void) { }
1445
1446 module_init(osi_probe_init);
1447 module_exit(osi_probe_exit);
1448 #endif
1449
1450 #else
1451 void *osi_find_syscall_table(int which)
1452 {
1453     return 0;
1454 }
1455 #endif /* EXPORTED_INIT_MM */