Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_ktrace.c
Show First 20 Lines • Show All 1,000 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
#ifdef KTRACE | #ifdef KTRACE | ||||
struct vnode *vp = NULL; | struct vnode *vp = NULL; | ||||
struct proc *p; | struct proc *p; | ||||
struct pgrp *pg; | struct pgrp *pg; | ||||
int facs = uap->facs & ~KTRFAC_ROOT; | int facs = uap->facs & ~KTRFAC_ROOT; | ||||
int ops = KTROP(uap->ops); | int ops = KTROP(uap->ops); | ||||
int descend = uap->ops & KTRFLAG_DESCEND; | int descend = uap->ops & KTRFLAG_DESCEND; | ||||
int nfound, ret = 0; | int ret = 0; | ||||
int flags, error = 0; | int flags, error = 0; | ||||
struct nameidata nd; | struct nameidata nd; | ||||
struct ktr_io_params *kiop, *old_kiop; | struct ktr_io_params *kiop, *old_kiop; | ||||
/* | /* | ||||
* Need something to (un)trace. | * Need something to (un)trace. | ||||
*/ | */ | ||||
if (ops != KTROP_CLEARFILE && facs == 0) | if (ops != KTROP_CLEARFILE && facs == 0) | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | if (uap->pid < 0) { | ||||
* by process group | * by process group | ||||
*/ | */ | ||||
pg = pgfind(-uap->pid); | pg = pgfind(-uap->pid); | ||||
if (pg == NULL) { | if (pg == NULL) { | ||||
sx_sunlock(&proctree_lock); | sx_sunlock(&proctree_lock); | ||||
error = ESRCH; | error = ESRCH; | ||||
goto done; | goto done; | ||||
} | } | ||||
/* | /* | ||||
* ktrops() may call vrele(). Lock pg_members | * ktrops() may call vrele(). Lock pg_members | ||||
* by the proctree_lock rather than pg_mtx. | * by the proctree_lock rather than pg_mtx. | ||||
*/ | */ | ||||
PGRP_UNLOCK(pg); | PGRP_UNLOCK(pg); | ||||
nfound = 0; | if (LIST_EMPTY(&pg->pg_members)) { | ||||
sx_sunlock(&proctree_lock); | |||||
error = ESRCH; | |||||
goto done; | |||||
} | |||||
LIST_FOREACH(p, &pg->pg_members, p_pglist) { | LIST_FOREACH(p, &pg->pg_members, p_pglist) { | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
if (p->p_state == PRS_NEW || | |||||
p_cansee(td, p) != 0) { | |||||
PROC_UNLOCK(p); | |||||
continue; | |||||
} | |||||
nfound++; | |||||
if (descend) | if (descend) | ||||
ret |= ktrsetchildren(td, p, ops, facs, kiop); | ret |= ktrsetchildren(td, p, ops, facs, kiop); | ||||
else | else | ||||
ret |= ktrops(td, p, ops, facs, kiop); | ret |= ktrops(td, p, ops, facs, kiop); | ||||
} | } | ||||
if (nfound == 0) { | |||||
sx_sunlock(&proctree_lock); | |||||
error = ESRCH; | |||||
goto done; | |||||
} | |||||
} else { | } else { | ||||
/* | /* | ||||
* by pid | * by pid | ||||
*/ | */ | ||||
p = pfind(uap->pid); | p = pfind(uap->pid); | ||||
if (p == NULL) | if (p == NULL) { | ||||
error = ESRCH; | error = ESRCH; | ||||
else | |||||
error = p_cansee(td, p); | |||||
if (error) { | |||||
if (p != NULL) | |||||
PROC_UNLOCK(p); | |||||
sx_sunlock(&proctree_lock); | sx_sunlock(&proctree_lock); | ||||
goto done; | goto done; | ||||
} | } | ||||
if (descend) | if (descend) | ||||
ret |= ktrsetchildren(td, p, ops, facs, kiop); | ret |= ktrsetchildren(td, p, ops, facs, kiop); | ||||
else | else | ||||
ret |= ktrops(td, p, ops, facs, kiop); | ret |= ktrops(td, p, ops, facs, kiop); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
struct ktr_io_params *old_kiop; | struct ktr_io_params *old_kiop; | ||||
PROC_LOCK_ASSERT(p, MA_OWNED); | PROC_LOCK_ASSERT(p, MA_OWNED); | ||||
if (!ktrcanset(td, p)) { | if (!ktrcanset(td, p)) { | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
return (0); | return (0); | ||||
} | } | ||||
if (p->p_flag & P_WEXIT) { | if ((ops == KTROP_SET && p->p_state == PRS_NEW) || !p_cansee(td, p)) { | ||||
/* If the process is exiting, just ignore it. */ | /* | ||||
* Disallow setting trace points if the process is being born. | |||||
* This avoids races with trace point inheritance in | |||||
* ktrprocfork(). | |||||
*/ | |||||
PROC_UNLOCK(p); | |||||
return (0); | |||||
} | |||||
if ((p->p_flag & P_WEXIT) != 0) { | |||||
/* | |||||
* There's nothing to do if the process is exiting, but avoid | |||||
* signaling an error. | |||||
*/ | |||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
return (1); | return (1); | ||||
} | } | ||||
old_kiop = NULL; | old_kiop = NULL; | ||||
mtx_lock(&ktrace_mtx); | mtx_lock(&ktrace_mtx); | ||||
if (ops == KTROP_SET) { | if (ops == KTROP_SET) { | ||||
if (p->p_ktrioparms != NULL && | if (p->p_ktrioparms != NULL && | ||||
p->p_ktrioparms->vp != new_kiop->vp) { | p->p_ktrioparms->vp != new_kiop->vp) { | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | else for (;;) { | ||||
break; | break; | ||||
} | } | ||||
p = p->p_pptr; | p = p->p_pptr; | ||||
} | } | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
} | } | ||||
/*NOTREACHED*/ | /*NOTREACHED*/ | ||||
} | } | ||||
kib: This is arguably wrong, as well as the fact that all children are walked. But at least it is… | |||||
Done Inline ActionsI don't quite follow "orphans are not iterated". Orphans are added to the reaper's p_children list as soon as the parent dies, so we visit them too, I believe. Skipping processes for which p->p_pptr != proc_realparent(p) seems reasonable: it would exclude debuggees and orphans whose parent has not yet been reaped. markj: I don't quite follow "orphans are not iterated". Orphans are added to the reaper's p_children… | |||||
Not Done Inline ActionsWhen we iterate to add all current descendants of the process to the traced list (KTR_SET and KTRFLAG_DESCEND), we should iterate both p_children (but avoid ptraced reparented child which is debuggee) and p_orphans, since orphans are our children being ptraced by other process. Similarly, when we clear ktracing for descendants, we should clear it for siblings and orphans now, not delaying it for the debugger termination. kib: When we iterate to add all current descendants of the process to the traced list (KTR_SET and… | |||||
static void | static void | ||||
ktr_writerequest(struct thread *td, struct ktr_request *req) | ktr_writerequest(struct thread *td, struct ktr_request *req) | ||||
{ | { | ||||
struct ktr_io_params *kiop, *kiop1; | struct ktr_io_params *kiop, *kiop1; | ||||
struct ktr_header *kth; | struct ktr_header *kth; | ||||
struct vnode *vp; | struct vnode *vp; | ||||
struct proc *p; | struct proc *p; | ||||
struct ucred *cred; | struct ucred *cred; | ||||
▲ Show 20 Lines • Show All 124 Lines • Show Last 20 Lines |
This is arguably wrong, as well as the fact that all children are walked. But at least it is consistent with the fact that orphans are not iterated.
For p_children, the fix would probably to check that p->p_pptr == proc_realparent(p).