/* * kernel_restorer.c * * Testtool for UML * This tool tests the kernels restorer code stubs. * Also it checks, whether syscall restarting is skipped on * return from sys_sigreturn() and sys_rt_sigreturn() * * Copyright (C) 2004 Fujitsu Siemens Computers GmbH * Author: Bodo Stroesser (bodo.stroesser@fujitsu-siemens.com) * * Licensed under the GPL */ #define __KERNEL__ #include #include #include #include #include #include #include int counter; int mod_eip; void sighdlr( int sig) { struct sigcontext * sc = (struct sigcontext *)(&sig + 1); printf("sighdlr(): signal %d caught\n", sig); if ( --counter ) alarm(1); else if ( mod_eip ) sc->eip -= 2; } void rt_sighdlr( int sig, siginfo_t * info, struct ucontext * uc) { printf("rt_sighdlr(): signal %d caught\n", sig); if ( --counter ) alarm(1); else if ( mod_eip ) uc->uc_mcontext.eip -= 2; } _syscall4( int, rt_sigaction, int, signr, struct k_sigaction *, new, struct k_sigaction *, old, int, size) void prepare( struct k_sigaction *sa, void * hdlr, int count) { int ret; counter = count; sa->sa.sa_handler = hdlr; sa->sa.sa_flags = SA_RESTART; if ( hdlr == rt_sighdlr ) sa->sa.sa_flags |= SA_SIGINFO; ret = rt_sigaction( SIGALRM, sa, NULL, sizeof( sigset_t)); if ( ret ) { perror("rt_sigaction()"); exit(1); } alarm(1); } void test_suspend( void) { int ret, errno_sav; sigset_t set; memset( &set, 0, sizeof( sigset_t)); ret = sigsuspend( &set); if ( ret ) { errno_sav=errno; perror("sigsuspend()"); if ( errno_sav != EINTR ) { printf("ERROR: sigsuspend() didn't return -EINTR\n"); exit(1); } } else { printf("ERROR: sigsuspend() returns O.K. --> this should never happen!\n"); exit(1); } if ( counter ) { printf("ERROR: signal counter not counted down to 0, is %d\n", counter); exit(1); } printf("==> OK.\n"); } void test_loop( void) { __asm__ volatile (" call 1f \n" " jmp 2f \n" " ret \n" " nop \n" "1: jmp 1b \n" "2: \n" : : "a" (-ERESTARTSYS)); alarm(0); if ( counter ) { printf("ERROR: signal counter not counted down to 0, is %d\n", counter); exit(1); } printf("==> OK.\n"); } int main( void) { struct k_sigaction sa; sa.sa.sa_restorer = NULL; memset( sa.sa.sa_mask.sig, 0xff, sizeof( sigset_t)); mod_eip = 0; printf("\nTesting kernels restorer for sigreturn(): this simply shouldn't crash\n\n"); prepare( &sa, sighdlr, 1); test_suspend(); printf("\nTesting kernels restorer for rt_sigreturn(): this simply shouldn't crash\n\n"); prepare( &sa, rt_sighdlr, 1); test_suspend(); mod_eip = 1; printf("\nTesting correct returncode-handling for sigreturn()\n"); prepare( &sa, sighdlr, 3); test_loop(); printf("\nTesting correct returncode-handling for rt_sigreturn()\n"); prepare( &sa, rt_sighdlr, 3); test_loop(); return 0; }