1237623b0SKonstantin Belousov /*- 2237623b0SKonstantin Belousov * Copyright (c) 2014 John Baldwin 3939457e3SKonstantin Belousov * Copyright (c) 2014, 2016 The FreeBSD Foundation 4237623b0SKonstantin Belousov * 5237623b0SKonstantin Belousov * Portions of this software were developed by Konstantin Belousov 6237623b0SKonstantin Belousov * under sponsorship from the FreeBSD Foundation. 7237623b0SKonstantin Belousov * 8237623b0SKonstantin Belousov * Redistribution and use in source and binary forms, with or without 9237623b0SKonstantin Belousov * modification, are permitted provided that the following conditions 10237623b0SKonstantin Belousov * are met: 11237623b0SKonstantin Belousov * 1. Redistributions of source code must retain the above copyright 12237623b0SKonstantin Belousov * notice, this list of conditions and the following disclaimer. 13237623b0SKonstantin Belousov * 2. Redistributions in binary form must reproduce the above copyright 14237623b0SKonstantin Belousov * notice, this list of conditions and the following disclaimer in the 15237623b0SKonstantin Belousov * documentation and/or other materials provided with the distribution. 16237623b0SKonstantin Belousov * 17237623b0SKonstantin Belousov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18237623b0SKonstantin Belousov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19237623b0SKonstantin Belousov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20237623b0SKonstantin Belousov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21237623b0SKonstantin Belousov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22237623b0SKonstantin Belousov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23237623b0SKonstantin Belousov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24237623b0SKonstantin Belousov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25237623b0SKonstantin Belousov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26237623b0SKonstantin Belousov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27237623b0SKonstantin Belousov * SUCH DAMAGE. 28237623b0SKonstantin Belousov */ 29237623b0SKonstantin Belousov 306a4616a5SJake Freeland #include "opt_ktrace.h" 316a4616a5SJake Freeland 32237623b0SKonstantin Belousov #include <sys/param.h> 3339794d80SKonstantin Belousov #include <sys/_unrhdr.h> 34237623b0SKonstantin Belousov #include <sys/systm.h> 35237623b0SKonstantin Belousov #include <sys/capsicum.h> 36237623b0SKonstantin Belousov #include <sys/lock.h> 376bb132baSBrooks Davis #include <sys/malloc.h> 385dc7e31aSKonstantin Belousov #include <sys/mman.h> 39237623b0SKonstantin Belousov #include <sys/mutex.h> 40237623b0SKonstantin Belousov #include <sys/priv.h> 41237623b0SKonstantin Belousov #include <sys/proc.h> 42237623b0SKonstantin Belousov #include <sys/procctl.h> 43237623b0SKonstantin Belousov #include <sys/sx.h> 44237623b0SKonstantin Belousov #include <sys/syscallsubr.h> 45237623b0SKonstantin Belousov #include <sys/sysproto.h> 462842ec6dSKonstantin Belousov #include <sys/taskqueue.h> 47237623b0SKonstantin Belousov #include <sys/wait.h> 48237623b0SKonstantin Belousov 49fa50a355SKonstantin Belousov #include <vm/vm.h> 50fa50a355SKonstantin Belousov #include <vm/pmap.h> 51fa50a355SKonstantin Belousov #include <vm/vm_map.h> 52fa50a355SKonstantin Belousov #include <vm/vm_extern.h> 53fa50a355SKonstantin Belousov 54237623b0SKonstantin Belousov static int 55237623b0SKonstantin Belousov protect_setchild(struct thread *td, struct proc *p, int flags) 56237623b0SKonstantin Belousov { 57237623b0SKonstantin Belousov 58237623b0SKonstantin Belousov PROC_LOCK_ASSERT(p, MA_OWNED); 59237623b0SKonstantin Belousov if (p->p_flag & P_SYSTEM || p_cansched(td, p) != 0) 60237623b0SKonstantin Belousov return (0); 61237623b0SKonstantin Belousov if (flags & PPROT_SET) { 62237623b0SKonstantin Belousov p->p_flag |= P_PROTECTED; 63237623b0SKonstantin Belousov if (flags & PPROT_INHERIT) 64237623b0SKonstantin Belousov p->p_flag2 |= P2_INHERIT_PROTECTED; 65237623b0SKonstantin Belousov } else { 66237623b0SKonstantin Belousov p->p_flag &= ~P_PROTECTED; 67237623b0SKonstantin Belousov p->p_flag2 &= ~P2_INHERIT_PROTECTED; 68237623b0SKonstantin Belousov } 69237623b0SKonstantin Belousov return (1); 70237623b0SKonstantin Belousov } 71237623b0SKonstantin Belousov 72237623b0SKonstantin Belousov static int 73237623b0SKonstantin Belousov protect_setchildren(struct thread *td, struct proc *top, int flags) 74237623b0SKonstantin Belousov { 75237623b0SKonstantin Belousov struct proc *p; 76237623b0SKonstantin Belousov int ret; 77237623b0SKonstantin Belousov 78237623b0SKonstantin Belousov p = top; 79237623b0SKonstantin Belousov ret = 0; 80237623b0SKonstantin Belousov sx_assert(&proctree_lock, SX_LOCKED); 81237623b0SKonstantin Belousov for (;;) { 82237623b0SKonstantin Belousov ret |= protect_setchild(td, p, flags); 83237623b0SKonstantin Belousov PROC_UNLOCK(p); 84237623b0SKonstantin Belousov /* 85237623b0SKonstantin Belousov * If this process has children, descend to them next, 86237623b0SKonstantin Belousov * otherwise do any siblings, and if done with this level, 87237623b0SKonstantin Belousov * follow back up the tree (but not past top). 88237623b0SKonstantin Belousov */ 89237623b0SKonstantin Belousov if (!LIST_EMPTY(&p->p_children)) 90237623b0SKonstantin Belousov p = LIST_FIRST(&p->p_children); 91237623b0SKonstantin Belousov else for (;;) { 92237623b0SKonstantin Belousov if (p == top) { 93237623b0SKonstantin Belousov PROC_LOCK(p); 94237623b0SKonstantin Belousov return (ret); 95237623b0SKonstantin Belousov } 96237623b0SKonstantin Belousov if (LIST_NEXT(p, p_sibling)) { 97237623b0SKonstantin Belousov p = LIST_NEXT(p, p_sibling); 98237623b0SKonstantin Belousov break; 99237623b0SKonstantin Belousov } 100237623b0SKonstantin Belousov p = p->p_pptr; 101237623b0SKonstantin Belousov } 102237623b0SKonstantin Belousov PROC_LOCK(p); 103237623b0SKonstantin Belousov } 104237623b0SKonstantin Belousov } 105237623b0SKonstantin Belousov 106237623b0SKonstantin Belousov static int 10768dc5b38SKonstantin Belousov protect_set(struct thread *td, struct proc *p, void *data) 108237623b0SKonstantin Belousov { 10968dc5b38SKonstantin Belousov int error, flags, ret; 110237623b0SKonstantin Belousov 11168dc5b38SKonstantin Belousov flags = *(int *)data; 112237623b0SKonstantin Belousov switch (PPROT_OP(flags)) { 113237623b0SKonstantin Belousov case PPROT_SET: 114237623b0SKonstantin Belousov case PPROT_CLEAR: 115237623b0SKonstantin Belousov break; 116237623b0SKonstantin Belousov default: 117237623b0SKonstantin Belousov return (EINVAL); 118237623b0SKonstantin Belousov } 119237623b0SKonstantin Belousov 120237623b0SKonstantin Belousov if ((PPROT_FLAGS(flags) & ~(PPROT_DESCEND | PPROT_INHERIT)) != 0) 121237623b0SKonstantin Belousov return (EINVAL); 122237623b0SKonstantin Belousov 123237623b0SKonstantin Belousov error = priv_check(td, PRIV_VM_MADV_PROTECT); 124237623b0SKonstantin Belousov if (error) 125237623b0SKonstantin Belousov return (error); 126237623b0SKonstantin Belousov 127237623b0SKonstantin Belousov if (flags & PPROT_DESCEND) 128237623b0SKonstantin Belousov ret = protect_setchildren(td, p, flags); 129237623b0SKonstantin Belousov else 130237623b0SKonstantin Belousov ret = protect_setchild(td, p, flags); 131237623b0SKonstantin Belousov if (ret == 0) 132237623b0SKonstantin Belousov return (EPERM); 133237623b0SKonstantin Belousov return (0); 134237623b0SKonstantin Belousov } 135237623b0SKonstantin Belousov 136237623b0SKonstantin Belousov static int 13768dc5b38SKonstantin Belousov reap_acquire(struct thread *td, struct proc *p, void *data __unused) 138237623b0SKonstantin Belousov { 139237623b0SKonstantin Belousov 140237623b0SKonstantin Belousov sx_assert(&proctree_lock, SX_XLOCKED); 1413692877aSKonstantin Belousov if (p != td->td_proc) 142237623b0SKonstantin Belousov return (EPERM); 143237623b0SKonstantin Belousov if ((p->p_treeflag & P_TREE_REAPER) != 0) 144237623b0SKonstantin Belousov return (EBUSY); 145237623b0SKonstantin Belousov p->p_treeflag |= P_TREE_REAPER; 146237623b0SKonstantin Belousov /* 147237623b0SKonstantin Belousov * We do not reattach existing children and the whole tree 148237623b0SKonstantin Belousov * under them to us, since p->p_reaper already seen them. 149237623b0SKonstantin Belousov */ 150237623b0SKonstantin Belousov return (0); 151237623b0SKonstantin Belousov } 152237623b0SKonstantin Belousov 153237623b0SKonstantin Belousov static int 15468dc5b38SKonstantin Belousov reap_release(struct thread *td, struct proc *p, void *data __unused) 155237623b0SKonstantin Belousov { 156237623b0SKonstantin Belousov 157237623b0SKonstantin Belousov sx_assert(&proctree_lock, SX_XLOCKED); 1583692877aSKonstantin Belousov if (p != td->td_proc) 159237623b0SKonstantin Belousov return (EPERM); 160237623b0SKonstantin Belousov if (p == initproc) 161237623b0SKonstantin Belousov return (EINVAL); 162237623b0SKonstantin Belousov if ((p->p_treeflag & P_TREE_REAPER) == 0) 163237623b0SKonstantin Belousov return (EINVAL); 164237623b0SKonstantin Belousov reaper_abandon_children(p, false); 165237623b0SKonstantin Belousov return (0); 166237623b0SKonstantin Belousov } 167237623b0SKonstantin Belousov 168237623b0SKonstantin Belousov static int 16968dc5b38SKonstantin Belousov reap_status(struct thread *td, struct proc *p, void *data) 170237623b0SKonstantin Belousov { 17145f1ade7SKonstantin Belousov struct proc *reap, *p2, *first_p; 17268dc5b38SKonstantin Belousov struct procctl_reaper_status *rs; 173237623b0SKonstantin Belousov 17468dc5b38SKonstantin Belousov rs = data; 175237623b0SKonstantin Belousov sx_assert(&proctree_lock, SX_LOCKED); 176237623b0SKonstantin Belousov if ((p->p_treeflag & P_TREE_REAPER) == 0) { 177237623b0SKonstantin Belousov reap = p->p_reaper; 178237623b0SKonstantin Belousov } else { 179237623b0SKonstantin Belousov reap = p; 180237623b0SKonstantin Belousov rs->rs_flags |= REAPER_STATUS_OWNED; 181237623b0SKonstantin Belousov } 182237623b0SKonstantin Belousov if (reap == initproc) 183237623b0SKonstantin Belousov rs->rs_flags |= REAPER_STATUS_REALINIT; 184237623b0SKonstantin Belousov rs->rs_reaper = reap->p_pid; 185237623b0SKonstantin Belousov rs->rs_descendants = 0; 186237623b0SKonstantin Belousov rs->rs_children = 0; 187237623b0SKonstantin Belousov if (!LIST_EMPTY(&reap->p_reaplist)) { 18845f1ade7SKonstantin Belousov first_p = LIST_FIRST(&reap->p_children); 18945f1ade7SKonstantin Belousov if (first_p == NULL) 19045f1ade7SKonstantin Belousov first_p = LIST_FIRST(&reap->p_reaplist); 19145f1ade7SKonstantin Belousov rs->rs_pid = first_p->p_pid; 192237623b0SKonstantin Belousov LIST_FOREACH(p2, &reap->p_reaplist, p_reapsibling) { 193237623b0SKonstantin Belousov if (proc_realparent(p2) == reap) 194237623b0SKonstantin Belousov rs->rs_children++; 195237623b0SKonstantin Belousov rs->rs_descendants++; 196237623b0SKonstantin Belousov } 197237623b0SKonstantin Belousov } else { 198237623b0SKonstantin Belousov rs->rs_pid = -1; 199237623b0SKonstantin Belousov } 200237623b0SKonstantin Belousov return (0); 201237623b0SKonstantin Belousov } 202237623b0SKonstantin Belousov 203237623b0SKonstantin Belousov static int 20468dc5b38SKonstantin Belousov reap_getpids(struct thread *td, struct proc *p, void *data) 205237623b0SKonstantin Belousov { 206237623b0SKonstantin Belousov struct proc *reap, *p2; 207237623b0SKonstantin Belousov struct procctl_reaper_pidinfo *pi, *pip; 20868dc5b38SKonstantin Belousov struct procctl_reaper_pids *rp; 209237623b0SKonstantin Belousov u_int i, n; 210237623b0SKonstantin Belousov int error; 211237623b0SKonstantin Belousov 21268dc5b38SKonstantin Belousov rp = data; 213237623b0SKonstantin Belousov sx_assert(&proctree_lock, SX_LOCKED); 214237623b0SKonstantin Belousov PROC_UNLOCK(p); 215237623b0SKonstantin Belousov reap = (p->p_treeflag & P_TREE_REAPER) == 0 ? p->p_reaper : p; 216237623b0SKonstantin Belousov n = i = 0; 217237623b0SKonstantin Belousov error = 0; 218237623b0SKonstantin Belousov LIST_FOREACH(p2, &reap->p_reaplist, p_reapsibling) 219237623b0SKonstantin Belousov n++; 220237623b0SKonstantin Belousov sx_unlock(&proctree_lock); 221237623b0SKonstantin Belousov if (rp->rp_count < n) 222237623b0SKonstantin Belousov n = rp->rp_count; 223237623b0SKonstantin Belousov pi = malloc(n * sizeof(*pi), M_TEMP, M_WAITOK); 224237623b0SKonstantin Belousov sx_slock(&proctree_lock); 225237623b0SKonstantin Belousov LIST_FOREACH(p2, &reap->p_reaplist, p_reapsibling) { 226237623b0SKonstantin Belousov if (i == n) 227237623b0SKonstantin Belousov break; 228237623b0SKonstantin Belousov pip = &pi[i]; 229237623b0SKonstantin Belousov bzero(pip, sizeof(*pip)); 230237623b0SKonstantin Belousov pip->pi_pid = p2->p_pid; 231237623b0SKonstantin Belousov pip->pi_subtree = p2->p_reapsubtree; 232237623b0SKonstantin Belousov pip->pi_flags = REAPER_PIDINFO_VALID; 233237623b0SKonstantin Belousov if (proc_realparent(p2) == reap) 234237623b0SKonstantin Belousov pip->pi_flags |= REAPER_PIDINFO_CHILD; 235ee50062cSKonstantin Belousov if ((p2->p_treeflag & P_TREE_REAPER) != 0) 236ee50062cSKonstantin Belousov pip->pi_flags |= REAPER_PIDINFO_REAPER; 23777f0e198SVal Packett if ((p2->p_flag & P_STOPPED) != 0) 23877f0e198SVal Packett pip->pi_flags |= REAPER_PIDINFO_STOPPED; 23977f0e198SVal Packett if (p2->p_state == PRS_ZOMBIE) 24077f0e198SVal Packett pip->pi_flags |= REAPER_PIDINFO_ZOMBIE; 24177f0e198SVal Packett else if ((p2->p_flag & P_WEXIT) != 0) 24277f0e198SVal Packett pip->pi_flags |= REAPER_PIDINFO_EXITING; 243237623b0SKonstantin Belousov i++; 244237623b0SKonstantin Belousov } 245237623b0SKonstantin Belousov sx_sunlock(&proctree_lock); 246237623b0SKonstantin Belousov error = copyout(pi, rp->rp_pids, i * sizeof(*pi)); 247237623b0SKonstantin Belousov free(pi, M_TEMP); 248237623b0SKonstantin Belousov sx_slock(&proctree_lock); 249237623b0SKonstantin Belousov PROC_LOCK(p); 250237623b0SKonstantin Belousov return (error); 251237623b0SKonstantin Belousov } 252237623b0SKonstantin Belousov 2532842ec6dSKonstantin Belousov struct reap_kill_proc_work { 2542842ec6dSKonstantin Belousov struct ucred *cr; 2552842ec6dSKonstantin Belousov struct proc *target; 2562842ec6dSKonstantin Belousov ksiginfo_t *ksi; 2572842ec6dSKonstantin Belousov struct procctl_reaper_kill *rk; 2582842ec6dSKonstantin Belousov int *error; 2592842ec6dSKonstantin Belousov struct task t; 2602842ec6dSKonstantin Belousov }; 261ee50062cSKonstantin Belousov 262addf103cSKonstantin Belousov static void 2632842ec6dSKonstantin Belousov reap_kill_proc_locked(struct reap_kill_proc_work *w) 26470978337SKonstantin Belousov { 2652842ec6dSKonstantin Belousov int error1; 26670978337SKonstantin Belousov bool need_stop; 26770978337SKonstantin Belousov 2682842ec6dSKonstantin Belousov PROC_LOCK_ASSERT(w->target, MA_OWNED); 2692842ec6dSKonstantin Belousov PROC_ASSERT_HELD(w->target); 27070978337SKonstantin Belousov 2712842ec6dSKonstantin Belousov error1 = cr_cansignal(w->cr, w->target, w->rk->rk_sig); 27270978337SKonstantin Belousov if (error1 != 0) { 2732842ec6dSKonstantin Belousov if (*w->error == ESRCH) { 2742842ec6dSKonstantin Belousov w->rk->rk_fpid = w->target->p_pid; 2752842ec6dSKonstantin Belousov *w->error = error1; 276ee50062cSKonstantin Belousov } 277addf103cSKonstantin Belousov return; 27870978337SKonstantin Belousov } 27970978337SKonstantin Belousov 28070978337SKonstantin Belousov /* 28170978337SKonstantin Belousov * The need_stop indicates if the target process needs to be 28270978337SKonstantin Belousov * suspended before being signalled. This is needed when we 28370978337SKonstantin Belousov * guarantee that all processes in subtree are signalled, 28470978337SKonstantin Belousov * avoiding the race with some process not yet fully linked 28570978337SKonstantin Belousov * into all structures during fork, ignored by iterator, and 28670978337SKonstantin Belousov * then escaping signalling. 28770978337SKonstantin Belousov * 28870978337SKonstantin Belousov * The thread cannot usefully stop itself anyway, and if other 28970978337SKonstantin Belousov * thread of the current process forks while the current 29070978337SKonstantin Belousov * thread signals the whole subtree, it is an application 29170978337SKonstantin Belousov * race. 29270978337SKonstantin Belousov */ 2932842ec6dSKonstantin Belousov if ((w->target->p_flag & (P_KPROC | P_SYSTEM | P_STOPPED)) == 0) 2942842ec6dSKonstantin Belousov need_stop = thread_single(w->target, SINGLE_ALLPROC) == 0; 2952842ec6dSKonstantin Belousov else 296addf103cSKonstantin Belousov need_stop = false; 29770978337SKonstantin Belousov 2982842ec6dSKonstantin Belousov (void)pksignal(w->target, w->rk->rk_sig, w->ksi); 2992842ec6dSKonstantin Belousov w->rk->rk_killed++; 3002842ec6dSKonstantin Belousov *w->error = error1; 30170978337SKonstantin Belousov 302addf103cSKonstantin Belousov if (need_stop) 3032842ec6dSKonstantin Belousov thread_single_end(w->target, SINGLE_ALLPROC); 30470978337SKonstantin Belousov } 30570978337SKonstantin Belousov 306addf103cSKonstantin Belousov static void 3072842ec6dSKonstantin Belousov reap_kill_proc_work(void *arg, int pending __unused) 30870978337SKonstantin Belousov { 3092842ec6dSKonstantin Belousov struct reap_kill_proc_work *w; 3102842ec6dSKonstantin Belousov 3112842ec6dSKonstantin Belousov w = arg; 3122842ec6dSKonstantin Belousov PROC_LOCK(w->target); 3132842ec6dSKonstantin Belousov if ((w->target->p_flag2 & P2_WEXIT) == 0) 3142842ec6dSKonstantin Belousov reap_kill_proc_locked(w); 3152842ec6dSKonstantin Belousov PROC_UNLOCK(w->target); 3162842ec6dSKonstantin Belousov 3172842ec6dSKonstantin Belousov sx_xlock(&proctree_lock); 3182842ec6dSKonstantin Belousov w->target = NULL; 3192842ec6dSKonstantin Belousov wakeup(&w->target); 3202842ec6dSKonstantin Belousov sx_xunlock(&proctree_lock); 321ee50062cSKonstantin Belousov } 322ee50062cSKonstantin Belousov 323ee50062cSKonstantin Belousov struct reap_kill_tracker { 324ee50062cSKonstantin Belousov struct proc *parent; 325ee50062cSKonstantin Belousov TAILQ_ENTRY(reap_kill_tracker) link; 326ee50062cSKonstantin Belousov }; 327ee50062cSKonstantin Belousov 328ee50062cSKonstantin Belousov TAILQ_HEAD(reap_kill_tracker_head, reap_kill_tracker); 329ee50062cSKonstantin Belousov 330ee50062cSKonstantin Belousov static void 331ee50062cSKonstantin Belousov reap_kill_sched(struct reap_kill_tracker_head *tracker, struct proc *p2) 332ee50062cSKonstantin Belousov { 333ee50062cSKonstantin Belousov struct reap_kill_tracker *t; 334ee50062cSKonstantin Belousov 335e0343eacSKonstantin Belousov PROC_LOCK(p2); 336e0343eacSKonstantin Belousov if ((p2->p_flag2 & P2_WEXIT) != 0) { 337e0343eacSKonstantin Belousov PROC_UNLOCK(p2); 338e0343eacSKonstantin Belousov return; 339e0343eacSKonstantin Belousov } 3408370e9dfSMark Johnston _PHOLD(p2); 341e0343eacSKonstantin Belousov PROC_UNLOCK(p2); 342ee50062cSKonstantin Belousov t = malloc(sizeof(struct reap_kill_tracker), M_TEMP, M_WAITOK); 343ee50062cSKonstantin Belousov t->parent = p2; 344ee50062cSKonstantin Belousov TAILQ_INSERT_TAIL(tracker, t, link); 345ee50062cSKonstantin Belousov } 346ee50062cSKonstantin Belousov 34754a11adbSKonstantin Belousov static void 348e0343eacSKonstantin Belousov reap_kill_sched_free(struct reap_kill_tracker *t) 349e0343eacSKonstantin Belousov { 350e0343eacSKonstantin Belousov PRELE(t->parent); 351e0343eacSKonstantin Belousov free(t, M_TEMP); 352e0343eacSKonstantin Belousov } 353e0343eacSKonstantin Belousov 354e0343eacSKonstantin Belousov static void 35554a11adbSKonstantin Belousov reap_kill_children(struct thread *td, struct proc *reaper, 35654a11adbSKonstantin Belousov struct procctl_reaper_kill *rk, ksiginfo_t *ksi, int *error) 35754a11adbSKonstantin Belousov { 35854a11adbSKonstantin Belousov struct proc *p2; 3592842ec6dSKonstantin Belousov int error1; 36054a11adbSKonstantin Belousov 36154a11adbSKonstantin Belousov LIST_FOREACH(p2, &reaper->p_children, p_sibling) { 3622842ec6dSKonstantin Belousov PROC_LOCK(p2); 3632842ec6dSKonstantin Belousov if ((p2->p_flag2 & P2_WEXIT) == 0) { 3642842ec6dSKonstantin Belousov error1 = p_cansignal(td, p2, rk->rk_sig); 3652842ec6dSKonstantin Belousov if (error1 != 0) { 3662842ec6dSKonstantin Belousov if (*error == ESRCH) { 3672842ec6dSKonstantin Belousov rk->rk_fpid = p2->p_pid; 3682842ec6dSKonstantin Belousov *error = error1; 3692842ec6dSKonstantin Belousov } 3702842ec6dSKonstantin Belousov 37154a11adbSKonstantin Belousov /* 3722842ec6dSKonstantin Belousov * Do not end the loop on error, 3732842ec6dSKonstantin Belousov * signal everything we can. 37454a11adbSKonstantin Belousov */ 3752842ec6dSKonstantin Belousov } else { 3762842ec6dSKonstantin Belousov (void)pksignal(p2, rk->rk_sig, ksi); 3772842ec6dSKonstantin Belousov rk->rk_killed++; 3782842ec6dSKonstantin Belousov } 3792842ec6dSKonstantin Belousov } 3802842ec6dSKonstantin Belousov PROC_UNLOCK(p2); 38154a11adbSKonstantin Belousov } 38254a11adbSKonstantin Belousov } 38354a11adbSKonstantin Belousov 38439794d80SKonstantin Belousov static bool 38539794d80SKonstantin Belousov reap_kill_subtree_once(struct thread *td, struct proc *p, struct proc *reaper, 3862842ec6dSKonstantin Belousov struct unrhdr *pids, struct reap_kill_proc_work *w) 38754a11adbSKonstantin Belousov { 38854a11adbSKonstantin Belousov struct reap_kill_tracker_head tracker; 38954a11adbSKonstantin Belousov struct reap_kill_tracker *t; 39054a11adbSKonstantin Belousov struct proc *p2; 3912842ec6dSKonstantin Belousov int r, xlocked; 3922842ec6dSKonstantin Belousov bool res, st; 39354a11adbSKonstantin Belousov 39439794d80SKonstantin Belousov res = false; 39554a11adbSKonstantin Belousov TAILQ_INIT(&tracker); 39654a11adbSKonstantin Belousov reap_kill_sched(&tracker, reaper); 39754a11adbSKonstantin Belousov while ((t = TAILQ_FIRST(&tracker)) != NULL) { 39854a11adbSKonstantin Belousov TAILQ_REMOVE(&tracker, t, link); 3991d4abf2cSKonstantin Belousov 4001d4abf2cSKonstantin Belousov /* 4011d4abf2cSKonstantin Belousov * Since reap_kill_proc() drops proctree_lock sx, it 4021d4abf2cSKonstantin Belousov * is possible that the tracked reaper is no longer. 4031d4abf2cSKonstantin Belousov * In this case the subtree is reparented to the new 4041d4abf2cSKonstantin Belousov * reaper, which should handle it. 4051d4abf2cSKonstantin Belousov */ 4061d4abf2cSKonstantin Belousov if ((t->parent->p_treeflag & P_TREE_REAPER) == 0) { 407e0343eacSKonstantin Belousov reap_kill_sched_free(t); 4081d4abf2cSKonstantin Belousov res = true; 4091d4abf2cSKonstantin Belousov continue; 4101d4abf2cSKonstantin Belousov } 4111d4abf2cSKonstantin Belousov 41254a11adbSKonstantin Belousov LIST_FOREACH(p2, &t->parent->p_reaplist, p_reapsibling) { 41354a11adbSKonstantin Belousov if (t->parent == reaper && 4142842ec6dSKonstantin Belousov (w->rk->rk_flags & REAPER_KILL_SUBTREE) != 0 && 4152842ec6dSKonstantin Belousov p2->p_reapsubtree != w->rk->rk_subtree) 41654a11adbSKonstantin Belousov continue; 41754a11adbSKonstantin Belousov if ((p2->p_treeflag & P_TREE_REAPER) != 0) 41854a11adbSKonstantin Belousov reap_kill_sched(&tracker, p2); 4198164032aSKonstantin Belousov 4208164032aSKonstantin Belousov /* 4218164032aSKonstantin Belousov * Handle possible pid reuse. If we recorded 4228164032aSKonstantin Belousov * p2 as killed but its p_flag2 does not 4238164032aSKonstantin Belousov * confirm it, that means that the process 4248164032aSKonstantin Belousov * terminated and its id was reused by other 4258164032aSKonstantin Belousov * process in the reaper subtree. 4268164032aSKonstantin Belousov * 4278164032aSKonstantin Belousov * Unlocked read of p2->p_flag2 is fine, it is 4288164032aSKonstantin Belousov * our thread that set the tested flag. 4298164032aSKonstantin Belousov */ 4308164032aSKonstantin Belousov if (alloc_unr_specific(pids, p2->p_pid) != p2->p_pid && 4318164032aSKonstantin Belousov (atomic_load_int(&p2->p_flag2) & 4328164032aSKonstantin Belousov (P2_REAPKILLED | P2_WEXIT)) != 0) 43370978337SKonstantin Belousov continue; 4348164032aSKonstantin Belousov 4352842ec6dSKonstantin Belousov if (p2 == td->td_proc) { 4362842ec6dSKonstantin Belousov if ((p2->p_flag & P_HADTHREADS) != 0 && 4372842ec6dSKonstantin Belousov (p2->p_flag2 & P2_WEXIT) == 0) { 4382842ec6dSKonstantin Belousov xlocked = sx_xlocked(&proctree_lock); 4392842ec6dSKonstantin Belousov sx_unlock(&proctree_lock); 4402842ec6dSKonstantin Belousov st = true; 4412842ec6dSKonstantin Belousov } else { 4422842ec6dSKonstantin Belousov st = false; 4432842ec6dSKonstantin Belousov } 4442842ec6dSKonstantin Belousov PROC_LOCK(p2); 4458164032aSKonstantin Belousov /* 4468164032aSKonstantin Belousov * sapblk ensures that only one thread 4478164032aSKonstantin Belousov * in the system sets this flag. 4488164032aSKonstantin Belousov */ 4498164032aSKonstantin Belousov p2->p_flag2 |= P2_REAPKILLED; 4502842ec6dSKonstantin Belousov if (st) 4512842ec6dSKonstantin Belousov r = thread_single(p2, SINGLE_NO_EXIT); 4522842ec6dSKonstantin Belousov (void)pksignal(p2, w->rk->rk_sig, w->ksi); 4532842ec6dSKonstantin Belousov w->rk->rk_killed++; 4542842ec6dSKonstantin Belousov if (st && r == 0) 4552842ec6dSKonstantin Belousov thread_single_end(p2, SINGLE_NO_EXIT); 4562842ec6dSKonstantin Belousov PROC_UNLOCK(p2); 4572842ec6dSKonstantin Belousov if (st) { 4582842ec6dSKonstantin Belousov if (xlocked) 4592842ec6dSKonstantin Belousov sx_xlock(&proctree_lock); 4602842ec6dSKonstantin Belousov else 4612842ec6dSKonstantin Belousov sx_slock(&proctree_lock); 4622842ec6dSKonstantin Belousov } 4632842ec6dSKonstantin Belousov } else { 4642842ec6dSKonstantin Belousov PROC_LOCK(p2); 4652842ec6dSKonstantin Belousov if ((p2->p_flag2 & P2_WEXIT) == 0) { 4668370e9dfSMark Johnston _PHOLD(p2); 4678164032aSKonstantin Belousov p2->p_flag2 |= P2_REAPKILLED; 4682842ec6dSKonstantin Belousov PROC_UNLOCK(p2); 4692842ec6dSKonstantin Belousov w->target = p2; 4702842ec6dSKonstantin Belousov taskqueue_enqueue(taskqueue_thread, 4712842ec6dSKonstantin Belousov &w->t); 4722842ec6dSKonstantin Belousov while (w->target != NULL) { 4732842ec6dSKonstantin Belousov sx_sleep(&w->target, 4742842ec6dSKonstantin Belousov &proctree_lock, PWAIT, 4752842ec6dSKonstantin Belousov "reapst", 0); 4762842ec6dSKonstantin Belousov } 4772842ec6dSKonstantin Belousov PROC_LOCK(p2); 4782842ec6dSKonstantin Belousov _PRELE(p2); 4792842ec6dSKonstantin Belousov } 4802842ec6dSKonstantin Belousov PROC_UNLOCK(p2); 4812842ec6dSKonstantin Belousov } 48239794d80SKonstantin Belousov res = true; 48339794d80SKonstantin Belousov } 484e0343eacSKonstantin Belousov reap_kill_sched_free(t); 48554a11adbSKonstantin Belousov } 48639794d80SKonstantin Belousov return (res); 48739794d80SKonstantin Belousov } 48839794d80SKonstantin Belousov 48939794d80SKonstantin Belousov static void 49039794d80SKonstantin Belousov reap_kill_subtree(struct thread *td, struct proc *p, struct proc *reaper, 4912842ec6dSKonstantin Belousov struct reap_kill_proc_work *w) 49239794d80SKonstantin Belousov { 49339794d80SKonstantin Belousov struct unrhdr pids; 4948164032aSKonstantin Belousov void *ihandle; 4958164032aSKonstantin Belousov struct proc *p2; 4968164032aSKonstantin Belousov int pid; 49739794d80SKonstantin Belousov 49839794d80SKonstantin Belousov /* 49939794d80SKonstantin Belousov * pids records processes which were already signalled, to 50039794d80SKonstantin Belousov * avoid doubling signals to them if iteration needs to be 50139794d80SKonstantin Belousov * repeated. 50239794d80SKonstantin Belousov */ 50339794d80SKonstantin Belousov init_unrhdr(&pids, 1, PID_MAX, UNR_NO_MTX); 5044493a13eSKonstantin Belousov PROC_LOCK(td->td_proc); 5054493a13eSKonstantin Belousov if ((td->td_proc->p_flag2 & P2_WEXIT) != 0) { 5064493a13eSKonstantin Belousov PROC_UNLOCK(td->td_proc); 5074493a13eSKonstantin Belousov goto out; 5084493a13eSKonstantin Belousov } 5094493a13eSKonstantin Belousov PROC_UNLOCK(td->td_proc); 5102842ec6dSKonstantin Belousov while (reap_kill_subtree_once(td, p, reaper, &pids, w)) 51139794d80SKonstantin Belousov ; 5128164032aSKonstantin Belousov 5138164032aSKonstantin Belousov ihandle = create_iter_unr(&pids); 5148164032aSKonstantin Belousov while ((pid = next_iter_unr(ihandle)) != -1) { 5158164032aSKonstantin Belousov p2 = pfind(pid); 5168164032aSKonstantin Belousov if (p2 != NULL) { 5178164032aSKonstantin Belousov p2->p_flag2 &= ~P2_REAPKILLED; 5188164032aSKonstantin Belousov PROC_UNLOCK(p2); 5198164032aSKonstantin Belousov } 5208164032aSKonstantin Belousov } 5218164032aSKonstantin Belousov free_iter_unr(ihandle); 5228164032aSKonstantin Belousov 5234493a13eSKonstantin Belousov out: 52439794d80SKonstantin Belousov clean_unrhdr(&pids); 52539794d80SKonstantin Belousov clear_unrhdr(&pids); 52654a11adbSKonstantin Belousov } 52754a11adbSKonstantin Belousov 528d1df3473SKonstantin Belousov static bool 529d1df3473SKonstantin Belousov reap_kill_sapblk(struct thread *td __unused, void *data) 530d1df3473SKonstantin Belousov { 531d1df3473SKonstantin Belousov struct procctl_reaper_kill *rk; 532d1df3473SKonstantin Belousov 533d1df3473SKonstantin Belousov rk = data; 534d1df3473SKonstantin Belousov return ((rk->rk_flags & REAPER_KILL_CHILDREN) == 0); 535d1df3473SKonstantin Belousov } 536d1df3473SKonstantin Belousov 537237623b0SKonstantin Belousov static int 53868dc5b38SKonstantin Belousov reap_kill(struct thread *td, struct proc *p, void *data) 539237623b0SKonstantin Belousov { 5402842ec6dSKonstantin Belousov struct reap_kill_proc_work w; 54154a11adbSKonstantin Belousov struct proc *reaper; 542237623b0SKonstantin Belousov ksiginfo_t ksi; 54368dc5b38SKonstantin Belousov struct procctl_reaper_kill *rk; 544ee50062cSKonstantin Belousov int error; 545237623b0SKonstantin Belousov 54668dc5b38SKonstantin Belousov rk = data; 547237623b0SKonstantin Belousov sx_assert(&proctree_lock, SX_LOCKED); 5486a4616a5SJake Freeland if (CAP_TRACING(td)) 5496a4616a5SJake Freeland ktrcapfail(CAPFAIL_SIGNAL, &rk->rk_sig); 550237623b0SKonstantin Belousov if (IN_CAPABILITY_MODE(td)) 551237623b0SKonstantin Belousov return (ECAPMODE); 552ee50062cSKonstantin Belousov if (rk->rk_sig <= 0 || rk->rk_sig > _SIG_MAXSIG || 553ee50062cSKonstantin Belousov (rk->rk_flags & ~(REAPER_KILL_CHILDREN | 554ee50062cSKonstantin Belousov REAPER_KILL_SUBTREE)) != 0 || (rk->rk_flags & 555ee50062cSKonstantin Belousov (REAPER_KILL_CHILDREN | REAPER_KILL_SUBTREE)) == 556ee50062cSKonstantin Belousov (REAPER_KILL_CHILDREN | REAPER_KILL_SUBTREE)) 557237623b0SKonstantin Belousov return (EINVAL); 5584b685a28SKonstantin Belousov PROC_UNLOCK(p); 559134529b1SKonstantin Belousov reaper = (p->p_treeflag & P_TREE_REAPER) == 0 ? p->p_reaper : p; 560237623b0SKonstantin Belousov ksiginfo_init(&ksi); 561237623b0SKonstantin Belousov ksi.ksi_signo = rk->rk_sig; 562237623b0SKonstantin Belousov ksi.ksi_code = SI_USER; 563237623b0SKonstantin Belousov ksi.ksi_pid = td->td_proc->p_pid; 564237623b0SKonstantin Belousov ksi.ksi_uid = td->td_ucred->cr_ruid; 565237623b0SKonstantin Belousov error = ESRCH; 566237623b0SKonstantin Belousov rk->rk_killed = 0; 567237623b0SKonstantin Belousov rk->rk_fpid = -1; 568ee50062cSKonstantin Belousov if ((rk->rk_flags & REAPER_KILL_CHILDREN) != 0) { 56954a11adbSKonstantin Belousov reap_kill_children(td, reaper, rk, &ksi, &error); 570ee50062cSKonstantin Belousov } else { 5712842ec6dSKonstantin Belousov w.cr = crhold(td->td_ucred); 5722842ec6dSKonstantin Belousov w.ksi = &ksi; 5732842ec6dSKonstantin Belousov w.rk = rk; 5742842ec6dSKonstantin Belousov w.error = &error; 5752842ec6dSKonstantin Belousov TASK_INIT(&w.t, 0, reap_kill_proc_work, &w); 5762842ec6dSKonstantin Belousov reap_kill_subtree(td, p, reaper, &w); 5772842ec6dSKonstantin Belousov crfree(w.cr); 578237623b0SKonstantin Belousov } 579237623b0SKonstantin Belousov PROC_LOCK(p); 580237623b0SKonstantin Belousov return (error); 581237623b0SKonstantin Belousov } 582237623b0SKonstantin Belousov 583677258f7SKonstantin Belousov static int 58468dc5b38SKonstantin Belousov trace_ctl(struct thread *td, struct proc *p, void *data) 585677258f7SKonstantin Belousov { 58668dc5b38SKonstantin Belousov int state; 587677258f7SKonstantin Belousov 588677258f7SKonstantin Belousov PROC_LOCK_ASSERT(p, MA_OWNED); 58968dc5b38SKonstantin Belousov state = *(int *)data; 590677258f7SKonstantin Belousov 591677258f7SKonstantin Belousov /* 592677258f7SKonstantin Belousov * Ktrace changes p_traceflag from or to zero under the 593677258f7SKonstantin Belousov * process lock, so the test does not need to acquire ktrace 594677258f7SKonstantin Belousov * mutex. 595677258f7SKonstantin Belousov */ 596677258f7SKonstantin Belousov if ((p->p_flag & P_TRACED) != 0 || p->p_traceflag != 0) 597677258f7SKonstantin Belousov return (EBUSY); 598677258f7SKonstantin Belousov 599677258f7SKonstantin Belousov switch (state) { 600677258f7SKonstantin Belousov case PROC_TRACE_CTL_ENABLE: 601677258f7SKonstantin Belousov if (td->td_proc != p) 602677258f7SKonstantin Belousov return (EPERM); 603677258f7SKonstantin Belousov p->p_flag2 &= ~(P2_NOTRACE | P2_NOTRACE_EXEC); 604677258f7SKonstantin Belousov break; 605677258f7SKonstantin Belousov case PROC_TRACE_CTL_DISABLE_EXEC: 606677258f7SKonstantin Belousov p->p_flag2 |= P2_NOTRACE_EXEC | P2_NOTRACE; 607677258f7SKonstantin Belousov break; 608677258f7SKonstantin Belousov case PROC_TRACE_CTL_DISABLE: 609677258f7SKonstantin Belousov if ((p->p_flag2 & P2_NOTRACE_EXEC) != 0) { 610677258f7SKonstantin Belousov KASSERT((p->p_flag2 & P2_NOTRACE) != 0, 611677258f7SKonstantin Belousov ("dandling P2_NOTRACE_EXEC")); 612677258f7SKonstantin Belousov if (td->td_proc != p) 613677258f7SKonstantin Belousov return (EPERM); 614677258f7SKonstantin Belousov p->p_flag2 &= ~P2_NOTRACE_EXEC; 615677258f7SKonstantin Belousov } else { 616677258f7SKonstantin Belousov p->p_flag2 |= P2_NOTRACE; 617677258f7SKonstantin Belousov } 618677258f7SKonstantin Belousov break; 619677258f7SKonstantin Belousov default: 620677258f7SKonstantin Belousov return (EINVAL); 621677258f7SKonstantin Belousov } 622677258f7SKonstantin Belousov return (0); 623677258f7SKonstantin Belousov } 624677258f7SKonstantin Belousov 625677258f7SKonstantin Belousov static int 62668dc5b38SKonstantin Belousov trace_status(struct thread *td, struct proc *p, void *data) 627677258f7SKonstantin Belousov { 62868dc5b38SKonstantin Belousov int *status; 629677258f7SKonstantin Belousov 63068dc5b38SKonstantin Belousov status = data; 631677258f7SKonstantin Belousov if ((p->p_flag2 & P2_NOTRACE) != 0) { 632677258f7SKonstantin Belousov KASSERT((p->p_flag & P_TRACED) == 0, 633677258f7SKonstantin Belousov ("%d traced but tracing disabled", p->p_pid)); 63468dc5b38SKonstantin Belousov *status = -1; 635677258f7SKonstantin Belousov } else if ((p->p_flag & P_TRACED) != 0) { 63668dc5b38SKonstantin Belousov *status = p->p_pptr->p_pid; 637677258f7SKonstantin Belousov } else { 63868dc5b38SKonstantin Belousov *status = 0; 639677258f7SKonstantin Belousov } 640677258f7SKonstantin Belousov return (0); 641677258f7SKonstantin Belousov } 642677258f7SKonstantin Belousov 643643f6f47SKonstantin Belousov static int 64468dc5b38SKonstantin Belousov trapcap_ctl(struct thread *td, struct proc *p, void *data) 645643f6f47SKonstantin Belousov { 64668dc5b38SKonstantin Belousov int state; 647643f6f47SKonstantin Belousov 648643f6f47SKonstantin Belousov PROC_LOCK_ASSERT(p, MA_OWNED); 64968dc5b38SKonstantin Belousov state = *(int *)data; 650643f6f47SKonstantin Belousov 651643f6f47SKonstantin Belousov switch (state) { 652643f6f47SKonstantin Belousov case PROC_TRAPCAP_CTL_ENABLE: 653643f6f47SKonstantin Belousov p->p_flag2 |= P2_TRAPCAP; 654643f6f47SKonstantin Belousov break; 655643f6f47SKonstantin Belousov case PROC_TRAPCAP_CTL_DISABLE: 656643f6f47SKonstantin Belousov p->p_flag2 &= ~P2_TRAPCAP; 657643f6f47SKonstantin Belousov break; 658643f6f47SKonstantin Belousov default: 659643f6f47SKonstantin Belousov return (EINVAL); 660643f6f47SKonstantin Belousov } 661643f6f47SKonstantin Belousov return (0); 662643f6f47SKonstantin Belousov } 663643f6f47SKonstantin Belousov 664643f6f47SKonstantin Belousov static int 66568dc5b38SKonstantin Belousov trapcap_status(struct thread *td, struct proc *p, void *data) 666643f6f47SKonstantin Belousov { 66768dc5b38SKonstantin Belousov int *status; 668643f6f47SKonstantin Belousov 66968dc5b38SKonstantin Belousov status = data; 67068dc5b38SKonstantin Belousov *status = (p->p_flag2 & P2_TRAPCAP) != 0 ? PROC_TRAPCAP_CTL_ENABLE : 671643f6f47SKonstantin Belousov PROC_TRAPCAP_CTL_DISABLE; 672643f6f47SKonstantin Belousov return (0); 673643f6f47SKonstantin Belousov } 674643f6f47SKonstantin Belousov 675fa50a355SKonstantin Belousov static int 67668dc5b38SKonstantin Belousov no_new_privs_ctl(struct thread *td, struct proc *p, void *data) 677db8d680eSEdward Tomasz Napierala { 67868dc5b38SKonstantin Belousov int state; 679db8d680eSEdward Tomasz Napierala 680db8d680eSEdward Tomasz Napierala PROC_LOCK_ASSERT(p, MA_OWNED); 68168dc5b38SKonstantin Belousov state = *(int *)data; 682db8d680eSEdward Tomasz Napierala 683db8d680eSEdward Tomasz Napierala if (state != PROC_NO_NEW_PRIVS_ENABLE) 684db8d680eSEdward Tomasz Napierala return (EINVAL); 685db8d680eSEdward Tomasz Napierala p->p_flag2 |= P2_NO_NEW_PRIVS; 686db8d680eSEdward Tomasz Napierala return (0); 687db8d680eSEdward Tomasz Napierala } 688db8d680eSEdward Tomasz Napierala 689db8d680eSEdward Tomasz Napierala static int 69068dc5b38SKonstantin Belousov no_new_privs_status(struct thread *td, struct proc *p, void *data) 691db8d680eSEdward Tomasz Napierala { 692db8d680eSEdward Tomasz Napierala 69368dc5b38SKonstantin Belousov *(int *)data = (p->p_flag2 & P2_NO_NEW_PRIVS) != 0 ? 694db8d680eSEdward Tomasz Napierala PROC_NO_NEW_PRIVS_ENABLE : PROC_NO_NEW_PRIVS_DISABLE; 695db8d680eSEdward Tomasz Napierala return (0); 696db8d680eSEdward Tomasz Napierala } 697db8d680eSEdward Tomasz Napierala 698db8d680eSEdward Tomasz Napierala static int 69968dc5b38SKonstantin Belousov protmax_ctl(struct thread *td, struct proc *p, void *data) 7005dc7e31aSKonstantin Belousov { 70168dc5b38SKonstantin Belousov int state; 70268dc5b38SKonstantin Belousov 7035dc7e31aSKonstantin Belousov PROC_LOCK_ASSERT(p, MA_OWNED); 70468dc5b38SKonstantin Belousov state = *(int *)data; 7055dc7e31aSKonstantin Belousov 7065dc7e31aSKonstantin Belousov switch (state) { 7075dc7e31aSKonstantin Belousov case PROC_PROTMAX_FORCE_ENABLE: 7085dc7e31aSKonstantin Belousov p->p_flag2 &= ~P2_PROTMAX_DISABLE; 7095dc7e31aSKonstantin Belousov p->p_flag2 |= P2_PROTMAX_ENABLE; 7105dc7e31aSKonstantin Belousov break; 7115dc7e31aSKonstantin Belousov case PROC_PROTMAX_FORCE_DISABLE: 7125dc7e31aSKonstantin Belousov p->p_flag2 |= P2_PROTMAX_DISABLE; 7135dc7e31aSKonstantin Belousov p->p_flag2 &= ~P2_PROTMAX_ENABLE; 7145dc7e31aSKonstantin Belousov break; 7155dc7e31aSKonstantin Belousov case PROC_PROTMAX_NOFORCE: 7165dc7e31aSKonstantin Belousov p->p_flag2 &= ~(P2_PROTMAX_ENABLE | P2_PROTMAX_DISABLE); 7175dc7e31aSKonstantin Belousov break; 7185dc7e31aSKonstantin Belousov default: 7195dc7e31aSKonstantin Belousov return (EINVAL); 7205dc7e31aSKonstantin Belousov } 7215dc7e31aSKonstantin Belousov return (0); 7225dc7e31aSKonstantin Belousov } 7235dc7e31aSKonstantin Belousov 7245dc7e31aSKonstantin Belousov static int 72568dc5b38SKonstantin Belousov protmax_status(struct thread *td, struct proc *p, void *data) 7265dc7e31aSKonstantin Belousov { 7275dc7e31aSKonstantin Belousov int d; 7285dc7e31aSKonstantin Belousov 7295dc7e31aSKonstantin Belousov switch (p->p_flag2 & (P2_PROTMAX_ENABLE | P2_PROTMAX_DISABLE)) { 7305dc7e31aSKonstantin Belousov case 0: 731dd175b11SEd Maste d = PROC_PROTMAX_NOFORCE; 7325dc7e31aSKonstantin Belousov break; 7335dc7e31aSKonstantin Belousov case P2_PROTMAX_ENABLE: 7345dc7e31aSKonstantin Belousov d = PROC_PROTMAX_FORCE_ENABLE; 7355dc7e31aSKonstantin Belousov break; 7365dc7e31aSKonstantin Belousov case P2_PROTMAX_DISABLE: 7375dc7e31aSKonstantin Belousov d = PROC_PROTMAX_FORCE_DISABLE; 7385dc7e31aSKonstantin Belousov break; 7395dc7e31aSKonstantin Belousov } 7405dc7e31aSKonstantin Belousov if (kern_mmap_maxprot(p, PROT_READ) == PROT_READ) 7415dc7e31aSKonstantin Belousov d |= PROC_PROTMAX_ACTIVE; 74268dc5b38SKonstantin Belousov *(int *)data = d; 7435dc7e31aSKonstantin Belousov return (0); 7445dc7e31aSKonstantin Belousov } 7455dc7e31aSKonstantin Belousov 7465dc7e31aSKonstantin Belousov static int 74768dc5b38SKonstantin Belousov aslr_ctl(struct thread *td, struct proc *p, void *data) 748fa50a355SKonstantin Belousov { 74968dc5b38SKonstantin Belousov int state; 750fa50a355SKonstantin Belousov 751fa50a355SKonstantin Belousov PROC_LOCK_ASSERT(p, MA_OWNED); 75268dc5b38SKonstantin Belousov state = *(int *)data; 753fa50a355SKonstantin Belousov 754fa50a355SKonstantin Belousov switch (state) { 755fa50a355SKonstantin Belousov case PROC_ASLR_FORCE_ENABLE: 756fa50a355SKonstantin Belousov p->p_flag2 &= ~P2_ASLR_DISABLE; 757fa50a355SKonstantin Belousov p->p_flag2 |= P2_ASLR_ENABLE; 758fa50a355SKonstantin Belousov break; 759fa50a355SKonstantin Belousov case PROC_ASLR_FORCE_DISABLE: 760fa50a355SKonstantin Belousov p->p_flag2 |= P2_ASLR_DISABLE; 761fa50a355SKonstantin Belousov p->p_flag2 &= ~P2_ASLR_ENABLE; 762fa50a355SKonstantin Belousov break; 763fa50a355SKonstantin Belousov case PROC_ASLR_NOFORCE: 764fa50a355SKonstantin Belousov p->p_flag2 &= ~(P2_ASLR_ENABLE | P2_ASLR_DISABLE); 765fa50a355SKonstantin Belousov break; 766fa50a355SKonstantin Belousov default: 767fa50a355SKonstantin Belousov return (EINVAL); 768fa50a355SKonstantin Belousov } 769fa50a355SKonstantin Belousov return (0); 770fa50a355SKonstantin Belousov } 771fa50a355SKonstantin Belousov 772fa50a355SKonstantin Belousov static int 77368dc5b38SKonstantin Belousov aslr_status(struct thread *td, struct proc *p, void *data) 774fa50a355SKonstantin Belousov { 775fa50a355SKonstantin Belousov struct vmspace *vm; 776fa50a355SKonstantin Belousov int d; 777fa50a355SKonstantin Belousov 778fa50a355SKonstantin Belousov switch (p->p_flag2 & (P2_ASLR_ENABLE | P2_ASLR_DISABLE)) { 779fa50a355SKonstantin Belousov case 0: 780fa50a355SKonstantin Belousov d = PROC_ASLR_NOFORCE; 781fa50a355SKonstantin Belousov break; 782fa50a355SKonstantin Belousov case P2_ASLR_ENABLE: 783fa50a355SKonstantin Belousov d = PROC_ASLR_FORCE_ENABLE; 784fa50a355SKonstantin Belousov break; 785fa50a355SKonstantin Belousov case P2_ASLR_DISABLE: 786fa50a355SKonstantin Belousov d = PROC_ASLR_FORCE_DISABLE; 787fa50a355SKonstantin Belousov break; 788fa50a355SKonstantin Belousov } 789fa50a355SKonstantin Belousov if ((p->p_flag & P_WEXIT) == 0) { 790fa50a355SKonstantin Belousov _PHOLD(p); 791fa50a355SKonstantin Belousov PROC_UNLOCK(p); 792fa50a355SKonstantin Belousov vm = vmspace_acquire_ref(p); 7930bdb2cbfSKonstantin Belousov if (vm != NULL) { 7940bdb2cbfSKonstantin Belousov if ((vm->vm_map.flags & MAP_ASLR) != 0) 795fa50a355SKonstantin Belousov d |= PROC_ASLR_ACTIVE; 796fa50a355SKonstantin Belousov vmspace_free(vm); 797fa50a355SKonstantin Belousov } 798fa50a355SKonstantin Belousov PROC_LOCK(p); 799fa50a355SKonstantin Belousov _PRELE(p); 800fa50a355SKonstantin Belousov } 80168dc5b38SKonstantin Belousov *(int *)data = d; 802fa50a355SKonstantin Belousov return (0); 803fa50a355SKonstantin Belousov } 804fa50a355SKonstantin Belousov 805fe69291fSKonstantin Belousov static int 80668dc5b38SKonstantin Belousov stackgap_ctl(struct thread *td, struct proc *p, void *data) 807fe69291fSKonstantin Belousov { 80868dc5b38SKonstantin Belousov int state; 80968dc5b38SKonstantin Belousov 810fe69291fSKonstantin Belousov PROC_LOCK_ASSERT(p, MA_OWNED); 81168dc5b38SKonstantin Belousov state = *(int *)data; 812fe69291fSKonstantin Belousov 813fe69291fSKonstantin Belousov if ((state & ~(PROC_STACKGAP_ENABLE | PROC_STACKGAP_DISABLE | 814fe69291fSKonstantin Belousov PROC_STACKGAP_ENABLE_EXEC | PROC_STACKGAP_DISABLE_EXEC)) != 0) 815fe69291fSKonstantin Belousov return (EINVAL); 816fe69291fSKonstantin Belousov switch (state & (PROC_STACKGAP_ENABLE | PROC_STACKGAP_DISABLE)) { 817fe69291fSKonstantin Belousov case PROC_STACKGAP_ENABLE: 818fe69291fSKonstantin Belousov if ((p->p_flag2 & P2_STKGAP_DISABLE) != 0) 819fe69291fSKonstantin Belousov return (EINVAL); 820fe69291fSKonstantin Belousov break; 821fe69291fSKonstantin Belousov case PROC_STACKGAP_DISABLE: 822fe69291fSKonstantin Belousov p->p_flag2 |= P2_STKGAP_DISABLE; 823fe69291fSKonstantin Belousov break; 824fe69291fSKonstantin Belousov case 0: 825fe69291fSKonstantin Belousov break; 826fe69291fSKonstantin Belousov default: 827fe69291fSKonstantin Belousov return (EINVAL); 828fe69291fSKonstantin Belousov } 829fe69291fSKonstantin Belousov switch (state & (PROC_STACKGAP_ENABLE_EXEC | 830fe69291fSKonstantin Belousov PROC_STACKGAP_DISABLE_EXEC)) { 831fe69291fSKonstantin Belousov case PROC_STACKGAP_ENABLE_EXEC: 832fe69291fSKonstantin Belousov p->p_flag2 &= ~P2_STKGAP_DISABLE_EXEC; 833fe69291fSKonstantin Belousov break; 834fe69291fSKonstantin Belousov case PROC_STACKGAP_DISABLE_EXEC: 835fe69291fSKonstantin Belousov p->p_flag2 |= P2_STKGAP_DISABLE_EXEC; 836fe69291fSKonstantin Belousov break; 837fe69291fSKonstantin Belousov case 0: 838fe69291fSKonstantin Belousov break; 839fe69291fSKonstantin Belousov default: 840fe69291fSKonstantin Belousov return (EINVAL); 841fe69291fSKonstantin Belousov } 842fe69291fSKonstantin Belousov return (0); 843fe69291fSKonstantin Belousov } 844fe69291fSKonstantin Belousov 845fe69291fSKonstantin Belousov static int 84668dc5b38SKonstantin Belousov stackgap_status(struct thread *td, struct proc *p, void *data) 847fe69291fSKonstantin Belousov { 84868dc5b38SKonstantin Belousov int d; 84968dc5b38SKonstantin Belousov 850fe69291fSKonstantin Belousov PROC_LOCK_ASSERT(p, MA_OWNED); 851fe69291fSKonstantin Belousov 85268dc5b38SKonstantin Belousov d = (p->p_flag2 & P2_STKGAP_DISABLE) != 0 ? PROC_STACKGAP_DISABLE : 853fe69291fSKonstantin Belousov PROC_STACKGAP_ENABLE; 85468dc5b38SKonstantin Belousov d |= (p->p_flag2 & P2_STKGAP_DISABLE_EXEC) != 0 ? 855fe69291fSKonstantin Belousov PROC_STACKGAP_DISABLE_EXEC : PROC_STACKGAP_ENABLE_EXEC; 85668dc5b38SKonstantin Belousov *(int *)data = d; 857fe69291fSKonstantin Belousov return (0); 858fe69291fSKonstantin Belousov } 859fe69291fSKonstantin Belousov 860796a8e1aSKonstantin Belousov static int 86168dc5b38SKonstantin Belousov wxmap_ctl(struct thread *td, struct proc *p, void *data) 862796a8e1aSKonstantin Belousov { 863796a8e1aSKonstantin Belousov struct vmspace *vm; 864796a8e1aSKonstantin Belousov vm_map_t map; 86568dc5b38SKonstantin Belousov int state; 866796a8e1aSKonstantin Belousov 867796a8e1aSKonstantin Belousov PROC_LOCK_ASSERT(p, MA_OWNED); 868796a8e1aSKonstantin Belousov if ((p->p_flag & P_WEXIT) != 0) 869796a8e1aSKonstantin Belousov return (ESRCH); 87068dc5b38SKonstantin Belousov state = *(int *)data; 871796a8e1aSKonstantin Belousov 872796a8e1aSKonstantin Belousov switch (state) { 873796a8e1aSKonstantin Belousov case PROC_WX_MAPPINGS_PERMIT: 874796a8e1aSKonstantin Belousov p->p_flag2 |= P2_WXORX_DISABLE; 875796a8e1aSKonstantin Belousov _PHOLD(p); 876796a8e1aSKonstantin Belousov PROC_UNLOCK(p); 877796a8e1aSKonstantin Belousov vm = vmspace_acquire_ref(p); 878796a8e1aSKonstantin Belousov if (vm != NULL) { 879796a8e1aSKonstantin Belousov map = &vm->vm_map; 880796a8e1aSKonstantin Belousov vm_map_lock(map); 881796a8e1aSKonstantin Belousov map->flags &= ~MAP_WXORX; 882796a8e1aSKonstantin Belousov vm_map_unlock(map); 883796a8e1aSKonstantin Belousov vmspace_free(vm); 884796a8e1aSKonstantin Belousov } 885796a8e1aSKonstantin Belousov PROC_LOCK(p); 886796a8e1aSKonstantin Belousov _PRELE(p); 887796a8e1aSKonstantin Belousov break; 888796a8e1aSKonstantin Belousov case PROC_WX_MAPPINGS_DISALLOW_EXEC: 889796a8e1aSKonstantin Belousov p->p_flag2 |= P2_WXORX_ENABLE_EXEC; 890796a8e1aSKonstantin Belousov break; 891796a8e1aSKonstantin Belousov default: 892796a8e1aSKonstantin Belousov return (EINVAL); 893796a8e1aSKonstantin Belousov } 894796a8e1aSKonstantin Belousov 895796a8e1aSKonstantin Belousov return (0); 896796a8e1aSKonstantin Belousov } 897796a8e1aSKonstantin Belousov 898796a8e1aSKonstantin Belousov static int 89968dc5b38SKonstantin Belousov wxmap_status(struct thread *td, struct proc *p, void *data) 900796a8e1aSKonstantin Belousov { 901796a8e1aSKonstantin Belousov struct vmspace *vm; 902796a8e1aSKonstantin Belousov int d; 903796a8e1aSKonstantin Belousov 904796a8e1aSKonstantin Belousov PROC_LOCK_ASSERT(p, MA_OWNED); 905796a8e1aSKonstantin Belousov if ((p->p_flag & P_WEXIT) != 0) 906796a8e1aSKonstantin Belousov return (ESRCH); 907796a8e1aSKonstantin Belousov 908796a8e1aSKonstantin Belousov d = 0; 909796a8e1aSKonstantin Belousov if ((p->p_flag2 & P2_WXORX_DISABLE) != 0) 910796a8e1aSKonstantin Belousov d |= PROC_WX_MAPPINGS_PERMIT; 911796a8e1aSKonstantin Belousov if ((p->p_flag2 & P2_WXORX_ENABLE_EXEC) != 0) 912796a8e1aSKonstantin Belousov d |= PROC_WX_MAPPINGS_DISALLOW_EXEC; 913796a8e1aSKonstantin Belousov _PHOLD(p); 914796a8e1aSKonstantin Belousov PROC_UNLOCK(p); 915796a8e1aSKonstantin Belousov vm = vmspace_acquire_ref(p); 916796a8e1aSKonstantin Belousov if (vm != NULL) { 917796a8e1aSKonstantin Belousov if ((vm->vm_map.flags & MAP_WXORX) != 0) 918796a8e1aSKonstantin Belousov d |= PROC_WXORX_ENFORCE; 919796a8e1aSKonstantin Belousov vmspace_free(vm); 920796a8e1aSKonstantin Belousov } 921796a8e1aSKonstantin Belousov PROC_LOCK(p); 922796a8e1aSKonstantin Belousov _PRELE(p); 92368dc5b38SKonstantin Belousov *(int *)data = d; 924796a8e1aSKonstantin Belousov return (0); 925796a8e1aSKonstantin Belousov } 926796a8e1aSKonstantin Belousov 92734f39a8cSKonstantin Belousov static int 92868dc5b38SKonstantin Belousov pdeathsig_ctl(struct thread *td, struct proc *p, void *data) 92934f39a8cSKonstantin Belousov { 93068dc5b38SKonstantin Belousov int signum; 93168dc5b38SKonstantin Belousov 93268dc5b38SKonstantin Belousov signum = *(int *)data; 93368dc5b38SKonstantin Belousov if (p != td->td_proc || (signum != 0 && !_SIG_VALID(signum))) 93434f39a8cSKonstantin Belousov return (EINVAL); 93568dc5b38SKonstantin Belousov p->p_pdeathsig = signum; 93634f39a8cSKonstantin Belousov return (0); 93734f39a8cSKonstantin Belousov } 93834f39a8cSKonstantin Belousov 93934f39a8cSKonstantin Belousov static int 94068dc5b38SKonstantin Belousov pdeathsig_status(struct thread *td, struct proc *p, void *data) 94134f39a8cSKonstantin Belousov { 94234f39a8cSKonstantin Belousov if (p != td->td_proc) 94334f39a8cSKonstantin Belousov return (EINVAL); 94434f39a8cSKonstantin Belousov *(int *)data = p->p_pdeathsig; 94534f39a8cSKonstantin Belousov return (0); 94634f39a8cSKonstantin Belousov } 94734f39a8cSKonstantin Belousov 948*dabf006aSKyle Evans static int 949*dabf006aSKyle Evans logsigexit_ctl(struct thread *td, struct proc *p, void *data) 950*dabf006aSKyle Evans { 951*dabf006aSKyle Evans int state; 952*dabf006aSKyle Evans 953*dabf006aSKyle Evans PROC_LOCK_ASSERT(p, MA_OWNED); 954*dabf006aSKyle Evans state = *(int *)data; 955*dabf006aSKyle Evans 956*dabf006aSKyle Evans switch (state) { 957*dabf006aSKyle Evans case PROC_LOGSIGEXIT_CTL_NOFORCE: 958*dabf006aSKyle Evans p->p_flag2 &= ~(P2_LOGSIGEXIT_CTL | P2_LOGSIGEXIT_ENABLE); 959*dabf006aSKyle Evans break; 960*dabf006aSKyle Evans case PROC_LOGSIGEXIT_CTL_FORCE_ENABLE: 961*dabf006aSKyle Evans p->p_flag2 |= P2_LOGSIGEXIT_CTL | P2_LOGSIGEXIT_ENABLE; 962*dabf006aSKyle Evans break; 963*dabf006aSKyle Evans case PROC_LOGSIGEXIT_CTL_FORCE_DISABLE: 964*dabf006aSKyle Evans p->p_flag2 |= P2_LOGSIGEXIT_CTL; 965*dabf006aSKyle Evans p->p_flag2 &= ~P2_LOGSIGEXIT_ENABLE; 966*dabf006aSKyle Evans break; 967*dabf006aSKyle Evans default: 968*dabf006aSKyle Evans return (EINVAL); 969*dabf006aSKyle Evans } 970*dabf006aSKyle Evans return (0); 971*dabf006aSKyle Evans } 972*dabf006aSKyle Evans 973*dabf006aSKyle Evans static int 974*dabf006aSKyle Evans logsigexit_status(struct thread *td, struct proc *p, void *data) 975*dabf006aSKyle Evans { 976*dabf006aSKyle Evans int state; 977*dabf006aSKyle Evans 978*dabf006aSKyle Evans if ((p->p_flag2 & P2_LOGSIGEXIT_CTL) == 0) 979*dabf006aSKyle Evans state = PROC_LOGSIGEXIT_CTL_NOFORCE; 980*dabf006aSKyle Evans else if ((p->p_flag2 & P2_LOGSIGEXIT_ENABLE) != 0) 981*dabf006aSKyle Evans state = PROC_LOGSIGEXIT_CTL_FORCE_ENABLE; 982*dabf006aSKyle Evans else 983*dabf006aSKyle Evans state = PROC_LOGSIGEXIT_CTL_FORCE_DISABLE; 984*dabf006aSKyle Evans *(int *)data = state; 985*dabf006aSKyle Evans return (0); 986*dabf006aSKyle Evans } 987*dabf006aSKyle Evans 988c7f38a2dSKonstantin Belousov enum { 989c7f38a2dSKonstantin Belousov PCTL_SLOCKED, 990c7f38a2dSKonstantin Belousov PCTL_XLOCKED, 991c7f38a2dSKonstantin Belousov PCTL_UNLOCKED, 992c7f38a2dSKonstantin Belousov }; 993c7f38a2dSKonstantin Belousov 9947ae879b1SKonstantin Belousov struct procctl_cmd_info { 9957ae879b1SKonstantin Belousov int lock_tree; 9967ae879b1SKonstantin Belousov bool one_proc : 1; 99734f39a8cSKonstantin Belousov bool esrch_is_einval : 1; 99856d5323bSKonstantin Belousov bool copyout_on_error : 1; 99956d5323bSKonstantin Belousov bool no_nonnull_data : 1; 10001c4dbee5SKonstantin Belousov bool need_candebug : 1; 100156d5323bSKonstantin Belousov int copyin_sz; 100256d5323bSKonstantin Belousov int copyout_sz; 100368dc5b38SKonstantin Belousov int (*exec)(struct thread *, struct proc *, void *); 1004d1df3473SKonstantin Belousov bool (*sapblk)(struct thread *, void *); 10057ae879b1SKonstantin Belousov }; 10067ae879b1SKonstantin Belousov static const struct procctl_cmd_info procctl_cmds_info[] = { 10077ae879b1SKonstantin Belousov [PROC_SPROTECT] = 1008c7f38a2dSKonstantin Belousov { .lock_tree = PCTL_SLOCKED, .one_proc = false, 100956d5323bSKonstantin Belousov .esrch_is_einval = false, .no_nonnull_data = false, 10101c4dbee5SKonstantin Belousov .need_candebug = false, 101156d5323bSKonstantin Belousov .copyin_sz = sizeof(int), .copyout_sz = 0, 101256d5323bSKonstantin Belousov .exec = protect_set, .copyout_on_error = false, }, 10137ae879b1SKonstantin Belousov [PROC_REAP_ACQUIRE] = 1014c7f38a2dSKonstantin Belousov { .lock_tree = PCTL_XLOCKED, .one_proc = true, 101556d5323bSKonstantin Belousov .esrch_is_einval = false, .no_nonnull_data = true, 10161c4dbee5SKonstantin Belousov .need_candebug = false, 101756d5323bSKonstantin Belousov .copyin_sz = 0, .copyout_sz = 0, 101856d5323bSKonstantin Belousov .exec = reap_acquire, .copyout_on_error = false, }, 10197ae879b1SKonstantin Belousov [PROC_REAP_RELEASE] = 1020c7f38a2dSKonstantin Belousov { .lock_tree = PCTL_XLOCKED, .one_proc = true, 102156d5323bSKonstantin Belousov .esrch_is_einval = false, .no_nonnull_data = true, 10221c4dbee5SKonstantin Belousov .need_candebug = false, 102356d5323bSKonstantin Belousov .copyin_sz = 0, .copyout_sz = 0, 102456d5323bSKonstantin Belousov .exec = reap_release, .copyout_on_error = false, }, 10257ae879b1SKonstantin Belousov [PROC_REAP_STATUS] = 1026c7f38a2dSKonstantin Belousov { .lock_tree = PCTL_SLOCKED, .one_proc = true, 102756d5323bSKonstantin Belousov .esrch_is_einval = false, .no_nonnull_data = false, 10281c4dbee5SKonstantin Belousov .need_candebug = false, 102956d5323bSKonstantin Belousov .copyin_sz = 0, 103056d5323bSKonstantin Belousov .copyout_sz = sizeof(struct procctl_reaper_status), 103156d5323bSKonstantin Belousov .exec = reap_status, .copyout_on_error = false, }, 10327ae879b1SKonstantin Belousov [PROC_REAP_GETPIDS] = 1033c7f38a2dSKonstantin Belousov { .lock_tree = PCTL_SLOCKED, .one_proc = true, 103456d5323bSKonstantin Belousov .esrch_is_einval = false, .no_nonnull_data = false, 10351c4dbee5SKonstantin Belousov .need_candebug = false, 103656d5323bSKonstantin Belousov .copyin_sz = sizeof(struct procctl_reaper_pids), 103756d5323bSKonstantin Belousov .copyout_sz = 0, 103856d5323bSKonstantin Belousov .exec = reap_getpids, .copyout_on_error = false, }, 10397ae879b1SKonstantin Belousov [PROC_REAP_KILL] = 1040c7f38a2dSKonstantin Belousov { .lock_tree = PCTL_SLOCKED, .one_proc = true, 104156d5323bSKonstantin Belousov .esrch_is_einval = false, .no_nonnull_data = false, 10421c4dbee5SKonstantin Belousov .need_candebug = false, 104356d5323bSKonstantin Belousov .copyin_sz = sizeof(struct procctl_reaper_kill), 104456d5323bSKonstantin Belousov .copyout_sz = sizeof(struct procctl_reaper_kill), 1045d1df3473SKonstantin Belousov .exec = reap_kill, .copyout_on_error = true, 1046d1df3473SKonstantin Belousov .sapblk = reap_kill_sapblk, }, 10477ae879b1SKonstantin Belousov [PROC_TRACE_CTL] = 1048c7f38a2dSKonstantin Belousov { .lock_tree = PCTL_SLOCKED, .one_proc = false, 104956d5323bSKonstantin Belousov .esrch_is_einval = false, .no_nonnull_data = false, 1050f5bb6e5aSKonstantin Belousov .need_candebug = true, 105156d5323bSKonstantin Belousov .copyin_sz = sizeof(int), .copyout_sz = 0, 105256d5323bSKonstantin Belousov .exec = trace_ctl, .copyout_on_error = false, }, 10537ae879b1SKonstantin Belousov [PROC_TRACE_STATUS] = 1054c7f38a2dSKonstantin Belousov { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 105556d5323bSKonstantin Belousov .esrch_is_einval = false, .no_nonnull_data = false, 10561c4dbee5SKonstantin Belousov .need_candebug = false, 105756d5323bSKonstantin Belousov .copyin_sz = 0, .copyout_sz = sizeof(int), 105856d5323bSKonstantin Belousov .exec = trace_status, .copyout_on_error = false, }, 10597ae879b1SKonstantin Belousov [PROC_TRAPCAP_CTL] = 1060c7f38a2dSKonstantin Belousov { .lock_tree = PCTL_SLOCKED, .one_proc = false, 106156d5323bSKonstantin Belousov .esrch_is_einval = false, .no_nonnull_data = false, 1062f5bb6e5aSKonstantin Belousov .need_candebug = true, 106356d5323bSKonstantin Belousov .copyin_sz = sizeof(int), .copyout_sz = 0, 106456d5323bSKonstantin Belousov .exec = trapcap_ctl, .copyout_on_error = false, }, 10657ae879b1SKonstantin Belousov [PROC_TRAPCAP_STATUS] = 1066c7f38a2dSKonstantin Belousov { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 106756d5323bSKonstantin Belousov .esrch_is_einval = false, .no_nonnull_data = false, 10681c4dbee5SKonstantin Belousov .need_candebug = false, 106956d5323bSKonstantin Belousov .copyin_sz = 0, .copyout_sz = sizeof(int), 107056d5323bSKonstantin Belousov .exec = trapcap_status, .copyout_on_error = false, }, 10717ae879b1SKonstantin Belousov [PROC_PDEATHSIG_CTL] = 1072c7f38a2dSKonstantin Belousov { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 107356d5323bSKonstantin Belousov .esrch_is_einval = true, .no_nonnull_data = false, 10741c4dbee5SKonstantin Belousov .need_candebug = false, 107556d5323bSKonstantin Belousov .copyin_sz = sizeof(int), .copyout_sz = 0, 107656d5323bSKonstantin Belousov .exec = pdeathsig_ctl, .copyout_on_error = false, }, 10777ae879b1SKonstantin Belousov [PROC_PDEATHSIG_STATUS] = 1078c7f38a2dSKonstantin Belousov { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 107956d5323bSKonstantin Belousov .esrch_is_einval = true, .no_nonnull_data = false, 10801c4dbee5SKonstantin Belousov .need_candebug = false, 108156d5323bSKonstantin Belousov .copyin_sz = 0, .copyout_sz = sizeof(int), 108256d5323bSKonstantin Belousov .exec = pdeathsig_status, .copyout_on_error = false, }, 10837ae879b1SKonstantin Belousov [PROC_ASLR_CTL] = 1084c7f38a2dSKonstantin Belousov { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 108556d5323bSKonstantin Belousov .esrch_is_einval = false, .no_nonnull_data = false, 1086f5bb6e5aSKonstantin Belousov .need_candebug = true, 108756d5323bSKonstantin Belousov .copyin_sz = sizeof(int), .copyout_sz = 0, 108856d5323bSKonstantin Belousov .exec = aslr_ctl, .copyout_on_error = false, }, 10897ae879b1SKonstantin Belousov [PROC_ASLR_STATUS] = 1090c7f38a2dSKonstantin Belousov { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 109156d5323bSKonstantin Belousov .esrch_is_einval = false, .no_nonnull_data = false, 10921c4dbee5SKonstantin Belousov .need_candebug = false, 109356d5323bSKonstantin Belousov .copyin_sz = 0, .copyout_sz = sizeof(int), 109456d5323bSKonstantin Belousov .exec = aslr_status, .copyout_on_error = false, }, 10957ae879b1SKonstantin Belousov [PROC_PROTMAX_CTL] = 1096c7f38a2dSKonstantin Belousov { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 109756d5323bSKonstantin Belousov .esrch_is_einval = false, .no_nonnull_data = false, 1098f5bb6e5aSKonstantin Belousov .need_candebug = true, 109956d5323bSKonstantin Belousov .copyin_sz = sizeof(int), .copyout_sz = 0, 110056d5323bSKonstantin Belousov .exec = protmax_ctl, .copyout_on_error = false, }, 11017ae879b1SKonstantin Belousov [PROC_PROTMAX_STATUS] = 1102c7f38a2dSKonstantin Belousov { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 110356d5323bSKonstantin Belousov .esrch_is_einval = false, .no_nonnull_data = false, 11041c4dbee5SKonstantin Belousov .need_candebug = false, 110556d5323bSKonstantin Belousov .copyin_sz = 0, .copyout_sz = sizeof(int), 110656d5323bSKonstantin Belousov .exec = protmax_status, .copyout_on_error = false, }, 11077ae879b1SKonstantin Belousov [PROC_STACKGAP_CTL] = 1108c7f38a2dSKonstantin Belousov { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 110956d5323bSKonstantin Belousov .esrch_is_einval = false, .no_nonnull_data = false, 1110f5bb6e5aSKonstantin Belousov .need_candebug = true, 111156d5323bSKonstantin Belousov .copyin_sz = sizeof(int), .copyout_sz = 0, 111256d5323bSKonstantin Belousov .exec = stackgap_ctl, .copyout_on_error = false, }, 11137ae879b1SKonstantin Belousov [PROC_STACKGAP_STATUS] = 1114c7f38a2dSKonstantin Belousov { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 111556d5323bSKonstantin Belousov .esrch_is_einval = false, .no_nonnull_data = false, 11161c4dbee5SKonstantin Belousov .need_candebug = false, 111756d5323bSKonstantin Belousov .copyin_sz = 0, .copyout_sz = sizeof(int), 111856d5323bSKonstantin Belousov .exec = stackgap_status, .copyout_on_error = false, }, 11197ae879b1SKonstantin Belousov [PROC_NO_NEW_PRIVS_CTL] = 1120c7f38a2dSKonstantin Belousov { .lock_tree = PCTL_SLOCKED, .one_proc = true, 112156d5323bSKonstantin Belousov .esrch_is_einval = false, .no_nonnull_data = false, 1122f5bb6e5aSKonstantin Belousov .need_candebug = true, 112356d5323bSKonstantin Belousov .copyin_sz = sizeof(int), .copyout_sz = 0, 112456d5323bSKonstantin Belousov .exec = no_new_privs_ctl, .copyout_on_error = false, }, 11257ae879b1SKonstantin Belousov [PROC_NO_NEW_PRIVS_STATUS] = 1126c7f38a2dSKonstantin Belousov { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 112756d5323bSKonstantin Belousov .esrch_is_einval = false, .no_nonnull_data = false, 11281c4dbee5SKonstantin Belousov .need_candebug = false, 112956d5323bSKonstantin Belousov .copyin_sz = 0, .copyout_sz = sizeof(int), 113056d5323bSKonstantin Belousov .exec = no_new_privs_status, .copyout_on_error = false, }, 11317ae879b1SKonstantin Belousov [PROC_WXMAP_CTL] = 1132c7f38a2dSKonstantin Belousov { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 113356d5323bSKonstantin Belousov .esrch_is_einval = false, .no_nonnull_data = false, 1134f5bb6e5aSKonstantin Belousov .need_candebug = true, 113556d5323bSKonstantin Belousov .copyin_sz = sizeof(int), .copyout_sz = 0, 113656d5323bSKonstantin Belousov .exec = wxmap_ctl, .copyout_on_error = false, }, 11377ae879b1SKonstantin Belousov [PROC_WXMAP_STATUS] = 1138c7f38a2dSKonstantin Belousov { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 113956d5323bSKonstantin Belousov .esrch_is_einval = false, .no_nonnull_data = false, 11401c4dbee5SKonstantin Belousov .need_candebug = false, 114156d5323bSKonstantin Belousov .copyin_sz = 0, .copyout_sz = sizeof(int), 114256d5323bSKonstantin Belousov .exec = wxmap_status, .copyout_on_error = false, }, 1143*dabf006aSKyle Evans [PROC_LOGSIGEXIT_CTL] = 1144*dabf006aSKyle Evans { .lock_tree = PCTL_SLOCKED, .one_proc = true, 1145*dabf006aSKyle Evans .esrch_is_einval = false, .no_nonnull_data = false, 1146*dabf006aSKyle Evans .need_candebug = true, 1147*dabf006aSKyle Evans .copyin_sz = sizeof(int), .copyout_sz = 0, 1148*dabf006aSKyle Evans .exec = logsigexit_ctl, .copyout_on_error = false, }, 1149*dabf006aSKyle Evans [PROC_LOGSIGEXIT_STATUS] = 1150*dabf006aSKyle Evans { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 1151*dabf006aSKyle Evans .esrch_is_einval = false, .no_nonnull_data = false, 1152*dabf006aSKyle Evans .need_candebug = false, 1153*dabf006aSKyle Evans .copyin_sz = 0, .copyout_sz = sizeof(int), 1154*dabf006aSKyle Evans .exec = logsigexit_status, .copyout_on_error = false, }, 11557ae879b1SKonstantin Belousov }; 11567ae879b1SKonstantin Belousov 1157237623b0SKonstantin Belousov int 1158237623b0SKonstantin Belousov sys_procctl(struct thread *td, struct procctl_args *uap) 1159237623b0SKonstantin Belousov { 1160237623b0SKonstantin Belousov union { 1161237623b0SKonstantin Belousov struct procctl_reaper_status rs; 1162237623b0SKonstantin Belousov struct procctl_reaper_pids rp; 1163237623b0SKonstantin Belousov struct procctl_reaper_kill rk; 116456d5323bSKonstantin Belousov int flags; 1165237623b0SKonstantin Belousov } x; 116656d5323bSKonstantin Belousov const struct procctl_cmd_info *cmd_info; 116756d5323bSKonstantin Belousov int error, error1; 1168237623b0SKonstantin Belousov 1169fd8d844fSKonstantin Belousov if (uap->com >= PROC_PROCCTL_MD_MIN) 1170fd8d844fSKonstantin Belousov return (cpu_procctl(td, uap->idtype, uap->id, 1171fd8d844fSKonstantin Belousov uap->com, uap->data)); 1172afc10f8bSOlivier Certner if (uap->com <= 0 || uap->com >= nitems(procctl_cmds_info)) 1173237623b0SKonstantin Belousov return (EINVAL); 117456d5323bSKonstantin Belousov cmd_info = &procctl_cmds_info[uap->com]; 117532026f59SKonstantin Belousov bzero(&x, sizeof(x)); 117632026f59SKonstantin Belousov 117756d5323bSKonstantin Belousov if (cmd_info->copyin_sz > 0) { 117856d5323bSKonstantin Belousov error = copyin(uap->data, &x, cmd_info->copyin_sz); 1179237623b0SKonstantin Belousov if (error != 0) 1180237623b0SKonstantin Belousov return (error); 118156d5323bSKonstantin Belousov } else if (cmd_info->no_nonnull_data && uap->data != NULL) { 1182237623b0SKonstantin Belousov return (EINVAL); 1183237623b0SKonstantin Belousov } 118456d5323bSKonstantin Belousov 118556d5323bSKonstantin Belousov error = kern_procctl(td, uap->idtype, uap->id, uap->com, &x); 118656d5323bSKonstantin Belousov 118756d5323bSKonstantin Belousov if (cmd_info->copyout_sz > 0 && (error == 0 || 118856d5323bSKonstantin Belousov cmd_info->copyout_on_error)) { 118956d5323bSKonstantin Belousov error1 = copyout(&x, uap->data, cmd_info->copyout_sz); 1190237623b0SKonstantin Belousov if (error == 0) 1191237623b0SKonstantin Belousov error = error1; 1192237623b0SKonstantin Belousov } 1193237623b0SKonstantin Belousov return (error); 1194237623b0SKonstantin Belousov } 1195237623b0SKonstantin Belousov 1196237623b0SKonstantin Belousov static int 1197237623b0SKonstantin Belousov kern_procctl_single(struct thread *td, struct proc *p, int com, void *data) 1198237623b0SKonstantin Belousov { 1199237623b0SKonstantin Belousov 1200237623b0SKonstantin Belousov PROC_LOCK_ASSERT(p, MA_OWNED); 120168dc5b38SKonstantin Belousov return (procctl_cmds_info[com].exec(td, p, data)); 1202237623b0SKonstantin Belousov } 1203237623b0SKonstantin Belousov 1204237623b0SKonstantin Belousov int 1205237623b0SKonstantin Belousov kern_procctl(struct thread *td, idtype_t idtype, id_t id, int com, void *data) 1206237623b0SKonstantin Belousov { 1207237623b0SKonstantin Belousov struct pgrp *pg; 1208237623b0SKonstantin Belousov struct proc *p; 12097ae879b1SKonstantin Belousov const struct procctl_cmd_info *cmd_info; 1210237623b0SKonstantin Belousov int error, first_error, ok; 1211d1df3473SKonstantin Belousov bool sapblk; 1212237623b0SKonstantin Belousov 12137ae879b1SKonstantin Belousov MPASS(com > 0 && com < nitems(procctl_cmds_info)); 12147ae879b1SKonstantin Belousov cmd_info = &procctl_cmds_info[com]; 12157ae879b1SKonstantin Belousov if (idtype != P_PID && cmd_info->one_proc) 1216237623b0SKonstantin Belousov return (EINVAL); 1217237623b0SKonstantin Belousov 1218d1df3473SKonstantin Belousov sapblk = false; 1219d1df3473SKonstantin Belousov if (cmd_info->sapblk != NULL) { 1220d1df3473SKonstantin Belousov sapblk = cmd_info->sapblk(td, data); 1221008b2e65SKonstantin Belousov if (sapblk && !stop_all_proc_block()) 1222008b2e65SKonstantin Belousov return (ERESTART); 1223d1df3473SKonstantin Belousov } 1224d1df3473SKonstantin Belousov 12257ae879b1SKonstantin Belousov switch (cmd_info->lock_tree) { 1226c7f38a2dSKonstantin Belousov case PCTL_XLOCKED: 1227237623b0SKonstantin Belousov sx_xlock(&proctree_lock); 1228677258f7SKonstantin Belousov break; 1229c7f38a2dSKonstantin Belousov case PCTL_SLOCKED: 12307ae879b1SKonstantin Belousov sx_slock(&proctree_lock); 1231237623b0SKonstantin Belousov break; 1232c7f38a2dSKonstantin Belousov default: 1233c7f38a2dSKonstantin Belousov break; 1234237623b0SKonstantin Belousov } 1235237623b0SKonstantin Belousov 1236237623b0SKonstantin Belousov switch (idtype) { 1237237623b0SKonstantin Belousov case P_PID: 1238f833ab9dSKonstantin Belousov if (id == 0) { 1239f833ab9dSKonstantin Belousov p = td->td_proc; 1240f833ab9dSKonstantin Belousov error = 0; 1241f833ab9dSKonstantin Belousov PROC_LOCK(p); 1242f833ab9dSKonstantin Belousov } else { 1243237623b0SKonstantin Belousov p = pfind(id); 1244237623b0SKonstantin Belousov if (p == NULL) { 124534f39a8cSKonstantin Belousov error = cmd_info->esrch_is_einval ? 124634f39a8cSKonstantin Belousov EINVAL : ESRCH; 1247237623b0SKonstantin Belousov break; 1248237623b0SKonstantin Belousov } 12491c4dbee5SKonstantin Belousov error = cmd_info->need_candebug ? p_candebug(td, p) : 12501c4dbee5SKonstantin Belousov p_cansee(td, p); 1251f833ab9dSKonstantin Belousov } 1252237623b0SKonstantin Belousov if (error == 0) 1253237623b0SKonstantin Belousov error = kern_procctl_single(td, p, com, data); 1254237623b0SKonstantin Belousov PROC_UNLOCK(p); 1255237623b0SKonstantin Belousov break; 1256237623b0SKonstantin Belousov case P_PGID: 1257237623b0SKonstantin Belousov /* 1258237623b0SKonstantin Belousov * Attempt to apply the operation to all members of the 1259237623b0SKonstantin Belousov * group. Ignore processes in the group that can't be 1260237623b0SKonstantin Belousov * seen. Ignore errors so long as at least one process is 1261237623b0SKonstantin Belousov * able to complete the request successfully. 1262237623b0SKonstantin Belousov */ 1263237623b0SKonstantin Belousov pg = pgfind(id); 1264237623b0SKonstantin Belousov if (pg == NULL) { 1265237623b0SKonstantin Belousov error = ESRCH; 1266237623b0SKonstantin Belousov break; 1267237623b0SKonstantin Belousov } 1268237623b0SKonstantin Belousov PGRP_UNLOCK(pg); 1269237623b0SKonstantin Belousov ok = 0; 1270237623b0SKonstantin Belousov first_error = 0; 1271237623b0SKonstantin Belousov LIST_FOREACH(p, &pg->pg_members, p_pglist) { 1272237623b0SKonstantin Belousov PROC_LOCK(p); 127349db81aaSKonstantin Belousov if (p->p_state == PRS_NEW || 127449db81aaSKonstantin Belousov p->p_state == PRS_ZOMBIE || 127549db81aaSKonstantin Belousov (cmd_info->need_candebug ? p_candebug(td, p) : 127649db81aaSKonstantin Belousov p_cansee(td, p)) != 0) { 1277237623b0SKonstantin Belousov PROC_UNLOCK(p); 1278237623b0SKonstantin Belousov continue; 1279237623b0SKonstantin Belousov } 1280237623b0SKonstantin Belousov error = kern_procctl_single(td, p, com, data); 1281237623b0SKonstantin Belousov PROC_UNLOCK(p); 1282237623b0SKonstantin Belousov if (error == 0) 1283237623b0SKonstantin Belousov ok = 1; 1284237623b0SKonstantin Belousov else if (first_error == 0) 1285237623b0SKonstantin Belousov first_error = error; 1286237623b0SKonstantin Belousov } 1287237623b0SKonstantin Belousov if (ok) 1288237623b0SKonstantin Belousov error = 0; 1289237623b0SKonstantin Belousov else if (first_error != 0) 1290237623b0SKonstantin Belousov error = first_error; 1291237623b0SKonstantin Belousov else 1292237623b0SKonstantin Belousov /* 1293237623b0SKonstantin Belousov * Was not able to see any processes in the 1294237623b0SKonstantin Belousov * process group. 1295237623b0SKonstantin Belousov */ 1296237623b0SKonstantin Belousov error = ESRCH; 1297237623b0SKonstantin Belousov break; 1298237623b0SKonstantin Belousov default: 1299237623b0SKonstantin Belousov error = EINVAL; 1300237623b0SKonstantin Belousov break; 1301237623b0SKonstantin Belousov } 13027ae879b1SKonstantin Belousov 13037ae879b1SKonstantin Belousov switch (cmd_info->lock_tree) { 1304c7f38a2dSKonstantin Belousov case PCTL_XLOCKED: 13057ae879b1SKonstantin Belousov sx_xunlock(&proctree_lock); 13067ae879b1SKonstantin Belousov break; 1307c7f38a2dSKonstantin Belousov case PCTL_SLOCKED: 13087ae879b1SKonstantin Belousov sx_sunlock(&proctree_lock); 13097ae879b1SKonstantin Belousov break; 1310c7f38a2dSKonstantin Belousov default: 1311c7f38a2dSKonstantin Belousov break; 13127ae879b1SKonstantin Belousov } 1313d1df3473SKonstantin Belousov if (sapblk) 1314d1df3473SKonstantin Belousov stop_all_proc_unblock(); 1315237623b0SKonstantin Belousov return (error); 1316237623b0SKonstantin Belousov } 1317