#include <afsconfig.h>
#include "afs/param.h"
-RCSID
- ("$Header$");
-#ifdef AFS_LINUX24_ENV
#include <linux/module.h> /* early to avoid printf->printk mapping */
-#endif
#include "afs/sysincludes.h"
#include "afsincludes.h"
#include "h/unistd.h" /* For syscall numbers. */
#include <linux/proc_fs.h>
#include <linux/slab.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
#include <linux/init.h>
#include <linux/sched.h>
-#endif
#ifndef NR_syscalls
#define NR_syscalls 222
#define SYSCALL2POINTER (void *)
#endif
-#if defined(AFS_S390X_LINUX24_ENV) && !defined(AFS_LINUX26_ENV)
-#define _S(x) ((x)<<1)
-#elif defined(AFS_IA64_LINUX20_ENV)
+#if defined(AFS_S390X_LINUX24_ENV)
+#define INSERT_SYSCALL(SLOT, TMPPAGE, FUNC) \
+ if (SYSCALL2POINTER FUNC > 0x7fffffff) { \
+ TMPPAGE = kmalloc ( PAGE_SIZE, GFP_DMA|GFP_KERNEL ); \
+ if (SYSCALL2POINTER TMPPAGE > 0x7fffffff) { \
+ printf("Cannot allocate page for FUNC syscall jump vector\n"); \
+ return EINVAL; \
+ } \
+ memcpy(TMPPAGE, syscall_jump_code, sizeof(syscall_jump_code)); \
+ *(void **)(TMPPAGE + 0x0c) = &FUNC; \
+ afs_sys_call_table[_S(SLOT)] = POINTER2SYSCALL TMPPAGE; \
+ } else \
+ afs_sys_call_table[_S(SLOT)] = POINTER2SYSCALL FUNC;
+#else
+#define INSERT_SYSCALL(SLOT, TMPPAGE, FUNC) \
+ afs_sys_call_table[_S(SLOT)] = POINTER2SYSCALL FUNC;
+#endif
+
+#if defined(AFS_IA64_LINUX20_ENV)
#define _S(x) ((x)-1024)
#else
#define _S(x) x
static SYSCALLTYPE *afs_sys_call_table;
static SYSCALLTYPE afs_ni_syscall = 0;
-extern long afs_xsetgroups();
-asmlinkage long (*sys_setgroupsp) (int gidsetsize, gid_t * grouplist);
+#ifdef AFS_S390X_LINUX24_ENV
+static void *afs_sys_setgroups_page = 0;
+static void *afs_sys_setgroups32_page = 0;
+static void *afs_syscall_page = 0;
-#ifdef AFS_LINUX24_ENV
-extern int afs_xsetgroups32();
-asmlinkage int (*sys_setgroups32p) (int gidsetsize,
- __kernel_gid32_t * grouplist);
-#endif
+/* Because of how the syscall table is handled, we need to ensure our
+ syscalls are within the first 2gb of address space. This means we need
+ self-modifying code we can inject to call our handlers if the module
+ is loaded high. If keyrings had advanced as fast as false protection
+ this would be unnecessary. */
-#if !defined(AFS_LINUX24_ENV)
-asmlinkage int (*sys_settimeofdayp) (struct timeval * tv, struct timezone * tz);
+uint32_t syscall_jump_code[] = {
+ 0xe3d0f030, 0x00240dd0, 0xa7f40006, 0xffffffff, 0xffffffff, 0xe310d004,
+ 0x0004e3d0, 0xf0300004, 0x07f10000,
+};
#endif
+extern long afs_xsetgroups(int gidsetsize, gid_t * grouplist);
+asmlinkage long (*sys_setgroupsp) (int gidsetsize, gid_t * grouplist);
+
+extern int afs_xsetgroups32(int gidsetsize, gid_t * grouplist);
+asmlinkage int (*sys_setgroups32p) (int gidsetsize,
+ __kernel_gid32_t * grouplist);
/***** AMD64 *****/
#ifdef AFS_AMD64_LINUX20_ENV
extern int afs32_xsetgroups();
asmlinkage long (*sys32_setgroupsp) (int gidsetsize, u16 * grouplist);
-#ifdef AFS_LINUX24_ENV
extern int afs32_xsetgroups32();
asmlinkage long (*sys32_setgroups32p) (int gidsetsize, gid_t * grouplist);
-#endif /* __NR_ia32_setgroups32 */
#endif /* AFS_AMD64_LINUX20_ENV */
printf("*** error! sys32_setgroups_stub called\n");
}
-#endif /* AFS_AMD64_LINUX20_ENV */
+#endif /* AFS_PPC64_LINUX26_ENV */
/***** SPARC64 *****/
-#ifdef AFS_SPARC64_LINUX20_ENV
#ifdef AFS_SPARC64_LINUX26_ENV
static SYSCALLTYPE *afs_sys_call_table32;
-#else
-extern SYSCALLTYPE *afs_sys_call_table32;
-#endif
static SYSCALLTYPE afs_ni_syscall32 = 0;
extern int afs32_xsetgroups();
-#ifdef AFS_SPARC64_LINUX26_ENV
asmlinkage int (*sys32_setgroupsp) (int gidsetsize,
__kernel_gid32_t * grouplist);
-#else
-asmlinkage int (*sys32_setgroupsp) (int gidsetsize,
- __kernel_gid_t32 * grouplist);
-#endif
-#ifdef AFS_LINUX24_ENV
/* This number is not exported for some bizarre reason. */
#define __NR_setgroups32 82
extern int afs32_xsetgroups32();
-#ifdef AFS_SPARC64_LINUX26_ENV
asmlinkage int (*sys32_setgroups32p) (int gidsetsize,
__kernel_gid32_t * grouplist);
-#else
-asmlinkage int (*sys32_setgroups32p) (int gidsetsize,
- __kernel_gid_t32 * grouplist);
-#endif
-#endif
asmlinkage int
afs_syscall32(long syscall, long parm1, long parm2, long parm3, long parm4,
afs_sys_call_table = osi_find_syscall_table(0);
if (afs_sys_call_table) {
-#if !defined(AFS_LINUX24_ENV)
- /* XXX no sys_settimeofday on IA64? */
-#endif
-
/* check we aren't already loaded */
/* XXX this can't be right */
if (SYSCALL2POINTER afs_sys_call_table[_S(__NR_afs_syscall)]
afs_sys_call_table = osi_find_syscall_table(0);
if (afs_sys_call_table) {
-#if !defined(AFS_LINUX24_ENV)
- sys_settimeofdayp =
- SYSCALL2POINTER afs_sys_call_table[_S(__NR_settimeofday)];
-#endif /* AFS_LINUX24_ENV */
/* check we aren't already loaded */
if (SYSCALL2POINTER afs_sys_call_table[_S(__NR_afs_syscall)]
/* setup AFS entry point */
afs_ni_syscall = afs_sys_call_table[_S(__NR_afs_syscall)];
- afs_sys_call_table[_S(__NR_afs_syscall)] = POINTER2SYSCALL afs_syscall;
+
+ INSERT_SYSCALL(__NR_afs_syscall, afs_syscall_page, afs_syscall)
/* setup setgroups */
sys_setgroupsp = SYSCALL2POINTER afs_sys_call_table[_S(__NR_setgroups)];
- afs_sys_call_table[_S(__NR_setgroups)] = POINTER2SYSCALL afs_xsetgroups;
+ INSERT_SYSCALL(__NR_setgroups, afs_sys_setgroups_page, afs_xsetgroups)
#if defined(__NR_setgroups32)
/* setup setgroups32 */
sys_setgroups32p = SYSCALL2POINTER afs_sys_call_table[__NR_setgroups32];
- afs_sys_call_table[__NR_setgroups32] = POINTER2SYSCALL afs_xsetgroups32;
+ INSERT_SYSCALL(__NR_setgroups32, afs_sys_setgroups32_page, afs_xsetgroups32)
#endif
}
#endif /* !AFS_IA64_LINUX20_ENV */
afs_ia32_sys_call_table[__NR_ia32_setgroups] =
POINTER2SYSCALL afs32_xsetgroups;
-#if AFS_LINUX24_ENV
/* setup setgroups32 for IA32 */
sys32_setgroups32p =
SYSCALL2POINTER afs_ia32_sys_call_table[__NR_ia32_setgroups32];
afs_ia32_sys_call_table[__NR_ia32_setgroups32] =
POINTER2SYSCALL afs32_xsetgroups32;
-#endif /* __NR_ia32_setgroups32 */
}
#endif /* AFS_AMD64_LINUX20_ENV */
sys32_setgroupsp = SYSCALL2POINTER afs_sys_call_table32[__NR_setgroups];
afs_sys_call_table32[__NR_setgroups] = POINTER2SYSCALL afs32_xsetgroups;
-#ifdef AFS_LINUX24_ENV
/* setup setgroups32 for 32-bit SPARC */
sys32_setgroups32p =
SYSCALL2POINTER afs_sys_call_table32[__NR_setgroups32];
afs_sys_call_table32[__NR_setgroups32] =
POINTER2SYSCALL afs32_xsetgroups32;
-#endif
}
#endif /* AFS_SPARC64_LINUX20_ENV */
return 0;
/* put back setgroups32 */
afs_sys_call_table[__NR_setgroups32] = POINTER2SYSCALL sys_setgroups32p;
#endif
+#if defined(AFS_S390X_LINUX24_ENV)
+#if defined(__NR_setgroups32) && !defined(AFS_IA64_LINUX20_ENV)
+ if (afs_sys_setgroups32_page)
+ kfree(afs_sys_setgroups32_page);
+#endif
+ if (afs_sys_setgroups_page)
+ kfree(afs_sys_setgroups_page);
+ if (afs_syscall_page)
+ kfree(afs_syscall_page);
+#endif
}
afs_ia32_sys_call_table[__NR_ia32_setgroups] =
POINTER2SYSCALL sys32_setgroupsp;
-#ifdef AFS_LINUX24_ENV
/* put back setgroups32 for IA32 */
afs_ia32_sys_call_table[__NR_ia32_setgroups32] =
POINTER2SYSCALL sys32_setgroups32p;
-#endif
}
#endif
afs_sys_call_table32[__NR_setgroups] =
POINTER2SYSCALL sys32_setgroupsp;
-#ifdef AFS_LINUX24_ENV
/* put back setgroups32 for IA32 */
afs_sys_call_table32[__NR_setgroups32] =
POINTER2SYSCALL sys32_setgroups32p;
-#endif
}
#endif
}