void efab_signal_process_fini(struct mm_signal_data *tramp_data) { int sig; OO_DEBUG_SIGNAL(ci_log("%s(%p) pid %d: current->flags=%x, " "tramp_data->user_data=%p", __func__, tramp_data, current->pid, (int)current->flags, CI_USER_PTR_GET(tramp_data->user_data))); /* Check if we should really do anything */ if( current->flags & PF_EXITING ) return; /* the process is exiting */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30) if( current->in_execve ) return; /* in execve() */ #endif if( CI_USER_PTR_GET(tramp_data->user_data) == NULL ) return; /* nothing was inited */ OO_DEBUG_SIGNAL(ci_log("%s(%p) pid %d: uninstall interception", __func__, tramp_data, current->pid)); for( sig = 1; sig <= _NSIG; sig++ ) { if( sig_kernel_only(sig) ) continue; if( efab_signal_report_sigaction(sig, NULL, tramp_data) != 0 ) { ci_log("%s: ERROR: pid %d failed to back off signal %d handler", __func__, current->pid, sig); continue; } } }
void efab_signal_process_init(struct mm_signal_data *tramp_data) { int sig; int rc; OO_DEBUG_SIGNAL(ci_log("%s(%p) pid %d", __func__, tramp_data, current->pid)); /* At start-of-day, we intercept all already-installed handlers * and deadly SIG_DFL */ for( sig = 1; sig <= _NSIG; sig++ ) { struct k_sigaction *k; tramp_data->signal_data[sig - 1].type = OO_SIGHANGLER_USER | OO_SIGHANGLER_IGN_BIT; CI_USER_PTR_SET(tramp_data->signal_data[sig - 1].handler, NULL); /* Never, never intercept SIGKILL. You'll get deadlock since exit_group * sends SIGKILL to all other threads. */ if( sig_kernel_only(sig) ) continue; /* If this is our handler, do nothing. This is second init from the * same process. It happens in fork hooks, when second netif is * created, etc. */ spin_lock_irq(¤t->sighand->siglock); k = ¤t->sighand->action[sig - 1]; if( k->sa.sa_handler == tramp_data->handler_postpone ) { spin_unlock_irq(¤t->sighand->siglock); OO_DEBUG_SIGNAL(ci_log("%s: double init pid=%d", __func__, current->pid)); rc = copy_from_user(tramp_data->signal_data, CI_USER_PTR_GET(tramp_data->user_data), sizeof(tramp_data->signal_data)); if( rc != 0 ) ci_log("%s: ERROR: failed to copy signal data (%d)", __func__, rc); break; } spin_unlock_irq(¤t->sighand->siglock); /* Ignore any errors */ (void) efab_signal_substitute(sig, NULL, tramp_data); } tramp_data->kernel_sighand = current->sighand; }
static struct pid *good_sigevent(sigevent_t * event) { struct task_struct *rtn = current->group_leader; int sig = event->sigev_signo; if ((event->sigev_notify & SIGEV_THREAD_ID ) && (!(rtn = find_task_by_vpid(event->sigev_notify_thread_id)) || !same_thread_group(rtn, current) || (event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_SIGNAL)) return NULL; if (((event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) && (sig <= 0 || sig > SIGRTMAX || sig_kernel_only(sig) || sig_kernel_coredump(sig))) return NULL; return task_pid(rtn); }
static int efab_signal_do_sigaction(int sig, struct sigaction *act, struct sigaction *oact, struct mm_signal_data *tramp_data, int *out_pass_to_kernel) { int rc = 0; if( !valid_signal(sig) || sig < 1 || (act != NULL && sig_kernel_only(sig)) ) return -EINVAL; if( oact != NULL ) { rc = efab_signal_report_sigaction(sig, oact, tramp_data); if( rc != 0 ) return rc; } if( act != NULL ) { sigdelsetmask(&act->sa_mask, sigmask(SIGKILL) | sigmask(SIGSTOP)); /* If the signal is ignored now, we should ignore all already-pending * signals. Instead of doing it, pass this to OS. */ if( act->sa_handler == SIG_IGN || (act->sa_handler == SIG_DFL && sig_kernel_ignore(sig)) ) *out_pass_to_kernel = 1; else if( act->sa_flags & SA_ONSTACK && !tramp_data->sa_onstack_intercept ) *out_pass_to_kernel = 1; else rc = efab_signal_substitute(sig, act, tramp_data); } else efab_signal_recheck(sig, tramp_data); return rc; }