linux-probe-syscall-table-again-20080703
[openafs.git] / src / afs / LINUX / osi_probe.c
index 16b5322..f661e9e 100644 (file)
@@ -52,6 +52,7 @@
 #include <afsconfig.h>
 #include "afs/param.h"
 #endif
+#if defined(EXPORTED_INIT_MM)
 #ifdef AFS_LINUX24_ENV
 #include <linux/module.h> /* early to avoid printf->printk mapping */
 #ifndef OSI_PROBE_STANDALONE
@@ -59,6 +60,7 @@
 #include "afsincludes.h"
 #endif
 #include <linux/version.h>
+#include <linux/sched.h>
 #ifdef CONFIG_H_EXISTS
 #include <linux/config.h>
 #endif
@@ -128,7 +130,7 @@ 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;
-#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");
@@ -153,9 +155,10 @@ MODULE_PARM_DESC(probe_ignore_syscalls, "Syscalls to ignore in table checks");
  * 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");
@@ -171,7 +174,7 @@ MODULE_PARM(probe_debug_addr, "1-4l");
 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");
@@ -179,7 +182,7 @@ 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");
@@ -298,6 +301,10 @@ typedef struct {
     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 **********/
@@ -512,9 +519,12 @@ static probectl main_probe = {
     /* 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)&generic_ro_fops,
+#elif defined(AFS_AMD64_LINUX20_ENV)
+    /* On this platform, it's in a different section! */
+    (unsigned long)&tasklist_lock,
 #else
     (unsigned long)&init_mm,
 #endif
@@ -535,10 +545,14 @@ static probectl main_probe = {
     (unsigned long)(&init_mm),
     0x1fffff,
     0x30000,
-#elif defined(AFS_AMD64_LINUX20_ENV)
+#elif defined(AFS_AMD64_LINUX26_ENV)
     (unsigned long)(&generic_ro_fops) - 0x30000,
     0,
     0x6000,
+#elif defined(AFS_AMD64_LINUX20_ENV)
+    (unsigned long)(&tasklist_lock) - 0x30000,
+    0,
+    0x6000,
 #elif defined(AFS_PPC64_LINUX26_ENV)
     (unsigned long)(&do_signal),
     0xfff,
@@ -940,6 +954,11 @@ static int check_table(probectl *P, PROBETYPE *ptr)
     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) {
@@ -1062,6 +1081,11 @@ static int check_harder(probectl *P, PROBETYPE *p)
     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])]) {
@@ -1349,7 +1373,7 @@ static void *do_find_syscall_table(probectl *P, char **method)
 }
 
 #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
@@ -1374,10 +1398,34 @@ static int check_writable(unsigned long address)
        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)
@@ -1405,7 +1453,7 @@ 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;
@@ -1434,3 +1482,9 @@ 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 */