/* * sigmasking.c * * Testtool for UML * This tool tests signal masking / unmasking in case of * errors while preparing sighandler's stackframe (invalid * stack). * * Copyright (C) 2004 Fujitsu Siemens Computers GmbH * Author: Bodo Stroesser (bstroesser@fujitsu-siemens.com) * * Licensed under the GPL */ #include #include #include #include sigset_t handler_set; void signal_handler( int sig) { printf("Signal %d caught\n", sig); sigaddset( &handler_set, sig); } int main( void) { struct sigaction sa; sigset_t emptyset, fullset, oldset, emptyUSR1set; stack_t stack; struct timespec ts, ts2; int i, ret, errno_sav, error = 0; printf("\n\n\n"); stack.ss_sp = (char *)0xf2345678; /* This should give us a segfault ...*/ stack.ss_size = 8*1024; stack.ss_flags = 0; if ( sigaltstack( &stack, NULL) ) { perror( "sigaltstack( &stack, NULL)"); exit(1); } sigemptyset( &emptyset); sigemptyset( &emptyUSR1set); sigaddset( &emptyUSR1set, SIGUSR1); sigfillset( &fullset); sigdelset( &fullset, SIGUSR1); printf("Installing signal handler for SIGSEGV, sa_mask = full mask - SIGUSR1\n"); sa.sa_restorer = NULL; sa.sa_handler = signal_handler; sigfillset( &(sa.sa_mask)); sa.sa_flags = 0; if ( sigaction( SIGSEGV, &sa, NULL) ) { perror("sigaction( SIGSEGV, &sa, NULL)"); exit(1); } printf("Installing signal handler for SIGALRM, SA_ONSTACK with invalid stack, " "sa_mask = full mask - SIGUSR1\n"); sa.sa_flags = SA_ONSTACK; if ( sigaction( SIGALRM, &sa, NULL) ) { perror("sigaction( SIGSEGV, &sa, NULL)"); exit(1); } for ( i=0; i<2; i++) { if ( i == 0 ) printf("\n\n===== Test 1: signal SIGALRM while waiting in sigsuspend() =====\n\n"); if ( i == 1 ) printf("\n\n===== Test 2: signal SIGALRM while waiting in nanosleep() =====\n\n"); printf("Unblocking all signals\n"); if ( sigprocmask( SIG_SETMASK, &emptyset, NULL) ) { perror( "sigprocmask( SIG_SETMASK, &emptyset, NULL)"); exit(1); } sigemptyset( &handler_set); printf("Calling alarm(2)\n"); alarm( 2); if ( i == 0 ) { printf("Calling sigsuspend( emptyset + SIGUSR1)\n"); ret = sigsuspend( &emptyUSR1set); errno_sav = errno; if ( sigprocmask( SIG_SETMASK, &fullset, &oldset) ) { perror( "sigprocmask( SIG_SETMASK, &fullset, NULL)"); exit(1); } printf("After return from sigsuspend(), blocked all signals, saved returned mask\n"); if ( ret < 0 ) { errno = errno_sav; perror("OK: sigsuspend()"); } else { printf("ERROR: sigsuspend returns O.K.\n"); error++; } } if ( i == 1 ) { printf("Calling nanosleep( 20s)\n"); ts = (struct timespec){ 20, 500000000}; ret = nanosleep( &ts, &ts2); errno_sav = errno; if ( sigprocmask( SIG_SETMASK, &fullset, &oldset) ) { perror( "sigprocmask( SIG_SETMASK, &fullset, NULL)"); exit(1); } printf("After return from nanosleep(), blocked all signals, saved returned mask\n"); if ( ret ) { errno = errno_sav; perror("OK: nanosleep()"); if ( ts2.tv_sec != 18 ) { printf("ERROR: remaining time=%ld/%ld, expected about 18 seconds\n", ts2.tv_sec, ts2.tv_nsec); error++; } } else { printf("ERROR: nanosleep() returns O.K.\n"); error++; } } if ( ! sigismember( &handler_set, SIGALRM) ) { printf("OK: sighandler for SIGALRM (%d) didn't run (invalid stack)\n", SIGALRM); } else { printf("ERROR: sighandler for SIGALRM (%d) did run, despite of invalid stack!\n", SIGALRM); } if ( ! sigismember( &oldset, SIGSEGV) ) { printf("OK: SIGSEGV is unmasked at end of test\n"); } else { printf("ERROR: SIGSEGV is masked at end of test\n"); error++; } if ( sigismember( &handler_set, SIGSEGV) ) { printf("OK: sighandler for SIGSEGV (%d) did run\n", SIGSEGV); } else { printf("ERROR: sighandler for SIGSEGV (%d) didn't run\n", SIGSEGV); error++; } if ( ! sigismember( &oldset, SIGUSR1) ) { printf("OK: SIGUSR1 is unmasked\n"); } else { printf("ERROR: SIGUSR1 is masked\n"); error++; } if ( ! sigismember( &oldset, SIGUSR2) ) { printf("OK: SIGUSR2 is unmasked\n"); } else { printf("ERROR: SIGUSR2 is masked\n"); error++; } if ( sigpending( &oldset) ) { perror("sigpending()"); exit(1); } if ( sigismember( &oldset, SIGSEGV) ) { printf("SIGSEGV is pending at end of test, unblocking it now ...\n"); if ( sigprocmask( SIG_SETMASK, &emptyset, NULL) ) { perror( "sigprocmask( SIG_SETMASK, &emptyset, NULL)"); exit(1); } if ( !sigismember( &handler_set, SIGSEGV) ) { printf("ERROR: Couldn't unblock SIGSEGV handler --> exiting\n"); exit(1); } printf("... done\n"); } } if ( error ) printf("\n\nTest ended with errors\n"); else printf("\n\nTest completed successfully\n"); return error; }