X-Git-Url: http://git.openafs.org/?p=openafs.git;a=blobdiff_plain;f=src%2Fafs%2FLINUX%2Fosi_syscall.c;h=0a85aa6b672ea2917c0fb92166b6cceaeeb2d657;hp=34133c25a409c572872f1b4f219aa824c9f35a3f;hb=109927bf6f54b58b76ac48ba41c2012c74937fed;hpb=4e3107a00270132b23194a0e776504f4cb425251 diff --git a/src/afs/LINUX/osi_syscall.c b/src/afs/LINUX/osi_syscall.c index 34133c2..0a85aa6 100644 --- a/src/afs/LINUX/osi_syscall.c +++ b/src/afs/LINUX/osi_syscall.c @@ -14,8 +14,6 @@ #include #include "afs/param.h" -RCSID - ("$Header$"); #include /* early to avoid printf->printk mapping */ #include "afs/sysincludes.h" @@ -24,16 +22,17 @@ RCSID #include "h/mm.h" #ifdef AFS_AMD64_LINUX20_ENV -#include "../asm/ia32_unistd.h" +#include #endif #include #include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) #include #include -#endif +#ifndef NR_syscalls +#define NR_syscalls 222 +#endif /* On SPARC64 and S390X, sys_call_table contains 32-bit entries * even though pointers are 64 bit quantities. @@ -49,9 +48,25 @@ RCSID #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 @@ -65,19 +80,29 @@ 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_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 @@ -86,38 +111,52 @@ 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; +#ifdef AFS_PPC64_LINUX26_ENV +static SYSCALLTYPE *afs_sys_call_table32; static SYSCALLTYPE afs_ni_syscall32 = 0; +static SYSCALLTYPE old_sys_setgroupsp = 0; +static SYSCALLTYPE old_sys32_setgroupsp = 0; extern int afs32_xsetgroups(); asmlinkage long (*sys32_setgroupsp)(int gidsetsize, gid_t *grouplist); -#endif /* AFS_AMD64_LINUX20_ENV */ + +asmlinkage long sys_close(unsigned int fd); +static void sys_setgroups_stub() + __attribute__ ((pure,const,no_instrument_function)); +static void sys_setgroups_stub() +{ + printf("*** error! sys_setgroups_stub called\n"); +} + +static void sys32_setgroups_stub() + __attribute__ ((pure,const,no_instrument_function)); +static void sys32_setgroups_stub() +{ + printf("*** error! sys32_setgroups_stub called\n"); +} + +#endif /* AFS_PPC64_LINUX26_ENV */ /***** SPARC64 *****/ -#ifdef AFS_SPARC64_LINUX20_ENV -extern SYSCALLTYPE *afs_sys_call_table32; +#ifdef AFS_SPARC64_LINUX26_ENV +static 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 + __kernel_gid32_t * grouplist); /* 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 + __kernel_gid32_t * grouplist); asmlinkage int afs_syscall32(long syscall, long parm1, long parm2, long parm3, long parm4, @@ -211,6 +250,127 @@ struct fptr { #endif /* AFS_IA64_LINUX20_ENV */ +/***** PPC64 ***** + * Spring 2005 + * sys_call_table hook for PPC64 + * by Soewono Effendi + * for IBM Deutschland + * Thanks go to SYSGO's team for their support: + * Horst Birthelmer + * Marius Groeger + */ +#if defined(AFS_PPC64_LINUX26_ENV) +extern void flush_cache(void *, unsigned long); +#define PPC_LO(v) ((v) & 0xffff) +#define PPC_HI(v) (((v) >> 16) & 0xffff) +#define PPC_HA(v) PPC_HI ((v) + 0x8000) +#define PPC_HLO(v) ((short)(((v) >> 32) & 0xffff)) +#define PPC_HHI(v) ((short)(((v) >> 48) & 0xffff)) + +struct ppc64_opd +{ + unsigned long funcaddr; + unsigned long r2; +}; + +struct ppc64_stub +{ + unsigned char jump[136]; + unsigned long r2; + unsigned long lr; + struct ppc64_opd opd; +} __attribute__ ((packed)); + +/* a stub to fix up r2 (TOC ptr) and to jump to our sys_call hook + function. We patch the new r2 value and function pointer into + the stub. */ +#define PPC64_STUB(stub) \ +static struct ppc64_stub stub = \ +{ .jump = { \ + 0xf8, 0x41, 0x00, 0x28, /* std r2,40(r1) */ \ + 0xfb, 0xc1, 0xff, 0xf0, /* std r30,-16(r1) */ \ + 0xfb, 0xa1, 0xff, 0xe8, /* std r29,-24(r1) */ \ + 0x7c, 0x5d, 0x13, 0x78, /* mr r29,r2 */ \ + 0x3c, 0x40, 0x12, 0x34, /*16: lis r2,4660 */ \ + 0x60, 0x42, 0x56, 0x78, /*20: ori r2,r2,22136 */ \ + 0x78, 0x42, 0x07, 0xc6, /* rldicr r2,r2,32,31 */ \ + 0x64, 0x42, 0x90, 0xab, /*28: oris r2,r2,37035 */ \ + 0x60, 0x42, 0xcd, 0xef, /*32: ori r2,r2,52719 */ \ + 0x3f, 0xc2, 0x00, 0x00, /*36: addis r30,r2,0 */ \ + 0x3b, 0xde, 0x00, 0x00, /*40: addi r30,r30,0 */ \ + 0xfb, 0xbe, 0x00, 0x88, /* std r29,136(r30) */ \ + 0x7f, 0xa8, 0x02, 0xa6, /* mflr r29 */ \ + 0xfb, 0xbe, 0x00, 0x90, /* std r29,144(r30) */ \ + 0xeb, 0xde, 0x00, 0x98, /* ld r30,152(r30) */ \ + 0x7f, 0xc8, 0x03, 0xa6, /* mtlr r30 */ \ + 0xeb, 0xa1, 0xff, 0xe8, /* ld r29,-24(r1) */ \ + 0xeb, 0xc1, 0xff, 0xf0, /* ld r30,-16(r1) */ \ + 0x4e, 0x80, 0x00, 0x21, /* blrl */ \ + 0x3c, 0x40, 0x12, 0x34, /*76: lis r2,4660 */ \ + 0x60, 0x42, 0x56, 0x78, /*80: ori r2,r2,22136 */ \ + 0x78, 0x42, 0x07, 0xc6, /* rldicr r2,r2,32,31 */ \ + 0x64, 0x42, 0x90, 0xab, /*88: oris r2,r2,37035 */ \ + 0x60, 0x42, 0xcd, 0xef, /*92: ori r2,r2,52719 */ \ + 0xfb, 0xc1, 0xff, 0xf0, /* std r30,-16(r1) */ \ + 0xfb, 0xa1, 0xff, 0xe8, /* std r29,-24(r1) */ \ + 0x3f, 0xc2, 0xab, 0xcd, /*104: addis r30,r2,-21555 */ \ + 0x3b, 0xde, 0x78, 0x90, /*108: addi r30,r30,30864 */ \ + 0xeb, 0xbe, 0x00, 0x90, /* ld r29,144(r30) */ \ + 0x7f, 0xa8, 0x03, 0xa6, /* mtlr r29 */ \ + 0xe8, 0x5e, 0x00, 0x88, /* ld r2,136(r30) */ \ + 0xeb, 0xa1, 0xff, 0xe8, /* ld r29,-24(r1) */ \ + 0xeb, 0xc1, 0xff, 0xf0, /* ld r30,-16(r1) */ \ + 0x4e, 0x80, 0x00, 0x20 /* blr */ \ +}} + +static void * create_stub(struct ppc64_stub *stub, + struct ppc64_opd *opd) +{ + unsigned short *p1, *p2, *p3, *p4; + unsigned long addr; + + stub->opd.funcaddr = opd->funcaddr; + stub->opd.r2 = opd->r2; + addr = (unsigned long) opd->r2; + p1 = (unsigned short*) &stub->jump[18]; + p2 = (unsigned short*) &stub->jump[22]; + p3 = (unsigned short*) &stub->jump[30]; + p4 = (unsigned short*) &stub->jump[34]; + + *p1 = PPC_HHI(addr); + *p2 = PPC_HLO(addr); + *p3 = PPC_HI(addr); + *p4 = PPC_LO(addr); + + addr = (unsigned long) stub - opd->r2; + p1 = (unsigned short*) &stub->jump[38]; + p2 = (unsigned short*) &stub->jump[42]; + *p1 = PPC_HA(addr); + *p2 = PPC_LO(addr); + p1 = (unsigned short*) &stub->jump[106]; + p2 = (unsigned short*) &stub->jump[110]; + *p1 = PPC_HA(addr); + *p2 = PPC_LO(addr); + + addr = (unsigned long) opd->r2; + p1 = (unsigned short*) &stub->jump[78]; + p2 = (unsigned short*) &stub->jump[82]; + p3 = (unsigned short*) &stub->jump[90]; + p4 = (unsigned short*) &stub->jump[94]; + + *p1 = PPC_HHI(addr); + *p2 = PPC_HLO(addr); + *p3 = PPC_HI(addr); + *p4 = PPC_LO(addr); + + flush_cache((void *)stub, sizeof(*stub)); + return ((void*)(stub)); +} + +PPC64_STUB(afs_sys_call_stub); +PPC64_STUB(afs_xsetgroups_stub); +PPC64_STUB(afs_xsetgroups32_stub); +#endif /* AFS_PPC64_LINUX26_ENV */ /**********************************************************************/ @@ -231,10 +391,6 @@ int osi_syscall_init(void) 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)] @@ -262,15 +418,55 @@ int osi_syscall_init(void) /* XXX no 32-bit syscalls on IA64? */ -/***** COMMON (except IA64) *****/ +#elif defined(AFS_PPC64_LINUX26_ENV) + + afs_sys_call_table = osi_find_syscall_table(0); + if (afs_sys_call_table) { + SYSCALLTYPE p; + struct ppc64_opd* opd = (struct ppc64_opd*) sys_close; + unsigned long r2 = opd->r2; + opd = (struct ppc64_opd*) afs_syscall; + afs_sys_call_table32 = (unsigned long)afs_sys_call_table - + NR_syscalls * sizeof(SYSCALLTYPE); + /* check we aren't already loaded */ + p = SYSCALL2POINTER afs_sys_call_table[_S(__NR_afs_syscall)]; + if ((unsigned long)p == opd->funcaddr) { + printf("AFS syscall entry point already in use!\n"); + return -EBUSY; + } + /* setup AFS entry point */ + p = create_stub(&afs_sys_call_stub, opd); + afs_ni_syscall = afs_sys_call_table[_S(__NR_afs_syscall)]; + afs_sys_call_table[_S(__NR_afs_syscall)] = POINTER2SYSCALL p; + + /* setup setgroups */ + opd = (struct ppc64_opd*) afs_xsetgroups; + p = create_stub(&afs_xsetgroups_stub, opd); + old_sys_setgroupsp = SYSCALL2POINTER afs_sys_call_table[_S(__NR_setgroups)]; + afs_sys_call_table[_S(__NR_setgroups)] = POINTER2SYSCALL p; + opd = (struct ppc64_opd*) sys_setgroups_stub; + opd->funcaddr = old_sys_setgroupsp; + opd->r2 = r2; + + /* setup setgroups32 */ + opd = (struct ppc64_opd*) afs32_xsetgroups; + p = create_stub(&afs_xsetgroups32_stub, opd); + old_sys32_setgroupsp = SYSCALL2POINTER afs_sys_call_table32[_S(__NR_setgroups)]; + afs_sys_call_table32[_S(__NR_setgroups)] = POINTER2SYSCALL p; + opd = (struct ppc64_opd*) sys32_setgroups_stub; + opd->funcaddr = old_sys32_setgroupsp; + opd->r2 = r2; + + flush_cache((void *)afs_sys_call_table, 2*NR_syscalls*sizeof(void*)); + + sys_setgroupsp = sys_setgroups_stub; + sys32_setgroupsp = sys32_setgroups_stub; + } +/***** COMMON (except IA64 or PPC64) *****/ #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)] @@ -281,16 +477,17 @@ int osi_syscall_init(void) /* 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 */ @@ -311,23 +508,15 @@ int osi_syscall_init(void) 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); @@ -340,13 +529,11 @@ int osi_syscall_init(void) 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; @@ -369,6 +556,12 @@ void osi_syscall_clean(void) #if defined(AFS_IA64_LINUX20_ENV) afs_sys_call_table[_S(__NR_setgroups)] = POINTER2SYSCALL((struct fptr *)sys_setgroupsp)->ip; +#elif defined(AFS_PPC64_LINUX26_ENV) + afs_sys_call_table[_S(__NR_setgroups)] = + POINTER2SYSCALL old_sys_setgroupsp; + /* put back setgroups32 for PPC64 */ + afs_sys_call_table32[__NR_setgroups] = + POINTER2SYSCALL old_sys32_setgroupsp; #else /* AFS_IA64_LINUX20_ENV */ afs_sys_call_table[_S(__NR_setgroups)] = POINTER2SYSCALL sys_setgroupsp; @@ -378,6 +571,16 @@ void osi_syscall_clean(void) /* 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 } @@ -398,21 +601,13 @@ void osi_syscall_clean(void) 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) { @@ -423,11 +618,9 @@ void osi_syscall_clean(void) 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 }