diff --git a/sys/kern/kern_procctl.c b/sys/kern/kern_procctl.c --- a/sys/kern/kern_procctl.c +++ b/sys/kern/kern_procctl.c @@ -102,10 +102,11 @@ } static int -protect_set(struct thread *td, struct proc *p, int flags) +protect_set(struct thread *td, struct proc *p, void *data) { - int error, ret; + int error, flags, ret; + flags = *(int *)data; switch (PPROT_OP(flags)) { case PPROT_SET: case PPROT_CLEAR: @@ -131,7 +132,7 @@ } static int -reap_acquire(struct thread *td, struct proc *p) +reap_acquire(struct thread *td, struct proc *p, void *data __unused) { sx_assert(&proctree_lock, SX_XLOCKED); @@ -148,7 +149,7 @@ } static int -reap_release(struct thread *td, struct proc *p) +reap_release(struct thread *td, struct proc *p, void *data __unused) { sx_assert(&proctree_lock, SX_XLOCKED); @@ -163,11 +164,12 @@ } static int -reap_status(struct thread *td, struct proc *p, - struct procctl_reaper_status *rs) +reap_status(struct thread *td, struct proc *p, void *data) { struct proc *reap, *p2, *first_p; + struct procctl_reaper_status *rs; + rs = data; sx_assert(&proctree_lock, SX_LOCKED); bzero(rs, sizeof(*rs)); if ((p->p_treeflag & P_TREE_REAPER) == 0) { @@ -198,13 +200,15 @@ } static int -reap_getpids(struct thread *td, struct proc *p, struct procctl_reaper_pids *rp) +reap_getpids(struct thread *td, struct proc *p, void *data) { struct proc *reap, *p2; struct procctl_reaper_pidinfo *pi, *pip; + struct procctl_reaper_pids *rp; u_int i, n; int error; + rp = data; sx_assert(&proctree_lock, SX_LOCKED); PROC_UNLOCK(p); reap = (p->p_treeflag & P_TREE_REAPER) == 0 ? p->p_reaper : p; @@ -276,14 +280,16 @@ } static int -reap_kill(struct thread *td, struct proc *p, struct procctl_reaper_kill *rk) +reap_kill(struct thread *td, struct proc *p, void *data) { struct proc *reap, *p2; ksiginfo_t ksi; struct reap_kill_tracker_head tracker; struct reap_kill_tracker *t; + struct procctl_reaper_kill *rk; int error; + rk = data; sx_assert(&proctree_lock, SX_LOCKED); if (IN_CAPABILITY_MODE(td)) return (ECAPMODE); @@ -336,10 +342,12 @@ } static int -trace_ctl(struct thread *td, struct proc *p, int state) +trace_ctl(struct thread *td, struct proc *p, void *data) { + int state; PROC_LOCK_ASSERT(p, MA_OWNED); + state = *(int *)data; /* * Ktrace changes p_traceflag from or to zero under the @@ -376,26 +384,30 @@ } static int -trace_status(struct thread *td, struct proc *p, int *data) +trace_status(struct thread *td, struct proc *p, void *data) { + int *status; + status = data; if ((p->p_flag2 & P2_NOTRACE) != 0) { KASSERT((p->p_flag & P_TRACED) == 0, ("%d traced but tracing disabled", p->p_pid)); - *data = -1; + *status = -1; } else if ((p->p_flag & P_TRACED) != 0) { - *data = p->p_pptr->p_pid; + *status = p->p_pptr->p_pid; } else { - *data = 0; + *status = 0; } return (0); } static int -trapcap_ctl(struct thread *td, struct proc *p, int state) +trapcap_ctl(struct thread *td, struct proc *p, void *data) { + int state; PROC_LOCK_ASSERT(p, MA_OWNED); + state = *(int *)data; switch (state) { case PROC_TRAPCAP_CTL_ENABLE: @@ -411,19 +423,23 @@ } static int -trapcap_status(struct thread *td, struct proc *p, int *data) +trapcap_status(struct thread *td, struct proc *p, void *data) { + int *status; - *data = (p->p_flag2 & P2_TRAPCAP) != 0 ? PROC_TRAPCAP_CTL_ENABLE : + status = data; + *status = (p->p_flag2 & P2_TRAPCAP) != 0 ? PROC_TRAPCAP_CTL_ENABLE : PROC_TRAPCAP_CTL_DISABLE; return (0); } static int -no_new_privs_ctl(struct thread *td, struct proc *p, int state) +no_new_privs_ctl(struct thread *td, struct proc *p, void *data) { + int state; PROC_LOCK_ASSERT(p, MA_OWNED); + state = *(int *)data; if (state != PROC_NO_NEW_PRIVS_ENABLE) return (EINVAL); @@ -432,18 +448,21 @@ } static int -no_new_privs_status(struct thread *td, struct proc *p, int *data) +no_new_privs_status(struct thread *td, struct proc *p, void *data) { - *data = (p->p_flag2 & P2_NO_NEW_PRIVS) != 0 ? + *(int *)data = (p->p_flag2 & P2_NO_NEW_PRIVS) != 0 ? PROC_NO_NEW_PRIVS_ENABLE : PROC_NO_NEW_PRIVS_DISABLE; return (0); } static int -protmax_ctl(struct thread *td, struct proc *p, int state) +protmax_ctl(struct thread *td, struct proc *p, void *data) { + int state; + PROC_LOCK_ASSERT(p, MA_OWNED); + state = *(int *)data; switch (state) { case PROC_PROTMAX_FORCE_ENABLE: @@ -464,7 +483,7 @@ } static int -protmax_status(struct thread *td, struct proc *p, int *data) +protmax_status(struct thread *td, struct proc *p, void *data) { int d; @@ -481,15 +500,17 @@ } if (kern_mmap_maxprot(p, PROT_READ) == PROT_READ) d |= PROC_PROTMAX_ACTIVE; - *data = d; + *(int *)data = d; return (0); } static int -aslr_ctl(struct thread *td, struct proc *p, int state) +aslr_ctl(struct thread *td, struct proc *p, void *data) { + int state; PROC_LOCK_ASSERT(p, MA_OWNED); + state = *(int *)data; switch (state) { case PROC_ASLR_FORCE_ENABLE: @@ -510,7 +531,7 @@ } static int -aslr_status(struct thread *td, struct proc *p, int *data) +aslr_status(struct thread *td, struct proc *p, void *data) { struct vmspace *vm; int d; @@ -538,14 +559,17 @@ PROC_LOCK(p); _PRELE(p); } - *data = d; + *(int *)data = d; return (0); } static int -stackgap_ctl(struct thread *td, struct proc *p, int state) +stackgap_ctl(struct thread *td, struct proc *p, void *data) { + int state; + PROC_LOCK_ASSERT(p, MA_OWNED); + state = *(int *)data; if ((state & ~(PROC_STACKGAP_ENABLE | PROC_STACKGAP_DISABLE | PROC_STACKGAP_ENABLE_EXEC | PROC_STACKGAP_DISABLE_EXEC)) != 0) @@ -580,26 +604,31 @@ } static int -stackgap_status(struct thread *td, struct proc *p, int *data) +stackgap_status(struct thread *td, struct proc *p, void *data) { + int d; + PROC_LOCK_ASSERT(p, MA_OWNED); - *data = (p->p_flag2 & P2_STKGAP_DISABLE) != 0 ? PROC_STACKGAP_DISABLE : + d = (p->p_flag2 & P2_STKGAP_DISABLE) != 0 ? PROC_STACKGAP_DISABLE : PROC_STACKGAP_ENABLE; - *data |= (p->p_flag2 & P2_STKGAP_DISABLE_EXEC) != 0 ? + d |= (p->p_flag2 & P2_STKGAP_DISABLE_EXEC) != 0 ? PROC_STACKGAP_DISABLE_EXEC : PROC_STACKGAP_ENABLE_EXEC; + *(int *)data = d; return (0); } static int -wxmap_ctl(struct thread *td, struct proc *p, int state) +wxmap_ctl(struct thread *td, struct proc *p, void *data) { struct vmspace *vm; vm_map_t map; + int state; PROC_LOCK_ASSERT(p, MA_OWNED); if ((p->p_flag & P_WEXIT) != 0) return (ESRCH); + state = *(int *)data; switch (state) { case PROC_WX_MAPPINGS_PERMIT: @@ -628,7 +657,7 @@ } static int -wxmap_status(struct thread *td, struct proc *p, int *data) +wxmap_status(struct thread *td, struct proc *p, void *data) { struct vmspace *vm; int d; @@ -652,19 +681,156 @@ } PROC_LOCK(p); _PRELE(p); - *data = d; + *(int *)data = d; + return (0); +} + +static int +pdeathsig_ctl(struct thread *td, struct proc *p, void *data) +{ + int signum; + + signum = *(int *)data; + if (p != td->td_proc || (data != 0 && !_SIG_VALID(signum))) + return (EINVAL); + p->p_pdeathsig = signum; + return (0); +} + +static int +pdeathsig_status(struct thread *td, struct proc *p, void *data) +{ + if (p != td->td_proc) + return (EINVAL); + *(int *)data = p->p_pdeathsig; return (0); } -#ifndef _SYS_SYSPROTO_H_ -struct procctl_args { - idtype_t idtype; - id_t id; - int com; - void *data; +struct procctl_cmd_info { + int lock_tree; + bool single_proc; + bool candebug; + bool always_copyout; + size_t copyin_sz; + size_t copyout_sz; + int (*exec)(struct thread *, struct proc *, void *); }; -#endif -/* ARGSUSED */ +static const struct procctl_cmd_info procctl_cmds_info[] = { + [PROC_SPROTECT] = + { .lock_tree = SA_SLOCKED, .single_proc = false, + .candebug = false, + .copyin_sz = sizeof(int), .copyout_sz = 0, + .exec = protect_set, .always_copyout = false, }, + [PROC_REAP_ACQUIRE] = + { .lock_tree = SA_XLOCKED, .single_proc = true, + .candebug = false, + .copyin_sz = 0, .copyout_sz = 0, + .exec = reap_acquire, .always_copyout = false, }, + [PROC_REAP_RELEASE] = + { .lock_tree = SA_XLOCKED, .single_proc = true, + .candebug = false, + .copyin_sz = 0, .copyout_sz = 0, + .exec = reap_release, .always_copyout = false, }, + [PROC_REAP_STATUS] = + { .lock_tree = SA_SLOCKED, .single_proc = true, + .candebug = false, + .copyin_sz = 0, + .copyout_sz = sizeof(struct procctl_reaper_status), + .exec = reap_status, .always_copyout = false, }, + [PROC_REAP_GETPIDS] = + { .lock_tree = SA_SLOCKED, .single_proc = true, + .candebug = false, + .copyin_sz = sizeof(struct procctl_reaper_pids), + .copyout_sz = 0, + .exec = reap_getpids, .always_copyout = false, }, + [PROC_REAP_KILL] = + { .lock_tree = SA_SLOCKED, .single_proc = true, + .candebug = false, + .copyin_sz = sizeof(struct procctl_reaper_kill), + .copyout_sz = sizeof(struct procctl_reaper_kill), + .exec = reap_kill, .always_copyout = true, }, + [PROC_TRACE_CTL] = + { .lock_tree = SA_SLOCKED, .single_proc = false, + .candebug = true, + .copyin_sz = sizeof(int), .copyout_sz = 0, + .exec = trace_ctl, .always_copyout = false, }, + [PROC_TRACE_STATUS] = + { .lock_tree = SA_UNLOCKED, .single_proc = true, + .candebug = false, + .copyin_sz = 0, .copyout_sz = sizeof(int), + .exec = trace_status, .always_copyout = false, }, + [PROC_TRAPCAP_CTL] = + { .lock_tree = SA_SLOCKED, .single_proc = false, + .candebug = true, + .copyin_sz = sizeof(int), .copyout_sz = 0, + .exec = trapcap_ctl, .always_copyout = false, }, + [PROC_TRAPCAP_STATUS] = + { .lock_tree = SA_UNLOCKED, .single_proc = true, + .candebug = false, + .copyin_sz = 0, .copyout_sz = sizeof(int), + .exec = trapcap_status, .always_copyout = false, }, + [PROC_PDEATHSIG_CTL] = + { .lock_tree = SA_UNLOCKED, .single_proc = true, + .candebug = false, + .copyin_sz = sizeof(int), .copyout_sz = 0, + .exec = pdeathsig_ctl, .always_copyout = false, }, + [PROC_PDEATHSIG_STATUS] = + { .lock_tree = SA_UNLOCKED, .single_proc = true, + .candebug = false, + .copyin_sz = 0, .copyout_sz = sizeof(int), + .exec = pdeathsig_status, .always_copyout = false, }, + [PROC_ASLR_CTL] = + { .lock_tree = SA_UNLOCKED, .single_proc = true, + .candebug = true, + .copyin_sz = sizeof(int), .copyout_sz = 0, + .exec = aslr_ctl, .always_copyout = false, }, + [PROC_ASLR_STATUS] = + { .lock_tree = SA_UNLOCKED, .single_proc = true, + .candebug = false, + .copyin_sz = 0, .copyout_sz = sizeof(int), + .exec = aslr_status, .always_copyout = false, }, + [PROC_PROTMAX_CTL] = + { .lock_tree = SA_UNLOCKED, .single_proc = true, + .candebug = true, + .copyin_sz = sizeof(int), .copyout_sz = 0, + .exec = protmax_ctl, .always_copyout = false, }, + [PROC_PROTMAX_STATUS] = + { .lock_tree = SA_UNLOCKED, .single_proc = true, + .candebug = false, + .copyin_sz = 0, .copyout_sz = sizeof(int), + .exec = protmax_status, .always_copyout = false, }, + [PROC_STACKGAP_CTL] = + { .lock_tree = SA_UNLOCKED, .single_proc = true, + .candebug = true, + .copyin_sz = sizeof(int), .copyout_sz = 9, + .exec = stackgap_ctl, .always_copyout = false, }, + [PROC_STACKGAP_STATUS] = + { .lock_tree = SA_UNLOCKED, .single_proc = true, + .candebug = false, + .copyin_sz = 0, .copyout_sz = sizeof(int), + .exec = stackgap_status, .always_copyout = false, }, + [PROC_NO_NEW_PRIVS_CTL] = + { .lock_tree = SA_SLOCKED, .single_proc = true, + .candebug = true, + .copyin_sz = sizeof(int), .copyout_sz = 0, + .exec = no_new_privs_ctl, .always_copyout = false, }, + [PROC_NO_NEW_PRIVS_STATUS] = + { .lock_tree = SA_UNLOCKED, .single_proc = true, + .candebug = false, + .copyin_sz = 0, .copyout_sz = sizeof(int), + .exec = no_new_privs_status, .always_copyout = false, }, + [PROC_WXMAP_CTL] = + { .lock_tree = SA_UNLOCKED, .single_proc = true, + .candebug = true, + .copyin_sz = sizeof(int), .copyout_sz = 0, + .exec = wxmap_ctl, .always_copyout = false, }, + [PROC_WXMAP_STATUS] = + { .lock_tree = SA_UNLOCKED, .single_proc = true, + .candebug = false, + .copyin_sz = 0, .copyout_sz = sizeof(int), + .exec = wxmap_status, .always_copyout = false, }, +}; + int sys_procctl(struct thread *td, struct procctl_args *uap) { @@ -673,94 +839,33 @@ struct procctl_reaper_status rs; struct procctl_reaper_pids rp; struct procctl_reaper_kill rk; + int flags; } x; - int error, error1, flags, signum; + const struct procctl_cmd_info *cmd_info; + int error, error1; if (uap->com >= PROC_PROCCTL_MD_MIN) return (cpu_procctl(td, uap->idtype, uap->id, uap->com, uap->data)); - - switch (uap->com) { - case PROC_ASLR_CTL: - case PROC_PROTMAX_CTL: - case PROC_SPROTECT: - case PROC_STACKGAP_CTL: - case PROC_TRACE_CTL: - case PROC_TRAPCAP_CTL: - case PROC_NO_NEW_PRIVS_CTL: - case PROC_WXMAP_CTL: - error = copyin(uap->data, &flags, sizeof(flags)); - if (error != 0) - return (error); - data = &flags; - break; - case PROC_REAP_ACQUIRE: - case PROC_REAP_RELEASE: - if (uap->data != NULL) - return (EINVAL); - data = NULL; - break; - case PROC_REAP_STATUS: - data = &x.rs; - break; - case PROC_REAP_GETPIDS: - error = copyin(uap->data, &x.rp, sizeof(x.rp)); - if (error != 0) - return (error); - data = &x.rp; - break; - case PROC_REAP_KILL: - error = copyin(uap->data, &x.rk, sizeof(x.rk)); - if (error != 0) - return (error); - data = &x.rk; - break; - case PROC_ASLR_STATUS: - case PROC_PROTMAX_STATUS: - case PROC_STACKGAP_STATUS: - case PROC_TRACE_STATUS: - case PROC_TRAPCAP_STATUS: - case PROC_NO_NEW_PRIVS_STATUS: - case PROC_WXMAP_STATUS: - data = &flags; - break; - case PROC_PDEATHSIG_CTL: - error = copyin(uap->data, &signum, sizeof(signum)); + if (uap->com == 0 || uap->com >= nitems(procctl_cmds_info)) + return (EINVAL); + cmd_info = &procctl_cmds_info[uap->com]; + if (cmd_info->copyin_sz > 0) { + error = copyin(uap->data, &x, cmd_info->copyin_sz); if (error != 0) return (error); - data = &signum; - break; - case PROC_PDEATHSIG_STATUS: - data = &signum; - break; - default: + } else if (uap->data != NULL) { return (EINVAL); } + + data = &x; error = kern_procctl(td, uap->idtype, uap->id, uap->com, data); - switch (uap->com) { - case PROC_REAP_STATUS: - if (error == 0) - error = copyout(&x.rs, uap->data, sizeof(x.rs)); - break; - case PROC_REAP_KILL: - error1 = copyout(&x.rk, uap->data, sizeof(x.rk)); + + if (cmd_info->copyout_sz > 0 && (error == 0 || + cmd_info->always_copyout)) { + error1 = copyout(&x, uap->data, cmd_info->copyout_sz); if (error == 0) error = error1; - break; - case PROC_ASLR_STATUS: - case PROC_PROTMAX_STATUS: - case PROC_STACKGAP_STATUS: - case PROC_TRACE_STATUS: - case PROC_TRAPCAP_STATUS: - case PROC_NO_NEW_PRIVS_STATUS: - case PROC_WXMAP_STATUS: - if (error == 0) - error = copyout(&flags, uap->data, sizeof(flags)); - break; - case PROC_PDEATHSIG_STATUS: - if (error == 0) - error = copyout(&signum, uap->data, sizeof(signum)); - break; } return (error); } @@ -770,50 +875,7 @@ { PROC_LOCK_ASSERT(p, MA_OWNED); - switch (com) { - case PROC_ASLR_CTL: - return (aslr_ctl(td, p, *(int *)data)); - case PROC_ASLR_STATUS: - return (aslr_status(td, p, data)); - case PROC_SPROTECT: - return (protect_set(td, p, *(int *)data)); - case PROC_PROTMAX_CTL: - return (protmax_ctl(td, p, *(int *)data)); - case PROC_PROTMAX_STATUS: - return (protmax_status(td, p, data)); - case PROC_STACKGAP_CTL: - return (stackgap_ctl(td, p, *(int *)data)); - case PROC_STACKGAP_STATUS: - return (stackgap_status(td, p, data)); - case PROC_REAP_ACQUIRE: - return (reap_acquire(td, p)); - case PROC_REAP_RELEASE: - return (reap_release(td, p)); - case PROC_REAP_STATUS: - return (reap_status(td, p, data)); - case PROC_REAP_GETPIDS: - return (reap_getpids(td, p, data)); - case PROC_REAP_KILL: - return (reap_kill(td, p, data)); - case PROC_TRACE_CTL: - return (trace_ctl(td, p, *(int *)data)); - case PROC_TRACE_STATUS: - return (trace_status(td, p, data)); - case PROC_TRAPCAP_CTL: - return (trapcap_ctl(td, p, *(int *)data)); - case PROC_TRAPCAP_STATUS: - return (trapcap_status(td, p, data)); - case PROC_NO_NEW_PRIVS_CTL: - return (no_new_privs_ctl(td, p, *(int *)data)); - case PROC_NO_NEW_PRIVS_STATUS: - return (no_new_privs_status(td, p, data)); - case PROC_WXMAP_CTL: - return (wxmap_ctl(td, p, *(int *)data)); - case PROC_WXMAP_STATUS: - return (wxmap_status(td, p, data)); - default: - return (EINVAL); - } + return (procctl_cmds_info[com].exec(td, p, data)); } int @@ -821,96 +883,38 @@ { struct pgrp *pg; struct proc *p; + const struct procctl_cmd_info *cmd_info; int error, first_error, ok; - int signum; - bool tree_locked; - - switch (com) { - case PROC_ASLR_CTL: - case PROC_ASLR_STATUS: - case PROC_PROTMAX_CTL: - case PROC_PROTMAX_STATUS: - case PROC_REAP_ACQUIRE: - case PROC_REAP_RELEASE: - case PROC_REAP_STATUS: - case PROC_REAP_GETPIDS: - case PROC_REAP_KILL: - case PROC_STACKGAP_CTL: - case PROC_STACKGAP_STATUS: - case PROC_TRACE_STATUS: - case PROC_TRAPCAP_STATUS: - case PROC_PDEATHSIG_CTL: - case PROC_PDEATHSIG_STATUS: - case PROC_NO_NEW_PRIVS_CTL: - case PROC_NO_NEW_PRIVS_STATUS: - case PROC_WXMAP_CTL: - case PROC_WXMAP_STATUS: - if (idtype != P_PID) - return (EINVAL); - } - switch (com) { - case PROC_PDEATHSIG_CTL: - signum = *(int *)data; - p = td->td_proc; - if ((id != 0 && id != p->p_pid) || - (signum != 0 && !_SIG_VALID(signum))) - return (EINVAL); - PROC_LOCK(p); - p->p_pdeathsig = signum; - PROC_UNLOCK(p); - return (0); - case PROC_PDEATHSIG_STATUS: - p = td->td_proc; - if (id != 0 && id != p->p_pid) - return (EINVAL); - PROC_LOCK(p); - *(int *)data = p->p_pdeathsig; - PROC_UNLOCK(p); - return (0); - } + MPASS(com > 0 && com < nitems(procctl_cmds_info)); + cmd_info = &procctl_cmds_info[com]; + if (idtype != P_PID && cmd_info->single_proc) + return (EINVAL); - switch (com) { - case PROC_SPROTECT: - case PROC_REAP_STATUS: - case PROC_REAP_GETPIDS: - case PROC_REAP_KILL: - case PROC_TRACE_CTL: - case PROC_TRAPCAP_CTL: - case PROC_NO_NEW_PRIVS_CTL: - sx_slock(&proctree_lock); - tree_locked = true; - break; - case PROC_REAP_ACQUIRE: - case PROC_REAP_RELEASE: + switch (cmd_info->lock_tree) { + case SA_XLOCKED: sx_xlock(&proctree_lock); - tree_locked = true; - break; - case PROC_ASLR_CTL: - case PROC_ASLR_STATUS: - case PROC_PROTMAX_CTL: - case PROC_PROTMAX_STATUS: - case PROC_STACKGAP_CTL: - case PROC_STACKGAP_STATUS: - case PROC_TRACE_STATUS: - case PROC_TRAPCAP_STATUS: - case PROC_NO_NEW_PRIVS_STATUS: - case PROC_WXMAP_CTL: - case PROC_WXMAP_STATUS: - tree_locked = false; break; - default: - return (EINVAL); + case SA_SLOCKED: + sx_slock(&proctree_lock); + break; } switch (idtype) { case P_PID: - p = pfind(id); - if (p == NULL) { - error = ESRCH; - break; + if (id == 0) { + p = td->td_proc; + error = 0; + PROC_LOCK(p); + } else { + p = pfind(id); + if (p == NULL) { + error = ESRCH; + break; + } + error = cmd_info->candebug ? p_candebug(td, p) : + p_cansee(td, p); } - error = p_cansee(td, p); if (error == 0) error = kern_procctl_single(td, p, com, data); PROC_UNLOCK(p); @@ -932,7 +936,8 @@ first_error = 0; LIST_FOREACH(p, &pg->pg_members, p_pglist) { PROC_LOCK(p); - if (p->p_state == PRS_NEW || p_cansee(td, p) != 0) { + if (p->p_state == PRS_NEW || (cmd_info->candebug ? + p_candebug(td, p) : p_cansee(td, p)) != 0) { PROC_UNLOCK(p); continue; } @@ -958,7 +963,14 @@ error = EINVAL; break; } - if (tree_locked) - sx_unlock(&proctree_lock); + + switch (cmd_info->lock_tree) { + case SA_XLOCKED: + sx_xunlock(&proctree_lock); + break; + case SA_SLOCKED: + sx_sunlock(&proctree_lock); + break; + } return (error); }