* [uml-devel] Testtools
@ 2004-10-29 14:43 Bodo Stroesser
0 siblings, 0 replies; only message in thread
From: Bodo Stroesser @ 2004-10-29 14:43 UTC (permalink / raw)
To: Jeff Dike; +Cc: BlaisorBlade, user-mode-linux-devel
[-- Attachment #1: Type: text/plain, Size: 1017 bytes --]
As promised, here are the next test tools.
interrupted_syscall.c checks, whether syscall restarting is correctly
done for
- nanosleep(), which returns -ERESTART_RESTARTBLOCK on interruption
- read(), which returns -ERESTARTSYS on interruption.
- sigsuspend(), which does do_signal() while being in the syscall and/or
on return to user.
The test sets SIG_IGN or a signal handler (nanosleep, read) and it tests
with and without SA_RESTART (read). And it does the test twice, once the
test running normal, and one with the test being PTRACE_SYSCALL'ed.
At least for SIG_IGN, this makes a difference.
kernel_restorer.c uses a directly coded call to sys_rt_sigaction(). By this
way, it can force the kernel to use it's own restorer-stub (For UML at the
moment, this is the code on the stack). It does this for both possible
stack-layouts / restorers.
A further test done by this tool is the exploit for sigreturn() doing a
wrong systemcall restart handling. This case is done for sigreturn() and
rt_sigreturn()
Bodo
[-- Attachment #2: interrupted_syscall.c --]
[-- Type: text/plain, Size: 6980 bytes --]
/*
* interrupted_syscall.c
*
* Testtool for UML
* This tool tests several cases of interrupted syscalls and
* checks for the syscall restarting being correctly done.
*
* Copyright (C) 2004 Fujitsu Siemens Computers GmbH
* Author: Bodo Stroesser (bodo.stroesser@fujitsu-siemens.com)
*
* Licensed under the GPL
*/
#include <stdio.h>
#include <time.h>
#include <signal.h>
#include <errno.h>
#include <sys/ptrace.h>
#include <asm/ptrace.h>
#include <sys/wait.h>
#include <sys/mman.h>
int child, tester;
int traced;
int pipe_fd[2];
volatile int * counterp;
char outbuf[512], *p;
void sighdlr( int sig)
{
if ( ! traced ) {
printf("Signal %d caught\n", sig);
}
}
void alarm_writer( int parent, int count)
{
while ( count-- ) {
sleep( 1);
if ( kill( parent, SIGALRM) ) {
perror("kill( parent, SIGALRM)");
exit(1);
}
}
if ( pipe_fd[0] == -1 )
goto out;
sleep( 1);
close( pipe_fd[0]);
if ( write( pipe_fd[1], "X", 1) != 1 ) {
perror("write( pipe_fd[1], \"X\", 1)");
exit(1);
}
out:
sleep(60);
exit(0);
}
void
prepare( int mkpipe, int count, void * hdlr, int flags)
{
struct sigaction sa;
int ret;
int pid = getpid();
if ( mkpipe ) {
if ( pipe( pipe_fd) ) {
perror("pipe( pipe_fd)");
exit(1);
}
} else
pipe_fd[0] = pipe_fd[1] = -1;
memset( &sa, 0, sizeof( sa));
sa.sa_handler = hdlr;
sa.sa_flags = flags;
if ( sigaction( SIGALRM, &sa, NULL) ) {
perror("sigaction( SIGALRM, &sa)");
exit(1);
}
if ( (child = fork()) < 0 ) {
perror("fork()");
exit(1);
}
else if ( !child )
alarm_writer( pid, count); /* Child will never return */
if ( mkpipe ) {
close( pipe_fd[1]);
pipe_fd[1] = -1;
}
counterp[0] = 0;
counterp[1] = 0;
if ( hdlr == SIG_IGN )
counterp[2] = 0;
else
counterp[2] = 1;
p = outbuf;
}
void
cleanup( int ok, int syscalls, int signals)
{
int status;
int syscall_count = counterp[0];
int signal_count = counterp[1];
printf( outbuf);
if ( pipe_fd[0] != -1 )
close( pipe_fd[0]);
if ( pipe_fd[1] != -1 )
close( pipe_fd[1]);
kill( child, SIGKILL);
waitpid( child, &status, 0);
if ( traced ) {
printf("Syscalls: %d, Signals: %d ==> ", syscall_count, signal_count);
if ( syscall_count != syscalls || signal_count != signals ) {
ok = 0;
printf(" ERROR!\nExpected: Syscalls: %d Signals: %d\n", syscalls, signals);
}
else
printf("OK.\n");
}
if ( ! ok ) {
printf("Test failed!\n");
exit(1);
}
printf("Test succeeded\n\n");
}
int
tester_fn( void)
{
struct timespec ts, ts2;
sigset_t set;
char buf[10];
int ret, errno_sav;
sigprocmask( SIG_BLOCK, NULL, &set);
printf("\n=====> Test case 1: nanosleep() 3.5 seconds, SIGALRM after 1 and 2 seconds, SIG_IGN\n");
prepare( 0, 2, SIG_IGN, 0);
ts = (struct timespec){ 3, 500000000};
ret = nanosleep( &ts, &ts2);
if ( ret ) {
p+=sprintf(p, "ERROR: nanosleep(): %s", strerror( errno));
p+=sprintf(p, "; remaining time=%ld/%ld\n", ts2.tv_sec, ts2.tv_nsec);
}
else
p+=sprintf(p, "OK: nanosleep() returns OK.\n");
cleanup( ret == 0 , 6, 2);
printf("\n=====> Test case 2: nanosleep() 3.5 seconds, SIGALRM after 1 and 2 seconds, signal handler\n");
prepare( 0, 2, sighdlr, 0);
ts = (struct timespec){ 3, 500000000};
ret = nanosleep( &ts, &ts2);
if ( ret ) {
p+=sprintf(p, "OK: nanosleep(): %s", strerror( errno));
p+=sprintf(p, "; remaining time=%ld/%ld\n", ts2.tv_sec, ts2.tv_nsec);
}
else
p+=sprintf(p, "ERROR: nanosleep() returns OK.\n");
cleanup( ret && ts2.tv_sec == 2 , 4, 1);
printf("\n=====> Test case 3: read(), SIGALRM after 1 and 2 seconds, 1 Byte after 3rd second, SIG_IGN\n");
prepare( 1, 2, SIG_IGN, 0);
ret = read( pipe_fd[0], buf, sizeof( buf));
if ( ret != 1 )
p+=sprintf(p, "ERROR: read( pipe_fd[0], buf, sizeof(buf)): %s\n", strerror( errno));
else
p+=sprintf(p, "OK: read received %d bytes\n", ret);
cleanup( ret == 1 , 6, 2);
printf("\n=====> Test case 4: read(), SIGALRM after 1 and 2 seconds, 1 Byte after 3rd second, signal handler, SA_RESTART\n");
prepare( 1, 2, sighdlr, SA_RESTART);
ret = read( pipe_fd[0], buf, sizeof( buf));
if ( ret != 1 )
p+=sprintf(p, "ERROR: read( pipe_fd[0], buf, sizeof(buf)): %s\n", strerror( errno));
else
p+=sprintf(p, "OK: read received %d bytes\n", ret);
cleanup( ret == 1 , 10, 2);
printf("\n=====> Test case 5: read(), SIGALRM after 1 second, 1 Byte after 2nd second, signal handler, ! SA_RESTART\n");
prepare( 1, 1, sighdlr, 0);
ret = read( pipe_fd[0], buf, sizeof( buf));
errno_sav = errno;
if ( ret != 1 )
p+=sprintf(p, "OK: read( pipe_fd[0], buf, sizeof(buf)): %s\n", strerror( errno));
else
p+=sprintf(p, "ERROR: read received %d bytes\n", ret);
cleanup( ret == -1 && errno_sav == EINTR , 4, 1);
printf("\n=====> Test case 6: sigsuspend(), SIGALRM after 1 second, signal handler, SA_RESTART\n");
prepare( 0, 1, sighdlr, SA_RESTART);
ret = sigsuspend( &set);
errno_sav = errno;
if ( ret < 0 )
p+=sprintf(p, "OK: sigsuspend(): %s\n", strerror( errno));
else
p+=sprintf(p, "ERROR: sigsuspend returns OK.\n");
cleanup( ret == -1 && errno_sav == EINTR , 4, 1);
}
int
main( int argc, char **argv)
{
int status, ret, sig, debug;
sigset_t set;
sigprocmask( SIG_BLOCK, NULL, &set);
sigdelset( &set, SIGCHLD);
sigprocmask( SIG_SETMASK, NULL, &set);
counterp = mmap( NULL, 4096, PROT_WRITE|PROT_READ, MAP_SHARED|MAP_ANONYMOUS, 0, 0);
if ( counterp == MAP_FAILED ) {
perror("mmap");
exit(1);
}
debug = argc > 1 && !strcmp("debug",argv[1]);
tester = fork();
if ( tester < 0 ) {
perror("fork()");
exit(1);
}
if ( ! tester ) {
printf("\n\nStarting Test: UNTRACED\n\n");
traced = 0;
tester_fn();
if ( ptrace( PTRACE_TRACEME, 0, (void *)0, (void *)0) ) {
perror("ptrace( PTRACE_TRACEME, 0, 0, 0)");
exit(1);
}
printf("\nStarting Test: TRACED\n");
traced = 1;
kill( getpid(), SIGTRAP);
tester_fn();
exit(0);
}
while (1) {
ret = waitpid( tester, &status, 0);
if ( ret != tester ) {
fprintf( stderr, "Tracer: ");
perror("waitpid");
exit(1);
}
if ( WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP ) {
sig = 0;
counterp[0]++;
if ( debug )
printf("TRAP: syscall-# = %d, count = %d\n",
ptrace( PTRACE_PEEKUSER, tester, (void *)(ORIG_EAX*4), NULL),
counterp[0]);
}
else if ( WIFSTOPPED(status) && WSTOPSIG(status) == SIGALRM ) {
if ( debug )
printf("SIGCHLD !!!!!\n");
sig = SIGALRM;
if ( counterp[2] )
printf("Signal %d caught\n", sig);
else
printf("Signal %d ignored\n", sig);
counterp[1]++;
}
else if ( WIFSTOPPED(status) && WSTOPSIG(status) == SIGCHLD ) {
if ( debug )
printf("SIGCHLD !!!!!\n");
sig = SIGCHLD;
}
else {
printf("\nTracer: Tester's status is %x: exiting\n", status);
return (status != 0);
}
if ( ptrace( PTRACE_SYSCALL, tester, (void *)0, sig) < 0 ) {
fprintf( stderr, "Parent: ");
perror("ptrace( PTRACE_SYSCALL, tester, 0, sig)");
exit(1);
}
}
}
[-- Attachment #3: kernel_restorer.c --]
[-- Type: text/plain, Size: 2954 bytes --]
/*
* 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 <asm/signal.h>
#include <asm/siginfo.h>
#include <asm/sigcontext.h>
#include <asm/ucontext.h>
#include <unistd.h>
#include <errno.h>
#include <asm/unistd.h>
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;
}
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2004-10-29 14:44 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-10-29 14:43 [uml-devel] Testtools Bodo Stroesser
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.