NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/43681: PT_SYSCALL appears to be broken



>Number:         43681
>Category:       kern
>Synopsis:       PT_SYSCALL appears to be broken
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Jul 28 11:25:00 +0000 2010
>Originator:     Artem Anisimov
>Release:        -current
>Organization:
>Environment:
NetBSD netbsd-i386.vault13 5.99.37 NetBSD 5.99.37 (GENERIC) #0: Tue Jul 13 
00:15:02 MSD 2010  
artem%netbsd-i386.vault13@localhost:/home/artem/obj/sys/arch/i386/compile/GENERIC
 i386
>Description:
I've been experimenting with ptrace() and found out that simply following man 
(2) ptrace is not enough.

  The attached problem is supposed to run "/bin/ls /" and stop at every system 
call it makes. The problem is that ptrace(PT_SYSCALL,...) at the end of the 
main loop seems simply to resume the child and make it run until it exits, but 
not until it makes a system call.

  Attached program works as expected under FreeBSD and Linux, so I believe 
there is some detail that needs to be taken into account for NetBSD and that I 
have missed.

  I've posted a question regarding usage of PT_SYSCALL to tech-kern and 
Christos Zoulas suggested that I file a bug report.

  Here is a program in question:

--------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <errno.h>

#if defined(BSD)
        #define REQ_TRACE_ME    PT_TRACE_ME
        #define REQ_SYSCALL     PT_SYSCALL
        #define REQ_KILL        PT_KILL
        #define CONT_ADDR       (caddr_t)1
#elif defined(LINUX)
        #define REQ_TRACE_ME    PTRACE_TRACEME
        #define REQ_SYSCALL     PTRACE_SYSCALL
        #define REQ_KILL        PTRACE_KILL
        #define CONT_ADDR       NULL
#else
        #error "Define BSD or LINUX."
#endif

static void __attribute__((noreturn)) die(const char *msg)
{
        printf("%s, errno=%d\n",msg,errno);
        _exit(1);
}

static void child()
{
const char      *args[] =       {"/bin/ls","/",NULL};
const char      *env[]  =       {NULL};

        if(0>ptrace(REQ_TRACE_ME,0,NULL,0))
                die("failed to trace myself");
        
        execve(args[0],(char * const *)args,(char * const *)env);
        die("failed to start the child");
}

int main()
{
pid_t   p;
int     status;
int     sig;

        p=fork();
        if(p<0)
                die("failed to fork");
        
        if(!p)
                child();
        
        for(;;)
        {
                if(0>waitpid(p,&status,0))
                        die("failed to wait for child");
                if(WIFSTOPPED(status))
                {
                        sig=WSTOPSIG(status);
                        printf("child stopped by signal %d 
(%s)\n",sig,strsignal(sig));
                        if(sig!=SIGTRAP)
                        {
                                printf("signal is not SIGTRAP; killing 
child\n");
                                if(0>ptrace(REQ_KILL,p,NULL,0))
                                        die("failed to kill the child");
                                break;
                        }
                }
                else if(WIFSIGNALED(status))
                {
                        sig=WTERMSIG(status);
                        printf("child was signaled by signal %d (%d)\n",
                                sig,strsignal(sig));
                        if(0>ptrace(REQ_KILL,p,NULL,0))
                                die("failed to kill the child");
                        break;
                }
                else if(WIFEXITED(status))
                {
                        printf("child exited with status 
%d\n",WEXITSTATUS(status));
                        break;
                }
                else
                {
                        printf("neither stopped, nor signaled, nor killed?\n");
                        if(0>ptrace(PT_KILL,p,NULL,0))
                                die("failed to kill the child");
                        break;
                }
                
                printf("resuming the child\n");
                if(0>ptrace(REQ_SYSCALL,p,CONT_ADDR,0))
                        die("failed to resume the child");
        }
        
        return 0;
}

>How-To-Repeat:
Compile the attached program and run it.
>Fix:



Home | Main Index | Thread Index | Old Index