DragonFlyBSD Kernel Audit
DF-0911 / ptrace_control.c
← back to finding ↓ download raw
/* Control: same scenario via ptrace(2) PT_ATTACH/PT_DETACH.
 * ptrace PT_ATTACH always saves p_oppid (sys_process.c:314), so
 * detach should restore the child to its original parent (the tracer
 * itself, since the tracer forked the child) and waitpid should work. */
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <signal.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(void) {
	pid_t child, wp; int st; int p[2]; char b[64]; ssize_t r;
	if (pipe(p)<0) err(1,"pipe");
	child=fork();
	if (child<0) err(1,"fork");
	if (child==0){
		close(p[0]);
		for(;;){pid_t pp=getppid();snprintf(b,sizeof b,"child ppid=%d\n",pp);
			(void)write(p[1],b,strlen(b));sleep(1);}
		_exit(0);
	}
	close(p[1]);
	r=read(p[0],b,sizeof b-1); if(r>0){b[r]=0;fprintf(stderr,"before ptrace attach: %s",b);}
	if (ptrace(PT_ATTACH, child, 0, 0) < 0) err(1,"ptrace ATTACH");
	waitpid(child, &st, 0);   /* child stops with SIGSTOP */
	if (ptrace(PT_DETACH, child, 0, 0) < 0) err(1,"ptrace DETACH");
	usleep(300000);
	r=read(p[0],b,sizeof b-1); if(r>0){b[r]=0;fprintf(stderr,"after ptrace detach:  %s",b);
		if (strncmp(b,"child ppid=0",12)==0)
			printf("ptrace RESULT: child ppid=0 (unexpected!)\n");
		else
			printf("ptrace RESULT: child ppid is non-zero (ptrace path is correct)\n");
	}
	errno=0; wp=waitpid(child,&st,WNOHANG);
	printf("ptrace waitpid(%d)=%d errno=%d (%s)\n",(int)child,(int)wp,errno,errno==ECHILD?"ECHILD":strerror(errno));
	(void)kill(child,SIGKILL); (void)waitpid(child,&st,0);
	return 0;
}