Exemplo n.º 1
0
int
netbsd32_ptrace(struct lwp *l, const struct netbsd32_ptrace_args *uap,
    register_t *retval)
{
	/* {
		syscallarg(int) req;
		syscallarg(pid_t) pid;
		syscallarg(netbsd32_voidp *) addr;
		syscallarg(int) data;
	} */

	return do_ptrace(&netbsd32_ptm, l, SCARG(uap, req), SCARG(uap, pid),
	    SCARG_P32(uap, addr), SCARG(uap, data), retval);
}
Exemplo n.º 2
0
static int
dt_proc_create_thread(dtrace_hdl_t *dtp, dt_proc_t *dpr, uint_t stop)
{
	dt_proc_control_data_t data;
	sigset_t nset, oset;
	pthread_attr_t a;
	int err;

#if defined(linux)
	/***********************************************/
	/*   Kernel bug -- a parent which attaches to  */
	/*   a  proc  --  cannot  share  with a child  */
	/*   thread.   So   we  have  to  detach  and  */
	/*   reattach  in  the child thread if we are  */
	/*   to work properly.			       */
	/***********************************************/
	if (stop == DT_PROC_STOP_GRAB) {
		do_ptrace(__func__, PTRACE_DETACH, dpr->dpr_pid, 0, 0);
	}
#endif
	(void) pthread_mutex_lock(&dpr->dpr_lock);
	dpr->dpr_stop |= stop; /* set bit for initial rendezvous */

	(void) pthread_attr_init(&a);
	(void) pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED);

	(void) sigfillset(&nset);
	(void) sigdelset(&nset, SIGABRT);	/* unblocked for assert() */
#if defined(sun)
	(void) sigdelset(&nset, SIGCANCEL);	/* see dt_proc_destroy() */
#else
	(void) sigdelset(&nset, SIGUSR1);	/* see dt_proc_destroy() */
#endif

	data.dpcd_hdl = dtp;
	data.dpcd_proc = dpr;

	(void) pthread_sigmask(SIG_SETMASK, &nset, &oset);
	err = pthread_create(&dpr->dpr_tid, &a, dt_proc_control, &data);
	(void) pthread_sigmask(SIG_SETMASK, &oset, NULL);

do_ptrace(__func__, PTRACE_DETACH, dpr->dpr_pid, 0, 0);
	/*
	 * If the control thread was created, then wait on dpr_cv for either
	 * dpr_done to be set (the victim died or the control thread failed)
	 * or DT_PROC_STOP_IDLE to be set, indicating that the victim is now
	 * stopped by /proc and the control thread is at the rendezvous event.
	 * On success, we return with the process and control thread stopped:
	 * the caller can then apply dt_proc_continue() to resume both.
	 */
	if (err == 0) {
//printf("0..waiting for dt_proc_control....dpr_done=%d stop=%d !stop=%d\n", dpr->dpr_done, dpr->dpr_stop, !(dpr->dpr_stop & DT_PROC_STOP_IDLE));
		while (!dpr->dpr_done && !(dpr->dpr_stop & DT_PROC_STOP_IDLE)) {
//printf("1..waiting for dt_proc_control....dpr_done=%d stop=%d\n", dpr->dpr_done, dpr->dpr_stop);
			(void) pthread_cond_wait(&dpr->dpr_cv, &dpr->dpr_lock);
		}
//printf("2..waiting for dt_proc_control....dpr_done=%d stop=%d\n", dpr->dpr_done, dpr->dpr_stop);

		/*
		 * If dpr_done is set, the control thread aborted before it
		 * reached the rendezvous event.  This is either due to PS_LOST
		 * or PS_UNDEAD (i.e. the process died).  We try to provide a
		 * small amount of useful information to help figure it out.
		 */
		if (dpr->dpr_done) {
			const psinfo_t *prp = Ppsinfo(dpr->dpr_proc);
			int stat = prp ? prp->pr_wstat : 0;
			int pid = dpr->dpr_pid;

			if (Pstate(dpr->dpr_proc) == PS_LOST) {
				(void) dt_proc_error(dpr->dpr_hdl, dpr,
				    "failed to control pid %d: process exec'd "
				    "set-id or unobservable program\n", pid);
			} else if (WIFSIGNALED(stat)) {
				(void) dt_proc_error(dpr->dpr_hdl, dpr,
				    "failed to control pid %d: process died "
				    "from signal %d\n", pid, WTERMSIG(stat));
			} else {
				(void) dt_proc_error(dpr->dpr_hdl, dpr,
				    "failed to control pid %d: process exited "
				    "with status %d\n", pid, WEXITSTATUS(stat));
			}

			err = ESRCH; /* cause grab() or create() to fail */
		}
	} else {
		(void) dt_proc_error(dpr->dpr_hdl, dpr,
		    "failed to create control thread for process-id %d: %s\n",
		    (int)dpr->dpr_pid, strerror(err));
	}

	(void) pthread_mutex_unlock(&dpr->dpr_lock);
	(void) pthread_attr_destroy(&a);

	return (err);
}
Exemplo n.º 3
0
/*
 * Main loop for all victim process control threads.  We initialize all the
 * appropriate /proc control mechanisms, and then enter a loop waiting for
 * the process to stop on an event or die.  We process any events by calling
 * appropriate subroutines, and exit when the victim dies or we lose control.
 *
 * The control thread synchronizes the use of dpr_proc with other libdtrace
 * threads using dpr_lock.  We hold the lock for all of our operations except
 * waiting while the process is running: this is accomplished by writing a
 * PCWSTOP directive directly to the underlying /proc/<pid>/ctl file.  If the
 * libdtrace client wishes to exit or abort our wait, SIGCANCEL can be used.
 */
