Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/sys_process.c
Show First 20 Lines • Show All 617 Lines • ▼ Show 20 Lines | #ifdef COMPAT_FREEBSD32 | ||||
int wrap32 = 0, safe = 0; | int wrap32 = 0, safe = 0; | ||||
#endif | #endif | ||||
curp = td->td_proc; | curp = td->td_proc; | ||||
/* Lock proctree before locking the process. */ | /* Lock proctree before locking the process. */ | ||||
switch (req) { | switch (req) { | ||||
case PT_TRACE_ME: | case PT_TRACE_ME: | ||||
case PT_INTERRUPT: | |||||
case PT_SEIZE: | |||||
case PT_ATTACH: | case PT_ATTACH: | ||||
case PT_STEP: | case PT_STEP: | ||||
case PT_CONTINUE: | case PT_CONTINUE: | ||||
case PT_TO_SCE: | case PT_TO_SCE: | ||||
case PT_TO_SCX: | case PT_TO_SCX: | ||||
case PT_SYSCALL: | case PT_SYSCALL: | ||||
case PT_FOLLOW_FORK: | case PT_FOLLOW_FORK: | ||||
case PT_LWP_EVENTS: | case PT_LWP_EVENTS: | ||||
▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | if (SV_PROC_FLAG(td2->td_proc, SV_ILP32)) | ||||
safe = 1; | safe = 1; | ||||
wrap32 = 1; | wrap32 = 1; | ||||
} | } | ||||
#endif | #endif | ||||
/* | /* | ||||
* Permissions check | * Permissions check | ||||
*/ | */ | ||||
switch (req) { | switch (req) { | ||||
case PT_INTERRUPT: | |||||
case PT_LISTEN: | |||||
/* | |||||
* Only works on tracees attached by PT_SEIZE. | |||||
kib: Why? | |||||
*/ | |||||
if ((p->p_flag2 & P2_SEIZED) == 0) { | |||||
error = EINVAL; | |||||
goto fail; | |||||
} | |||||
break; | |||||
case PT_TRACE_ME: | case PT_TRACE_ME: | ||||
/* | /* | ||||
* Always legal, when there is a parent process which | * Always legal, when there is a parent process which | ||||
* could trace us. Otherwise, reject. | * could trace us. Otherwise, reject. | ||||
*/ | */ | ||||
if ((p->p_flag & P_TRACED) != 0) { | if ((p->p_flag & P_TRACED) != 0) { | ||||
error = EBUSY; | error = EBUSY; | ||||
goto fail; | goto fail; | ||||
} | } | ||||
if (p->p_pptr == initproc) { | if (p->p_pptr == initproc) { | ||||
error = EPERM; | error = EPERM; | ||||
goto fail; | goto fail; | ||||
} | } | ||||
break; | break; | ||||
case PT_SEIZE: | |||||
case PT_ATTACH: | case PT_ATTACH: | ||||
/* Self */ | /* Self */ | ||||
if (p == td->td_proc) { | if (p == td->td_proc) { | ||||
error = EINVAL; | error = EINVAL; | ||||
goto fail; | goto fail; | ||||
} | } | ||||
/* Already traced */ | /* Already traced */ | ||||
▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | #endif | ||||
case PT_TRACE_ME: | case PT_TRACE_ME: | ||||
/* set my trace flag and "owner" so it can read/write me */ | /* set my trace flag and "owner" so it can read/write me */ | ||||
proc_set_traced(p, false); | proc_set_traced(p, false); | ||||
if (p->p_flag & P_PPWAIT) | if (p->p_flag & P_PPWAIT) | ||||
p->p_flag |= P_PPTRACE; | p->p_flag |= P_PPTRACE; | ||||
CTR1(KTR_PTRACE, "PT_TRACE_ME: pid %d", p->p_pid); | CTR1(KTR_PTRACE, "PT_TRACE_ME: pid %d", p->p_pid); | ||||
break; | break; | ||||
case PT_SEIZE: | |||||
proc_set_traced(p, false); | |||||
proc_reparent(p, td->td_proc, false); | |||||
CTR2(KTR_PTRACE, "PT_ATTACH: pid %d, oppid %d", p->p_pid, | |||||
p->p_oppid); | |||||
sx_xunlock(&proctree_lock); | |||||
proctree_locked = false; | |||||
MPASS(p->p_xthread == NULL); | |||||
MPASS((p->p_flag & P_STOPPED_TRACE) == 0); | |||||
p->p_flag2 |= P2_SEIZED; | |||||
/* | |||||
* XXX Do we actually have to do anything here? | |||||
*/ | |||||
break; | |||||
case PT_INTERRUPT: | |||||
sx_xunlock(&proctree_lock); | |||||
proctree_locked = false; | |||||
MPASS(p->p_xthread == NULL); | |||||
MPASS((p->p_flag & P_STOPPED_TRACE) == 0); | |||||
/* | |||||
* If already stopped due to a stop signal, clear the | |||||
* existing stop before triggering a traced SIGSTOP. | |||||
*/ | |||||
if ((p->p_flag & P_STOPPED_SIG) != 0) { | |||||
PROC_SLOCK(p); | |||||
p->p_flag &= ~(P_STOPPED_SIG | P_WAITED); | |||||
thread_unsuspend(p); | |||||
PROC_SUNLOCK(p); | |||||
} | |||||
kern_psignal(p, SIGSTOP); | |||||
break; | |||||
case PT_LISTEN: | |||||
// XXX not sure | |||||
td2->td_dbgflags |= TDB_SUSPEND; | |||||
thread_lock(td2); | |||||
td2->td_flags |= TDF_NEEDSUSPCHK; | |||||
thread_unlock(td2); | |||||
break; | |||||
case PT_ATTACH: | case PT_ATTACH: | ||||
/* security check done above */ | /* security check done above */ | ||||
/* | /* | ||||
* It would be nice if the tracing relationship was separate | * It would be nice if the tracing relationship was separate | ||||
* from the parent relationship but that would require | * from the parent relationship but that would require | ||||
* another set of links in the proc struct or for "wait" | * another set of links in the proc struct or for "wait" | ||||
* to scan the entire proc table. To make life easier, | * to scan the entire proc table. To make life easier, | ||||
* we just re-parent the process we're trying to trace. | * we just re-parent the process we're trying to trace. | ||||
* The old parent is remembered so we can put things back | * The old parent is remembered so we can put things back | ||||
* on a "detach". | * on a "detach". | ||||
*/ | */ | ||||
proc_set_traced(p, true); | proc_set_traced(p, req == PT_ATTACH); | ||||
proc_reparent(p, td->td_proc, false); | proc_reparent(p, td->td_proc, false); | ||||
CTR2(KTR_PTRACE, "PT_ATTACH: pid %d, oppid %d", p->p_pid, | CTR2(KTR_PTRACE, "PT_ATTACH: pid %d, oppid %d", p->p_pid, | ||||
p->p_oppid); | p->p_oppid); | ||||
sx_xunlock(&proctree_lock); | sx_xunlock(&proctree_lock); | ||||
proctree_locked = 0; | proctree_locked = 0; | ||||
MPASS(p->p_xthread == NULL); | MPASS(p->p_xthread == NULL); | ||||
MPASS((p->p_flag & P_STOPPED_TRACE) == 0); | MPASS((p->p_flag & P_STOPPED_TRACE) == 0); | ||||
▲ Show 20 Lines • Show All 498 Lines • Show Last 20 Lines |
Why?