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