1 /*- 2 * Copyright (c) 2014 John Baldwin 3 * Copyright (c) 2014, 2016 The FreeBSD Foundation 4 * 5 * Portions of this software were developed by Konstantin Belousov 6 * under sponsorship from the FreeBSD Foundation. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 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. 16 * 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 27 * SUCH DAMAGE. 28 */ 29 30 #include "opt_ktrace.h" 31 32 #include <sys/param.h> 33 #include <sys/_unrhdr.h> 34 #include <sys/systm.h> 35 #include <sys/capsicum.h> 36 #include <sys/lock.h> 37 #include <sys/malloc.h> 38 #include <sys/mman.h> 39 #include <sys/mutex.h> 40 #include <sys/priv.h> 41 #include <sys/proc.h> 42 #include <sys/procctl.h> 43 #include <sys/sx.h> 44 #include <sys/syscallsubr.h> 45 #include <sys/sysproto.h> 46 #include <sys/wait.h> 47 48 #include <vm/vm.h> 49 #include <vm/pmap.h> 50 #include <vm/vm_map.h> 51 #include <vm/vm_extern.h> 52 53 static int 54 protect_setchild(struct thread *td, struct proc *p, int flags) 55 { 56 57 PROC_LOCK_ASSERT(p, MA_OWNED); 58 if (p->p_flag & P_SYSTEM || p_cansched(td, p) != 0) 59 return (0); 60 if (flags & PPROT_SET) { 61 p->p_flag |= P_PROTECTED; 62 if (flags & PPROT_INHERIT) 63 p->p_flag2 |= P2_INHERIT_PROTECTED; 64 } else { 65 p->p_flag &= ~P_PROTECTED; 66 p->p_flag2 &= ~P2_INHERIT_PROTECTED; 67 } 68 return (1); 69 } 70 71 static int 72 protect_setchildren(struct thread *td, struct proc *top, int flags) 73 { 74 struct proc *p; 75 int ret; 76 77 p = top; 78 ret = 0; 79 sx_assert(&proctree_lock, SX_LOCKED); 80 for (;;) { 81 ret |= protect_setchild(td, p, flags); 82 PROC_UNLOCK(p); 83 /* 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). 87 */ 88 if (!LIST_EMPTY(&p->p_children)) 89 p = LIST_FIRST(&p->p_children); 90 else for (;;) { 91 if (p == top) { 92 PROC_LOCK(p); 93 return (ret); 94 } 95 if (LIST_NEXT(p, p_sibling)) { 96 p = LIST_NEXT(p, p_sibling); 97 break; 98 } 99 p = p->p_pptr; 100 } 101 PROC_LOCK(p); 102 } 103 } 104 105 static int 106 protect_set(struct thread *td, struct proc *p, void *data) 107 { 108 int error, flags, ret; 109 110 flags = *(int *)data; 111 switch (PPROT_OP(flags)) { 112 case PPROT_SET: 113 case PPROT_CLEAR: 114 break; 115 default: 116 return (EINVAL); 117 } 118 119 if ((PPROT_FLAGS(flags) & ~(PPROT_DESCEND | PPROT_INHERIT)) != 0) 120 return (EINVAL); 121 122 error = priv_check(td, PRIV_VM_MADV_PROTECT); 123 if (error) 124 return (error); 125 126 if (flags & PPROT_DESCEND) 127 ret = protect_setchildren(td, p, flags); 128 else 129 ret = protect_setchild(td, p, flags); 130 if (ret == 0) 131 return (EPERM); 132 return (0); 133 } 134 135 static struct proc * 136 get_reaper_or_p(struct proc *p) 137 { 138 sx_assert(&proctree_lock, SX_LOCKED); 139 return ((p->p_treeflag & P_TREE_REAPER) == 0 ? p->p_reaper : p); 140 } 141 142 static int 143 reap_acquire(struct thread *td, struct proc *p, void *data __unused) 144 { 145 146 sx_assert(&proctree_lock, SX_XLOCKED); 147 if (p != td->td_proc) 148 return (EPERM); 149 if ((p->p_treeflag & P_TREE_REAPER) != 0) 150 return (EBUSY); 151 p->p_treeflag |= P_TREE_REAPER; 152 /* 153 * We do not reattach existing children and the whole tree 154 * under them to us, since p->p_reaper already seen them. 155 */ 156 return (0); 157 } 158 159 static int 160 reap_release(struct thread *td, struct proc *p, void *data __unused) 161 { 162 163 sx_assert(&proctree_lock, SX_XLOCKED); 164 if (p != td->td_proc) 165 return (EPERM); 166 if (p == initproc) 167 return (EINVAL); 168 if ((p->p_treeflag & P_TREE_REAPER) == 0) 169 return (EINVAL); 170 reaper_abandon_children(p, false); 171 return (0); 172 } 173 174 static int 175 reap_status(struct thread *td, struct proc *p, void *data) 176 { 177 struct proc *reap, *p2, *first_p; 178 struct procctl_reaper_status *rs; 179 180 rs = data; 181 sx_assert(&proctree_lock, SX_LOCKED); 182 reap = get_reaper_or_p(p); 183 if (reap == p) 184 rs->rs_flags |= REAPER_STATUS_OWNED; 185 if (reap == initproc) 186 rs->rs_flags |= REAPER_STATUS_REALINIT; 187 rs->rs_reaper = reap->p_pid; 188 rs->rs_descendants = 0; 189 rs->rs_children = 0; 190 if (!LIST_EMPTY(&reap->p_reaplist)) { 191 first_p = LIST_FIRST(&reap->p_children); 192 if (first_p == NULL) 193 first_p = LIST_FIRST(&reap->p_reaplist); 194 rs->rs_pid = first_p->p_pid; 195 LIST_FOREACH(p2, &reap->p_reaplist, p_reapsibling) { 196 if (proc_realparent(p2) == reap) 197 rs->rs_children++; 198 rs->rs_descendants++; 199 } 200 } else { 201 rs->rs_pid = -1; 202 } 203 return (0); 204 } 205 206 static int 207 reap_getpids_count(struct proc **reapp, struct proc *p, 208 const struct procctl_reaper_pids *rp) 209 { 210 struct proc *reap, *p2; 211 int n; 212 213 sx_assert(&proctree_lock, SX_LOCKED); 214 215 reap = get_reaper_or_p(p); 216 n = 0; 217 LIST_FOREACH(p2, &reap->p_reaplist, p_reapsibling) 218 n++; 219 if (rp->rp_count < n) 220 n = rp->rp_count; 221 *reapp = reap; 222 return (n); 223 } 224 225 static int 226 reap_getpids(struct thread *td, struct proc *p, void *data) 227 { 228 struct proc *reap, *p2; 229 struct procctl_reaper_pidinfo *pi, *pip; 230 struct procctl_reaper_pids *rp; 231 u_int i, n, n1; 232 int error; 233 234 rp = data; 235 sx_assert(&proctree_lock, SX_LOCKED); 236 PROC_UNLOCK(p); 237 i = 0; 238 for (;;) { 239 n1 = reap_getpids_count(&reap, p, rp); 240 sx_unlock(&proctree_lock); 241 pi = mallocarray(n1, sizeof(*pi), M_TEMP, M_WAITOK); 242 sx_slock(&proctree_lock); 243 n = reap_getpids_count(&reap, p, rp); 244 if (n <= n1) 245 break; 246 free(pi, M_TEMP); 247 } 248 249 LIST_FOREACH(p2, &reap->p_reaplist, p_reapsibling) { 250 if (i == n) 251 break; 252 pip = &pi[i]; 253 bzero(pip, sizeof(*pip)); 254 pip->pi_pid = p2->p_pid; 255 pip->pi_subtree = p2->p_reapsubtree; 256 pip->pi_flags = REAPER_PIDINFO_VALID; 257 if (proc_realparent(p2) == reap) 258 pip->pi_flags |= REAPER_PIDINFO_CHILD; 259 if ((p2->p_treeflag & P_TREE_REAPER) != 0) 260 pip->pi_flags |= REAPER_PIDINFO_REAPER; 261 if ((p2->p_flag & P_STOPPED) != 0) 262 pip->pi_flags |= REAPER_PIDINFO_STOPPED; 263 if (p2->p_state == PRS_ZOMBIE) 264 pip->pi_flags |= REAPER_PIDINFO_ZOMBIE; 265 else if ((p2->p_flag & P_WEXIT) != 0) 266 pip->pi_flags |= REAPER_PIDINFO_EXITING; 267 i++; 268 } 269 sx_sunlock(&proctree_lock); 270 error = copyout(pi, rp->rp_pids, i * sizeof(*pi)); 271 free(pi, M_TEMP); 272 sx_slock(&proctree_lock); 273 PROC_LOCK(p); 274 return (error); 275 } 276 277 struct reap_kill_proc_work { 278 struct ucred *cr; 279 struct proc *target; 280 ksiginfo_t *ksi; 281 struct procctl_reaper_kill *rk; 282 int *error; 283 }; 284 285 static void 286 reap_kill_proc_locked(struct reap_kill_proc_work *w) 287 { 288 int error; 289 290 PROC_LOCK_ASSERT(w->target, MA_OWNED); 291 PROC_ASSERT_HELD(w->target); 292 293 error = cr_cansignal(w->cr, w->target, w->rk->rk_sig); 294 if (error != 0) { 295 /* 296 * Hide ESRCH errors to ensure that this function 297 * cannot be used as an oracle for process visibility. 298 */ 299 if (error != ESRCH && *w->error == 0) { 300 w->rk->rk_fpid = w->target->p_pid; 301 *w->error = error; 302 } 303 return; 304 } 305 306 (void)pksignal(w->target, w->rk->rk_sig, w->ksi); 307 w->rk->rk_killed++; 308 *w->error = error; 309 } 310 311 static void 312 reap_kill_proc(struct reap_kill_proc_work *w, bool *proctree_dropped) 313 { 314 struct pgrp *pgrp; 315 int xlocked; 316 317 sx_assert(&proctree_lock, SX_LOCKED); 318 xlocked = sx_xlocked(&proctree_lock); 319 PROC_LOCK_ASSERT(w->target, MA_OWNED); 320 PROC_ASSERT_HELD(w->target); 321 322 /* Sync with forks. */ 323 for (;;) { 324 /* 325 * Short-circuit handling of the exiting process, do 326 * not wait for it to single-thread (hold prevents it 327 * from exiting further). This avoids 328 * locking pg_killsx for it, and reduces the 329 * proctree_lock contention. 330 */ 331 if ((w->target->p_flag2 & P2_WEXIT) != 0) 332 return; 333 334 pgrp = w->target->p_pgrp; 335 if (pgrp == NULL || sx_try_xlock(&pgrp->pg_killsx)) 336 break; 337 338 PROC_UNLOCK(w->target); 339 sx_unlock(&proctree_lock); 340 /* This is safe because pgrp zone is nofree. */ 341 sx_xlock(&pgrp->pg_killsx); 342 sx_xunlock(&pgrp->pg_killsx); 343 *proctree_dropped = true; 344 if (xlocked) 345 sx_xlock(&proctree_lock); 346 else 347 sx_slock(&proctree_lock); 348 PROC_LOCK(w->target); 349 } 350 351 reap_kill_proc_locked(w); 352 353 if (pgrp != NULL) 354 sx_xunlock(&pgrp->pg_killsx); 355 } 356 357 struct reap_kill_tracker { 358 struct proc *parent; 359 TAILQ_ENTRY(reap_kill_tracker) link; 360 }; 361 362 TAILQ_HEAD(reap_kill_tracker_head, reap_kill_tracker); 363 364 static void 365 reap_kill_sched(struct reap_kill_tracker_head *tracker, struct proc *p2) 366 { 367 struct reap_kill_tracker *t; 368 369 PROC_LOCK(p2); 370 if ((p2->p_flag2 & P2_WEXIT) != 0) { 371 PROC_UNLOCK(p2); 372 return; 373 } 374 _PHOLD(p2); 375 PROC_UNLOCK(p2); 376 t = malloc(sizeof(struct reap_kill_tracker), M_TEMP, M_WAITOK); 377 t->parent = p2; 378 TAILQ_INSERT_TAIL(tracker, t, link); 379 } 380 381 static void 382 reap_kill_sched_free(struct reap_kill_tracker *t) 383 { 384 PRELE(t->parent); 385 free(t, M_TEMP); 386 } 387 388 static void 389 reap_kill_children(struct thread *td, struct proc *reaper, 390 struct procctl_reaper_kill *rk, ksiginfo_t *ksi, int *error) 391 { 392 struct proc *p2; 393 int error1; 394 395 LIST_FOREACH(p2, &reaper->p_children, p_sibling) { 396 PROC_LOCK(p2); 397 if ((p2->p_flag2 & P2_WEXIT) == 0) { 398 error1 = p_cansignal(td, p2, rk->rk_sig); 399 if (error1 != 0) { 400 if (*error == ESRCH) { 401 rk->rk_fpid = p2->p_pid; 402 *error = error1; 403 } 404 405 /* 406 * Do not end the loop on error, 407 * signal everything we can. 408 */ 409 } else { 410 (void)pksignal(p2, rk->rk_sig, ksi); 411 rk->rk_killed++; 412 } 413 } 414 PROC_UNLOCK(p2); 415 } 416 } 417 418 static bool 419 reap_kill_subtree_once(struct thread *td, struct proc *p, struct proc *reaper, 420 struct unrhdr *pids, struct reap_kill_proc_work *w) 421 { 422 struct reap_kill_tracker_head tracker; 423 struct reap_kill_tracker *t; 424 struct proc *p2; 425 bool proctree_dropped, res; 426 427 res = false; 428 TAILQ_INIT(&tracker); 429 reap_kill_sched(&tracker, reaper); 430 while ((t = TAILQ_FIRST(&tracker)) != NULL) { 431 TAILQ_REMOVE(&tracker, t, link); 432 433 again: 434 /* 435 * Since reap_kill_proc() drops proctree_lock sx, it 436 * is possible that the tracked reaper is no longer. 437 * In this case the subtree is reparented to the new 438 * reaper, which should handle it. 439 */ 440 if ((t->parent->p_treeflag & P_TREE_REAPER) == 0) { 441 reap_kill_sched_free(t); 442 res = true; 443 continue; 444 } 445 446 LIST_FOREACH(p2, &t->parent->p_reaplist, p_reapsibling) { 447 if (t->parent == reaper && 448 (w->rk->rk_flags & REAPER_KILL_SUBTREE) != 0 && 449 p2->p_reapsubtree != w->rk->rk_subtree) 450 continue; 451 if ((p2->p_treeflag & P_TREE_REAPER) != 0) 452 reap_kill_sched(&tracker, p2); 453 454 /* 455 * Handle possible pid reuse. If we recorded 456 * p2 as killed but its p_flag2 does not 457 * confirm it, that means that the process 458 * terminated and its id was reused by other 459 * process in the reaper subtree. 460 * 461 * Unlocked read of p2->p_flag2 is fine, it is 462 * our thread that set the tested flag. 463 */ 464 if (alloc_unr_specific(pids, p2->p_pid) != p2->p_pid && 465 (atomic_load_int(&p2->p_flag2) & 466 (P2_REAPKILLED | P2_WEXIT)) != 0) 467 continue; 468 469 proctree_dropped = false; 470 PROC_LOCK(p2); 471 if ((p2->p_flag2 & P2_WEXIT) == 0) { 472 _PHOLD(p2); 473 474 /* 475 * sapblk ensures that only one thread 476 * in the system sets this flag. 477 */ 478 p2->p_flag2 |= P2_REAPKILLED; 479 480 w->target = p2; 481 reap_kill_proc(w, &proctree_dropped); 482 _PRELE(p2); 483 } 484 PROC_UNLOCK(p2); 485 res = true; 486 if (proctree_dropped) 487 goto again; 488 } 489 reap_kill_sched_free(t); 490 } 491 return (res); 492 } 493 494 static void 495 reap_kill_subtree(struct thread *td, struct proc *p, struct proc *reaper, 496 struct reap_kill_proc_work *w) 497 { 498 struct unrhdr pids; 499 void *ihandle; 500 struct proc *p2; 501 int pid; 502 503 /* 504 * pids records processes which were already signalled, to 505 * avoid doubling signals to them if iteration needs to be 506 * repeated. 507 */ 508 init_unrhdr(&pids, 1, PID_MAX, UNR_NO_MTX); 509 PROC_LOCK(td->td_proc); 510 if ((td->td_proc->p_flag2 & P2_WEXIT) != 0) { 511 PROC_UNLOCK(td->td_proc); 512 goto out; 513 } 514 PROC_UNLOCK(td->td_proc); 515 while (reap_kill_subtree_once(td, p, reaper, &pids, w)) 516 ; 517 518 ihandle = create_iter_unr(&pids); 519 while ((pid = next_iter_unr(ihandle)) != -1) { 520 p2 = pfind(pid); 521 if (p2 != NULL) { 522 p2->p_flag2 &= ~P2_REAPKILLED; 523 PROC_UNLOCK(p2); 524 } 525 } 526 free_iter_unr(ihandle); 527 528 out: 529 clean_unrhdr(&pids); 530 clear_unrhdr(&pids); 531 } 532 533 static bool 534 reap_kill_sapblk(struct thread *td __unused, void *data) 535 { 536 struct procctl_reaper_kill *rk; 537 538 rk = data; 539 return ((rk->rk_flags & REAPER_KILL_CHILDREN) == 0); 540 } 541 542 static int 543 reap_kill(struct thread *td, struct proc *p, void *data) 544 { 545 struct reap_kill_proc_work w; 546 struct proc *reaper; 547 ksiginfo_t ksi; 548 struct procctl_reaper_kill *rk; 549 int error; 550 551 rk = data; 552 sx_assert(&proctree_lock, SX_LOCKED); 553 if (CAP_TRACING(td)) 554 ktrcapfail(CAPFAIL_SIGNAL, &rk->rk_sig); 555 if (IN_CAPABILITY_MODE(td)) 556 return (ECAPMODE); 557 if (rk->rk_sig <= 0 || rk->rk_sig > _SIG_MAXSIG || 558 (rk->rk_flags & ~(REAPER_KILL_CHILDREN | 559 REAPER_KILL_SUBTREE)) != 0 || (rk->rk_flags & 560 (REAPER_KILL_CHILDREN | REAPER_KILL_SUBTREE)) == 561 (REAPER_KILL_CHILDREN | REAPER_KILL_SUBTREE)) 562 return (EINVAL); 563 PROC_UNLOCK(p); 564 reaper = get_reaper_or_p(p); 565 ksiginfo_init(&ksi); 566 ksi.ksi_signo = rk->rk_sig; 567 ksi.ksi_code = SI_USER; 568 ksi.ksi_pid = td->td_proc->p_pid; 569 ksi.ksi_uid = td->td_ucred->cr_ruid; 570 error = ESRCH; 571 rk->rk_killed = 0; 572 rk->rk_fpid = -1; 573 if ((rk->rk_flags & REAPER_KILL_CHILDREN) != 0) { 574 reap_kill_children(td, reaper, rk, &ksi, &error); 575 } else { 576 w.cr = crhold(td->td_ucred); 577 w.ksi = &ksi; 578 w.rk = rk; 579 w.error = &error; 580 reap_kill_subtree(td, p, reaper, &w); 581 crfree(w.cr); 582 } 583 PROC_LOCK(p); 584 return (error); 585 } 586 587 static int 588 trace_ctl(struct thread *td, struct proc *p, void *data) 589 { 590 int state; 591 592 PROC_LOCK_ASSERT(p, MA_OWNED); 593 state = *(int *)data; 594 595 /* 596 * Ktrace changes p_traceflag from or to zero under the 597 * process lock, so the test does not need to acquire ktrace 598 * mutex. 599 */ 600 if ((p->p_flag & P_TRACED) != 0 || p->p_traceflag != 0) 601 return (EBUSY); 602 603 switch (state) { 604 case PROC_TRACE_CTL_ENABLE: 605 if (td->td_proc != p) 606 return (EPERM); 607 p->p_flag2 &= ~(P2_NOTRACE | P2_NOTRACE_EXEC); 608 break; 609 case PROC_TRACE_CTL_DISABLE_EXEC: 610 p->p_flag2 |= P2_NOTRACE_EXEC | P2_NOTRACE; 611 break; 612 case PROC_TRACE_CTL_DISABLE: 613 if ((p->p_flag2 & P2_NOTRACE_EXEC) != 0) { 614 KASSERT((p->p_flag2 & P2_NOTRACE) != 0, 615 ("dandling P2_NOTRACE_EXEC")); 616 if (td->td_proc != p) 617 return (EPERM); 618 p->p_flag2 &= ~P2_NOTRACE_EXEC; 619 } else { 620 p->p_flag2 |= P2_NOTRACE; 621 } 622 break; 623 default: 624 return (EINVAL); 625 } 626 return (0); 627 } 628 629 static int 630 trace_status(struct thread *td, struct proc *p, void *data) 631 { 632 int *status; 633 634 status = data; 635 if ((p->p_flag2 & P2_NOTRACE) != 0) { 636 KASSERT((p->p_flag & P_TRACED) == 0, 637 ("%d traced but tracing disabled", p->p_pid)); 638 *status = -1; 639 } else if ((p->p_flag & P_TRACED) != 0) { 640 *status = p->p_pptr->p_pid; 641 } else { 642 *status = 0; 643 } 644 return (0); 645 } 646 647 static int 648 trapcap_ctl(struct thread *td, struct proc *p, void *data) 649 { 650 int state; 651 652 PROC_LOCK_ASSERT(p, MA_OWNED); 653 state = *(int *)data; 654 655 switch (state) { 656 case PROC_TRAPCAP_CTL_ENABLE: 657 p->p_flag2 |= P2_TRAPCAP; 658 break; 659 case PROC_TRAPCAP_CTL_DISABLE: 660 p->p_flag2 &= ~P2_TRAPCAP; 661 break; 662 default: 663 return (EINVAL); 664 } 665 return (0); 666 } 667 668 static int 669 trapcap_status(struct thread *td, struct proc *p, void *data) 670 { 671 int *status; 672 673 status = data; 674 *status = (p->p_flag2 & P2_TRAPCAP) != 0 ? PROC_TRAPCAP_CTL_ENABLE : 675 PROC_TRAPCAP_CTL_DISABLE; 676 return (0); 677 } 678 679 static int 680 no_new_privs_ctl(struct thread *td, struct proc *p, void *data) 681 { 682 int state; 683 684 PROC_LOCK_ASSERT(p, MA_OWNED); 685 state = *(int *)data; 686 687 if (state != PROC_NO_NEW_PRIVS_ENABLE) 688 return (EINVAL); 689 p->p_flag2 |= P2_NO_NEW_PRIVS; 690 return (0); 691 } 692 693 static int 694 no_new_privs_status(struct thread *td, struct proc *p, void *data) 695 { 696 697 *(int *)data = (p->p_flag2 & P2_NO_NEW_PRIVS) != 0 ? 698 PROC_NO_NEW_PRIVS_ENABLE : PROC_NO_NEW_PRIVS_DISABLE; 699 return (0); 700 } 701 702 static int 703 protmax_ctl(struct thread *td, struct proc *p, void *data) 704 { 705 int state; 706 707 PROC_LOCK_ASSERT(p, MA_OWNED); 708 state = *(int *)data; 709 710 switch (state) { 711 case PROC_PROTMAX_FORCE_ENABLE: 712 p->p_flag2 &= ~P2_PROTMAX_DISABLE; 713 p->p_flag2 |= P2_PROTMAX_ENABLE; 714 break; 715 case PROC_PROTMAX_FORCE_DISABLE: 716 p->p_flag2 |= P2_PROTMAX_DISABLE; 717 p->p_flag2 &= ~P2_PROTMAX_ENABLE; 718 break; 719 case PROC_PROTMAX_NOFORCE: 720 p->p_flag2 &= ~(P2_PROTMAX_ENABLE | P2_PROTMAX_DISABLE); 721 break; 722 default: 723 return (EINVAL); 724 } 725 return (0); 726 } 727 728 static int 729 protmax_status(struct thread *td, struct proc *p, void *data) 730 { 731 int d; 732 733 switch (p->p_flag2 & (P2_PROTMAX_ENABLE | P2_PROTMAX_DISABLE)) { 734 case 0: 735 d = PROC_PROTMAX_NOFORCE; 736 break; 737 case P2_PROTMAX_ENABLE: 738 d = PROC_PROTMAX_FORCE_ENABLE; 739 break; 740 case P2_PROTMAX_DISABLE: 741 d = PROC_PROTMAX_FORCE_DISABLE; 742 break; 743 } 744 if (kern_mmap_maxprot(p, PROT_READ) == PROT_READ) 745 d |= PROC_PROTMAX_ACTIVE; 746 *(int *)data = d; 747 return (0); 748 } 749 750 static int 751 aslr_ctl(struct thread *td, struct proc *p, void *data) 752 { 753 int state; 754 755 PROC_LOCK_ASSERT(p, MA_OWNED); 756 state = *(int *)data; 757 758 switch (state) { 759 case PROC_ASLR_FORCE_ENABLE: 760 p->p_flag2 &= ~P2_ASLR_DISABLE; 761 p->p_flag2 |= P2_ASLR_ENABLE; 762 break; 763 case PROC_ASLR_FORCE_DISABLE: 764 p->p_flag2 |= P2_ASLR_DISABLE; 765 p->p_flag2 &= ~P2_ASLR_ENABLE; 766 break; 767 case PROC_ASLR_NOFORCE: 768 p->p_flag2 &= ~(P2_ASLR_ENABLE | P2_ASLR_DISABLE); 769 break; 770 default: 771 return (EINVAL); 772 } 773 return (0); 774 } 775 776 static int 777 aslr_status(struct thread *td, struct proc *p, void *data) 778 { 779 struct vmspace *vm; 780 int d; 781 782 switch (p->p_flag2 & (P2_ASLR_ENABLE | P2_ASLR_DISABLE)) { 783 case 0: 784 d = PROC_ASLR_NOFORCE; 785 break; 786 case P2_ASLR_ENABLE: 787 d = PROC_ASLR_FORCE_ENABLE; 788 break; 789 case P2_ASLR_DISABLE: 790 d = PROC_ASLR_FORCE_DISABLE; 791 break; 792 } 793 PROC_UNLOCK(p); 794 vm = vmspace_acquire_ref(p); 795 if (vm != NULL) { 796 if ((vm->vm_map.flags & MAP_ASLR) != 0) 797 d |= PROC_ASLR_ACTIVE; 798 vmspace_free(vm); 799 } 800 *(int *)data = d; 801 PROC_LOCK(p); 802 return (0); 803 } 804 805 static int 806 stackgap_ctl(struct thread *td, struct proc *p, void *data) 807 { 808 int state; 809 810 PROC_LOCK_ASSERT(p, MA_OWNED); 811 state = *(int *)data; 812 813 if ((state & ~(PROC_STACKGAP_ENABLE | PROC_STACKGAP_DISABLE | 814 PROC_STACKGAP_ENABLE_EXEC | PROC_STACKGAP_DISABLE_EXEC)) != 0) 815 return (EINVAL); 816 switch (state & (PROC_STACKGAP_ENABLE | PROC_STACKGAP_DISABLE)) { 817 case PROC_STACKGAP_ENABLE: 818 if ((p->p_flag2 & P2_STKGAP_DISABLE) != 0) 819 return (EINVAL); 820 break; 821 case PROC_STACKGAP_DISABLE: 822 p->p_flag2 |= P2_STKGAP_DISABLE; 823 break; 824 case 0: 825 break; 826 default: 827 return (EINVAL); 828 } 829 switch (state & (PROC_STACKGAP_ENABLE_EXEC | 830 PROC_STACKGAP_DISABLE_EXEC)) { 831 case PROC_STACKGAP_ENABLE_EXEC: 832 p->p_flag2 &= ~P2_STKGAP_DISABLE_EXEC; 833 break; 834 case PROC_STACKGAP_DISABLE_EXEC: 835 p->p_flag2 |= P2_STKGAP_DISABLE_EXEC; 836 break; 837 case 0: 838 break; 839 default: 840 return (EINVAL); 841 } 842 return (0); 843 } 844 845 static int 846 stackgap_status(struct thread *td, struct proc *p, void *data) 847 { 848 int d; 849 850 PROC_LOCK_ASSERT(p, MA_OWNED); 851 852 d = (p->p_flag2 & P2_STKGAP_DISABLE) != 0 ? PROC_STACKGAP_DISABLE : 853 PROC_STACKGAP_ENABLE; 854 d |= (p->p_flag2 & P2_STKGAP_DISABLE_EXEC) != 0 ? 855 PROC_STACKGAP_DISABLE_EXEC : PROC_STACKGAP_ENABLE_EXEC; 856 *(int *)data = d; 857 return (0); 858 } 859 860 static int 861 wxmap_ctl(struct thread *td, struct proc *p, void *data) 862 { 863 struct vmspace *vm; 864 vm_map_t map; 865 int state; 866 867 PROC_LOCK_ASSERT(p, MA_OWNED); 868 state = *(int *)data; 869 870 switch (state) { 871 case PROC_WX_MAPPINGS_PERMIT: 872 p->p_flag2 |= P2_WXORX_DISABLE; 873 PROC_UNLOCK(p); 874 vm = vmspace_acquire_ref(p); 875 if (vm != NULL) { 876 map = &vm->vm_map; 877 vm_map_lock(map); 878 map->flags &= ~MAP_WXORX; 879 vm_map_unlock(map); 880 vmspace_free(vm); 881 } 882 PROC_LOCK(p); 883 break; 884 case PROC_WX_MAPPINGS_DISALLOW_EXEC: 885 p->p_flag2 |= P2_WXORX_ENABLE_EXEC; 886 break; 887 default: 888 return (EINVAL); 889 } 890 891 return (0); 892 } 893 894 static int 895 wxmap_status(struct thread *td, struct proc *p, void *data) 896 { 897 struct vmspace *vm; 898 int d; 899 900 PROC_LOCK_ASSERT(p, MA_OWNED); 901 902 d = 0; 903 if ((p->p_flag2 & P2_WXORX_DISABLE) != 0) 904 d |= PROC_WX_MAPPINGS_PERMIT; 905 if ((p->p_flag2 & P2_WXORX_ENABLE_EXEC) != 0) 906 d |= PROC_WX_MAPPINGS_DISALLOW_EXEC; 907 PROC_UNLOCK(p); 908 vm = vmspace_acquire_ref(p); 909 if (vm != NULL) { 910 if ((vm->vm_map.flags & MAP_WXORX) != 0) 911 d |= PROC_WXORX_ENFORCE; 912 vmspace_free(vm); 913 } 914 *(int *)data = d; 915 PROC_LOCK(p); 916 return (0); 917 } 918 919 static int 920 pdeathsig_ctl(struct thread *td, struct proc *p, void *data) 921 { 922 int signum; 923 924 signum = *(int *)data; 925 if (p != td->td_proc || (signum != 0 && !_SIG_VALID(signum))) 926 return (EINVAL); 927 p->p_pdeathsig = signum; 928 return (0); 929 } 930 931 static int 932 pdeathsig_status(struct thread *td, struct proc *p, void *data) 933 { 934 if (p != td->td_proc) 935 return (EINVAL); 936 *(int *)data = p->p_pdeathsig; 937 return (0); 938 } 939 940 static int 941 logsigexit_ctl(struct thread *td, struct proc *p, void *data) 942 { 943 int state; 944 945 PROC_LOCK_ASSERT(p, MA_OWNED); 946 state = *(int *)data; 947 948 switch (state) { 949 case PROC_LOGSIGEXIT_CTL_NOFORCE: 950 p->p_flag2 &= ~(P2_LOGSIGEXIT_CTL | P2_LOGSIGEXIT_ENABLE); 951 break; 952 case PROC_LOGSIGEXIT_CTL_FORCE_ENABLE: 953 p->p_flag2 |= P2_LOGSIGEXIT_CTL | P2_LOGSIGEXIT_ENABLE; 954 break; 955 case PROC_LOGSIGEXIT_CTL_FORCE_DISABLE: 956 p->p_flag2 |= P2_LOGSIGEXIT_CTL; 957 p->p_flag2 &= ~P2_LOGSIGEXIT_ENABLE; 958 break; 959 default: 960 return (EINVAL); 961 } 962 return (0); 963 } 964 965 static int 966 logsigexit_status(struct thread *td, struct proc *p, void *data) 967 { 968 int state; 969 970 if ((p->p_flag2 & P2_LOGSIGEXIT_CTL) == 0) 971 state = PROC_LOGSIGEXIT_CTL_NOFORCE; 972 else if ((p->p_flag2 & P2_LOGSIGEXIT_ENABLE) != 0) 973 state = PROC_LOGSIGEXIT_CTL_FORCE_ENABLE; 974 else 975 state = PROC_LOGSIGEXIT_CTL_FORCE_DISABLE; 976 *(int *)data = state; 977 return (0); 978 } 979 980 enum { 981 PCTL_SLOCKED, 982 PCTL_XLOCKED, 983 PCTL_UNLOCKED, 984 }; 985 986 struct procctl_cmd_info { 987 int lock_tree; 988 bool one_proc : 1; 989 bool esrch_is_einval : 1; 990 bool copyout_on_error : 1; 991 bool no_nonnull_data : 1; 992 bool need_candebug : 1; 993 int copyin_sz; 994 int copyout_sz; 995 int (*exec)(struct thread *, struct proc *, void *); 996 bool (*sapblk)(struct thread *, void *); 997 }; 998 static const struct procctl_cmd_info procctl_cmds_info[] = { 999 [PROC_SPROTECT] = 1000 { .lock_tree = PCTL_SLOCKED, .one_proc = false, 1001 .esrch_is_einval = false, .no_nonnull_data = false, 1002 .need_candebug = false, 1003 .copyin_sz = sizeof(int), .copyout_sz = 0, 1004 .exec = protect_set, .copyout_on_error = false, }, 1005 [PROC_REAP_ACQUIRE] = 1006 { .lock_tree = PCTL_XLOCKED, .one_proc = true, 1007 .esrch_is_einval = false, .no_nonnull_data = true, 1008 .need_candebug = false, 1009 .copyin_sz = 0, .copyout_sz = 0, 1010 .exec = reap_acquire, .copyout_on_error = false, }, 1011 [PROC_REAP_RELEASE] = 1012 { .lock_tree = PCTL_XLOCKED, .one_proc = true, 1013 .esrch_is_einval = false, .no_nonnull_data = true, 1014 .need_candebug = false, 1015 .copyin_sz = 0, .copyout_sz = 0, 1016 .exec = reap_release, .copyout_on_error = false, }, 1017 [PROC_REAP_STATUS] = 1018 { .lock_tree = PCTL_SLOCKED, .one_proc = true, 1019 .esrch_is_einval = false, .no_nonnull_data = false, 1020 .need_candebug = false, 1021 .copyin_sz = 0, 1022 .copyout_sz = sizeof(struct procctl_reaper_status), 1023 .exec = reap_status, .copyout_on_error = false, }, 1024 [PROC_REAP_GETPIDS] = 1025 { .lock_tree = PCTL_SLOCKED, .one_proc = true, 1026 .esrch_is_einval = false, .no_nonnull_data = false, 1027 .need_candebug = false, 1028 .copyin_sz = sizeof(struct procctl_reaper_pids), 1029 .copyout_sz = 0, 1030 .exec = reap_getpids, .copyout_on_error = false, }, 1031 [PROC_REAP_KILL] = 1032 { .lock_tree = PCTL_SLOCKED, .one_proc = true, 1033 .esrch_is_einval = false, .no_nonnull_data = false, 1034 .need_candebug = false, 1035 .copyin_sz = sizeof(struct procctl_reaper_kill), 1036 .copyout_sz = sizeof(struct procctl_reaper_kill), 1037 .exec = reap_kill, .copyout_on_error = true, 1038 .sapblk = reap_kill_sapblk, }, 1039 [PROC_TRACE_CTL] = 1040 { .lock_tree = PCTL_SLOCKED, .one_proc = false, 1041 .esrch_is_einval = false, .no_nonnull_data = false, 1042 .need_candebug = true, 1043 .copyin_sz = sizeof(int), .copyout_sz = 0, 1044 .exec = trace_ctl, .copyout_on_error = false, }, 1045 [PROC_TRACE_STATUS] = 1046 { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 1047 .esrch_is_einval = false, .no_nonnull_data = false, 1048 .need_candebug = false, 1049 .copyin_sz = 0, .copyout_sz = sizeof(int), 1050 .exec = trace_status, .copyout_on_error = false, }, 1051 [PROC_TRAPCAP_CTL] = 1052 { .lock_tree = PCTL_SLOCKED, .one_proc = false, 1053 .esrch_is_einval = false, .no_nonnull_data = false, 1054 .need_candebug = true, 1055 .copyin_sz = sizeof(int), .copyout_sz = 0, 1056 .exec = trapcap_ctl, .copyout_on_error = false, }, 1057 [PROC_TRAPCAP_STATUS] = 1058 { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 1059 .esrch_is_einval = false, .no_nonnull_data = false, 1060 .need_candebug = false, 1061 .copyin_sz = 0, .copyout_sz = sizeof(int), 1062 .exec = trapcap_status, .copyout_on_error = false, }, 1063 [PROC_PDEATHSIG_CTL] = 1064 { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 1065 .esrch_is_einval = true, .no_nonnull_data = false, 1066 .need_candebug = false, 1067 .copyin_sz = sizeof(int), .copyout_sz = 0, 1068 .exec = pdeathsig_ctl, .copyout_on_error = false, }, 1069 [PROC_PDEATHSIG_STATUS] = 1070 { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 1071 .esrch_is_einval = true, .no_nonnull_data = false, 1072 .need_candebug = false, 1073 .copyin_sz = 0, .copyout_sz = sizeof(int), 1074 .exec = pdeathsig_status, .copyout_on_error = false, }, 1075 [PROC_ASLR_CTL] = 1076 { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 1077 .esrch_is_einval = false, .no_nonnull_data = false, 1078 .need_candebug = true, 1079 .copyin_sz = sizeof(int), .copyout_sz = 0, 1080 .exec = aslr_ctl, .copyout_on_error = false, }, 1081 [PROC_ASLR_STATUS] = 1082 { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 1083 .esrch_is_einval = false, .no_nonnull_data = false, 1084 .need_candebug = false, 1085 .copyin_sz = 0, .copyout_sz = sizeof(int), 1086 .exec = aslr_status, .copyout_on_error = false, }, 1087 [PROC_PROTMAX_CTL] = 1088 { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 1089 .esrch_is_einval = false, .no_nonnull_data = false, 1090 .need_candebug = true, 1091 .copyin_sz = sizeof(int), .copyout_sz = 0, 1092 .exec = protmax_ctl, .copyout_on_error = false, }, 1093 [PROC_PROTMAX_STATUS] = 1094 { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 1095 .esrch_is_einval = false, .no_nonnull_data = false, 1096 .need_candebug = false, 1097 .copyin_sz = 0, .copyout_sz = sizeof(int), 1098 .exec = protmax_status, .copyout_on_error = false, }, 1099 [PROC_STACKGAP_CTL] = 1100 { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 1101 .esrch_is_einval = false, .no_nonnull_data = false, 1102 .need_candebug = true, 1103 .copyin_sz = sizeof(int), .copyout_sz = 0, 1104 .exec = stackgap_ctl, .copyout_on_error = false, }, 1105 [PROC_STACKGAP_STATUS] = 1106 { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 1107 .esrch_is_einval = false, .no_nonnull_data = false, 1108 .need_candebug = false, 1109 .copyin_sz = 0, .copyout_sz = sizeof(int), 1110 .exec = stackgap_status, .copyout_on_error = false, }, 1111 [PROC_NO_NEW_PRIVS_CTL] = 1112 { .lock_tree = PCTL_SLOCKED, .one_proc = true, 1113 .esrch_is_einval = false, .no_nonnull_data = false, 1114 .need_candebug = true, 1115 .copyin_sz = sizeof(int), .copyout_sz = 0, 1116 .exec = no_new_privs_ctl, .copyout_on_error = false, }, 1117 [PROC_NO_NEW_PRIVS_STATUS] = 1118 { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 1119 .esrch_is_einval = false, .no_nonnull_data = false, 1120 .need_candebug = false, 1121 .copyin_sz = 0, .copyout_sz = sizeof(int), 1122 .exec = no_new_privs_status, .copyout_on_error = false, }, 1123 [PROC_WXMAP_CTL] = 1124 { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 1125 .esrch_is_einval = false, .no_nonnull_data = false, 1126 .need_candebug = true, 1127 .copyin_sz = sizeof(int), .copyout_sz = 0, 1128 .exec = wxmap_ctl, .copyout_on_error = false, }, 1129 [PROC_WXMAP_STATUS] = 1130 { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 1131 .esrch_is_einval = false, .no_nonnull_data = false, 1132 .need_candebug = false, 1133 .copyin_sz = 0, .copyout_sz = sizeof(int), 1134 .exec = wxmap_status, .copyout_on_error = false, }, 1135 [PROC_LOGSIGEXIT_CTL] = 1136 { .lock_tree = PCTL_SLOCKED, .one_proc = true, 1137 .esrch_is_einval = false, .no_nonnull_data = false, 1138 .need_candebug = true, 1139 .copyin_sz = sizeof(int), .copyout_sz = 0, 1140 .exec = logsigexit_ctl, .copyout_on_error = false, }, 1141 [PROC_LOGSIGEXIT_STATUS] = 1142 { .lock_tree = PCTL_UNLOCKED, .one_proc = true, 1143 .esrch_is_einval = false, .no_nonnull_data = false, 1144 .need_candebug = false, 1145 .copyin_sz = 0, .copyout_sz = sizeof(int), 1146 .exec = logsigexit_status, .copyout_on_error = false, }, 1147 }; 1148 1149 int 1150 sys_procctl(struct thread *td, struct procctl_args *uap) 1151 { 1152 union { 1153 struct procctl_reaper_status rs; 1154 struct procctl_reaper_pids rp; 1155 struct procctl_reaper_kill rk; 1156 int flags; 1157 } x; 1158 const struct procctl_cmd_info *cmd_info; 1159 int error, error1; 1160 1161 if (uap->com >= PROC_PROCCTL_MD_MIN) 1162 return (cpu_procctl(td, uap->idtype, uap->id, 1163 uap->com, uap->data)); 1164 if (uap->com <= 0 || uap->com >= nitems(procctl_cmds_info)) 1165 return (EINVAL); 1166 cmd_info = &procctl_cmds_info[uap->com]; 1167 bzero(&x, sizeof(x)); 1168 1169 if (cmd_info->copyin_sz > 0) { 1170 error = copyin(uap->data, &x, cmd_info->copyin_sz); 1171 if (error != 0) 1172 return (error); 1173 } else if (cmd_info->no_nonnull_data && uap->data != NULL) { 1174 return (EINVAL); 1175 } 1176 1177 error = kern_procctl(td, uap->idtype, uap->id, uap->com, &x); 1178 1179 if (cmd_info->copyout_sz > 0 && (error == 0 || 1180 cmd_info->copyout_on_error)) { 1181 error1 = copyout(&x, uap->data, cmd_info->copyout_sz); 1182 if (error == 0) 1183 error = error1; 1184 } 1185 return (error); 1186 } 1187 1188 static int 1189 kern_procctl_single(struct thread *td, struct proc *p, int com, void *data) 1190 { 1191 int error; 1192 1193 PROC_LOCK_ASSERT(p, MA_OWNED); 1194 if ((p->p_flag & P_WEXIT) != 0) 1195 return (ESRCH); 1196 _PHOLD(p); 1197 error = procctl_cmds_info[com].exec(td, p, data); 1198 _PRELE(p); 1199 return (error); 1200 } 1201 1202 int 1203 kern_procctl(struct thread *td, idtype_t idtype, id_t id, int com, void *data) 1204 { 1205 struct pgrp *pg; 1206 struct proc *p; 1207 const struct procctl_cmd_info *cmd_info; 1208 int error, first_error, ok; 1209 bool sapblk; 1210 1211 MPASS(com > 0 && com < nitems(procctl_cmds_info)); 1212 cmd_info = &procctl_cmds_info[com]; 1213 if (idtype != P_PID && cmd_info->one_proc) 1214 return (EINVAL); 1215 1216 sapblk = false; 1217 if (cmd_info->sapblk != NULL) { 1218 sapblk = cmd_info->sapblk(td, data); 1219 if (sapblk && !stop_all_proc_block()) 1220 return (ERESTART); 1221 } 1222 1223 switch (cmd_info->lock_tree) { 1224 case PCTL_XLOCKED: 1225 sx_xlock(&proctree_lock); 1226 break; 1227 case PCTL_SLOCKED: 1228 sx_slock(&proctree_lock); 1229 break; 1230 default: 1231 break; 1232 } 1233 1234 switch (idtype) { 1235 case P_PID: 1236 if (id == 0) { 1237 p = td->td_proc; 1238 error = 0; 1239 PROC_LOCK(p); 1240 } else { 1241 p = pfind(id); 1242 if (p == NULL) { 1243 error = cmd_info->esrch_is_einval ? 1244 EINVAL : ESRCH; 1245 break; 1246 } 1247 error = cmd_info->need_candebug ? p_candebug(td, p) : 1248 p_cansee(td, p); 1249 } 1250 if (error == 0) 1251 error = kern_procctl_single(td, p, com, data); 1252 PROC_UNLOCK(p); 1253 break; 1254 case P_PGID: 1255 /* 1256 * Attempt to apply the operation to all members of the 1257 * group. Ignore processes in the group that can't be 1258 * seen. Ignore errors so long as at least one process is 1259 * able to complete the request successfully. 1260 */ 1261 pg = pgfind(id); 1262 if (pg == NULL) { 1263 error = ESRCH; 1264 break; 1265 } 1266 PGRP_UNLOCK(pg); 1267 ok = 0; 1268 first_error = 0; 1269 LIST_FOREACH(p, &pg->pg_members, p_pglist) { 1270 PROC_LOCK(p); 1271 if (p->p_state == PRS_NEW || 1272 p->p_state == PRS_ZOMBIE || 1273 (cmd_info->need_candebug ? p_candebug(td, p) : 1274 p_cansee(td, p)) != 0) { 1275 PROC_UNLOCK(p); 1276 continue; 1277 } 1278 error = kern_procctl_single(td, p, com, data); 1279 PROC_UNLOCK(p); 1280 if (error == 0) 1281 ok = 1; 1282 else if (first_error == 0) 1283 first_error = error; 1284 } 1285 if (ok) 1286 error = 0; 1287 else if (first_error != 0) 1288 error = first_error; 1289 else 1290 /* 1291 * Was not able to see any processes in the 1292 * process group. 1293 */ 1294 error = ESRCH; 1295 break; 1296 default: 1297 error = EINVAL; 1298 break; 1299 } 1300 1301 switch (cmd_info->lock_tree) { 1302 case PCTL_XLOCKED: 1303 sx_xunlock(&proctree_lock); 1304 break; 1305 case PCTL_SLOCKED: 1306 sx_sunlock(&proctree_lock); 1307 break; 1308 default: 1309 break; 1310 } 1311 if (sapblk) 1312 stop_all_proc_unblock(); 1313 return (error); 1314 } 1315