/* 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
+
+#if defined(ENABLE_LINUX_SYSCALL_PROBING) && defined(EXPORTED_INIT_MM)
#include <linux/module.h> /* early to avoid printf->printk mapping */
+#include <scsi/scsi.h> /* for scsi_command_size */
#ifndef OSI_PROBE_STANDALONE
-#include "afs/sysincludes.h"
-#include "afsincludes.h"
+# include "afs/sysincludes.h"
+# include "afsincludes.h"
#endif
#include <linux/version.h>
-#include <linux/config.h>
+#include <linux/sched.h>
+#ifdef HAVE_LINUX_CONFIG_H
+# include <linux/config.h>
+#endif
#include <linux/linkage.h>
#include <linux/init.h>
#include <linux/unistd.h>
#include <linux/mm.h>
-#ifdef AFS_LINUX26_ENV
-#include <scsi/scsi.h> /* for scsi_command_size */
-#endif
#if defined(AFS_PPC64_LINUX26_ENV)
-#include <asm/abs_addr.h>
+# include <asm/abs_addr.h>
#endif
#ifdef AFS_AMD64_LINUX20_ENV
-#include <asm/ia32_unistd.h>
+# include <asm/ia32_unistd.h>
#endif
/* number of syscalls */
/* If this is set, we are more careful about avoiding duplicate matches */
static int probe_carefully = 1;
-#ifdef module_param
+#if defined(module_param) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
module_param(probe_carefully, int, 0);
#else
MODULE_PARM(probe_carefully, "i");
* 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;
-#ifdef module_param
+#if defined(module_param) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
module_param(probe_debug, int, 0);
#else
MODULE_PARM(probe_debug, "i");
MODULE_PARM_DESC(probe_debug_addr, "Debug range starting locations");
static unsigned long probe_debug_range = 0;
-#ifdef module_param
+#if defined(module_param) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
module_param(probe_debug_range, long, 0);
#else
MODULE_PARM(probe_debug_range, "l");
MODULE_PARM_DESC(probe_debug_range, "Debug range length");
static unsigned long probe_debug_tag = 0;
-#ifdef module_param
+#if defined(module_param) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
module_param(probe_debug_tag, long, 0);
#else
MODULE_PARM(probe_debug_tag, "l");
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));
-extern rwlock_t tasklist_lock __attribute__((weak));
/* Structures used to control probing. We put all the details of which
int debug_ignore_NR[4]; /* syscalls to ignore for debugging */
} probectl;
+#if defined(AFS_I386_LINUX26_ENV) || defined(AFS_AMD64_LINUX26_ENV)
+static int check_access(unsigned long, int);
+static int check_table_readable(probectl *, PROBETYPE *);
+#endif
/********** Probing Configuration: sys_call_table **********/
* 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
/* symbol in section to try scanning */
#if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390_LINUX20_ENV) || defined(AFS_S390X_LINUX20_ENV)
(unsigned long)&sys_close,
-#elif defined(AFS_AMD64_LINUX20_ENV)
+#elif defined(AFS_AMD64_LINUX26_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
(unsigned long)(&init_mm),
0x1fffff,
0x30000,
-#elif defined(AFS_AMD64_LINUX20_ENV)
- (unsigned long)(&tasklist_lock) - 0x30000,
+#elif defined(AFS_AMD64_LINUX26_ENV)
+ (unsigned long)(&generic_ro_fops) - 0x30000,
0,
0x6000,
#elif defined(AFS_PPC64_LINUX26_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
-#ifdef AFS_LINUX26_ENV
- (unsigned long)scsi_command_size,
(unsigned long)scsi_command_size,
+ (unsigned long)scsi_command_size - 0x10000,
0x3ffff,
- 0x30000,
-#else
- 0, 0, 0, 0,
-#endif
+ 0x40000,
/* number and list of unimplemented system calls */
((sizeof(main_zapped_syscalls)/sizeof(main_zapped_syscalls[0])) - 1),
0,
(0x180000 / sizeof(unsigned long *)),
-#ifdef AFS_LINUX26_ENV
- (unsigned long)scsi_command_size,
(unsigned long)scsi_command_size,
+ (unsigned long)scsi_command_size - 0x10000,
0x3ffff,
- 0x30000,
-#else
- 0, 0, 0, 0,
-#endif
+ 0x40000,
/* number and list of unimplemented system calls */
16384,
#endif
-#ifdef AFS_LINUX26_ENV
- (unsigned long)scsi_command_size,
(unsigned long)scsi_command_size,
+ (unsigned long)scsi_command_size - 0x10000,
0x3ffff,
- 0x30000,
-#else
- 0, 0, 0, 0,
-#endif
+ 0x40000,
/* number and list of unimplemented system calls */
((sizeof(sct32_zapped_syscalls)/sizeof(sct32_zapped_syscalls[0])) - 1),
0xfffff,
0x20000,
-#ifdef AFS_LINUX26_ENV
- (unsigned long)scsi_command_size,
(unsigned long)scsi_command_size,
+ (unsigned long)scsi_command_size - 0x10000,
0x3ffff,
- 0x30000,
-#else
- 0, 0, 0, 0,
-#endif
+ 0x40000,
/* number and list of unimplemented system calls */
((sizeof(emu_zapped_syscalls)/sizeof(emu_zapped_syscalls[0])) - 1),
PROBETYPE *x;
int i, j;
+#if defined(AFS_I386_LINUX26_ENV) || defined(AFS_AMD64_LINUX26_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) {
ptr = aptr;
#endif
if ((unsigned long)ptr < init_mm.start_code ||
- (unsigned long)ptr > init_mm.end_data) {
+#if defined(AFS_AMD64_LINUX20_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;
}
unsigned long ip1;
int i, s;
+#if defined(AFS_I386_LINUX26_ENV) || defined(AFS_AMD64_LINUX26_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])]) {
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 ||
- (unsigned long)ptr > init_mm.end_data) {
+ if ((unsigned long)ptr < init_mm.start_code ||
+#if defined(AFS_AMD64_LINUX20_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;
}
if (probe_debug & 0x0001) { \
printk("<7>osi_probe: %s = 0x%016lx %s\n", P->symbol, (unsigned long)(x), (m)); \
} \
- if ((x)) { \
+ if ((x) && ((int)(x)) != -ENOENT) { \
*method = (m); \
final_answer = (void *)(x); \
} \
} while (0)
#else
#define check_result(x,m) do { \
- if ((x)) { \
+ if ((x) && ((int)(x)) != -ENOENT) { \
*method = (m); \
return (void *)(x); \
} \
}
#if defined(AFS_I386_LINUX26_ENV) || defined(AFS_AMD64_LINUX26_ENV)
-static int check_writable(unsigned long address)
+static int check_access(unsigned long address, int mode)
{
pgd_t *pgd = pgd_offset_k(address);
#ifdef PUD_SIZE
pte = (pte_t *)pmd;
else
pte = pte_offset_kernel(pmd, address);
- if (pte_none(*pte) || !pte_present(*pte) || !pte_write(*pte))
+ 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
+ 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)
}
printk("Found %s at 0x%lx (%s)\n", P->desc, (unsigned long)answer, method);
#if defined(AFS_I386_LINUX26_ENV) || defined(AFS_AMD64_LINUX26_ENV)
- if (!check_writable((unsigned long)answer)) {
+ 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;
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 */