#include #include #include #include #include #include #include int test_signal; int *page_address; pthread_t tid; int is_signal_blocked(int signum) { sigset_t set; pthread_sigmask(SIG_BLOCK, 0, &set); return (sigismember(&set, signum)); } void *eip(struct ucontext *context) { return (void *)context->uc_mcontext.gregs[14]; } void test_handler(int signal, siginfo_t *info, void *context) { } void sigsegv_handler(int signal, siginfo_t *info, void *context) { /* The test signal is blocked only in test_handler. */ if (is_signal_blocked(test_signal)) { printf("eip: %x\n", eip(context)); _exit(27); } mprotect(page_address, 4096, PROT_READ | PROT_WRITE); } void *make_faults(void *arg) { while (1) { mprotect(page_address, 4096, PROT_NONE); *page_address = 1; } } void *reserve_page(void) { int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE; void *actual = mmap(0, 4096, PROT_NONE, flags, -1, 0); if (actual == MAP_FAILED) { perror("mmap"); return 0; } return actual; } void install_handlers(void) { struct sigaction sa; sa.sa_flags = SA_SIGINFO; sigemptyset(&sa.sa_mask); sa.sa_sigaction = test_handler; sigaction(test_signal, &sa, 0); sa.sa_sigaction = sigsegv_handler; sigaction(SIGSEGV, &sa, 0); } void test_with_pthread_kill() { page_address = (int *)reserve_page(); install_handlers(); if (pthread_create(&tid, 0, make_faults, 0) < 0) perror("pthread_create"); while(1) { pthread_kill(tid, test_signal); } } void test_with_kill() { pid_t pid = fork(); if (pid == 0) { page_address = (int *)reserve_page(); install_handlers(); make_faults(0); } else { while (1) { kill(pid, test_signal); } } } int main(void) { test_signal = SIGUSR1; printf("test_handler=%x\n", test_handler); printf("sigsegv_handler=%x\n", sigsegv_handler); test_with_pthread_kill(); /* Forking and kill()ing works as expected: */ /* test_with_kill(); */ }