static void *
dt_proc_control(void *arg)
{
	dt_proc_control_data_t *datap = arg;
	dtrace_hdl_t *dtp = datap->dpcd_hdl;
	dt_proc_t *dpr = datap->dpcd_proc;
	dt_proc_hash_t *dph = dpr->dpr_hdl->dt_procs;
	struct ps_prochandle *P = dpr->dpr_proc;

#if defined(sun)
	int pfd = Pctlfd(P);

	const long wstop = PCWSTOP;
#endif
	int notify = B_FALSE;

	/*
	 * We disable the POSIX thread cancellation mechanism so that the
	 * client program using libdtrace can't accidentally cancel our thread.
	 * dt_proc_destroy() uses SIGCANCEL explicitly to simply poke us out
	 * of PCWSTOP with EINTR, at which point we will see dpr_quit and exit.
	 */
	(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

	dpr->dpr_pid = proc_getpid(P);
	int pid = dpr->dpr_pid;

	/*
	 * Set up the corresponding process for tracing by libdtrace.  We want
	 * to be able to catch breakpoints and efficiently single-step over
	 * them, and we need to enable librtld_db to watch libdl activity.
	 */
	do_ptrace(__func__, PTRACE_ATTACH, dpr->dpr_pid, 0, 0);
	(void) pthread_mutex_lock(&dpr->dpr_lock);

	(void) Punsetflags(P, PR_ASYNC);	/* require synchronous mode */
	(void) Psetflags(P, PR_BPTADJ);		/* always adjust eip on x86 */
	(void) Punsetflags(P, PR_FORK);		/* do not inherit on fork */

	(void) Pfault(P, FLTBPT, B_TRUE);	/* always trace breakpoints */
	(void) Pfault(P, FLTTRACE, B_TRUE);	/* always trace single-step */

	/*
	 * We must trace exit from exec() system calls so that if the exec is
	 * successful, we can reset our breakpoints and re-initialize libproc.
	 */
	(void) Psysexit(P, SYS_exec, B_TRUE);
	(void) Psysexit(P, SYS_execve, B_TRUE);

	/*
	 * We must trace entry and exit for fork() system calls in order to
	 * disable our breakpoints temporarily during the fork.  We do not set
	 * the PR_FORK flag, so if fork succeeds the child begins executing and
	 * does not inherit any other tracing behaviors or a control thread.
	 */
	(void) Psysentry(P, SYS_vfork, B_TRUE);
	(void) Psysexit(P, SYS_vfork, B_TRUE);
	(void) Psysentry(P, SYS_fork1, B_TRUE);
	(void) Psysexit(P, SYS_fork1, B_TRUE);
	(void) Psysentry(P, SYS_forkall, B_TRUE);
	(void) Psysexit(P, SYS_forkall, B_TRUE);
	(void) Psysentry(P, SYS_forksys, B_TRUE);
	(void) Psysexit(P, SYS_forksys, B_TRUE);

	Psync(P);				/* enable all /proc changes */
	dt_proc_attach(dpr, B_FALSE);		/* enable rtld breakpoints */

	/*
	 * If PR_KLC is set, we created the process; otherwise we grabbed it.
	 * Check for an appropriate stop request and wait for dt_proc_continue.
	 */
	dpr->dpr_stop |= DT_PROC_STOP_CREATE;
	if (Pstatus(P)->pr_flags & PR_KLC)
		dt_proc_stop(dpr, DT_PROC_STOP_CREATE);
	else
		dt_proc_stop(dpr, DT_PROC_STOP_GRAB);

	if (Psetrun(P, 0, 0) == -1) {
		dt_dprintf("pid %d: failed to set running: %s\n",
		    (int)dpr->dpr_pid, strerror(errno));
	}

	(void) pthread_mutex_unlock(&dpr->dpr_lock);

	/*
	 * Wait for the process corresponding to this control thread to stop,
	 * process the event, and then set it running again.  We want to sleep
	 * with dpr_lock *unheld* so that other parts of libdtrace can use the
	 * ps_prochandle in the meantime (e.g. ustack()).  To do this, we write
	 * a PCWSTOP directive directly to the underlying /proc/<pid>/ctl file.
	 * Once the process stops, we wake up, grab dpr_lock, and then call
	 * Pwait() (which will return immediately) and do our processing.
	 */
//printf("%s: waiting to quit\n", __func__);
	while (!dpr->dpr_quit) {
		const lwpstatus_t *psp;
#if defined(sun)

		if (write(pfd, &wstop, sizeof (wstop)) == -1 && errno == EINTR)
			continue; /* check dpr_quit and continue waiting */
#else
		/* Wait for the process to report status. */
                proc_wait(P);
#endif
		(void) pthread_mutex_lock(&dpr->dpr_lock);
pwait_locked:
		if (Pstopstatus(P, PCNULL, 0) == -1 && errno == EINTR) {
//printf("%s stopstatus (loop) pr_pid pid=%d\n", __func__, Pstatus(dpr->dpr_proc)->pr_pid);
			(void) pthread_mutex_unlock(&dpr->dpr_lock);
			continue; /* check dpr_quit and continue waiting */
		}

		switch (Pstate(P)) {
		case PS_STOP:
			psp = &Pstatus(P)->pr_lwp;

			dt_dprintf("pid %d: proc stopped showing %d/%d\n",
			    pid, psp->pr_why, psp->pr_what);

#if defined(sun)
			/*
			 * If the process stops showing PR_REQUESTED, then the
			 * DTrace stop() action was applied to it or another
			 * debugging utility (e.g. pstop(1)) asked it to stop.
			 * In either case, the user's intention is for the
			 * process to remain stopped until another external
			 * mechanism (e.g. prun(1)) is applied.  So instead of
			 * setting the process running ourself, we wait for
			 * someone else to do so.  Once that happens, we return
			 * to our normal loop waiting for an event of interest.
			 */
			if (psp->pr_why == PR_REQUESTED) {
				dt_proc_waitrun(dpr);
				(void) pthread_mutex_unlock(&dpr->dpr_lock);
				continue;
			}

			/*
			 * If the process stops showing one of the events that
			 * we are tracing, perform the appropriate response.
			 * Note that we ignore PR_SUSPENDED, PR_CHECKPOINT, and
			 * PR_JOBCONTROL by design: if one of these conditions
			 * occurs, we will fall through to Psetrun() but the
			 * process will remain stopped in the kernel by the
			 * corresponding mechanism (e.g. job control stop).
			 */
			if (psp->pr_why == PR_FAULTED && psp->pr_what == FLTBPT)
				dt_proc_bpmatch(dtp, dpr);
			else if (psp->pr_why == PR_SYSENTRY &&
			    IS_SYS_FORK(psp->pr_what))
				dt_proc_bpdisable(dpr);
			else if (psp->pr_why == PR_SYSEXIT &&
			    IS_SYS_FORK(psp->pr_what))
				dt_proc_bpenable(dpr);
			else if (psp->pr_why == PR_SYSEXIT &&
			    IS_SYS_EXEC(psp->pr_what))
				dt_proc_attach(dpr, B_TRUE);
#endif
//printf("In PS_STOP dpr_stop=%x\n", dpr->dpr_stop);
			break;

		case PS_LOST:
//printf("in PS_LOST\n");
			if (Preopen(P) == 0)
				goto pwait_locked;

			dt_dprintf("pid %d: proc lost: %s\n",
			    pid, strerror(errno));

			dpr->dpr_quit = B_TRUE;
			notify = B_TRUE;
			break;

		case PS_UNDEAD:
		case PS_DEAD:
			dt_dprintf("pid %d: proc died\n", pid);
			dpr->dpr_quit = B_TRUE;
			notify = B_TRUE;
			break;

		}

		if (Pstate(P) != PS_UNDEAD && Psetrun(P, 0, 0) == -1) {
			dt_dprintf("pid %d: failed to set running: %s\n",
			    (int)dpr->dpr_pid, strerror(errno));
		}

		(void) pthread_mutex_unlock(&dpr->dpr_lock);
	}

	/*
	 * If the control thread detected PS_UNDEAD or PS_LOST, then enqueue
	 * the dt_proc_t structure on the dt_proc_hash_t notification list.
	 */
	if (notify)
		dt_proc_notify(dtp, dph, dpr, NULL);

	/*
	 * Destroy and remove any remaining breakpoints, set dpr_done and clear
	 * dpr_tid to indicate the control thread has exited, and notify any
	 * waiting thread in dt_proc_destroy() that we have succesfully exited.
	 */
	(void) pthread_mutex_lock(&dpr->dpr_lock);

	dt_proc_bpdestroy(dpr, B_TRUE);
	dpr->dpr_done = B_TRUE;
	dpr->dpr_tid = 0;

	(void) pthread_cond_broadcast(&dpr->dpr_cv);
	(void) pthread_mutex_unlock(&dpr->dpr_lock);

	return (NULL);
}
Exemplo n.º 4
0
static long do_pokeuser(long offset, long val)
{
	return do_ptrace(PTRACE_POKEUSER, (void *)offset, (void *)val);
}
Exemplo n.º 5
0
static long do_peekuser(long offset)
{
	return do_ptrace(PTRACE_PEEKUSER, (void *)offset, NULL);
}
Exemplo n.º 6
0
static int trace_sysnum_regs(void *vregs)
{
	trace_regs *regs = vregs;
	do_ptrace(PTRACE_GETREGS, regs, NULL);
	return regs->u_regs[U_REG_G1] ? : SB_SYS_EXECVE;
}