#include #include #include #include #include # include # define zero_fd -1 # define map_flags MAP_ANON | MAP_PRIVATE # define SIGSEGV_FAULT_ADDRESS_ROUNDOFF_BITS 0UL unsigned long page; int handler_called = 0; void sigsegv_handler (int sig, siginfo_t *sip, void *ucp) { void *fault_address = (void *) (sip->si_addr); handler_called++; if (handler_called == 10) exit (4); if (fault_address != (void*)((page + 0x678) & ~SIGSEGV_FAULT_ADDRESS_ROUNDOFF_BITS)) exit (3); if (mprotect ((void *) page, 0x10000, PROT_READ | PROT_WRITE) < 0) exit (2); } void crasher (unsigned long p) { *(int *) (p + 0x678) = 42; } int main () { void *p; struct sigaction action; /* Preparations. */ /* Setup some mmaped memory. */ p = mmap ((void *) 0x12340000, 0x10000, PROT_READ | PROT_WRITE, map_flags, zero_fd, 0); if (p == (void *)(-1)) exit (2); page = (unsigned long) p; /* Make it read-only. */ if (mprotect ((void *) page, 0x10000, PROT_READ) < 0) exit (2); /* Install the SIGSEGV handler. */ sigemptyset(&action.sa_mask); action.sa_sigaction = &sigsegv_handler; action.sa_flags = SA_SIGINFO; sigaction (SIGSEGV, &action, (struct sigaction *) NULL); sigaction (SIGBUS, &action, (struct sigaction *) NULL); /* The first write access should invoke the handler and then complete. */ crasher (page); /* The second write access should not invoke the handler. */ crasher (page); /* Check that the handler was called only once. */ if (handler_called != 1) exit (1); /* Test passed! */ return 0; }