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