Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_procctl.c
Show First 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | |||||
static int | static int | ||||
protect_setchildren(struct thread *td, struct proc *top, int flags) | protect_setchildren(struct thread *td, struct proc *top, int flags) | ||||
{ | { | ||||
struct proc *p; | struct proc *p; | ||||
int ret; | int ret; | ||||
p = top; | p = top; | ||||
ret = 0; | ret = 0; | ||||
sx_assert(&proctree_lock, SX_LOCKED); | sx_assert(&V_proctree_lock, SX_LOCKED); | ||||
for (;;) { | for (;;) { | ||||
ret |= protect_setchild(td, p, flags); | ret |= protect_setchild(td, p, flags); | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
/* | /* | ||||
* If this process has children, descend to them next, | * If this process has children, descend to them next, | ||||
* otherwise do any siblings, and if done with this level, | * otherwise do any siblings, and if done with this level, | ||||
* follow back up the tree (but not past top). | * follow back up the tree (but not past top). | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | if (ret == 0) | ||||
return (EPERM); | return (EPERM); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
reap_acquire(struct thread *td, struct proc *p) | reap_acquire(struct thread *td, struct proc *p) | ||||
{ | { | ||||
sx_assert(&proctree_lock, SX_XLOCKED); | sx_assert(&V_proctree_lock, SX_XLOCKED); | ||||
if (p != curproc) | if (p != curproc) | ||||
return (EPERM); | return (EPERM); | ||||
if ((p->p_treeflag & P_TREE_REAPER) != 0) | if ((p->p_treeflag & P_TREE_REAPER) != 0) | ||||
return (EBUSY); | return (EBUSY); | ||||
p->p_treeflag |= P_TREE_REAPER; | p->p_treeflag |= P_TREE_REAPER; | ||||
/* | /* | ||||
* We do not reattach existing children and the whole tree | * We do not reattach existing children and the whole tree | ||||
* under them to us, since p->p_reaper already seen them. | * under them to us, since p->p_reaper already seen them. | ||||
*/ | */ | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
reap_release(struct thread *td, struct proc *p) | reap_release(struct thread *td, struct proc *p) | ||||
{ | { | ||||
sx_assert(&proctree_lock, SX_XLOCKED); | sx_assert(&V_proctree_lock, SX_XLOCKED); | ||||
if (p != curproc) | if (p != curproc) | ||||
return (EPERM); | return (EPERM); | ||||
if (p == initproc) | if (p == V_initproc) | ||||
return (EINVAL); | return (EINVAL); | ||||
if ((p->p_treeflag & P_TREE_REAPER) == 0) | if ((p->p_treeflag & P_TREE_REAPER) == 0) | ||||
return (EINVAL); | return (EINVAL); | ||||
reaper_abandon_children(p, false); | reaper_abandon_children(p, false); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
reap_status(struct thread *td, struct proc *p, | reap_status(struct thread *td, struct proc *p, | ||||
struct procctl_reaper_status *rs) | struct procctl_reaper_status *rs) | ||||
{ | { | ||||
struct proc *reap, *p2, *first_p; | struct proc *reap, *p2, *first_p; | ||||
sx_assert(&proctree_lock, SX_LOCKED); | sx_assert(&V_proctree_lock, SX_LOCKED); | ||||
bzero(rs, sizeof(*rs)); | bzero(rs, sizeof(*rs)); | ||||
if ((p->p_treeflag & P_TREE_REAPER) == 0) { | if ((p->p_treeflag & P_TREE_REAPER) == 0) { | ||||
reap = p->p_reaper; | reap = p->p_reaper; | ||||
} else { | } else { | ||||
reap = p; | reap = p; | ||||
rs->rs_flags |= REAPER_STATUS_OWNED; | rs->rs_flags |= REAPER_STATUS_OWNED; | ||||
} | } | ||||
if (reap == initproc) | if (reap == V_initproc) | ||||
rs->rs_flags |= REAPER_STATUS_REALINIT; | rs->rs_flags |= REAPER_STATUS_REALINIT; | ||||
rs->rs_reaper = reap->p_pid; | rs->rs_reaper = reap->p_pid; | ||||
rs->rs_descendants = 0; | rs->rs_descendants = 0; | ||||
rs->rs_children = 0; | rs->rs_children = 0; | ||||
if (!LIST_EMPTY(&reap->p_reaplist)) { | if (!LIST_EMPTY(&reap->p_reaplist)) { | ||||
first_p = LIST_FIRST(&reap->p_children); | first_p = LIST_FIRST(&reap->p_children); | ||||
if (first_p == NULL) | if (first_p == NULL) | ||||
first_p = LIST_FIRST(&reap->p_reaplist); | first_p = LIST_FIRST(&reap->p_reaplist); | ||||
Show All 12 Lines | |||||
static int | static int | ||||
reap_getpids(struct thread *td, struct proc *p, struct procctl_reaper_pids *rp) | reap_getpids(struct thread *td, struct proc *p, struct procctl_reaper_pids *rp) | ||||
{ | { | ||||
struct proc *reap, *p2; | struct proc *reap, *p2; | ||||
struct procctl_reaper_pidinfo *pi, *pip; | struct procctl_reaper_pidinfo *pi, *pip; | ||||
u_int i, n; | u_int i, n; | ||||
int error; | int error; | ||||
sx_assert(&proctree_lock, SX_LOCKED); | sx_assert(&V_proctree_lock, SX_LOCKED); | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
reap = (p->p_treeflag & P_TREE_REAPER) == 0 ? p->p_reaper : p; | reap = (p->p_treeflag & P_TREE_REAPER) == 0 ? p->p_reaper : p; | ||||
n = i = 0; | n = i = 0; | ||||
error = 0; | error = 0; | ||||
LIST_FOREACH(p2, &reap->p_reaplist, p_reapsibling) | LIST_FOREACH(p2, &reap->p_reaplist, p_reapsibling) | ||||
n++; | n++; | ||||
sx_unlock(&proctree_lock); | sx_unlock(&V_proctree_lock); | ||||
if (rp->rp_count < n) | if (rp->rp_count < n) | ||||
n = rp->rp_count; | n = rp->rp_count; | ||||
pi = malloc(n * sizeof(*pi), M_TEMP, M_WAITOK); | pi = malloc(n * sizeof(*pi), M_TEMP, M_WAITOK); | ||||
sx_slock(&proctree_lock); | sx_slock(&V_proctree_lock); | ||||
LIST_FOREACH(p2, &reap->p_reaplist, p_reapsibling) { | LIST_FOREACH(p2, &reap->p_reaplist, p_reapsibling) { | ||||
if (i == n) | if (i == n) | ||||
break; | break; | ||||
pip = &pi[i]; | pip = &pi[i]; | ||||
bzero(pip, sizeof(*pip)); | bzero(pip, sizeof(*pip)); | ||||
pip->pi_pid = p2->p_pid; | pip->pi_pid = p2->p_pid; | ||||
pip->pi_subtree = p2->p_reapsubtree; | pip->pi_subtree = p2->p_reapsubtree; | ||||
pip->pi_flags = REAPER_PIDINFO_VALID; | pip->pi_flags = REAPER_PIDINFO_VALID; | ||||
if (proc_realparent(p2) == reap) | if (proc_realparent(p2) == reap) | ||||
pip->pi_flags |= REAPER_PIDINFO_CHILD; | pip->pi_flags |= REAPER_PIDINFO_CHILD; | ||||
if ((p2->p_treeflag & P_TREE_REAPER) != 0) | if ((p2->p_treeflag & P_TREE_REAPER) != 0) | ||||
pip->pi_flags |= REAPER_PIDINFO_REAPER; | pip->pi_flags |= REAPER_PIDINFO_REAPER; | ||||
i++; | i++; | ||||
} | } | ||||
sx_sunlock(&proctree_lock); | sx_sunlock(&V_proctree_lock); | ||||
error = copyout(pi, rp->rp_pids, i * sizeof(*pi)); | error = copyout(pi, rp->rp_pids, i * sizeof(*pi)); | ||||
free(pi, M_TEMP); | free(pi, M_TEMP); | ||||
sx_slock(&proctree_lock); | sx_slock(&V_proctree_lock); | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
return (error); | return (error); | ||||
} | } | ||||
static void | static void | ||||
reap_kill_proc(struct thread *td, struct proc *p2, ksiginfo_t *ksi, | reap_kill_proc(struct thread *td, struct proc *p2, ksiginfo_t *ksi, | ||||
struct procctl_reaper_kill *rk, int *error) | struct procctl_reaper_kill *rk, int *error) | ||||
{ | { | ||||
Show All 33 Lines | |||||
reap_kill(struct thread *td, struct proc *p, struct procctl_reaper_kill *rk) | reap_kill(struct thread *td, struct proc *p, struct procctl_reaper_kill *rk) | ||||
{ | { | ||||
struct proc *reap, *p2; | struct proc *reap, *p2; | ||||
ksiginfo_t ksi; | ksiginfo_t ksi; | ||||
struct reap_kill_tracker_head tracker; | struct reap_kill_tracker_head tracker; | ||||
struct reap_kill_tracker *t; | struct reap_kill_tracker *t; | ||||
int error; | int error; | ||||
sx_assert(&proctree_lock, SX_LOCKED); | sx_assert(&V_proctree_lock, SX_LOCKED); | ||||
if (IN_CAPABILITY_MODE(td)) | if (IN_CAPABILITY_MODE(td)) | ||||
return (ECAPMODE); | return (ECAPMODE); | ||||
if (rk->rk_sig <= 0 || rk->rk_sig > _SIG_MAXSIG || | if (rk->rk_sig <= 0 || rk->rk_sig > _SIG_MAXSIG || | ||||
(rk->rk_flags & ~(REAPER_KILL_CHILDREN | | (rk->rk_flags & ~(REAPER_KILL_CHILDREN | | ||||
REAPER_KILL_SUBTREE)) != 0 || (rk->rk_flags & | REAPER_KILL_SUBTREE)) != 0 || (rk->rk_flags & | ||||
(REAPER_KILL_CHILDREN | REAPER_KILL_SUBTREE)) == | (REAPER_KILL_CHILDREN | REAPER_KILL_SUBTREE)) == | ||||
(REAPER_KILL_CHILDREN | REAPER_KILL_SUBTREE)) | (REAPER_KILL_CHILDREN | REAPER_KILL_SUBTREE)) | ||||
return (EINVAL); | return (EINVAL); | ||||
▲ Show 20 Lines • Show All 290 Lines • ▼ Show 20 Lines | kern_procctl(struct thread *td, idtype_t idtype, id_t id, int com, void *data) | ||||
switch (com) { | switch (com) { | ||||
case PROC_SPROTECT: | case PROC_SPROTECT: | ||||
case PROC_REAP_STATUS: | case PROC_REAP_STATUS: | ||||
case PROC_REAP_GETPIDS: | case PROC_REAP_GETPIDS: | ||||
case PROC_REAP_KILL: | case PROC_REAP_KILL: | ||||
case PROC_TRACE_CTL: | case PROC_TRACE_CTL: | ||||
case PROC_TRAPCAP_CTL: | case PROC_TRAPCAP_CTL: | ||||
sx_slock(&proctree_lock); | sx_slock(&V_proctree_lock); | ||||
tree_locked = true; | tree_locked = true; | ||||
break; | break; | ||||
case PROC_REAP_ACQUIRE: | case PROC_REAP_ACQUIRE: | ||||
case PROC_REAP_RELEASE: | case PROC_REAP_RELEASE: | ||||
sx_xlock(&proctree_lock); | sx_xlock(&V_proctree_lock); | ||||
tree_locked = true; | tree_locked = true; | ||||
break; | break; | ||||
case PROC_TRACE_STATUS: | case PROC_TRACE_STATUS: | ||||
case PROC_TRAPCAP_STATUS: | case PROC_TRAPCAP_STATUS: | ||||
tree_locked = false; | tree_locked = false; | ||||
break; | break; | ||||
default: | default: | ||||
return (EINVAL); | return (EINVAL); | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | else | ||||
*/ | */ | ||||
error = ESRCH; | error = ESRCH; | ||||
break; | break; | ||||
default: | default: | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
} | } | ||||
if (tree_locked) | if (tree_locked) | ||||
sx_unlock(&proctree_lock); | sx_unlock(&V_proctree_lock); | ||||
return (error); | return (error); | ||||
} | } |