From f126dbdbe226bb05687f0bcbd0e379431f666219 Mon Sep 17 00:00:00 2001 From: Jeffrey Hutzelman Date: Sat, 29 Jan 2005 05:41:59 +0000 Subject: [PATCH] osi-probe-syscall-20050129 FIXES 17405 add osi_probe --- src/afs/LINUX/osi_module.c | 439 +---------- src/afs/LINUX/osi_probe.c | 1125 +++++++++++++++++++++++++++++ src/afs/LINUX/osi_prototypes.h | 7 + src/afs/LINUX/osi_syscall.c | 382 ++++++++++ src/libafs/Makefile.common.in | 4 + src/libafs/MakefileProto.LINUX.in | 2 + 6 files changed, 1525 insertions(+), 434 deletions(-) create mode 100644 src/afs/LINUX/osi_probe.c create mode 100644 src/afs/LINUX/osi_syscall.c diff --git a/src/afs/LINUX/osi_module.c b/src/afs/LINUX/osi_module.c index b7e5f2a29..f021681b4 100644 --- a/src/afs/LINUX/osi_module.c +++ b/src/afs/LINUX/osi_module.c @@ -33,38 +33,6 @@ RCSID #include #include #endif -#if !defined(EXPORTED_SYS_CALL_TABLE) && defined(HAVE_KERNEL_LINUX_SYSCALL_H) -#include -#endif - -#ifdef AFS_SPARC64_LINUX24_ENV -#define __NR_setgroups32 82 /* This number is not exported for some bizarre reason. */ -#endif - -#if !defined(AFS_LINUX24_ENV) -asmlinkage int (*sys_settimeofdayp) (struct timeval * tv, - struct timezone * tz); -#endif -asmlinkage long (*sys_setgroupsp) (int gidsetsize, gid_t * grouplist); -#ifdef EXPORTED_SYS_CALL_TABLE -#if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390X_LINUX24_ENV) -extern unsigned int sys_call_table[]; /* changed to uint because SPARC64 and S390X have syscalltable of 32bit items */ -#else -extern void *sys_call_table[]; /* safer for other linuces */ -#endif -#else /* EXPORTED_SYS_CALL_TABLE */ -#if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390X_LINUX24_ENV) -static unsigned int *sys_call_table; /* changed to uint because SPARC64 and S390X have syscalltable of 32bit items */ -#else -static void **sys_call_table; /* safer for other linuces */ -#endif -#endif - -#if defined(AFS_S390X_LINUX24_ENV) -#define _S(x) ((x)<<1) -#else -#define _S(x) x -#endif extern struct file_system_type afs_fs_type; @@ -82,56 +50,6 @@ int afs_global_owner = 0; unsigned long afs_linux_page_offset = 0; /* contains the PAGE_OFFSET value */ #endif -/* Since sys_ni_syscall is not exported, I need to cache it in order to restore - * it. - */ -#if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390X_LINUX24_ENV) -static unsigned int afs_ni_syscall = 0; -#else -static void *afs_ni_syscall = 0; -#endif - -#ifdef AFS_AMD64_LINUX20_ENV -#ifdef EXPORTED_IA32_SYS_CALL_TABLE -extern void *ia32_sys_call_table[]; -#else -static void **ia32_sys_call_table; -#endif - -static void *ia32_ni_syscall = 0; -asmlinkage long (*sys32_setgroupsp) (int gidsetsize, u16 * grouplist); -#if defined(__NR_ia32_setgroups32) -asmlinkage long (*sys32_setgroups32p) (int gidsetsize, gid_t * grouplist); -#endif /* __NR_ia32_setgroups32 */ -#endif /* AFS_AMD64_LINUX20_ENV */ - -#ifdef AFS_PPC64_LINUX20_ENV -asmlinkage long (*sys32_setgroupsp)(int gidsetsize, gid_t *grouplist); -#endif /* AFS_AMD64_LINUX20_ENV */ - -#ifdef AFS_SPARC64_LINUX20_ENV -static unsigned int afs_ni_syscall32 = 0; -asmlinkage int (*sys32_setgroupsp) (int gidsetsize, - __kernel_gid_t32 * grouplist); -#if defined(__NR_setgroups32) -asmlinkage int (*sys32_setgroups32p) (int gidsetsize, - __kernel_gid_t32 * grouplist); -#endif /* __NR_setgroups32 */ -#ifdef EXPORTED_SYS_CALL_TABLE -extern unsigned int sys_call_table32[]; -#else /* EXPORTED_SYS_CALL_TABLE */ -static unsigned int *sys_call_table32; -#endif /* EXPORTED_SYS_CALL_TABLE */ - -asmlinkage int -afs_syscall32(long syscall, long parm1, long parm2, long parm3, long parm4, - long parm5) -{ - __asm__ __volatile__("srl %o4, 0, %o4\n\t" "mov %o7, %i7\n\t" - "call afs_syscall\n\t" "srl %o5, 0, %o5\n\t" - "ret\n\t" "nop"); -} -#endif /* AFS_SPARC64_LINUX20_ENV */ static int afs_ioctl(struct inode *, struct file *, unsigned int, unsigned long); @@ -569,48 +487,6 @@ afs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, sysargs.param2, sysargs.param3, sysargs.param4); } -#ifdef AFS_IA64_LINUX20_ENV - -asmlinkage long -afs_syscall_stub(int r0, int r1, long r2, long r3, long r4, long gp) -{ - __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t" "mov r41 = b0\n\t" /* save rp */ - "mov out0 = in0\n\t" "mov out1 = in1\n\t" "mov out2 = in2\n\t" "mov out3 = in3\n\t" "mov out4 = in4\n\t" "mov out5 = gp\n\t" /* save gp */ - ";;\n" ".L1:\n\t" "mov r3 = ip\n\t" ";;\n\t" "addl r15=.fptr_afs_syscall-.L1,r3\n\t" ";;\n\t" "ld8 r15=[r15]\n\t" ";;\n\t" "ld8 r16=[r15],8\n\t" ";;\n\t" "ld8 gp=[r15]\n\t" "mov b6=r16\n\t" "br.call.sptk.many b0 = b6\n\t" ";;\n\t" "mov ar.pfs = r42\n\t" "mov b0 = r41\n\t" "mov gp = r48\n\t" /* restore gp */ - "br.ret.sptk.many b0\n" ".fptr_afs_syscall:\n\t" - "data8 @fptr(afs_syscall)\n\t" ".skip 8"); -} - -asmlinkage long -afs_xsetgroups_stub(int r0, int r1, long r2, long r3, long r4, long gp) -{ - __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t" "mov r41 = b0\n\t" /* save rp */ - "mov out0 = in0\n\t" "mov out1 = in1\n\t" "mov out2 = in2\n\t" "mov out3 = in3\n\t" "mov out4 = in4\n\t" "mov out5 = gp\n\t" /* save gp */ - ";;\n" ".L2:\n\t" "mov r3 = ip\n\t" ";;\n\t" "addl r15=.fptr_afs_xsetgroups - .L2,r3\n\t" ";;\n\t" "ld8 r15=[r15]\n\t" ";;\n\t" "ld8 r16=[r15],8\n\t" ";;\n\t" "ld8 gp=[r15]\n\t" "mov b6=r16\n\t" "br.call.sptk.many b0 = b6\n\t" ";;\n\t" "mov ar.pfs = r42\n\t" "mov b0 = r41\n\t" "mov gp = r48\n\t" /* restore gp */ - "br.ret.sptk.many b0\n" ".fptr_afs_xsetgroups:\n\t" - "data8 @fptr(afs_xsetgroups)\n\t" ".skip 8"); -} - -struct fptr { - void *ip; - unsigned long gp; -}; - -#endif /* AFS_IA64_LINUX20_ENV */ - -#ifdef AFS_LINUX24_ENV -asmlinkage int (*sys_setgroups32p) (int gidsetsize, - __kernel_gid32_t * grouplist); -#endif /* AFS_LINUX24_ENV */ - -#if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390X_LINUX24_ENV) -#define POINTER2SYSCALL (unsigned int)(unsigned long) -#define SYSCALL2POINTER (void *)(long) -#else -#define POINTER2SYSCALL (void *) -#define SYSCALL2POINTER (void *) -#endif - #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) int __init @@ -620,45 +496,7 @@ int init_module(void) #endif { -#if defined(AFS_IA64_LINUX20_ENV) - unsigned long kernel_gp = 0; - static struct fptr sys_setgroups; -#endif /* defined(AFS_IA64_LINUX20_ENV) */ - extern long afs_xsetgroups(); -#if defined(__NR_setgroups32) - extern int afs_xsetgroups32(); -#endif /* __NR_setgroups32 */ -#if defined(AFS_SPARC64_LINUX20_ENV) || defined (AFS_AMD64_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV) - extern int afs32_xsetgroups(); -#if (defined(__NR_setgroups32) && defined(AFS_SPARC64_LINUX20_ENV)) - extern int afs32_xsetgroups32(); -#endif /* defined(__NR_setgroups32) && defined(AFS_SPARC64_LINUX20_ENV) */ -#if (defined(__NR_ia32_setgroups32) && defined(AFS_AMD64_LINUX20_ENV)) - extern int afs32_xsetgroups32(); -#endif /* (defined(__NR_ia32_setgroups32) && defined(AFS_AMD64_LINUX20_ENV) */ -#endif /* AFS_SPARC64_LINUX20_ENV || AFS_AMD64_LINUX20_ENV || AFS_PPC64_LINUX20_ENV */ - -#if !defined(EXPORTED_SYS_CALL_TABLE) || (defined(AFS_AMD64_LINUX20_ENV) && !defined(EXPORTED_IA32_SYS_CALL_TABLE)) - unsigned long *ptr; - unsigned long offset=0; - unsigned long datalen=0; -#if defined(EXPORTED_KALLSYMS_SYMBOL) - unsigned long token=0; -#endif -#if defined(EXPORTED_KALLSYMS_SYMBOL) || defined(EXPORTED_KALLSYMS_ADDRESS) - int ret; - char *mod_name; - unsigned long mod_start=0; - unsigned long mod_end=0; - char *sec_name; - unsigned long sec_start=0; - unsigned long sec_end=0; - char *sym_name; - unsigned long sym_start=0; - unsigned long sym_end=0; -#endif -#endif /* EXPORTED_SYS_CALL_TABLE */ - + int e; RWLOCK_INIT(&afs_xosi, "afs_xosi"); #if !defined(AFS_LINUX24_ENV) @@ -674,246 +512,11 @@ init_module(void) #endif /* AFS_S390_LINUX22_ENV */ #endif /* !defined(AFS_LINUX24_ENV) */ -#ifndef EXPORTED_SYS_CALL_TABLE - sys_call_table = 0; - -#ifdef EXPORTED_KALLSYMS_SYMBOL - ret = 1; - token = 0; - while (ret) { - sym_start = 0; - ret = - kallsyms_symbol_to_address("sys_call_table", &token, &mod_name, - &mod_start, &mod_end, &sec_name, - &sec_start, &sec_end, &sym_name, - &sym_start, &sym_end); - if (ret && !strcmp(mod_name, "kernel")) - break; - } - if (ret && sym_start) { - sys_call_table = sym_start; - } -#elif defined(EXPORTED_KALLSYMS_ADDRESS) - ret = - kallsyms_address_to_symbol((unsigned long)&init_mm, &mod_name, - &mod_start, &mod_end, &sec_name, - &sec_start, &sec_end, &sym_name, - &sym_start, &sym_end); - ptr = (unsigned long *)sec_start; - datalen = (sec_end - sec_start) / sizeof(unsigned long); -#elif defined(AFS_IA64_LINUX20_ENV) - ptr = (unsigned long *)(&sys_close - 0x180000); - datalen = 0x180000 / sizeof(ptr); -#elif defined(AFS_AMD64_LINUX20_ENV) - ptr = (unsigned long *)&init_mm; - datalen = 0x360000 / sizeof(ptr); -#else - ptr = (unsigned long *)&init_mm; - datalen = 16384; -#endif - for (offset = 0; offset < datalen; ptr++, offset++) { -#if defined(AFS_IA64_LINUX20_ENV) - unsigned long close_ip = - (unsigned long)((struct fptr *)&sys_close)->ip; - unsigned long chdir_ip = - (unsigned long)((struct fptr *)&sys_chdir)->ip; - unsigned long write_ip = - (unsigned long)((struct fptr *)&sys_write)->ip; - if (ptr[0] == close_ip && ptr[__NR_chdir - __NR_close] == chdir_ip - && ptr[__NR_write - __NR_close] == write_ip) { - sys_call_table = (void *)&(ptr[-1 * (__NR_close - 1024)]); - break; - } -#elif defined(EXPORTED_SYS_WAIT4) && defined(EXPORTED_SYS_CLOSE) - if (ptr[0] == (unsigned long)&sys_close - && ptr[__NR_wait4 - __NR_close] == (unsigned long)&sys_wait4) { - sys_call_table = ptr - __NR_close; - break; - } -#elif defined(EXPORTED_SYS_CHDIR) && defined(EXPORTED_SYS_CLOSE) - if (ptr[0] == (unsigned long)&sys_close - && ptr[__NR_chdir - __NR_close] == (unsigned long)&sys_chdir) { - sys_call_table = ptr - __NR_close; - break; - } -#elif defined(EXPORTED_SYS_OPEN) - if (ptr[0] == (unsigned long)&sys_exit - && ptr[__NR_open - __NR_exit] == (unsigned long)&sys_open) { - sys_call_table = ptr - __NR_exit; - break; - } -#else /* EXPORTED_SYS_OPEN */ - break; -#endif /* EXPORTED_KALLSYMS_ADDRESS */ - } -#ifdef EXPORTED_KALLSYMS_ADDRESS - ret = - kallsyms_address_to_symbol((unsigned long)sys_call_table, &mod_name, - &mod_start, &mod_end, &sec_name, - &sec_start, &sec_end, &sym_name, - &sym_start, &sym_end); - if (ret && strcmp(sym_name, "sys_call_table")) - sys_call_table = 0; -#endif /* EXPORTED_KALLSYMS_ADDRESS */ - if (!sys_call_table) { - printf("Failed to find address of sys_call_table\n"); - } else { - printf("Found sys_call_table at %lx\n", (unsigned long)sys_call_table); -#if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390X_LINUX24_ENV) - error cant support this yet.; -#endif /* AFS_SPARC64_LINUX20_ENV */ -#endif /* EXPORTED_SYS_CALL_TABLE */ - -#ifdef AFS_AMD64_LINUX20_ENV -#ifndef EXPORTED_IA32_SYS_CALL_TABLE - ia32_sys_call_table = 0; -#ifdef EXPORTED_KALLSYMS_SYMBOL - ret = 1; - token = 0; - while (ret) { - sym_start = 0; - ret = kallsyms_symbol_to_address("ia32_sys_call_table", &token, - &mod_name, &mod_start, &mod_end, - &sec_name, &sec_start, &sec_end, - &sym_name, &sym_start, &sym_end); - if (ret && !strcmp(mod_name, "kernel")) - break; - } - if (ret && sym_start) { - ia32_sys_call_table = sym_start; - } -#else /* EXPORTED_KALLSYMS_SYMBOL */ -#ifdef EXPORTED_KALLSYMS_ADDRESS - ret = kallsyms_address_to_symbol((unsigned long) - &interruptible_sleep_on, - &mod_name, &mod_start, &mod_end, - &sec_name, &sec_start, &sec_end, - &sym_name, &sym_start, &sym_end); - ptr = (unsigned long *)sec_start; - datalen = (sec_end - sec_start) / sizeof(unsigned long); -#else /* EXPORTED_KALLSYMS_ADDRESS */ -#if defined(AFS_AMD64_LINUX20_ENV) - ptr = (unsigned long *)&interruptible_sleep_on; - datalen = 0x180000 / sizeof(ptr); -#else /* AFS_AMD64_LINUX20_ENV */ - ptr = (unsigned long *)&interruptible_sleep_on; - datalen = 16384; -#endif /* AFS_AMD64_LINUX20_ENV */ -#endif /* EXPORTED_KALLSYMS_ADDRESS */ - for (offset = 0; offset < datalen; ptr++, offset++) { - if (ptr[0] == (unsigned long)&sys_exit - && ptr[__NR_ia32_open - __NR_ia32_exit] == - (unsigned long)&sys_open) { - ia32_sys_call_table = ptr - __NR_ia32_exit; - break; - } - } -#ifdef EXPORTED_KALLSYMS_ADDRESS - ret = kallsyms_address_to_symbol((unsigned long)ia32_sys_call_table, - &mod_name, &mod_start, &mod_end, - &sec_name, &sec_start, &sec_end, - &sym_name, &sym_start, &sym_end); - if (ret && strcmp(sym_name, "ia32_sys_call_table")) - ia32_sys_call_table = 0; -#endif /* EXPORTED_KALLSYMS_ADDRESS */ -#endif /* EXPORTED_KALLSYMS_SYMBOL */ - if (!ia32_sys_call_table) { - printf("Warning: Failed to find address of ia32_sys_call_table\n"); - } else { - printf("Found ia32_sys_call_table at %lx\n", (unsigned long)ia32_sys_call_table); - } -#else - printf("Found ia32_sys_call_table at %lx\n", (unsigned long)ia32_sys_call_table); -#endif /* IA32_SYS_CALL_TABLE */ -#endif - - /* Initialize pointers to kernel syscalls. */ -#if !defined(AFS_LINUX24_ENV) - sys_settimeofdayp = SYSCALL2POINTER sys_call_table[_S(__NR_settimeofday)]; -#endif /* AFS_IA64_LINUX20_ENV */ - - /* setup AFS entry point. */ - if ( -#if defined(AFS_IA64_LINUX20_ENV) - SYSCALL2POINTER sys_call_table[__NR_afs_syscall - 1024] -#else - SYSCALL2POINTER sys_call_table[_S(__NR_afs_syscall)] -#endif - == afs_syscall) { - printf("AFS syscall entry point already in use!\n"); - return -EBUSY; - } -#if defined(AFS_IA64_LINUX20_ENV) - afs_ni_syscall = sys_call_table[__NR_afs_syscall - 1024]; - sys_call_table[__NR_afs_syscall - 1024] = - POINTER2SYSCALL((struct fptr *)afs_syscall_stub)->ip; -#else /* AFS_IA64_LINUX20_ENV */ - afs_ni_syscall = sys_call_table[_S(__NR_afs_syscall)]; - sys_call_table[_S(__NR_afs_syscall)] = POINTER2SYSCALL afs_syscall; -#ifdef AFS_SPARC64_LINUX20_ENV - afs_ni_syscall32 = sys_call_table32[__NR_afs_syscall]; - sys_call_table32[__NR_afs_syscall] = POINTER2SYSCALL afs_syscall32; -#endif -#endif /* AFS_IA64_LINUX20_ENV */ -#ifdef AFS_AMD64_LINUX20_ENV - if (ia32_sys_call_table) { - ia32_ni_syscall = ia32_sys_call_table[__NR_ia32_afs_syscall]; - ia32_sys_call_table[__NR_ia32_afs_syscall] = - POINTER2SYSCALL afs_syscall; - } -#endif /* AFS_S390_LINUX22_ENV */ -#ifndef EXPORTED_SYS_CALL_TABLE - } -#endif /* EXPORTED_SYS_CALL_TABLE */ osi_Init(); - register_filesystem(&afs_fs_type); - - /* Intercept setgroups calls */ - if (sys_call_table) { -#if defined(AFS_IA64_LINUX20_ENV) - sys_setgroupsp = (void *)&sys_setgroups; - - ((struct fptr *)sys_setgroupsp)->ip = - SYSCALL2POINTER sys_call_table[__NR_setgroups - 1024]; - ((struct fptr *)sys_setgroupsp)->gp = kernel_gp; - - sys_call_table[__NR_setgroups - 1024] = - POINTER2SYSCALL((struct fptr *)afs_xsetgroups_stub)->ip; -#else /* AFS_IA64_LINUX20_ENV */ - sys_setgroupsp = SYSCALL2POINTER sys_call_table[_S(__NR_setgroups)]; - sys_call_table[_S(__NR_setgroups)] = POINTER2SYSCALL afs_xsetgroups; -#ifdef AFS_SPARC64_LINUX20_ENV - sys32_setgroupsp = SYSCALL2POINTER sys_call_table32[__NR_setgroups]; - sys_call_table32[__NR_setgroups] = POINTER2SYSCALL afs32_xsetgroups; -#endif /* AFS_SPARC64_LINUX20_ENV */ -#if defined(__NR_setgroups32) - sys_setgroups32p = SYSCALL2POINTER sys_call_table[__NR_setgroups32]; - sys_call_table[__NR_setgroups32] = POINTER2SYSCALL afs_xsetgroups32; -#ifdef AFS_SPARC64_LINUX20_ENV - sys32_setgroups32p = - SYSCALL2POINTER sys_call_table32[__NR_setgroups32]; - sys_call_table32[__NR_setgroups32] = - POINTER2SYSCALL afs32_xsetgroups32; -#endif /* AFS_SPARC64_LINUX20_ENV */ -#endif /* __NR_setgroups32 */ -#ifdef AFS_AMD64_LINUX20_ENV - if (ia32_sys_call_table) { - sys32_setgroupsp = - SYSCALL2POINTER ia32_sys_call_table[__NR_ia32_setgroups]; - ia32_sys_call_table[__NR_ia32_setgroups] = - POINTER2SYSCALL afs32_xsetgroups; -#if defined(__NR_ia32_setgroups32) - sys32_setgroups32p = - SYSCALL2POINTER ia32_sys_call_table[__NR_ia32_setgroups32]; - ia32_sys_call_table[__NR_ia32_setgroups32] = - POINTER2SYSCALL afs32_xsetgroups32; -#endif /* __NR_ia32_setgroups32 */ - } -#endif /* AFS_AMD64_LINUX20_ENV */ -#endif /* AFS_IA64_LINUX20_ENV */ - - } + e = osi_syscall_init(); + if (e) return e; + register_filesystem(&afs_fs_type); osi_sysctl_init(); afsproc_init(); @@ -929,39 +532,7 @@ cleanup_module(void) #endif { osi_sysctl_clean(); - if (sys_call_table) { -#if defined(AFS_IA64_LINUX20_ENV) - sys_call_table[__NR_setgroups - 1024] = - POINTER2SYSCALL((struct fptr *)sys_setgroupsp)->ip; - sys_call_table[__NR_afs_syscall - 1024] = afs_ni_syscall; -#else /* AFS_IA64_LINUX20_ENV */ - sys_call_table[_S(__NR_setgroups)] = POINTER2SYSCALL sys_setgroupsp; - sys_call_table[_S(__NR_afs_syscall)] = afs_ni_syscall; -# ifdef AFS_SPARC64_LINUX20_ENV - sys_call_table32[__NR_setgroups] = POINTER2SYSCALL sys32_setgroupsp; - sys_call_table32[__NR_afs_syscall] = afs_ni_syscall32; -# endif -# if defined(__NR_setgroups32) - sys_call_table[__NR_setgroups32] = POINTER2SYSCALL sys_setgroups32p; -# ifdef AFS_SPARC64_LINUX20_ENV - sys_call_table32[__NR_setgroups32] = - POINTER2SYSCALL sys32_setgroups32p; -# endif -# endif -#endif /* AFS_IA64_LINUX20_ENV */ -#ifdef AFS_AMD64_LINUX20_ENV - if (ia32_sys_call_table) { - ia32_sys_call_table[__NR_ia32_setgroups] = - POINTER2SYSCALL sys32_setgroupsp; - ia32_sys_call_table[__NR_ia32_afs_syscall] = - POINTER2SYSCALL ia32_ni_syscall; -# if defined(__NR_setgroups32) - ia32_sys_call_table[__NR_ia32_setgroups32] = - POINTER2SYSCALL sys32_setgroups32p; -#endif - } -#endif - } + osi_syscall_clean(); unregister_filesystem(&afs_fs_type); osi_linux_free_inode_pages(); /* Invalidate all pages using AFS inodes. */ diff --git a/src/afs/LINUX/osi_probe.c b/src/afs/LINUX/osi_probe.c new file mode 100644 index 000000000..fc9c3945a --- /dev/null +++ b/src/afs/LINUX/osi_probe.c @@ -0,0 +1,1125 @@ +/* + * vi:set cin noet sw=4 tw=70: + * Copyright 2004, International Business Machines Corporation and others. + * All Rights Reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + * + * Portions of this code borrowed from arla under the following terms: + * Copyright (c) 2003-2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* Code to find the Linux syscall table */ + +#ifdef OSI_PROBE_STANDALONE +#define OSI_PROBE_DEBUG +#endif +#ifndef OSI_PROBE_STANDALONE +#include +#include "afs/param.h" +#endif +#include /* early to avoid printf->printk mapping */ +#ifndef OSI_PROBE_STANDALONE +#include "afs/sysincludes.h" +#include "afsincludes.h" +#endif +#include +#include +#include +#include +#include +#include + +#ifdef AFS_AMD64_LINUX20_ENV +#include +#endif + +#ifdef HAVE_KERNEL_LINUX_SYSCALL_H +#include +#endif + +/* number of syscalls */ +/* NB: on MIPS we care about the 4xxx range */ +#ifndef NR_syscalls +#define NR_syscalls 222 +#endif + +/* lower bound of valid kernel text pointers */ +//#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +#define ktxt_lower_bound (((unsigned long)&kernel_thread ) & ~0xfffffL) +//#else +//#define ktxt_lower_bound (((unsigned long)&empty_zero_page) & ~0xfffffL) +//#endif + +/* 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) +#define SYSCALLTYPE unsigned int +#define PROBETYPE int +#else +#define SYSCALLTYPE void * +#define PROBETYPE long +#endif + + +/* 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_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_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_PARM_DESC(probe_ignore_syscalls, "Syscalls to ignore in table checks"); + +#ifdef OSI_PROBE_DEBUG +/* + * Debugging flags: + * 0x0001 - General debugging + * 0x0002 - detail - try + * 0x0004 - detail - try_harder + * 0x0008 - detail - check_table + * 0x0010 - detail - check_harder + * 0x0020 - detail - check_harder/zapped + * 0x0040 - automatically ignore setgroups and afs_syscall + */ +static int probe_debug = 0x41; +MODULE_PARM(probe_debug, "i"); +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_PARM_DESC(probe_debug_addr, "Debug range starting locations"); + +static unsigned long probe_debug_range = 0; +MODULE_PARM(probe_debug_range, "l"); +MODULE_PARM_DESC(probe_debug_range, "Debug range length"); + +static unsigned long probe_debug_tag = 0; +MODULE_PARM(probe_debug_tag, "l"); +MODULE_PARM_DESC(probe_debug_tag, "Debugging output start tag"); +#endif + + +/* Weak references are our friends. They are supported by the in-kernel + * linker in Linux 2.6 and by all versions of modutils back to 2.2pre1. + * A weak reference not satisified by the kernel will have value zero. + */ +extern int kallsyms_symbol_to_address(char *name, unsigned long *token, + char **mod_name, + unsigned long *mod_start, + unsigned long *mod_end, + char **sec_name, + unsigned long *sec_start, + unsigned long *sec_end, + char **sym_name, + unsigned long *sym_start, + unsigned long *sym_end + ) __attribute__((weak)); + +extern int kallsyms_address_to_symbol(unsigned long address, + char **mod_name, + unsigned long *mod_start, + unsigned long *mod_end, + char **sec_name, + unsigned long *sec_start, + unsigned long *sec_end, + char **sym_name, + unsigned long *sym_start, + unsigned long *sym_end + ) __attribute__((weak)); + +extern SYSCALLTYPE sys_call_table[] __attribute__((weak)); +extern SYSCALLTYPE ia32_sys_call_table[] __attribute__((weak)); +extern SYSCALLTYPE sys_call_table32[] __attribute__((weak)); + +extern asmlinkage long sys_close(unsigned int) __attribute__((weak)); +extern asmlinkage long sys_chdir(const char *) __attribute__((weak)); +extern asmlinkage int 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 int sys_exit (int) __attribute__((weak)); +extern asmlinkage long sys_open (const char *, int, int) __attribute__((weak)); +extern asmlinkage long sys_ioctl(unsigned int, unsigned int, unsigned long) __attribute__((weak)); + + +/* Structures used to control probing. We put all the details of which + * symbols we're interested in, what syscall functions to look for, etc + * into tables, so we can then have a single copy of the functions that + * actually do the work. + */ +typedef struct { + char *name; + int NR1; + void *fn1; + int NR2; + void *fn2; + int NR3; + void *fn3; +} tryctl; + +typedef struct { + char *symbol; /* symbol name */ + char *desc; /* description for messages */ + int offset; /* first syscall number in table */ + + void *weak_answer; /* weak symbol ref */ + void *parm_answer; /* module parameter answer */ + void *debug_answer; /* module parameter answer */ + unsigned long given_answer; /* compiled-in answer, if any */ + + tryctl *trylist; /* array of combinations to try */ + + unsigned long try_sect_sym; /* symbol in section to try scanning */ + unsigned long try_base; /* default base address for scan */ + unsigned long try_base_mask; /* base address bits to force to zero */ + unsigned long try_length; /* default length for scan */ + + int n_zapped_syscalls; /* number of unimplemented system calls */ + int *zapped_syscalls; /* list of unimplemented system calls */ + + int n_unique_syscalls; /* number of unique system calls */ + int *unique_syscalls; /* list of unimplemented system calls */ + + int verifyNR; /* syscall number to verify match */ + void *verify_fn; /* syscall pointer to verify match */ + + int debug_ignore_NR[4]; /* syscalls to ignore for debugging */ +} probectl; + + + +/********** 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) + { "scan: close+chdir+write", __NR_close, &sys_close, __NR_chdir, &sys_chdir, __NR_write, &sys_write }, +#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) + { "scan: close+chdir", __NR_close, &sys_close, __NR_chdir, &sys_chdir, -1, 0 }, +#endif + { "scan: close+ioctl", __NR_close, &sys_close, __NR_ioctl, &sys_ioctl, -1, 0 }, + { "scan: exit+open", __NR_exit, &sys_exit, __NR_open, &sys_open, -1, 0 }, + { 0 } +}; + +/* zapped syscalls for try_harder */ +/* this list is based on the table in 'zapped_syscalls' */ + +static int main_zapped_syscalls[] = { +/* + * SPARC-Linux uses syscall number mappings chosen to be compatible + * with SunOS. So, it doesn't have any of the traditional calls or + * the new STREAMS ones. However, there are a number of syscalls + * which are SunOS-specific (not implemented on Linux), i386-specific + * (not implemented on SPARC-Linux), or implemented only on one of + * sparc32 or sparc64. Of course, there are no __NR macros for most + * of these. + * + * Note that the calls we list here are implemented by sys_nis_syscall, + * not by sys_ni_syscall. That means we have to exclude all of the + * 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) + /* mmap2, fstat64, getmsg, putmsg, modify_ldt */ + 56, 63, 151, 152, 218, +#elif defined(AFS_SPARC_LINUX20_ENV) + /* memory_ordering, getmsg, putmsg, unimplemented, modify_ldt */ + 52, 151, 152, 164, 218, +#else /* !AFS_SPARC_LINUX20_ENV */ + +/* + * These 7 syscalls are present in the syscall table on most "older" + * platforms that use the traditional syscall number mappings. They + * are not implemented on any platform. + */ +#ifdef __NR_break + __NR_break, +#endif +#ifdef __NR_stty + __NR_stty, +#endif +#ifdef __NR_gtty + __NR_gtty, +#endif +#ifdef __NR_ftime + __NR_ftime, +#endif +#ifdef __NR_prof + __NR_prof, +#endif +#ifdef __NR_lock + __NR_lock, +#endif +#ifdef __NR_mpx + __NR_mpx, +#endif +/* + * On s390 and arm (but not arm26), the seven traditional unimplemented + * system calls are indeed present and unimplemented. However, the + * corresponding __NR macros are not defined, so the tests above fail. + * Instead, we just have to know the numbers for these. + */ +#ifdef AFS_S390_LINUX20_ENV + /* break, stty, gtty, ftime, prof, lock, mpx */ + 17, 31, 32, 35, 44, 53, 56, +#endif + +/* + * Sadly, some newer platforms like IA64, amd64, and PA-RISC don't have + * the traditional numbers, so the list above are not helpful. They + * do have entries for getpmsg/putpmsg, which are always unimplemented. + */ +#ifdef __NR_getpmsg + __NR_getpmsg, +#endif +#ifdef __NR_putpmsg + __NR_putpmsg, +#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_query_module + __NR_query_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 + /* 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 + * the new STREAMS ones, but it does have several OSF/1-specific + * syscalls which are not implemented on Linux. These don't exist on + * any other platform. + */ +#ifdef __NR_osf_syscall + __NR_osf_syscall, +#endif +#ifdef __NR_osf_profil + __NR_osf_profil, +#endif +#ifdef __NR_osf_reboot + __NR_osf_reboot, +#endif +#ifdef __NR_osf_kmodcall + __NR_osf_kmodcall, +#endif +#ifdef __NR_osf_old_vtrace + __NR_osf_old_vtrace, +#endif + +/* + * On PPC64, we need a couple more entries to distinguish the two + * tables, since the system call numbers are the same and the sets of + * unimplemented calls are very similar. + * mmap2 and fstat64 are implemented only for 32-bit calls + */ +#ifdef AFS_PPC64_LINUX20_ENV + __NR_mmap2, + __NR_fstat64, +#endif /* AFS_PPC64_LINUX20_ENV */ + +/* Similarly for S390X, with lcown16 and fstat64 */ +#ifdef AFS_S390X_LINUX20_ENV + /* lchown16, fstat64 */ + 16, 197, +#endif +#endif /* !AFS_SPARC_LINUX20_ENV */ + 0 +}; + +/* unique syscalls for try_harder */ +static int main_unique_syscalls[] = { + __NR_exit, __NR_mount, __NR_read, __NR_write, + __NR_open, __NR_close, __NR_unlink +}; + +/* probe control structure */ +static probectl main_probe = { + /* symbol name and description */ + "sys_call_table", + "system call table", + + /* syscall number of first entry in table */ +#ifdef AFS_IA64_LINUX20_ENV + 1024, +#else + 0, +#endif + + sys_call_table, /* weak symbol ref */ + 0, 0, /* module parameter answers */ +#ifdef AFS_LINUX_sys_call_table + AFS_LINUX_sys_call_table, /* compiled-in answer, if any */ +#else + 0, +#endif + + main_try, /* array of combinations to try */ + + /* symbol in section to try scanning */ +#if defined(AFS_SPARC64_LINUX20_ENV) + (unsigned long)&sys_close, +#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 + + /* default base address for scan */ + /* base address bits to force to zero */ + /* default length for scan */ +#if defined(AFS_SPARC64_LINUX20_ENV) + (unsigned long)(&sys_close), + 0xfffff, + 0x10000, +#elif defined(AFS_IA64_LINUX20_ENV) + (unsigned long)(&sys_close - 0x180000), + 0, + (0x180000 / sizeof(unsigned long *)), +#elif defined(AFS_AMD64_LINUX20_ENV) + (unsigned long)(&tasklist_lock - 0x1000), + 0, + 16384, +#else + (unsigned long)&init_mm, + 0, + 16384, +#endif + + /* number and list of unimplemented system calls */ + ((sizeof(main_zapped_syscalls)/sizeof(main_zapped_syscalls[0])) - 1), + main_zapped_syscalls, + + /* number and list of unique system calls */ + (sizeof(main_unique_syscalls)/sizeof(main_unique_syscalls[0])), + main_unique_syscalls, + + /* syscall number and pointer to verify match */ + __NR_close, &sys_close, + + /* syscalls to ignore for debugging */ + { +#if defined(AFS_ALPHA_LINUX20_ENV) + 338, +#elif defined(AFS_AMD64_LINUX20_ENV) + 183, +#elif defined(AFS_IA64_LINUX20_ENV) + 1141, +#elif defined(AFS_SPARC_LINUX20_ENV) || defined(AFS_SPARC64_LINUX20_ENV) + 227, +#else + 137, +#endif + __NR_setgroups, +#ifdef __NR_setgroups32 + __NR_setgroups32, +#else + -1, +#endif + -1, + } +}; + + +/********** Probing Configuration: amd64 ia32_sys_call_table **********/ +#if defined(AFS_AMD64_LINUX20_ENV) + +/* syscall pairs/triplets to probe */ +static tryctl ia32_try[] = { + { "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 }, + { 0 } +}; + +/* zapped syscalls for try_harder */ +static int ia32_zapped_syscalls[] = { + __NR_ia32_break, __NR_ia32_stty, __NR_ia32_gtty, __NR_ia32_ftime, + __NR_ia32_prof, __NR_ia32_lock, __NR_ia32_mpx, + 0 +}; + +/* unique syscalls for try_harder */ +static int ia32_unique_syscalls[] = { + __NR_ia32_exit, __NR_ia32_mount, __NR_ia32_read, __NR_ia32_write, + __NR_ia32_open, __NR_ia32_close, __NR_ia32_unlink +}; + +/* probe control structure */ +static probectl ia32_probe = { + /* symbol name and description */ + "ia32_sys_call_table", + "32-bit system call table", + + /* syscall number of first entry in table */ + 0, + + ia32_sys_call_table, /* weak symbol ref */ + 0, 0, /* module parameter answers */ +#ifdef AFS_LINUX_ia32_sys_call_table + AFS_LINUX_ia32_sys_call_table,/* compiled-in answer, if any */ +#else + 0, +#endif + + ia32_try, /* array of combinations to try */ + + /* symbol in section to try scanning */ + (unsigned long)&init_mm, + + /* default base address for scan */ + /* base address bits to force to zero */ + /* default length for scan */ + (unsigned long)&init_mm, + 0, + (0x180000 / sizeof(unsigned long *)), + + /* number and list of unimplemented system calls */ + ((sizeof(ia32_zapped_syscalls)/sizeof(ia32_zapped_syscalls[0])) - 1), + ia32_zapped_syscalls, + + /* number and list of unique system calls */ + (sizeof(ia32_unique_syscalls)/sizeof(ia32_unique_syscalls[0])), + ia32_unique_syscalls, + + /* syscall number and pointer to verify match */ + __NR_ia32_close, &sys_close, + + /* syscalls to ignore for debugging */ + { + 137, + __NR_ia32_setgroups, + __NR_ia32_setgroups32, + -1, + } +}; + +static probectl *probe_list[] = { + &main_probe, &ia32_probe +}; + + +/********** Probing Configuration: ppc64, sparc64 sys_call_table32 **********/ +#elif defined(AFS_PPC64_LINUX20_ENV) || defined(AFS_SPARC64_LINUX20_ENV) + +/* + * syscall pairs/triplets to probe + * This has to be empty, because anything that would work will + * also match the main table, and that's no good. + */ +static tryctl sct32_try[] = { + { 0 } +}; + +/* zapped syscalls for try_harder */ +static int sct32_zapped_syscalls[] = { +#ifdef AFS_PPC64_LINUX20_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 + /* memory_ordering, getmsg, putmsg, unimplemented, modify_ldt */ + 52, 151, 152, 164, 218, +#endif + 0 +}; + +/* 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 + __NR_mmap2, __NR_fstat64, +#endif + __NR_exit, __NR_mount, __NR_read, __NR_write, + __NR_open, __NR_close, __NR_unlink +}; + +/* probe control structure */ +static probectl sct32_probe = { + /* symbol name and description */ + "sys_call_table32", + "32-bit system call table", + + /* syscall number of first entry in table */ + 0, + + sys_call_table32, /* weak symbol ref */ + 0, 0, /* module parameter answers */ +#ifdef AFS_LINUX_sys_call_table32 + AFS_LINUX_sys_call_table32, /* compiled-in answer, if any */ +#else + 0, +#endif + + sct32_try, /* array of combinations to try */ + + /* symbol in section to try scanning */ +#if defined(AFS_SPARC64_LINUX20_ENV) + (unsigned long)&sys_close, +#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) + (unsigned long)(&sys_close), + 0xfffff, + 0x10000, +#else + (unsigned long)&init_mm, + 0, + 16384, +#endif + + /* number and list of unimplemented system calls */ + ((sizeof(sct32_zapped_syscalls)/sizeof(sct32_zapped_syscalls[0])) - 1), + sct32_zapped_syscalls, + + /* number and list of unique system calls */ + (sizeof(sct32_unique_syscalls)/sizeof(sct32_unique_syscalls[0])), + sct32_unique_syscalls, + + /* syscall number and pointer to verify match */ + __NR_close, &sys_close, + + /* syscalls to ignore for debugging */ + { +#if defined(AFS_SPARC64_LINUX20_ENV) + 227, +#else + 137, +#endif + __NR_setgroups, + -1, + -1, + } +}; + +static probectl *probe_list[] = { + &main_probe, &sct32_probe +}; + + +/********** Probing Configuration: s390x sys_call_table_emu **********/ +#elif defined(AFS_S390X_LINUX20_ENV) + +/* syscall pairs/triplets to probe */ +/* nothing worthwhile is exported, so this is empty */ +static tryctl emu_try[] = { + { 0 } +}; + +/* zapped syscalls for try_harder */ +static int emu_zapped_syscalls[] = { + /* break, stty, gtty, ftime, prof, lock, mpx */ + 17, 31, 32, 35, 44, 53, 56, + 0 +}; + +/* unique syscalls for try_harder */ +static int emu_unique_syscalls[] = { + /* lchown16, fstat64 */ + 16, 197, + __NR_exit, __NR_mount, __NR_read, __NR_write, + __NR_open, __NR_close, __NR_unlink +}; + +/* probe control structure */ +static probectl emu_probe = { + /* symbol name and description */ + "sys_call_table_emu", + "32-bit system call table", + + /* syscall number of first entry in table */ + 0, + + sys_call_table_emu, /* weak symbol ref */ + 0, 0, /* module parameter answers */ +#ifdef AFS_LINUX_sys_call_table_emu + AFS_LINUX_sys_call_table_emu, /* compiled-in answer, if any */ +#else + 0, +#endif + + emu_try, /* array of combinations to try */ + + /* symbol in section to try scanning */ + (unsigned long)&init_mm, + + /* default base address for scan */ + /* base address bits to force to zero */ + /* default length for scan */ + (unsigned long)&init_mm, + 0, + 16384, + + /* number and list of unimplemented system calls */ + ((sizeof(emu_zapped_syscalls)/sizeof(emu_zapped_syscalls[0])) - 1), + emu_zapped_syscalls, + + /* number and list of unique system calls */ + (sizeof(emu_unique_syscalls)/sizeof(emu_unique_syscalls[0])), + emu_unique_syscalls, + + /* syscall number and pointer to verify match */ + __NR_close, &sys_close, + + /* syscalls to ignore for debugging */ + { + 137, + __NR_setgroups, + -1, + -1, + } +}; + +static probectl *probe_list[] = { + &main_probe, &emu_probe +}; + + +/********** End of Probing Configuration **********/ + +#else /* no per-platform probe control, so use the default list */ +static probectl *probe_list[] = { + &main_probe +}; +#endif + +#define N_PROBE_LIST (sizeof(probe_list) / sizeof(*probe_list)) +#define DEBUG_IN_RANGE(P,x) (!probe_debug_range || \ + (P->debug_answer && \ + (unsigned long)(x) >= (unsigned long)P->debug_answer && \ + (unsigned long)(x) < (unsigned long)P->debug_answer + probe_debug_range)) + + + +static int check_table(probectl *P, PROBETYPE *ptr) +{ + PROBETYPE *x; + int i, j; + + for (x = ptr, i = 0; i < NR_syscalls; i++, x++) { +#ifdef OSI_PROBE_DEBUG + if (probe_debug & 0x0040) { + for (j = 0; j < 4; j++) { + if (P->debug_ignore_NR[j] == i) break; + } + if (j < 4) continue; + } +#endif + for (j = 0; j < 8; j++) { + if (probe_ignore_syscalls[j] == i) break; + } + if (j < 8) continue; + if (*x <= ktxt_lower_bound) { +#ifdef OSI_PROBE_DEBUG + if ((probe_debug & 0x0008) && DEBUG_IN_RANGE(P,ptr)) + printk("<7>check 0x%lx -> %d [0x%lx]\n", + (unsigned long)ptr, i, (unsigned long)*x); +#endif + return i; + } + } +#ifdef OSI_PROBE_DEBUG + if ((probe_debug & 0x0008) && DEBUG_IN_RANGE(P,ptr)) + printk("<7>check 0x%lx -> ok\n", (unsigned long)ptr); +#endif + return -1; +} + +static void *try(probectl *P, tryctl *T, PROBETYPE *ptr, + unsigned long datalen) +{ + char *mod_name, *sec_name, *sym_name; + unsigned long mod_start, mod_end; + unsigned long sec_start, sec_end; + unsigned long sym_start, sym_end; + unsigned long offset, ip1, ip2, ip3; + int ret; + +#ifdef AFS_IA64_LINUX20_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; +#else + ip1 = (unsigned long)T->fn1; + ip2 = (unsigned long)T->fn2; + ip3 = (unsigned long)T->fn3; +#endif + +#ifdef OSI_PROBE_DEBUG + if (probe_debug & 0x0001) + printk("<7>osi_probe: %s %s (%d->0x%lx, %d->0x%lx, %d->0x%lx)\n", + P->symbol, T->name, T->NR1, ip1, T->NR2, ip2, T->NR3, ip3); +#endif + + if (!ip1 || !ip2 || (T->NR3 >= 0 && !ip3)) + return 0; + + for (offset = 0; offset < datalen; offset++, ptr++) { + ret = check_table(P, ptr); + if (ret >= 0) { + /* return value is number of entries to skip */ + ptr += ret; + offset += ret; + continue; + } + +#ifdef OSI_PROBE_DEBUG + if ((probe_debug & 0x0002) && DEBUG_IN_RANGE(P,ptr)) + printk("<7>try 0x%lx\n", (unsigned long)ptr); +#endif + if (ptr[T->NR1 - P->offset] != ip1) continue; + if (ptr[T->NR2 - P->offset] != ip2) continue; + if (ip3 && ptr[T->NR3 - P->offset] != ip3) continue; + +#ifdef OSI_PROBE_DEBUG + if (probe_debug & 0x0002) + printk("<7>try found 0x%lx\n", (unsigned long)ptr); +#endif + if (kallsyms_address_to_symbol) { + ret = kallsyms_address_to_symbol((unsigned long)ptr, + &mod_name, &mod_start, &mod_end, + &sec_name, &sec_start, &sec_end, + &sym_name, &sym_start, &sym_end); + if (!ret || strcmp(sym_name, P->symbol)) continue; + } + /* XXX should we make sure there is only one match? */ + return (void *)ptr; + } + return 0; +} + + +static int check_harder(probectl *P, PROBETYPE *p) +{ + unsigned long ip1; + int i, s; + + /* Check zapped syscalls */ + for (i = 1; i < P->n_zapped_syscalls; i++) { + if (p[P->zapped_syscalls[i]] != p[P->zapped_syscalls[0]]) { +#ifdef OSI_PROBE_DEBUG + if ((probe_debug & 0x0020) && DEBUG_IN_RANGE(P,p)) + printk("<7>check_harder 0x%lx zapped failed i=%d\n", (unsigned long)p, i); +#endif + return 0; + } + } + + /* Check unique syscalls */ + for (i = 0; i < P->n_unique_syscalls; i++) { + for (s = 0; s < NR_syscalls; s++) { + if (p[s] == p[P->unique_syscalls[i]] && s != P->unique_syscalls[i]) { +#ifdef OSI_PROBE_DEBUG + if ((probe_debug & 0x0010) && DEBUG_IN_RANGE(P,p)) + printk("<7>check_harder 0x%lx unique failed i=%d s=%d\n", (unsigned long)p, i, s); +#endif + return 0; + } + } + } + +#ifdef AFS_IA64_LINUX20_ENV + ip1 = P->verify_fn ? (unsigned long)((struct fptr *)(P->verify_fn))->ip : 0; +#else + ip1 = (unsigned long)(P->verify_fn); +#endif + + if (ip1 && p[P->verifyNR - P->offset] != ip1) { +#ifdef OSI_PROBE_DEBUG + if ((probe_debug & 0x0010) && DEBUG_IN_RANGE(P,p)) + printk("<7>check_harder 0x%lx verify failed\n", (unsigned long)p); +#endif + return 0; + } + +#ifdef OSI_PROBE_DEBUG + if ((probe_debug & 0x0010) && DEBUG_IN_RANGE(P,p)) + printk("<7>check_harder 0x%lx success!\n", (unsigned long)p); +#endif + return 1; +} + +static void *try_harder(probectl *P, PROBETYPE *ptr, unsigned long datalen) +{ + char *mod_name, *sec_name, *sym_name; + unsigned long mod_start, mod_end; + unsigned long sec_start, sec_end; + unsigned long sym_start, sym_end; + unsigned long offset; + void *match = 0; + int ret; + +#ifdef OSI_PROBE_DEBUG + if (probe_debug & 0x0001) + printk("<7>osi_probe: %s try_harder\n", P->symbol); +#endif + for (offset = 0; offset < datalen; offset++, ptr++) { + ret = check_table(P, ptr); + if (ret >= 0) { + /* return value is number of entries to skip */ + ptr += ret; + offset += ret; + continue; + } + +#ifdef OSI_PROBE_DEBUG + if ((probe_debug & 0x0004) && DEBUG_IN_RANGE(P,ptr)) + printk("<7>try_harder 0x%lx\n", (unsigned long)ptr); +#endif + if (!check_harder(P, ptr)) + continue; + +#ifdef OSI_PROBE_DEBUG + if (probe_debug & 0x0004) + printk("<7>try_harder found 0x%lx\n", (unsigned long)ptr); +#endif + + if (kallsyms_address_to_symbol) { + ret = kallsyms_address_to_symbol((unsigned long)ptr, + &mod_name, &mod_start, &mod_end, + &sec_name, &sec_start, &sec_end, + &sym_name, &sym_start, &sym_end); + if (!ret || strcmp(sym_name, P->symbol)) continue; + } + + if (match) { +#ifdef OSI_PROBE_DEBUG + if (probe_debug & 0x0005) + printk("<7>%s: try_harder found multiple matches!\n", P->symbol); +#endif + return 0; + } + + match = (void *)ptr; + if (!probe_carefully) + break; + } + return match; +} + + +#ifdef OSI_PROBE_DEBUG +#define check_result(x,m) do { \ + if (probe_debug & 0x0001) { \ + printk("<7>osi_probe: %s = 0x%016lx %s\n", P->symbol, (unsigned long)(x), (m)); \ + } \ + if ((x)) { \ + *method = (m); \ + final_answer = (void *)(x); \ + } \ +} while (0) +#else +#define check_result(x,m) do { \ + if ((x)) { \ + *method = (m); \ + return (void *)(x); \ + } \ +} while (0) +#endif +static void *do_find_syscall_table(probectl *P, char **method) +{ + char *mod_name, *sec_name, *sym_name; + unsigned long mod_start, mod_end; + unsigned long sec_start, sec_end; + unsigned long sym_start, sym_end; + PROBETYPE *B; + unsigned long token, L; + tryctl *T; + void *answer; +#ifdef OSI_PROBE_DEBUG + void *final_answer = 0; +#endif + int ret; + + *method = "not found"; + + /* if it's exported, there's nothing to do */ + check_result(P->weak_answer, "exported"); + + /* ask the kernel to do the name lookup, if it's willing */ + if (kallsyms_symbol_to_address) { + token = 0; + sym_start = 0; + do { + ret = kallsyms_symbol_to_address(P->symbol, &token, + &mod_name, &mod_start, &mod_end, + &sec_name, &sec_start, &sec_end, + &sym_name, &sym_start, &sym_end); + if (ret && !strcmp(mod_name, "kernel") && sym_start) + break; + sym_start = 0; + } while (ret); + check_result(sym_start, "kallsyms_symbol_to_address"); + } + + /* Maybe a little birdie told us */ + check_result(P->parm_answer, "module parameter"); + check_result(P->given_answer, "compiled-in"); + + /* OK, so we have to scan. */ + B = (PROBETYPE *)((P->try_base) & ~(P->try_base_mask)); + L = P->try_length; + /* Now, see if the kernel will tell us something better than the default */ + if (kallsyms_address_to_symbol) { + ret = kallsyms_address_to_symbol(P->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); + } + } + +#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); + check_result(answer, T->name); + } + + /* XXX more checks here */ + + answer = try_harder(P, B, L); + check_result(answer, "pattern scan"); + +#ifdef OSI_PROBE_DEBUG + return final_answer; +#else + return 0; +#endif +} + +void *osi_find_syscall_table(int which) +{ + probectl *P; + void *answer; + char *method; + + if (which < 0 || which >= N_PROBE_LIST) { + printk("error - afs_find_syscall_table called with invalid index!\n"); + return 0; + } + P = probe_list[which]; + if (which < 4) { + P->parm_answer = (void *)sys_call_table_addr[which]; +#ifdef OSI_PROBE_DEBUG + P->debug_answer = (void *)probe_debug_addr[which]; +#endif + } + answer = do_find_syscall_table(P, &method); + if (!answer) { + printk("Warning: failed to find address of %s\n", P->desc); + printk("System call hooks will not be installed; proceeding anyway\n"); + return 0; + } + printk("Found %s at 0x%lx (%s)\n", P->desc, (unsigned long)answer, method); + return answer; +} + + +#ifdef OSI_PROBE_STANDALONE +int __init osi_probe_init(void) +{ + int i; + + if (!probe_debug_tag) probe_debug_tag = jiffies; + printk("*** osi_probe %ld debug = 0x%04x ***\n", + probe_debug_tag, probe_debug); + for (i = 0; i < N_PROBE_LIST; i++) + (void)osi_find_syscall_table(i); + return 0; +} + +void osi_probe_exit(void) { } + +module_init(osi_probe_init); +module_exit(osi_probe_exit); +#endif diff --git a/src/afs/LINUX/osi_prototypes.h b/src/afs/LINUX/osi_prototypes.h index 3174826f9..05effc3b1 100644 --- a/src/afs/LINUX/osi_prototypes.h +++ b/src/afs/LINUX/osi_prototypes.h @@ -41,6 +41,13 @@ extern void afs_osi_SetTime(osi_timeval_t * tvp); extern void osi_linux_free_inode_pages(void); extern void check_bad_parent(struct dentry *dp); +/* osi_probe.c */ +extern void *osi_find_syscall_table(int which); + +/* osi_syscall.c */ +extern int osi_syscall_init(void); +extern void osi_syscall_clean(void); + /* osi_sysctl.c */ extern int osi_sysctl_init(void); extern void osi_sysctl_clean(void); diff --git a/src/afs/LINUX/osi_syscall.c b/src/afs/LINUX/osi_syscall.c new file mode 100644 index 000000000..f4ddebf0a --- /dev/null +++ b/src/afs/LINUX/osi_syscall.c @@ -0,0 +1,382 @@ +/* + * Copyright 2000, International Business Machines Corporation and others. + * All Rights Reserved. + * + * This software has been released under the terms of the IBM Public + * License. For details, see the LICENSE file in the top-level source + * directory or online at http://www.openafs.org/dl/license10.html + */ + +/* + * Linux module support routines. + * + */ +#include +#include "afs/param.h" + +RCSID + ("$Header$"); + +#include /* early to avoid printf->printk mapping */ +#include "afs/sysincludes.h" +#include "afsincludes.h" +#include "h/unistd.h" /* For syscall numbers. */ +#include "h/mm.h" + +#ifdef AFS_AMD64_LINUX20_ENV +#include "../asm/ia32_unistd.h" +#endif + +#include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +#include +#include +#endif + + +/* On SPARC64 and S390X, sys_call_table contains 32-bit entries + * even though pointers are 64 bit quantities. + * XXX unify this with osi_probe.c + */ +#if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390X_LINUX24_ENV) +#define SYSCALLTYPE unsigned int +#define POINTER2SYSCALL (unsigned int)(unsigned long) +#define SYSCALL2POINTER (void *)(long) +#else +#define SYSCALLTYPE void * +#define POINTER2SYSCALL (void *) +#define SYSCALL2POINTER (void *) +#endif + +#if defined(AFS_S390X_LINUX24_ENV) +#define _S(x) ((x)<<1) +#elif defined(AFS_IA64_LINUX20_ENV) +#define _S(x) ((x)-1024) +#else +#define _S(x) x +#endif + + +/***** ALL PLATFORMS *****/ +extern asmlinkage long +afs_syscall(long syscall, long parm1, long parm2, long parm3, long parm4); + +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_LINUX24_ENV +extern int afs_xsetgroups32(); +asmlinkage int (*sys_setgroups32p) (int gidsetsize, + __kernel_gid32_t * grouplist); +#endif + +#if !defined(AFS_LINUX24_ENV) +asmlinkage int (*sys_settimeofdayp) (struct timeval * tv, struct timezone * tz); +#endif + + +/***** AMD64 *****/ +#ifdef AFS_AMD64_LINUX20_ENV +static SYSCALLTYPE *afs_ia32_sys_call_table; +static SYSCALLTYPE ia32_ni_syscall = 0; + +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 */ + + +/***** PPC64 *****/ +#ifdef AFS_PPC64_LINUX20_ENV +extern SYSCALLTYPE *afs_sys_call_table32; +static SYSCALLTYPE afs_ni_syscall32 = 0; + +extern int afs32_xsetgroups(); +asmlinkage long (*sys32_setgroupsp)(int gidsetsize, gid_t *grouplist); +#endif /* AFS_AMD64_LINUX20_ENV */ + + +/***** SPARC64 *****/ +#ifdef AFS_SPARC64_LINUX20_ENV +extern SYSCALLTYPE *afs_sys_call_table32; +static SYSCALLTYPE afs_ni_syscall32 = 0; + +extern int afs32_xsetgroups(); +asmlinkage int (*sys32_setgroupsp) (int gidsetsize, + __kernel_gid_t32 * grouplist); +#ifdef AFS_LINUX24_ENV +/* This number is not exported for some bizarre reason. */ +#define __NR_setgroups32 82 +extern int afs32_xsetgroups32(); +asmlinkage int (*sys32_setgroups32p) (int gidsetsize, + __kernel_gid_t32 * grouplist); +#endif + +asmlinkage int +afs_syscall32(long syscall, long parm1, long parm2, long parm3, long parm4, + long parm5) +{ + __asm__ __volatile__("srl %o4, 0, %o4\n\t" "mov %o7, %i7\n\t" + "call afs_syscall\n\t" "srl %o5, 0, %o5\n\t" + "ret\n\t" "nop"); +} +#endif /* AFS_SPARC64_LINUX20_ENV */ + + +/***** IA64 *****/ +#ifdef AFS_IA64_LINUX20_ENV + +asmlinkage long +afs_syscall_stub(int r0, int r1, long r2, long r3, long r4, long gp) +{ + __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t" "mov r41 = b0\n\t" /* save rp */ + "mov out0 = in0\n\t" "mov out1 = in1\n\t" "mov out2 = in2\n\t" "mov out3 = in3\n\t" "mov out4 = in4\n\t" "mov out5 = gp\n\t" /* save gp */ + ";;\n" ".L1:\n\t" "mov r3 = ip\n\t" ";;\n\t" "addl r15=.fptr_afs_syscall-.L1,r3\n\t" ";;\n\t" "ld8 r15=[r15]\n\t" ";;\n\t" "ld8 r16=[r15],8\n\t" ";;\n\t" "ld8 gp=[r15]\n\t" "mov b6=r16\n\t" "br.call.sptk.many b0 = b6\n\t" ";;\n\t" "mov ar.pfs = r42\n\t" "mov b0 = r41\n\t" "mov gp = r48\n\t" /* restore gp */ + "br.ret.sptk.many b0\n" ".fptr_afs_syscall:\n\t" + "data8 @fptr(afs_syscall)\n\t" ".skip 8"); +} + +asmlinkage long +afs_xsetgroups_stub(int r0, int r1, long r2, long r3, long r4, long gp) +{ + __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t" "mov r41 = b0\n\t" /* save rp */ + "mov out0 = in0\n\t" "mov out1 = in1\n\t" "mov out2 = in2\n\t" "mov out3 = in3\n\t" "mov out4 = in4\n\t" "mov out5 = gp\n\t" /* save gp */ + ";;\n" ".L2:\n\t" "mov r3 = ip\n\t" ";;\n\t" "addl r15=.fptr_afs_xsetgroups - .L2,r3\n\t" ";;\n\t" "ld8 r15=[r15]\n\t" ";;\n\t" "ld8 r16=[r15],8\n\t" ";;\n\t" "ld8 gp=[r15]\n\t" "mov b6=r16\n\t" "br.call.sptk.many b0 = b6\n\t" ";;\n\t" "mov ar.pfs = r42\n\t" "mov b0 = r41\n\t" "mov gp = r48\n\t" /* restore gp */ + "br.ret.sptk.many b0\n" ".fptr_afs_xsetgroups:\n\t" + "data8 @fptr(afs_xsetgroups)\n\t" ".skip 8"); +} + +struct fptr { + void *ip; + unsigned long gp; +}; + +#endif /* AFS_IA64_LINUX20_ENV */ + + + +/**********************************************************************/ +/********************* System Call Initialization *********************/ +/**********************************************************************/ + +int osi_syscall_init(void) +{ +/***** IA64 *****/ +#ifdef AFS_IA64_LINUX20_ENV + /* This needs to be first because we are declaring variables, and + * also because the handling of syscall pointers is bizarre enough + * that we want to special-case even the "common" part. + */ + unsigned long kernel_gp = 0; + static struct fptr sys_setgroups; + + 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_syscall) { + printf("AFS syscall entry point already in use!\n"); + return -EBUSY; + } + + /* setup AFS entry point */ + afs_ni_syscall = afs_sys_call_table[_S(__NR_afs_syscall)]; + afs_sys_call_table[_S(__NR_afs_syscall)] = + POINTER2SYSCALL((struct fptr *)afs_syscall_stub)->ip; + + /* setup setgroups */ + sys_setgroupsp = (void *)&sys_setgroups; + + ((struct fptr *)sys_setgroupsp)->ip = + SYSCALL2POINTER afs_sys_call_table[_S(__NR_setgroups)]; + ((struct fptr *)sys_setgroupsp)->gp = kernel_gp; + + afs_sys_call_table[__S(_NR_setgroups)] = + POINTER2SYSCALL((struct fptr *)afs_xsetgroups_stub)->ip; + } + + /* XXX no 32-bit syscalls on IA64? */ + + +/***** COMMON (except IA64) *****/ +#else /* !AFS_IA64_LINUX20_ENV */ + + 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)] + == afs_syscall) { + printf("AFS syscall entry point already in use!\n"); + return -EBUSY; + } + + /* 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; + + /* setup setgroups */ + sys_setgroupsp = SYSCALL2POINTER afs_sys_call_table[_S(__NR_setgroups)]; + afs_sys_call_table[_S(__NR_setgroups)] = POINTER2SYSCALL 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; +#endif + } +#endif /* !AFS_IA64_LINUX20_ENV */ + + +/***** AMD64 *****/ +#ifdef AFS_AMD64_LINUX20_ENV + afs_ia32_sys_call_table = osi_find_syscall_table(1); + if (afs_ia32_sys_call_table) { + /* setup AFS entry point for IA32 */ + ia32_ni_syscall = afs_ia32_sys_call_table[__NR_ia32_afs_syscall]; + afs_ia32_sys_call_table[__NR_ia32_afs_syscall] = + POINTER2SYSCALL afs_syscall; + + /* setup setgroups for IA32 */ + sys32_setgroupsp = + SYSCALL2POINTER afs_ia32_sys_call_table[__NR_ia32_setgroups]; + 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 */ + + +/***** PPC64 *****/ +#ifdef AFS_PPC64_LINUX20_ENV + /* XXX no 32-bit syscalls on PPC64? */ +#endif + + +/***** SPARC64 *****/ +#ifdef AFS_SPARC64_LINUX20_ENV + afs_sys_call_table32 = osi_find_syscall_table(1); + if (afs_sys_call_table32) { + /* setup AFS entry point for 32-bit SPARC */ + afs_ni_syscall32 = afs_sys_call_table32[__NR_afs_syscall]; + afs_sys_call_table32[__NR_afs_syscall] = POINTER2SYSCALL afs_syscall32; + + /* setup setgroups for 32-bit SPARC */ + 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; +} + + + +/**********************************************************************/ +/************************ System Call Cleanup *************************/ +/**********************************************************************/ + +void osi_syscall_clean(void) +{ +/***** COMMON *****/ + if (afs_sys_call_table) { + /* put back the AFS entry point */ + afs_sys_call_table[_S(__NR_afs_syscall)] = afs_ni_syscall; + + /* put back setgroups */ +#if defined(AFS_IA64_LINUX20_ENV) + afs_sys_call_table[_S(__NR_setgroups)] = + POINTER2SYSCALL((struct fptr *)sys_setgroupsp)->ip; +#else /* AFS_IA64_LINUX20_ENV */ + afs_sys_call_table[_S(__NR_setgroups)] = + POINTER2SYSCALL sys_setgroupsp; +#endif + +#if defined(__NR_setgroups32) && !defined(AFS_IA64_LINUX20_ENV) + /* put back setgroups32 */ + afs_sys_call_table[__NR_setgroups32] = POINTER2SYSCALL sys_setgroups32p; +#endif + } + + +/***** IA64 *****/ +#ifdef AFS_IA64_LINUX20_ENV + /* XXX no 32-bit syscalls on IA64? */ +#endif + + +/***** AMD64 *****/ +#ifdef AFS_AMD64_LINUX20_ENV + if (afs_ia32_sys_call_table) { + /* put back AFS entry point for IA32 */ + afs_ia32_sys_call_table[__NR_ia32_afs_syscall] = + POINTER2SYSCALL ia32_ni_syscall; + + /* put back setgroups for IA32 */ + 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 + + +/***** PPC64 *****/ +#ifdef AFS_PPC64_LINUX20_ENV + /* XXX no 32-bit syscalls on PPC64? */ +#endif + + +/***** SPARC64 *****/ +#ifdef AFS_SPARC64_LINUX20_ENV + if (afs_sys_call_table32) { + /* put back AFS entry point for 32-bit SPARC */ + afs_sys_call_table32[__NR_afs_syscall] = afs_ni_syscall32; + + /* put back setgroups for IA32 */ + 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 +} diff --git a/src/libafs/Makefile.common.in b/src/libafs/Makefile.common.in index 8be95e21f..9ee7e74f3 100644 --- a/src/libafs/Makefile.common.in +++ b/src/libafs/Makefile.common.in @@ -387,6 +387,10 @@ osi_debug.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_debug.c $(CRULE_OPT) osi_module.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_module.c $(CRULE_NOOPT) +osi_probe.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_probe.c + $(CRULE_NOOPT) +osi_syscall.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_syscall.c + $(CRULE_NOOPT) osi_sysctl.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_sysctl.c $(CRULE_NOOPT) osi_alloc.o: $(TOP_SRCDIR)/afs/$(MKAFS_OSTYPE)/osi_alloc.c diff --git a/src/libafs/MakefileProto.LINUX.in b/src/libafs/MakefileProto.LINUX.in index 211dd1008..e834f7cfb 100644 --- a/src/libafs/MakefileProto.LINUX.in +++ b/src/libafs/MakefileProto.LINUX.in @@ -18,7 +18,9 @@ AFS_OS_OBJS = \ osi_file.o \ osi_misc.o \ osi_module.o \ + osi_probe.o \ osi_sleep.o \ + osi_syscall.o \ osi_sysctl.o \ osi_vfsops.o \ osi_vm.o \ -- 2.39.5