asmlinkage long efab_linux_trampoline_sigaction(int sig, const struct sigaction *act, struct sigaction *oact, size_t sigsetsize) { int rc = 0; struct sigaction old, new; struct mm_signal_data *tramp_data; int pass_to_kernel = 0; efab_syscall_enter(); if( sigsetsize != sizeof(sigset_t) ) { efab_syscall_exit(); return -EINVAL; } /* Is it our process? */ if( efab_signal_get_tramp_data(&tramp_data) ) { rc = efab_linux_sys_sigaction(sig, act, oact); efab_syscall_exit(); return rc; } if( act != NULL ) { /* If we are in vfork child, we have the same mm but different sighand. * We should not change parent UL structure in this case, se we'd * better off from this signal while running in the child. */ if( tramp_data->kernel_sighand != current->sighand ) pass_to_kernel = 1; else { rc = copy_from_user(&new, act, sizeof(new)); if( rc != 0 ) { efab_signal_put_tramp_data(tramp_data); efab_syscall_exit(); return -EFAULT; } } } rc = efab_signal_do_sigaction(sig, (act && !pass_to_kernel) ? &new : NULL, oact ? &old : NULL, tramp_data, &pass_to_kernel); efab_signal_put_tramp_data(tramp_data); if( pass_to_kernel ) efab_linux_sys_sigaction(sig, act, NULL); if( rc == 0 && oact != NULL ) { rc = copy_to_user(oact, &old, sizeof(old)); if( rc != 0 ) { efab_syscall_exit(); return -EFAULT; } } efab_syscall_exit(); return rc; }
/* Our close handler, 64-bit */ static int efab_linux_trampoline_close64(int fd) { /* Firstly, is this one our sockets? If not, do the usual thing */ struct file *f; int rc; TRAMP_DEBUG("close64: %d\n", fd); efab_syscall_enter(); f = fget (fd); if (f) { if (FILE_IS_ENDPOINT(f)) { /* Yep -- it's one of ours. This means current process must be using the * module (otherwise how did one of our sockets get in this proc's fd * table?). It seems it didn't get intercepted -- trampoline back up. * However, only set up trampoline if this has been called via the * correct sys-call entry point */ if (setup_trampoline (PT_REGS_FROM_SYSCALL(), CI_TRAMP_OPCODE_CLOSE, fd, TRAMPOLINE_BITS_64) == 0) { /* The trampoline will get run. Let it handle the rest. */ fput(f); efab_syscall_exit(); return 0; } } /* Undo the fget above */ fput(f); } TRAMP_DEBUG("going unto %p\n", THUNKPTR(state.replace_close->original_entry64)); /* Not one of our FDs -- usual close */ rc = ((int (*)(int))THUNKPTR(state.replace_close->original_entry64))(fd); TRAMP_DEBUG("Close64: Chain returns %d \n", rc); efab_syscall_exit(); return rc; }
/* On PPC there is no 32-bit sigaction - or rather, all sigaction calls are 32-bit. */ asmlinkage int efab_linux_trampoline_sigaction32(int sig, const struct sigaction32 *act32, struct sigaction32 *oact32, unsigned int sigsetsize) { struct sigaction act, oact; compat_sigset_t set32; int rc; struct mm_signal_data *tramp_data; int pass_to_kernel = 0; efab_syscall_enter(); if( sigsetsize != sizeof(compat_sigset_t) ) { efab_syscall_exit(); return -EINVAL; } /* Is it our process? */ if( efab_signal_get_tramp_data(&tramp_data) ) { rc = efab_linux_sys_sigaction32(sig, act32, oact32); efab_syscall_exit(); return rc; } /* Do not change UL data if we are in vfork child */ if( act32 != NULL && tramp_data->kernel_sighand != current->sighand ) pass_to_kernel = 1; if( act32 != NULL && !pass_to_kernel ) { compat_uptr_t handler, restorer; if( !access_ok(VERIFY_READ, act32, sizeof(*act32)) || __get_user(handler, &act32->sa_handler) || __get_user(act.sa_flags, &act32->sa_flags) || __get_user(restorer, &act32->sa_restorer) || __copy_from_user(&set32, &act32->sa_mask, sizeof(compat_sigset_t)) ) { efab_signal_put_tramp_data(tramp_data); efab_syscall_exit(); return -EFAULT; } act.sa_handler = compat_ptr(handler); act.sa_restorer = compat_ptr(restorer); ci_assert_ge(_COMPAT_NSIG_WORDS, _NSIG_WORDS << 1); switch (_NSIG_WORDS) { /* Note: no break */ case 4: act.sa_mask.sig[3] = set32.sig[6] | (((long)set32.sig[7]) << 32); case 3: act.sa_mask.sig[2] = set32.sig[4] | (((long)set32.sig[5]) << 32); case 2: act.sa_mask.sig[1] = set32.sig[2] | (((long)set32.sig[3]) << 32); case 1: act.sa_mask.sig[0] = set32.sig[0] | (((long)set32.sig[1]) << 32); } } rc = efab_signal_do_sigaction(sig, (act32 && !pass_to_kernel) ? &act : NULL, oact32 ? &oact : NULL, tramp_data, &pass_to_kernel); efab_signal_put_tramp_data(tramp_data); if( pass_to_kernel ) efab_linux_sys_sigaction32(sig, act32, NULL); if( rc == 0 && oact32 != NULL ) { switch (_NSIG_WORDS) { /* Note: no break */ case 4: set32.sig[7] = (oact.sa_mask.sig[3] >> 32); set32.sig[6] = oact.sa_mask.sig[3]; case 3: set32.sig[5] = (oact.sa_mask.sig[2] >> 32); set32.sig[4] = oact.sa_mask.sig[2]; case 2: set32.sig[3] = (oact.sa_mask.sig[1] >> 32); set32.sig[2] = oact.sa_mask.sig[1]; case 1: set32.sig[1] = (oact.sa_mask.sig[0] >> 32); set32.sig[0] = oact.sa_mask.sig[0]; } if( !access_ok(VERIFY_WRITE, oact32, sizeof(*oact32)) || __put_user(ptr_to_compat(oact.sa_handler), &oact32->sa_handler) || __put_user(ptr_to_compat(oact.sa_restorer), &oact32->sa_restorer) || __put_user(oact.sa_flags, &oact32->sa_flags) || __copy_to_user(&oact32->sa_mask, &set32, sizeof(compat_sigset_t))) { efab_syscall_exit(); return -EFAULT; } } efab_syscall_exit(); return rc; }