/* Code to find the Linux syscall table */
#ifdef OSI_PROBE_STANDALONE
-#define OSI_PROBE_DEBUG
+# define OSI_PROBE_DEBUG
#endif
#ifndef OSI_PROBE_STANDALONE
-#include <afsconfig.h>
-#include "afs/param.h"
+# include <afsconfig.h>
+# include "afs/param.h"
#endif
-#ifdef AFS_LINUX24_ENV
+
+#include <linux/version.h>
+#if defined(ENABLE_LINUX_SYSCALL_PROBING)
#include <linux/module.h> /* early to avoid printf->printk mapping */
+#include <scsi/scsi.h> /* for scsi_command_size */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26)
+/* Slightly kludgy, but too bad */
+#define scsi_command_size scsi_command_size_tbl
+#endif
#ifndef OSI_PROBE_STANDALONE
-#include "afs/sysincludes.h"
-#include "afsincludes.h"
+# include "afs/sysincludes.h"
+# include "afsincludes.h"
+#endif
+#include <linux/sched.h>
+#ifdef HAVE_LINUX_CONFIG_H
+# include <linux/config.h>
#endif
-#include <linux/version.h>
-#include <linux/config.h>
#include <linux/linkage.h>
#include <linux/init.h>
#include <linux/unistd.h>
#include <linux/mm.h>
-#if defined(AFS_PPC64_LINUX26_ENV)
-#include <asm/abs_addr.h>
+#if defined(AFS_PPC64_LINUX_ENV)
+# include <asm/abs_addr.h>
#endif
-#ifdef AFS_AMD64_LINUX20_ENV
-#include <asm/ia32_unistd.h>
+#ifdef AFS_AMD64_LINUX_ENV
+# include <asm/ia32_unistd.h>
#endif
/* number of syscalls */
#endif
/* lower bound of valid kernel text pointers */
-#ifdef AFS_IA64_LINUX20_ENV
+#ifdef AFS_IA64_LINUX_ENV
#define ktxt_lower_bound (((unsigned long)&kernel_thread ) & 0xfff00000L)
-#elif defined(AFS_PPC64_LINUX20_ENV)
+#elif defined(AFS_PPC64_LINUX_ENV)
#define ktxt_lower_bound (KERNELBASE)
#else
#define ktxt_lower_bound (((unsigned long)&kernel_thread ) & ~0xfffffL)
/* On SPARC64 and S390X, sys_call_table contains 32-bit entries
* even though pointers are 64 bit quantities.
*/
-#if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390X_LINUX24_ENV)
+#if defined(AFS_SPARC64_LINUX_ENV) || defined(AFS_S390X_LINUX_ENV)
#define SYSCALLTYPE unsigned int
#define PROBETYPE int
#else
#define PROBETYPE long
#endif
-#if defined(AFS_S390X_LINUX20_ENV) && !defined(AFS_S390X_LINUX26_ENV)
+#if defined(AFS_S390X_LINUX_ENV) && !defined(AFS_S390X_LINUX_ENV)
#define _SS(x) ((x) << 1)
#define _SX(x) ((x) &~ 1)
#else
/* Allow the user to specify sys_call_table addresses */
static unsigned long sys_call_table_addr[4] = { 0,0,0,0 };
-MODULE_PARM(sys_call_table_addr, "1-4l");
+module_param_array(sys_call_table_addr, long, NULL, 0);
MODULE_PARM_DESC(sys_call_table_addr, "Location of system call tables");
/* If this is set, we are more careful about avoiding duplicate matches */
static int probe_carefully = 1;
-MODULE_PARM(probe_carefully, "i");
+module_param(probe_carefully, int, 0);
MODULE_PARM_DESC(probe_carefully, "Probe for system call tables carefully");
static int probe_ignore_syscalls[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
-MODULE_PARM(probe_ignore_syscalls, "1-8i");
+module_param_array(probe_ignore_syscalls, int, NULL, 0);
MODULE_PARM_DESC(probe_ignore_syscalls, "Syscalls to ignore in table checks");
#ifdef OSI_PROBE_DEBUG
* 0x0010 - detail - check_harder
* 0x0020 - detail - check_harder/zapped
* 0x0040 - automatically ignore setgroups and afs_syscall
+ * 0x0080 - detail - check_table_readable
*/
static int probe_debug = 0x41;
-MODULE_PARM(probe_debug, "i");
+module_param(probe_debug, int, 0);
MODULE_PARM_DESC(probe_debug, "Debugging level");
static unsigned long probe_debug_addr[4] = { 0,0,0,0 };
-MODULE_PARM(probe_debug_addr, "1-4l");
+module_param_array(probe_debug_addr, long, NULL, 0);
MODULE_PARM_DESC(probe_debug_addr, "Debug range starting locations");
static unsigned long probe_debug_range = 0;
-MODULE_PARM(probe_debug_range, "l");
+module_param(probe_debug_range, long, 0);
MODULE_PARM_DESC(probe_debug_range, "Debug range length");
static unsigned long probe_debug_tag = 0;
-MODULE_PARM(probe_debug_tag, "l");
+module_param(probe_debug_tag, long, 0);
MODULE_PARM_DESC(probe_debug_tag, "Debugging output start tag");
#endif
extern asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count) __attribute__((weak));
extern asmlinkage long sys_close(unsigned int) __attribute__((weak));
+#if defined(EXPORTED_SYS_CHDIR)
extern asmlinkage long sys_chdir(const char *) __attribute__((weak));
+#endif
extern asmlinkage ssize_t sys_write(unsigned int, const char *, size_t) __attribute__((weak));
-#ifdef AFS_LINUX26_ENV
extern asmlinkage long sys_wait4(pid_t, int *, int, struct rusage *) __attribute__((weak));
-#else
-extern asmlinkage long sys_wait4(pid_t, unsigned int *, int, struct rusage *) __attribute__((weak));
-#endif
extern asmlinkage long sys_exit (int) __attribute__((weak));
+#if defined(EXPORTED_SYS_OPEN)
extern asmlinkage long sys_open (const char *, int, int) __attribute__((weak));
+#endif
extern asmlinkage long sys_ioctl(unsigned int, unsigned int, unsigned long) __attribute__((weak));
unsigned long try_base_mask; /* base address bits to force to zero */
unsigned long try_length; /* default length for scan */
+ unsigned long alt_try_sect_sym; /* symbol in section to try scanning */
+ unsigned long alt_try_base; /* default base address for scan */
+ unsigned long alt_try_base_mask; /* base address bits to force to zero */
+ unsigned long alt_try_length; /* default length for scan */
+
int n_zapped_syscalls; /* number of unimplemented system calls */
int *zapped_syscalls; /* list of unimplemented system calls */
int debug_ignore_NR[4]; /* syscalls to ignore for debugging */
} probectl;
+#if defined(AFS_I386_LINUX_ENV) || defined(AFS_AMD64_LINUX_ENV)
+static int check_access(unsigned long, int);
+static int check_table_readable(probectl *, PROBETYPE *);
+#endif
/********** Probing Configuration: sys_call_table **********/
/* syscall pairs/triplets to probe */
/* On PPC64 and SPARC64, we need to omit the ones that might match both tables */
static tryctl main_try[] = {
-#if !defined(AFS_PPC64_LINUX20_ENV) && !defined(AFS_SPARC64_LINUX20_ENV)
+#if !defined(AFS_PPC64_LINUX_ENV) && !defined(AFS_SPARC64_LINUX_ENV)
+#if defined(EXPORTED_SYS_CHDIR)
{ "scan: close+chdir+write", __NR_close, &sys_close, __NR_chdir, &sys_chdir, __NR_write, &sys_write },
#endif
+#endif
{ "scan: close+wait4", __NR_close, &sys_close, __NR_wait4, &sys_wait4, -1, 0 },
-#if !defined(AFS_PPC64_LINUX20_ENV) && !defined(AFS_SPARC64_LINUX20_ENV)
+#if !defined(AFS_PPC64_LINUX_ENV) && !defined(AFS_SPARC64_LINUX_ENV)
+#if defined(EXPORTED_SYS_CHDIR)
{ "scan: close+chdir", __NR_close, &sys_close, __NR_chdir, &sys_chdir, -1, 0 },
#endif
+#endif
{ "scan: close+ioctl", __NR_close, &sys_close, __NR_ioctl, &sys_ioctl, -1, 0 },
+#if defined(EXPORTED_SYS_OPEN)
{ "scan: exit+open", __NR_exit, &sys_exit, __NR_open, &sys_open, -1, 0 },
+#endif
{ 0 }
};
* other entries, or we might get a sys_ni_syscall into the list and
* the test would no longer work.
*/
-#if defined(AFS_SPARC64_LINUX20_ENV)
+#if defined(AFS_SPARC64_LINUX_ENV)
/* mmap2, fstat64, getmsg, putmsg, modify_ldt */
56, 63, 151, 152, 218,
-#elif defined(AFS_SPARC_LINUX20_ENV)
+#elif defined(AFS_SPARC_LINUX_ENV)
/* memory_ordering, getmsg, putmsg, unimplemented, modify_ldt */
52, 151, 152, 164, 218,
-#else /* !AFS_SPARC_LINUX20_ENV */
+#else /* !AFS_SPARC_LINUX_ENV */
/*
* These 7 syscalls are present in the syscall table on most "older"
* corresponding __NR macros are not defined, so the tests above fail.
* Instead, we just have to know the numbers for these.
*/
-#if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
+#if defined(AFS_S390_LINUX_ENV) || defined(AFS_S390X_LINUX_ENV)
/* break, stty, gtty, ftime, prof, lock, mpx */
17, 31, 32, 35, 44, 53, 56,
#endif
* The module-loading mechanism changed in Linux 2.6, and insmod's
* loss is our gain: three new unimplemented system calls!
*/
-#if defined(AFS_LINUX26_ENV)
#ifdef __NR_
__NR_create_module,
#endif
#ifdef __NR_get_kernel_syms
__NR_get_kernel_syms,
#endif
-#endif /* AFS_LINUX26_ENV */
/*
* On IA64, the old module-loading calls are indeed present and
* unimplemented, but the __NR macros are not defined. Again,
* we simply have to know their numbers.
*/
-#ifdef AFS_IA64_LINUX26_ENV
+#ifdef AFS_IA64_LINUX_ENV
/* create_module, query_module, get_kernel_sysms */
1132, 1136, 1135,
#endif
-/* And the same deal for arm (not arm26), if we ever support that. */
-#if 0
- /* create_module, query_module, get_kernel_sysms */
- 127, 167, 130,
-#endif
-
/*
* Alpha-Linux uses syscall number mappings chosen to be compatible
* with OSF/1. So, it doesn't have any of the traditional calls or
* unimplemented calls are very similar.
* mmap2 and fstat64 are implemented only for 32-bit calls
*/
-#ifdef AFS_PPC64_LINUX20_ENV
+#ifdef AFS_PPC64_LINUX_ENV
/* _mmap2, _fstat64 */
192, 197,
-#endif /* AFS_PPC64_LINUX20_ENV */
+#endif /* AFS_PPC64_LINUX_ENV */
/* Similarly for S390X, with lcown16 and fstat64 */
-#ifdef AFS_S390X_LINUX20_ENV
+#ifdef AFS_S390X_LINUX_ENV
/* lchown16, fstat64 */
16, 197,
#endif
-#endif /* !AFS_SPARC_LINUX20_ENV */
+#endif /* !AFS_SPARC_LINUX_ENV */
0
};
/* unique syscalls for try_harder */
static int main_unique_syscalls[] = {
-#if defined(AFS_SPARC64_LINUX24_ENV) || defined(AFS_SPARC_LINUX24_ENV)
+#if defined(AFS_SPARC64_LINUX_ENV) || defined(AFS_SPARC_LINUX_ENV)
/*
* On SPARC, we need some additional unique calls to make sure
* we don't match the SunOS-compatibility table.
"system call table",
/* syscall number of first entry in table */
-#ifdef AFS_IA64_LINUX20_ENV
+#ifdef AFS_IA64_LINUX_ENV
1024,
#else
0,
main_try, /* array of combinations to try */
/* symbol in section to try scanning */
-#if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
+#if defined(AFS_SPARC64_LINUX_ENV) || defined(AFS_S390_LINUX_ENV) || defined(AFS_S390X_LINUX_ENV)
(unsigned long)&sys_close,
-#elif defined(AFS_AMD64_LINUX20_ENV)
+#elif defined(AFS_AMD64_LINUX_ENV)
/* On this platform, it's in a different section! */
- (unsigned long)&tasklist_lock,
+ (unsigned long)&generic_ro_fops,
#else
(unsigned long)&init_mm,
#endif
/* default base address for scan */
/* base address bits to force to zero */
/* default length for scan */
-#if defined(AFS_SPARC64_LINUX20_ENV)
+#if defined(AFS_SPARC64_LINUX_ENV)
(unsigned long)(&sys_close),
0xfffff,
0x10000,
-#elif defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
+#elif defined(AFS_S390_LINUX_ENV) || defined(AFS_S390X_LINUX_ENV)
/* bleah; this is so suboptimal */
(unsigned long)(&sys_close),
0xfffff,
0x20000,
-#elif defined(AFS_IA64_LINUX20_ENV)
+#elif defined(AFS_IA64_LINUX_ENV)
(unsigned long)(&init_mm),
0x1fffff,
0x30000,
-#elif defined(AFS_AMD64_LINUX20_ENV)
- (unsigned long)(&tasklist_lock) - 0x30000,
+#elif defined(AFS_AMD64_LINUX_ENV)
+ (unsigned long)(&generic_ro_fops) - 0x30000,
0,
0x6000,
-#elif defined(AFS_PPC64_LINUX26_ENV)
+#elif defined(AFS_PPC64_LINUX_ENV)
(unsigned long)(&do_signal),
0xfff,
0x400,
-#elif defined(AFS_PPC_LINUX20_ENV) || defined(AFS_PPC_LINUX20_ENV)
- (unsigned long)&init_mm,
- 0xffff,
- 16384,
#else
(unsigned long)&init_mm,
0,
16384,
#endif
+ (unsigned long)scsi_command_size,
+ (unsigned long)scsi_command_size - 0x10000,
+ 0x3ffff,
+ 0x40000,
+
/* number and list of unimplemented system calls */
((sizeof(main_zapped_syscalls)/sizeof(main_zapped_syscalls[0])) - 1),
main_zapped_syscalls,
/* syscalls to ignore for debugging */
{
-#if defined(AFS_ALPHA_LINUX20_ENV)
+#if defined(AFS_ALPHA_LINUX_ENV)
338,
-#elif defined(AFS_AMD64_LINUX20_ENV)
+#elif defined(AFS_AMD64_LINUX_ENV)
183,
-#elif defined(AFS_IA64_LINUX20_ENV)
+#elif defined(AFS_IA64_LINUX_ENV)
1141,
-#elif defined(AFS_SPARC_LINUX20_ENV) || defined(AFS_SPARC64_LINUX20_ENV)
+#elif defined(AFS_SPARC_LINUX_ENV) || defined(AFS_SPARC64_LINUX_ENV)
227,
#else
137,
/********** Probing Configuration: amd64 ia32_sys_call_table **********/
-#if defined(AFS_AMD64_LINUX20_ENV)
+#if defined(AFS_AMD64_LINUX_ENV)
/* syscall pairs/triplets to probe */
static tryctl ia32_try[] = {
+#if defined(EXPORTED_SYS_CHDIR)
{ "scan: close+chdir+write", __NR_ia32_close, &sys_close, __NR_ia32_chdir, &sys_chdir, __NR_ia32_write, &sys_write },
{ "scan: close+chdir", __NR_ia32_close, &sys_close, __NR_ia32_chdir, &sys_chdir, -1, 0 },
+#endif
{ 0 }
};
0,
(0x180000 / sizeof(unsigned long *)),
+ (unsigned long)scsi_command_size,
+ (unsigned long)scsi_command_size - 0x10000,
+ 0x3ffff,
+ 0x40000,
+
+
/* number and list of unimplemented system calls */
((sizeof(ia32_zapped_syscalls)/sizeof(ia32_zapped_syscalls[0])) - 1),
ia32_zapped_syscalls,
/********** Probing Configuration: IA64 **********/
-#elif defined(AFS_IA64_LINUX20_ENV)
+#elif defined(AFS_IA64_LINUX_ENV)
struct fptr {
void *ip;
unsigned long gp;
/********** Probing Configuration: ppc64, sparc64 sys_call_table32 **********/
-#elif defined(AFS_PPC64_LINUX20_ENV) || defined(AFS_SPARC64_LINUX20_ENV)
+#elif defined(AFS_PPC64_LINUX_ENV) || defined(AFS_SPARC64_LINUX_ENV)
struct fptr {
void *ip;
unsigned long gp;
/* zapped syscalls for try_harder */
static int sct32_zapped_syscalls[] = {
-#ifdef AFS_PPC64_LINUX20_ENV
+#ifdef AFS_PPC64_LINUX_ENV
/* These should be sufficient */
__NR_break, __NR_stty, __NR_gtty, __NR_ftime,
__NR_prof, __NR_lock, __NR_mpx,
#endif
-#ifdef AFS_SPARC64_LINUX20_ENV
+#ifdef AFS_SPARC64_LINUX_ENV
/* memory_ordering, getmsg, putmsg, unimplemented, modify_ldt */
52, 151, 152, 164, 218,
#endif
/* unique syscalls for try_harder */
/* mmap2 and fstat64 are implemented only for 32-bit calls */
static int sct32_unique_syscalls[] = {
-#ifdef AFS_PPC64_LINUX20_ENV
+#ifdef AFS_PPC64_LINUX_ENV
/* _mmap2, _fstat64 */
192, 197,
#endif
-#ifdef AFS_SPARC64_LINUX24_ENV
+#ifdef AFS_SPARC64_LINUX_ENV
/*
* On SPARC, we need some additional unique calls to make sure
* we don't match the SunOS-compatibility table.
sct32_try, /* array of combinations to try */
/* symbol in section to try scanning */
-#if defined(AFS_SPARC64_LINUX20_ENV)
+#if defined(AFS_SPARC64_LINUX_ENV)
(unsigned long)&sys_close,
#else
(unsigned long)&init_mm,
/* default base address for scan */
/* base address bits to force to zero */
/* default length for scan */
-#if defined(AFS_SPARC64_LINUX20_ENV)
+#if defined(AFS_SPARC64_LINUX_ENV)
(unsigned long)(&sys_close),
0xfffff,
0x10000,
-#elif defined(AFS_PPC64_LINUX26_ENV)
+#elif defined(AFS_PPC64_LINUX_ENV)
(unsigned long)(&do_signal),
0xfff,
0x400,
16384,
#endif
+ (unsigned long)scsi_command_size,
+ (unsigned long)scsi_command_size - 0x10000,
+ 0x3ffff,
+ 0x40000,
+
/* number and list of unimplemented system calls */
((sizeof(sct32_zapped_syscalls)/sizeof(sct32_zapped_syscalls[0])) - 1),
sct32_zapped_syscalls,
/* syscalls to ignore for debugging */
{
-#if defined(AFS_SPARC64_LINUX20_ENV)
+#if defined(AFS_SPARC64_LINUX_ENV)
227,
#else
137,
* On earlier versions, the two tables were interleaved and so
* have related base addresses.
*/
-#elif defined(AFS_S390X_LINUX26_ENV)
+#elif defined(AFS_S390X_LINUX_ENV)
/* syscall pairs/triplets to probe */
/* nothing worthwhile is exported, so this is empty */
0xfffff,
0x20000,
+ (unsigned long)scsi_command_size,
+ (unsigned long)scsi_command_size - 0x10000,
+ 0x3ffff,
+ 0x40000,
+
/* number and list of unimplemented system calls */
((sizeof(emu_zapped_syscalls)/sizeof(emu_zapped_syscalls[0])) - 1),
emu_zapped_syscalls,
PROBETYPE *x;
int i, j;
+#if defined(AFS_I386_LINUX_ENV) || defined(AFS_AMD64_LINUX_ENV)
+ i = check_table_readable(P, ptr);
+ if (i >= 0) return i;
+#endif
+
for (x = ptr, i = 0; i < _SS(NR_syscalls); i++, x++) {
#ifdef OSI_PROBE_DEBUG
if (probe_debug & 0x0040) {
int ret;
PROBETYPE *ptr;
-#if defined(AFS_IA64_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV)
+#if defined(AFS_IA64_LINUX_ENV) || defined(AFS_PPC64_LINUX_ENV)
ip1 = T->fn1 ? (unsigned long)((struct fptr *)T->fn1)->ip : 0;
ip2 = T->fn2 ? (unsigned long)((struct fptr *)T->fn2)->ip : 0;
ip3 = T->fn3 ? (unsigned long)((struct fptr *)T->fn3)->ip : 0;
return 0;
for (offset = 0; offset < datalen; offset++, aptr++) {
-#if defined(AFS_PPC64_LINUX20_ENV)
+#if defined(AFS_PPC64_LINUX_ENV)
ptr = (PROBETYPE*)(*aptr);
if ((unsigned long)ptr <= KERNELBASE) {
continue;
#else
ptr = aptr;
#endif
+ if ((unsigned long)ptr < init_mm.start_code ||
+#if defined(AFS_AMD64_LINUX_ENV)
+ (unsigned long)ptr > init_mm.brk)
+#else
+ (unsigned long)ptr > init_mm.end_data)
+#endif
+ {
+/* printk("address 0x%lx (from 0x%lx %d) is out of range in check_table. wtf?\n", (unsigned long)x, (unsigned long)ptr, i);*/
+ continue;
+ }
+
ret = check_table(P, ptr);
if (ret >= 0) {
/* return value is number of entries to skip */
unsigned long ip1;
int i, s;
+#if defined(AFS_I386_LINUX_ENV) || defined(AFS_AMD64_LINUX_ENV)
+ i = check_table_readable(P, p);
+ if (i >= 0) return 0;
+#endif
+
/* Check zapped syscalls */
for (i = 1; i < P->n_zapped_syscalls; i++) {
if (p[_SS(P->zapped_syscalls[i])] != p[_SS(P->zapped_syscalls[0])]) {
}
}
-#if defined(AFS_IA64_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV)
+#if defined(AFS_IA64_LINUX_ENV) || defined(AFS_PPC64_LINUX_ENV)
ip1 = P->verify_fn ? (unsigned long)((struct fptr *)(P->verify_fn))->ip : 0;
#else
ip1 = (unsigned long)(P->verify_fn);
printk("<7>osi_probe: %s try_harder\n", P->symbol);
#endif
for (offset = 0; offset < datalen; offset++, ptr++) {
+ if ((unsigned long)ptr < init_mm.start_code ||
+#if defined(AFS_AMD64_LINUX_ENV)
+ (unsigned long)ptr > init_mm.brk)
+#else
+ (unsigned long)ptr > init_mm.end_data)
+#endif
+ {
+/* printk("address 0x%lx (from 0x%lx %d) is out of range in check_table. wtf?\n", (unsigned long)x, (unsigned long)ptr, i);*/
+ continue;
+ }
ret = check_table(P, ptr);
if (ret >= 0) {
/* return value is number of entries to skip */
if (probe_debug & 0x0001) { \
printk("<7>osi_probe: %s = 0x%016lx %s\n", P->symbol, (unsigned long)(x), (m)); \
} \
- if ((x)) { \
+ if ((x) && ((long)(x)) != -ENOENT) { \
*method = (m); \
final_answer = (void *)(x); \
} \
} while (0)
#else
#define check_result(x,m) do { \
- if ((x)) { \
+ if ((x) && ((long)(x)) != -ENOENT) { \
*method = (m); \
return (void *)(x); \
} \
} while (0)
#endif
+static void *scan_for_syscall_table(probectl *P, PROBETYPE *B, unsigned long L)
+{
+ tryctl *T;
+ void *answer;
+#if defined(AFS_S390_LINUX_ENV) || defined(AFS_S390X_LINUX_ENV)
+ void *answer2;
+#endif
+#ifdef OSI_PROBE_DEBUG
+ void *final_answer = 0;
+#endif
+#ifdef OSI_PROBE_DEBUG
+ if (probe_debug & 0x0007)
+ printk("<7>osi_probe: %s base=0x%lx, len=0x%lx\n",
+ P->symbol, (unsigned long)B, L);
+ if (probe_debug & 0x0009) {
+ printk("<7>osi_probe: %s ktxt_lower_bound=0x%lx\n",
+ P->symbol, ktxt_lower_bound);
+ printk("<7>osi_probe: %s NR_syscalls=%d\n",
+ P->symbol, NR_syscalls);
+ }
+#endif
+
+ for (T = P->trylist; T->name; T++) {
+ answer = try(P, T, B, L);
+#if defined(AFS_S390_LINUX_ENV) || defined(AFS_S390X_LINUX_ENV)
+ answer2 = try(P, T, (PROBETYPE *)(2 + (void *)B), L);
+#ifdef OSI_PROBE_DEBUG
+ if (probe_debug & 0x0003) {
+ printk("<7>osi_probe: %s = 0x%016lx %s (even)\n",
+ P->symbol, (unsigned long)(answer), T->name);
+ printk("<7>osi_probe: %s = 0x%016lx %s (odd)\n",
+ P->symbol, (unsigned long)(answer2), T->name);
+ }
+#endif
+ if (answer && answer2) answer = 0;
+ else if (answer2) answer = answer2;
+#endif
+ if (answer)
+ return answer;
+ }
+
+ /* XXX more checks here */
+
+ answer = try_harder(P, B, L);
+#if defined(AFS_S390_LINUX_ENV) || defined(AFS_S390X_LINUX_ENV)
+ answer2 = try_harder(P, (PROBETYPE *)(2 + (void *)B), L);
+#ifdef OSI_PROBE_DEBUG
+ if (probe_debug & 0x0005) {
+ printk("<7>osi_probe: %s = 0x%016lx pattern scan (even)\n",
+ P->symbol, (unsigned long)(answer));
+ printk("<7>osi_probe: %s = 0x%016lx pattern scan (odd)\n",
+ P->symbol, (unsigned long)(answer2));
+ }
+#endif
+ if (answer && answer2) answer = 0;
+ else if (answer2) answer = answer2;
+#endif
+ return answer;
+}
+
static void *do_find_syscall_table(probectl *P, char **method)
{
#ifdef OSI_PROBE_KALLSYMS
#endif
PROBETYPE *B;
unsigned long L;
- tryctl *T;
void *answer;
-#if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
- void *answer2;
-#endif
#ifdef OSI_PROBE_DEBUG
void *final_answer = 0;
#endif
}
}
#endif
-
-#ifdef OSI_PROBE_DEBUG
- if (probe_debug & 0x0007)
- printk("<7>osi_probe: %s base=0x%lx, len=0x%lx\n",
- P->symbol, (unsigned long)B, L);
- if (probe_debug & 0x0009) {
- printk("<7>osi_probe: %s ktxt_lower_bound=0x%lx\n",
- P->symbol, ktxt_lower_bound);
- printk("<7>osi_probe: %s NR_syscalls=%d\n",
- P->symbol, NR_syscalls);
+
+ answer = scan_for_syscall_table(P, B, L);
+ check_result(answer, "pattern scan");
+ B = (PROBETYPE *)((P->alt_try_base) & ~(P->alt_try_base_mask));
+ L = P->alt_try_length;
+ /* Now, see if the kernel will tell us something better than the default */
+#ifdef OSI_PROBE_KALLSYMS
+ if (kallsyms_address_to_symbol && P->alt_try_sect_sym) {
+ ret = kallsyms_address_to_symbol(P->alt_try_sect_sym,
+ &mod_name, &mod_start, &mod_end,
+ &sec_name, &sec_start, &sec_end,
+ &sym_name, &sym_start, &sym_end);
+ if (ret) {
+ B = (PROBETYPE *)sec_start;
+ L = (sec_end - sec_start) / sizeof(unsigned long);
+ }
}
#endif
-
- for (T = P->trylist; T->name; T++) {
- answer = try(P, T, B, L);
-#if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
- answer2 = try(P, T, (PROBETYPE *)(2 + (void *)B), L);
+ if (B && L) {
+ answer = scan_for_syscall_table(P, B, L);
+ check_result(answer, "pattern scan");
+ }
#ifdef OSI_PROBE_DEBUG
- if (probe_debug & 0x0003) {
- printk("<7>osi_probe: %s = 0x%016lx %s (even)\n",
- P->symbol, (unsigned long)(answer), T->name);
- printk("<7>osi_probe: %s = 0x%016lx %s (odd)\n",
- P->symbol, (unsigned long)(answer2), T->name);
- }
-#endif
- if (answer && answer2) answer = 0;
- else if (answer2) answer = answer2;
+ return final_answer;
+#else
+ return 0;
#endif
- check_result(answer, T->name);
- }
-
- /* XXX more checks here */
+}
- answer = try_harder(P, B, L);
-#if defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
- answer2 = try_harder(P, (PROBETYPE *)(2 + (void *)B), L);
-#ifdef OSI_PROBE_DEBUG
- if (probe_debug & 0x0005) {
- printk("<7>osi_probe: %s = 0x%016lx pattern scan (even)\n",
- P->symbol, (unsigned long)(answer));
- printk("<7>osi_probe: %s = 0x%016lx pattern scan (odd)\n",
- P->symbol, (unsigned long)(answer2));
- }
+#if defined(AFS_I386_LINUX_ENV) || defined(AFS_AMD64_LINUX_ENV)
+static int check_access(unsigned long address, int mode)
+{
+ pgd_t *pgd = pgd_offset_k(address);
+#ifdef PUD_SIZE
+ pud_t *pud;
#endif
- if (answer && answer2) answer = 0;
- else if (answer2) answer = answer2;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ if (pgd_none(*pgd))
+ return 0;
+#ifdef PUD_SIZE
+ pud = pud_offset(pgd, address);
+ if (pud_none(*pud))
+ return 0;
+ pmd = pmd_offset(pud, address);
+#else
+ pmd = pmd_offset(pgd, address);
#endif
- check_result(answer, "pattern scan");
+ if (pmd_none(*pmd))
+ return 0;
+ if (pmd_large(*pmd))
+ pte = (pte_t *)pmd;
+ else
+ pte = pte_offset_kernel(pmd, address);
+ if (pte_none(*pte) || !pte_present(*pte))
+ return 0;
+ if (mode && !pte_write(*pte))
+ return 0;
+ return 1;
+}
+
+static int check_table_readable(probectl *P, PROBETYPE *ptr)
+{
+ PROBETYPE *next_page;
+ int i = 0, delta;
+ while (i < _SS(NR_syscalls)) {
+ next_page = (PROBETYPE *)PAGE_ALIGN((unsigned long)(ptr+1));
+ delta = next_page - ptr;
+ if (!check_access((unsigned long)ptr, 0)) {
#ifdef OSI_PROBE_DEBUG
- return final_answer;
-#else
- return 0;
+ if (probe_debug & 0x0080)
+ printk("<7>osi_probe: %s 0x%016lx not readable; delta=0x%lx\n",
+ P->symbol, (unsigned long)ptr, delta);
#endif
+ return delta - 1;
+ }
+ ptr += delta;
+ i += delta;
+ }
+ return -1;
}
+#endif
void *osi_find_syscall_table(int which)
{
return 0;
}
printk("Found %s at 0x%lx (%s)\n", P->desc, (unsigned long)answer, method);
+#if defined(AFS_I386_LINUX_ENV) || defined(AFS_AMD64_LINUX_ENV)
+ if (!check_access((unsigned long)answer, 1)) {
+ printk("Address 0x%lx is not writable.\n", (unsigned long)answer);
+ printk("System call hooks will not be installed; proceeding anyway\n");
+ return 0;
+ }
+#endif
return answer;
}
module_init(osi_probe_init);
module_exit(osi_probe_exit);
#endif
-#endif
+
+#else
+void *osi_find_syscall_table(int which)
+{
+ return 0;
+}
+#endif /* EXPORTED_INIT_MM */