2 * Copyright (c) 2014 John Baldwin
3 * Copyright (c) 2014, 2016 The FreeBSD Foundation
5 * Portions of this software were developed by Konstantin Belousov
6 * under sponsorship from the FreeBSD Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/param.h>
34 #include <sys/_unrhdr.h>
35 #include <sys/systm.h>
36 #include <sys/capsicum.h>
39 #include <sys/mutex.h>
42 #include <sys/procctl.h>
44 #include <sys/syscallsubr.h>
45 #include <sys/sysproto.h>
50 #include <vm/vm_map.h>
51 #include <vm/vm_extern.h>
54 protect_setchild(struct thread *td, struct proc *p, int flags)
57 PROC_LOCK_ASSERT(p, MA_OWNED);
58 if (p->p_flag & P_SYSTEM || p_cansched(td, p) != 0)
60 if (flags & PPROT_SET) {
61 p->p_flag |= P_PROTECTED;
62 if (flags & PPROT_INHERIT)
63 p->p_flag2 |= P2_INHERIT_PROTECTED;
65 p->p_flag &= ~P_PROTECTED;
66 p->p_flag2 &= ~P2_INHERIT_PROTECTED;
72 protect_setchildren(struct thread *td, struct proc *top, int flags)
79 sx_assert(&proctree_lock, SX_LOCKED);
81 ret |= protect_setchild(td, p, flags);
84 * If this process has children, descend to them next,
85 * otherwise do any siblings, and if done with this level,
86 * follow back up the tree (but not past top).
88 if (!LIST_EMPTY(&p->p_children))
89 p = LIST_FIRST(&p->p_children);
95 if (LIST_NEXT(p, p_sibling)) {
96 p = LIST_NEXT(p, p_sibling);
106 protect_set(struct thread *td, struct proc *p, void *data)
108 int error, flags, ret;
110 flags = *(int *)data;
111 switch (PPROT_OP(flags)) {
119 if ((PPROT_FLAGS(flags) & ~(PPROT_DESCEND | PPROT_INHERIT)) != 0)
122 error = priv_check(td, PRIV_VM_MADV_PROTECT);
126 if (flags & PPROT_DESCEND)
127 ret = protect_setchildren(td, p, flags);
129 ret = protect_setchild(td, p, flags);
136 reap_acquire(struct thread *td, struct proc *p, void *data __unused)
139 sx_assert(&proctree_lock, SX_XLOCKED);
140 if (p != td->td_proc)
142 if ((p->p_treeflag & P_TREE_REAPER) != 0)
144 p->p_treeflag |= P_TREE_REAPER;
146 * We do not reattach existing children and the whole tree
147 * under them to us, since p->p_reaper already seen them.
153 reap_release(struct thread *td, struct proc *p, void *data __unused)
156 sx_assert(&proctree_lock, SX_XLOCKED);
157 if (p != td->td_proc)
161 if ((p->p_treeflag & P_TREE_REAPER) == 0)
163 reaper_abandon_children(p, false);
168 reap_status(struct thread *td, struct proc *p, void *data)
170 struct proc *reap, *p2, *first_p;
171 struct procctl_reaper_status *rs;
174 sx_assert(&proctree_lock, SX_LOCKED);
175 if ((p->p_treeflag & P_TREE_REAPER) == 0) {
179 rs->rs_flags |= REAPER_STATUS_OWNED;
181 if (reap == initproc)
182 rs->rs_flags |= REAPER_STATUS_REALINIT;
183 rs->rs_reaper = reap->p_pid;
184 rs->rs_descendants = 0;
186 if (!LIST_EMPTY(&reap->p_reaplist)) {
187 first_p = LIST_FIRST(&reap->p_children);
189 first_p = LIST_FIRST(&reap->p_reaplist);
190 rs->rs_pid = first_p->p_pid;
191 LIST_FOREACH(p2, &reap->p_reaplist, p_reapsibling) {
192 if (proc_realparent(p2) == reap)
194 rs->rs_descendants++;
203 reap_getpids(struct thread *td, struct proc *p, void *data)
205 struct proc *reap, *p2;
206 struct procctl_reaper_pidinfo *pi, *pip;
207 struct procctl_reaper_pids *rp;
212 sx_assert(&proctree_lock, SX_LOCKED);
214 reap = (p->p_treeflag & P_TREE_REAPER) == 0 ? p->p_reaper : p;
217 LIST_FOREACH(p2, &reap->p_reaplist, p_reapsibling)
219 sx_unlock(&proctree_lock);
220 if (rp->rp_count < n)
222 pi = malloc(n * sizeof(*pi), M_TEMP, M_WAITOK);
223 sx_slock(&proctree_lock);
224 LIST_FOREACH(p2, &reap->p_reaplist, p_reapsibling) {
228 bzero(pip, sizeof(*pip));
229 pip->pi_pid = p2->p_pid;
230 pip->pi_subtree = p2->p_reapsubtree;
231 pip->pi_flags = REAPER_PIDINFO_VALID;
232 if (proc_realparent(p2) == reap)
233 pip->pi_flags |= REAPER_PIDINFO_CHILD;
234 if ((p2->p_treeflag & P_TREE_REAPER) != 0)
235 pip->pi_flags |= REAPER_PIDINFO_REAPER;
238 sx_sunlock(&proctree_lock);
239 error = copyout(pi, rp->rp_pids, i * sizeof(*pi));
241 sx_slock(&proctree_lock);
247 reap_kill_proc_relock(struct proc *p, int xlocked)
251 sx_xlock(&proctree_lock);
253 sx_slock(&proctree_lock);
258 reap_kill_proc_locked(struct thread *td, struct proc *p2,
259 ksiginfo_t *ksi, struct procctl_reaper_kill *rk, int *error)
261 int error1, r, xlocked;
264 PROC_LOCK_ASSERT(p2, MA_OWNED);
265 PROC_ASSERT_HELD(p2);
267 error1 = p_cansignal(td, p2, rk->rk_sig);
269 if (*error == ESRCH) {
270 rk->rk_fpid = p2->p_pid;
277 * The need_stop indicates if the target process needs to be
278 * suspended before being signalled. This is needed when we
279 * guarantee that all processes in subtree are signalled,
280 * avoiding the race with some process not yet fully linked
281 * into all structures during fork, ignored by iterator, and
282 * then escaping signalling.
284 * If need_stop is true, then reap_kill_proc() returns true if
285 * the process was successfully stopped and signalled, and
286 * false if stopping failed and the signal was not sent.
288 * The thread cannot usefully stop itself anyway, and if other
289 * thread of the current process forks while the current
290 * thread signals the whole subtree, it is an application
293 need_stop = p2 != td->td_proc &&
294 (td->td_proc->p_flag2 & P2_WEXIT) == 0 &&
295 (p2->p_flag & (P_KPROC | P_SYSTEM | P_STOPPED)) == 0 &&
296 (rk->rk_flags & REAPER_KILL_CHILDREN) == 0;
299 xlocked = sx_xlocked(&proctree_lock);
300 sx_unlock(&proctree_lock);
301 r = thread_single(p2, SINGLE_ALLPROC);
302 reap_kill_proc_relock(p2, xlocked);
307 pksignal(p2, rk->rk_sig, ksi);
312 thread_single_end(p2, SINGLE_ALLPROC);
316 reap_kill_proc(struct thread *td, struct proc *p2, ksiginfo_t *ksi,
317 struct procctl_reaper_kill *rk, int *error)
320 if ((p2->p_flag2 & P2_WEXIT) == 0) {
322 reap_kill_proc_locked(td, p2, ksi, rk, error);
328 struct reap_kill_tracker {
330 TAILQ_ENTRY(reap_kill_tracker) link;
333 TAILQ_HEAD(reap_kill_tracker_head, reap_kill_tracker);
336 reap_kill_sched(struct reap_kill_tracker_head *tracker, struct proc *p2)
338 struct reap_kill_tracker *t;
341 if ((p2->p_flag2 & P2_WEXIT) != 0) {
347 t = malloc(sizeof(struct reap_kill_tracker), M_TEMP, M_WAITOK);
349 TAILQ_INSERT_TAIL(tracker, t, link);
353 reap_kill_sched_free(struct reap_kill_tracker *t)
360 reap_kill_children(struct thread *td, struct proc *reaper,
361 struct procctl_reaper_kill *rk, ksiginfo_t *ksi, int *error)
365 LIST_FOREACH(p2, &reaper->p_children, p_sibling) {
366 (void)reap_kill_proc(td, p2, ksi, rk, error);
368 * Do not end the loop on error, signal everything we
375 reap_kill_subtree_once(struct thread *td, struct proc *p, struct proc *reaper,
376 struct procctl_reaper_kill *rk, ksiginfo_t *ksi, int *error,
379 struct reap_kill_tracker_head tracker;
380 struct reap_kill_tracker *t;
385 TAILQ_INIT(&tracker);
386 reap_kill_sched(&tracker, reaper);
387 while ((t = TAILQ_FIRST(&tracker)) != NULL) {
388 TAILQ_REMOVE(&tracker, t, link);
391 * Since reap_kill_proc() drops proctree_lock sx, it
392 * is possible that the tracked reaper is no longer.
393 * In this case the subtree is reparented to the new
394 * reaper, which should handle it.
396 if ((t->parent->p_treeflag & P_TREE_REAPER) == 0) {
397 reap_kill_sched_free(t);
402 LIST_FOREACH(p2, &t->parent->p_reaplist, p_reapsibling) {
403 if (t->parent == reaper &&
404 (rk->rk_flags & REAPER_KILL_SUBTREE) != 0 &&
405 p2->p_reapsubtree != rk->rk_subtree)
407 if ((p2->p_treeflag & P_TREE_REAPER) != 0)
408 reap_kill_sched(&tracker, p2);
409 if (alloc_unr_specific(pids, p2->p_pid) != p2->p_pid)
411 reap_kill_proc(td, p2, ksi, rk, error);
414 reap_kill_sched_free(t);
420 reap_kill_subtree(struct thread *td, struct proc *p, struct proc *reaper,
421 struct procctl_reaper_kill *rk, ksiginfo_t *ksi, int *error)
426 * pids records processes which were already signalled, to
427 * avoid doubling signals to them if iteration needs to be
430 init_unrhdr(&pids, 1, PID_MAX, UNR_NO_MTX);
431 PROC_LOCK(td->td_proc);
432 if ((td->td_proc->p_flag2 & P2_WEXIT) != 0) {
433 PROC_UNLOCK(td->td_proc);
436 td->td_proc->p_singlethr++;
437 PROC_UNLOCK(td->td_proc);
438 while (reap_kill_subtree_once(td, p, reaper, rk, ksi, error, &pids))
440 PROC_LOCK(td->td_proc);
441 td->td_proc->p_singlethr--;
442 if (td->td_proc->p_singlethr == 0)
443 wakeup(&p->p_singlethr);
444 PROC_UNLOCK(td->td_proc);
451 reap_kill_sapblk(struct thread *td __unused, void *data)
453 struct procctl_reaper_kill *rk;
456 return ((rk->rk_flags & REAPER_KILL_CHILDREN) == 0);
460 reap_kill(struct thread *td, struct proc *p, void *data)
464 struct procctl_reaper_kill *rk;
468 sx_assert(&proctree_lock, SX_LOCKED);
469 if (IN_CAPABILITY_MODE(td))
471 if (rk->rk_sig <= 0 || rk->rk_sig > _SIG_MAXSIG ||
472 (rk->rk_flags & ~(REAPER_KILL_CHILDREN |
473 REAPER_KILL_SUBTREE)) != 0 || (rk->rk_flags &
474 (REAPER_KILL_CHILDREN | REAPER_KILL_SUBTREE)) ==
475 (REAPER_KILL_CHILDREN | REAPER_KILL_SUBTREE))
478 reaper = (p->p_treeflag & P_TREE_REAPER) == 0 ? p->p_reaper : p;
480 ksi.ksi_signo = rk->rk_sig;
481 ksi.ksi_code = SI_USER;
482 ksi.ksi_pid = td->td_proc->p_pid;
483 ksi.ksi_uid = td->td_ucred->cr_ruid;
487 if ((rk->rk_flags & REAPER_KILL_CHILDREN) != 0) {
488 reap_kill_children(td, reaper, rk, &ksi, &error);
490 reap_kill_subtree(td, p, reaper, rk, &ksi, &error);
497 trace_ctl(struct thread *td, struct proc *p, void *data)
501 PROC_LOCK_ASSERT(p, MA_OWNED);
502 state = *(int *)data;
505 * Ktrace changes p_traceflag from or to zero under the
506 * process lock, so the test does not need to acquire ktrace
509 if ((p->p_flag & P_TRACED) != 0 || p->p_traceflag != 0)
513 case PROC_TRACE_CTL_ENABLE:
514 if (td->td_proc != p)
516 p->p_flag2 &= ~(P2_NOTRACE | P2_NOTRACE_EXEC);
518 case PROC_TRACE_CTL_DISABLE_EXEC:
519 p->p_flag2 |= P2_NOTRACE_EXEC | P2_NOTRACE;
521 case PROC_TRACE_CTL_DISABLE:
522 if ((p->p_flag2 & P2_NOTRACE_EXEC) != 0) {
523 KASSERT((p->p_flag2 & P2_NOTRACE) != 0,
524 ("dandling P2_NOTRACE_EXEC"));
525 if (td->td_proc != p)
527 p->p_flag2 &= ~P2_NOTRACE_EXEC;
529 p->p_flag2 |= P2_NOTRACE;
539 trace_status(struct thread *td, struct proc *p, void *data)
544 if ((p->p_flag2 & P2_NOTRACE) != 0) {
545 KASSERT((p->p_flag & P_TRACED) == 0,
546 ("%d traced but tracing disabled", p->p_pid));
548 } else if ((p->p_flag & P_TRACED) != 0) {
549 *status = p->p_pptr->p_pid;
557 trapcap_ctl(struct thread *td, struct proc *p, void *data)
561 PROC_LOCK_ASSERT(p, MA_OWNED);
562 state = *(int *)data;
565 case PROC_TRAPCAP_CTL_ENABLE:
566 p->p_flag2 |= P2_TRAPCAP;
568 case PROC_TRAPCAP_CTL_DISABLE:
569 p->p_flag2 &= ~P2_TRAPCAP;
578 trapcap_status(struct thread *td, struct proc *p, void *data)
583 *status = (p->p_flag2 & P2_TRAPCAP) != 0 ? PROC_TRAPCAP_CTL_ENABLE :
584 PROC_TRAPCAP_CTL_DISABLE;
589 no_new_privs_ctl(struct thread *td, struct proc *p, void *data)
593 PROC_LOCK_ASSERT(p, MA_OWNED);
594 state = *(int *)data;
596 if (state != PROC_NO_NEW_PRIVS_ENABLE)
598 p->p_flag2 |= P2_NO_NEW_PRIVS;
603 no_new_privs_status(struct thread *td, struct proc *p, void *data)
606 *(int *)data = (p->p_flag2 & P2_NO_NEW_PRIVS) != 0 ?
607 PROC_NO_NEW_PRIVS_ENABLE : PROC_NO_NEW_PRIVS_DISABLE;
612 protmax_ctl(struct thread *td, struct proc *p, void *data)
616 PROC_LOCK_ASSERT(p, MA_OWNED);
617 state = *(int *)data;
620 case PROC_PROTMAX_FORCE_ENABLE:
621 p->p_flag2 &= ~P2_PROTMAX_DISABLE;
622 p->p_flag2 |= P2_PROTMAX_ENABLE;
624 case PROC_PROTMAX_FORCE_DISABLE:
625 p->p_flag2 |= P2_PROTMAX_DISABLE;
626 p->p_flag2 &= ~P2_PROTMAX_ENABLE;
628 case PROC_PROTMAX_NOFORCE:
629 p->p_flag2 &= ~(P2_PROTMAX_ENABLE | P2_PROTMAX_DISABLE);
638 protmax_status(struct thread *td, struct proc *p, void *data)
642 switch (p->p_flag2 & (P2_PROTMAX_ENABLE | P2_PROTMAX_DISABLE)) {
644 d = PROC_PROTMAX_NOFORCE;
646 case P2_PROTMAX_ENABLE:
647 d = PROC_PROTMAX_FORCE_ENABLE;
649 case P2_PROTMAX_DISABLE:
650 d = PROC_PROTMAX_FORCE_DISABLE;
653 if (kern_mmap_maxprot(p, PROT_READ) == PROT_READ)
654 d |= PROC_PROTMAX_ACTIVE;
660 aslr_ctl(struct thread *td, struct proc *p, void *data)
664 PROC_LOCK_ASSERT(p, MA_OWNED);
665 state = *(int *)data;
668 case PROC_ASLR_FORCE_ENABLE:
669 p->p_flag2 &= ~P2_ASLR_DISABLE;
670 p->p_flag2 |= P2_ASLR_ENABLE;
672 case PROC_ASLR_FORCE_DISABLE:
673 p->p_flag2 |= P2_ASLR_DISABLE;
674 p->p_flag2 &= ~P2_ASLR_ENABLE;
676 case PROC_ASLR_NOFORCE:
677 p->p_flag2 &= ~(P2_ASLR_ENABLE | P2_ASLR_DISABLE);
686 aslr_status(struct thread *td, struct proc *p, void *data)
691 switch (p->p_flag2 & (P2_ASLR_ENABLE | P2_ASLR_DISABLE)) {
693 d = PROC_ASLR_NOFORCE;
696 d = PROC_ASLR_FORCE_ENABLE;
698 case P2_ASLR_DISABLE:
699 d = PROC_ASLR_FORCE_DISABLE;
702 if ((p->p_flag & P_WEXIT) == 0) {
705 vm = vmspace_acquire_ref(p);
707 if ((vm->vm_map.flags & MAP_ASLR) != 0)
708 d |= PROC_ASLR_ACTIVE;
719 stackgap_ctl(struct thread *td, struct proc *p, void *data)
723 PROC_LOCK_ASSERT(p, MA_OWNED);
724 state = *(int *)data;
726 if ((state & ~(PROC_STACKGAP_ENABLE | PROC_STACKGAP_DISABLE |
727 PROC_STACKGAP_ENABLE_EXEC | PROC_STACKGAP_DISABLE_EXEC)) != 0)
729 switch (state & (PROC_STACKGAP_ENABLE | PROC_STACKGAP_DISABLE)) {
730 case PROC_STACKGAP_ENABLE:
731 if ((p->p_flag2 & P2_STKGAP_DISABLE) != 0)
734 case PROC_STACKGAP_DISABLE:
735 p->p_flag2 |= P2_STKGAP_DISABLE;
742 switch (state & (PROC_STACKGAP_ENABLE_EXEC |
743 PROC_STACKGAP_DISABLE_EXEC)) {
744 case PROC_STACKGAP_ENABLE_EXEC:
745 p->p_flag2 &= ~P2_STKGAP_DISABLE_EXEC;
747 case PROC_STACKGAP_DISABLE_EXEC:
748 p->p_flag2 |= P2_STKGAP_DISABLE_EXEC;
759 stackgap_status(struct thread *td, struct proc *p, void *data)
763 PROC_LOCK_ASSERT(p, MA_OWNED);
765 d = (p->p_flag2 & P2_STKGAP_DISABLE) != 0 ? PROC_STACKGAP_DISABLE :
766 PROC_STACKGAP_ENABLE;
767 d |= (p->p_flag2 & P2_STKGAP_DISABLE_EXEC) != 0 ?
768 PROC_STACKGAP_DISABLE_EXEC : PROC_STACKGAP_ENABLE_EXEC;
774 wxmap_ctl(struct thread *td, struct proc *p, void *data)
780 PROC_LOCK_ASSERT(p, MA_OWNED);
781 if ((p->p_flag & P_WEXIT) != 0)
783 state = *(int *)data;
786 case PROC_WX_MAPPINGS_PERMIT:
787 p->p_flag2 |= P2_WXORX_DISABLE;
790 vm = vmspace_acquire_ref(p);
794 map->flags &= ~MAP_WXORX;
801 case PROC_WX_MAPPINGS_DISALLOW_EXEC:
802 p->p_flag2 |= P2_WXORX_ENABLE_EXEC;
812 wxmap_status(struct thread *td, struct proc *p, void *data)
817 PROC_LOCK_ASSERT(p, MA_OWNED);
818 if ((p->p_flag & P_WEXIT) != 0)
822 if ((p->p_flag2 & P2_WXORX_DISABLE) != 0)
823 d |= PROC_WX_MAPPINGS_PERMIT;
824 if ((p->p_flag2 & P2_WXORX_ENABLE_EXEC) != 0)
825 d |= PROC_WX_MAPPINGS_DISALLOW_EXEC;
828 vm = vmspace_acquire_ref(p);
830 if ((vm->vm_map.flags & MAP_WXORX) != 0)
831 d |= PROC_WXORX_ENFORCE;
841 pdeathsig_ctl(struct thread *td, struct proc *p, void *data)
845 signum = *(int *)data;
846 if (p != td->td_proc || (signum != 0 && !_SIG_VALID(signum)))
848 p->p_pdeathsig = signum;
853 pdeathsig_status(struct thread *td, struct proc *p, void *data)
855 if (p != td->td_proc)
857 *(int *)data = p->p_pdeathsig;
867 struct procctl_cmd_info {
870 bool esrch_is_einval : 1;
871 bool copyout_on_error : 1;
872 bool no_nonnull_data : 1;
873 bool need_candebug : 1;
876 int (*exec)(struct thread *, struct proc *, void *);
877 bool (*sapblk)(struct thread *, void *);
879 static const struct procctl_cmd_info procctl_cmds_info[] = {
881 { .lock_tree = PCTL_SLOCKED, .one_proc = false,
882 .esrch_is_einval = false, .no_nonnull_data = false,
883 .need_candebug = false,
884 .copyin_sz = sizeof(int), .copyout_sz = 0,
885 .exec = protect_set, .copyout_on_error = false, },
886 [PROC_REAP_ACQUIRE] =
887 { .lock_tree = PCTL_XLOCKED, .one_proc = true,
888 .esrch_is_einval = false, .no_nonnull_data = true,
889 .need_candebug = false,
890 .copyin_sz = 0, .copyout_sz = 0,
891 .exec = reap_acquire, .copyout_on_error = false, },
892 [PROC_REAP_RELEASE] =
893 { .lock_tree = PCTL_XLOCKED, .one_proc = true,
894 .esrch_is_einval = false, .no_nonnull_data = true,
895 .need_candebug = false,
896 .copyin_sz = 0, .copyout_sz = 0,
897 .exec = reap_release, .copyout_on_error = false, },
899 { .lock_tree = PCTL_SLOCKED, .one_proc = true,
900 .esrch_is_einval = false, .no_nonnull_data = false,
901 .need_candebug = false,
903 .copyout_sz = sizeof(struct procctl_reaper_status),
904 .exec = reap_status, .copyout_on_error = false, },
905 [PROC_REAP_GETPIDS] =
906 { .lock_tree = PCTL_SLOCKED, .one_proc = true,
907 .esrch_is_einval = false, .no_nonnull_data = false,
908 .need_candebug = false,
909 .copyin_sz = sizeof(struct procctl_reaper_pids),
911 .exec = reap_getpids, .copyout_on_error = false, },
913 { .lock_tree = PCTL_SLOCKED, .one_proc = true,
914 .esrch_is_einval = false, .no_nonnull_data = false,
915 .need_candebug = false,
916 .copyin_sz = sizeof(struct procctl_reaper_kill),
917 .copyout_sz = sizeof(struct procctl_reaper_kill),
918 .exec = reap_kill, .copyout_on_error = true,
919 .sapblk = reap_kill_sapblk, },
921 { .lock_tree = PCTL_SLOCKED, .one_proc = false,
922 .esrch_is_einval = false, .no_nonnull_data = false,
923 .need_candebug = true,
924 .copyin_sz = sizeof(int), .copyout_sz = 0,
925 .exec = trace_ctl, .copyout_on_error = false, },
926 [PROC_TRACE_STATUS] =
927 { .lock_tree = PCTL_UNLOCKED, .one_proc = true,
928 .esrch_is_einval = false, .no_nonnull_data = false,
929 .need_candebug = false,
930 .copyin_sz = 0, .copyout_sz = sizeof(int),
931 .exec = trace_status, .copyout_on_error = false, },
933 { .lock_tree = PCTL_SLOCKED, .one_proc = false,
934 .esrch_is_einval = false, .no_nonnull_data = false,
935 .need_candebug = true,
936 .copyin_sz = sizeof(int), .copyout_sz = 0,
937 .exec = trapcap_ctl, .copyout_on_error = false, },
938 [PROC_TRAPCAP_STATUS] =
939 { .lock_tree = PCTL_UNLOCKED, .one_proc = true,
940 .esrch_is_einval = false, .no_nonnull_data = false,
941 .need_candebug = false,
942 .copyin_sz = 0, .copyout_sz = sizeof(int),
943 .exec = trapcap_status, .copyout_on_error = false, },
944 [PROC_PDEATHSIG_CTL] =
945 { .lock_tree = PCTL_UNLOCKED, .one_proc = true,
946 .esrch_is_einval = true, .no_nonnull_data = false,
947 .need_candebug = false,
948 .copyin_sz = sizeof(int), .copyout_sz = 0,
949 .exec = pdeathsig_ctl, .copyout_on_error = false, },
950 [PROC_PDEATHSIG_STATUS] =
951 { .lock_tree = PCTL_UNLOCKED, .one_proc = true,
952 .esrch_is_einval = true, .no_nonnull_data = false,
953 .need_candebug = false,
954 .copyin_sz = 0, .copyout_sz = sizeof(int),
955 .exec = pdeathsig_status, .copyout_on_error = false, },
957 { .lock_tree = PCTL_UNLOCKED, .one_proc = true,
958 .esrch_is_einval = false, .no_nonnull_data = false,
959 .need_candebug = true,
960 .copyin_sz = sizeof(int), .copyout_sz = 0,
961 .exec = aslr_ctl, .copyout_on_error = false, },
963 { .lock_tree = PCTL_UNLOCKED, .one_proc = true,
964 .esrch_is_einval = false, .no_nonnull_data = false,
965 .need_candebug = false,
966 .copyin_sz = 0, .copyout_sz = sizeof(int),
967 .exec = aslr_status, .copyout_on_error = false, },
969 { .lock_tree = PCTL_UNLOCKED, .one_proc = true,
970 .esrch_is_einval = false, .no_nonnull_data = false,
971 .need_candebug = true,
972 .copyin_sz = sizeof(int), .copyout_sz = 0,
973 .exec = protmax_ctl, .copyout_on_error = false, },
974 [PROC_PROTMAX_STATUS] =
975 { .lock_tree = PCTL_UNLOCKED, .one_proc = true,
976 .esrch_is_einval = false, .no_nonnull_data = false,
977 .need_candebug = false,
978 .copyin_sz = 0, .copyout_sz = sizeof(int),
979 .exec = protmax_status, .copyout_on_error = false, },
980 [PROC_STACKGAP_CTL] =
981 { .lock_tree = PCTL_UNLOCKED, .one_proc = true,
982 .esrch_is_einval = false, .no_nonnull_data = false,
983 .need_candebug = true,
984 .copyin_sz = sizeof(int), .copyout_sz = 0,
985 .exec = stackgap_ctl, .copyout_on_error = false, },
986 [PROC_STACKGAP_STATUS] =
987 { .lock_tree = PCTL_UNLOCKED, .one_proc = true,
988 .esrch_is_einval = false, .no_nonnull_data = false,
989 .need_candebug = false,
990 .copyin_sz = 0, .copyout_sz = sizeof(int),
991 .exec = stackgap_status, .copyout_on_error = false, },
992 [PROC_NO_NEW_PRIVS_CTL] =
993 { .lock_tree = PCTL_SLOCKED, .one_proc = true,
994 .esrch_is_einval = false, .no_nonnull_data = false,
995 .need_candebug = true,
996 .copyin_sz = sizeof(int), .copyout_sz = 0,
997 .exec = no_new_privs_ctl, .copyout_on_error = false, },
998 [PROC_NO_NEW_PRIVS_STATUS] =
999 { .lock_tree = PCTL_UNLOCKED, .one_proc = true,
1000 .esrch_is_einval = false, .no_nonnull_data = false,
1001 .need_candebug = false,
1002 .copyin_sz = 0, .copyout_sz = sizeof(int),
1003 .exec = no_new_privs_status, .copyout_on_error = false, },
1005 { .lock_tree = PCTL_UNLOCKED, .one_proc = true,
1006 .esrch_is_einval = false, .no_nonnull_data = false,
1007 .need_candebug = true,
1008 .copyin_sz = sizeof(int), .copyout_sz = 0,
1009 .exec = wxmap_ctl, .copyout_on_error = false, },
1010 [PROC_WXMAP_STATUS] =
1011 { .lock_tree = PCTL_UNLOCKED, .one_proc = true,
1012 .esrch_is_einval = false, .no_nonnull_data = false,
1013 .need_candebug = false,
1014 .copyin_sz = 0, .copyout_sz = sizeof(int),
1015 .exec = wxmap_status, .copyout_on_error = false, },
1019 sys_procctl(struct thread *td, struct procctl_args *uap)
1022 struct procctl_reaper_status rs;
1023 struct procctl_reaper_pids rp;
1024 struct procctl_reaper_kill rk;
1027 const struct procctl_cmd_info *cmd_info;
1030 if (uap->com >= PROC_PROCCTL_MD_MIN)
1031 return (cpu_procctl(td, uap->idtype, uap->id,
1032 uap->com, uap->data));
1033 if (uap->com == 0 || uap->com >= nitems(procctl_cmds_info))
1035 cmd_info = &procctl_cmds_info[uap->com];
1036 bzero(&x, sizeof(x));
1038 if (cmd_info->copyin_sz > 0) {
1039 error = copyin(uap->data, &x, cmd_info->copyin_sz);
1042 } else if (cmd_info->no_nonnull_data && uap->data != NULL) {
1046 error = kern_procctl(td, uap->idtype, uap->id, uap->com, &x);
1048 if (cmd_info->copyout_sz > 0 && (error == 0 ||
1049 cmd_info->copyout_on_error)) {
1050 error1 = copyout(&x, uap->data, cmd_info->copyout_sz);
1058 kern_procctl_single(struct thread *td, struct proc *p, int com, void *data)
1061 PROC_LOCK_ASSERT(p, MA_OWNED);
1062 return (procctl_cmds_info[com].exec(td, p, data));
1066 kern_procctl(struct thread *td, idtype_t idtype, id_t id, int com, void *data)
1070 const struct procctl_cmd_info *cmd_info;
1071 int error, first_error, ok;
1074 MPASS(com > 0 && com < nitems(procctl_cmds_info));
1075 cmd_info = &procctl_cmds_info[com];
1076 if (idtype != P_PID && cmd_info->one_proc)
1080 if (cmd_info->sapblk != NULL) {
1081 sapblk = cmd_info->sapblk(td, data);
1082 if (sapblk && !stop_all_proc_block())
1086 switch (cmd_info->lock_tree) {
1088 sx_xlock(&proctree_lock);
1091 sx_slock(&proctree_lock);
1106 error = cmd_info->esrch_is_einval ?
1110 error = cmd_info->need_candebug ? p_candebug(td, p) :
1114 error = kern_procctl_single(td, p, com, data);
1119 * Attempt to apply the operation to all members of the
1120 * group. Ignore processes in the group that can't be
1121 * seen. Ignore errors so long as at least one process is
1122 * able to complete the request successfully.
1132 LIST_FOREACH(p, &pg->pg_members, p_pglist) {
1134 if (p->p_state == PRS_NEW ||
1135 p->p_state == PRS_ZOMBIE ||
1136 (cmd_info->need_candebug ? p_candebug(td, p) :
1137 p_cansee(td, p)) != 0) {
1141 error = kern_procctl_single(td, p, com, data);
1145 else if (first_error == 0)
1146 first_error = error;
1150 else if (first_error != 0)
1151 error = first_error;
1154 * Was not able to see any processes in the
1164 switch (cmd_info->lock_tree) {
1166 sx_xunlock(&proctree_lock);
1169 sx_sunlock(&proctree_lock);
1175 stop_all_proc_unblock();