1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 #include <sys/types.h>
30 #include <sys/sysmacros.h>
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/file.h>
34 #include <sys/vnode.h>
35 #include <sys/errno.h>
36 #include <sys/signal.h>
37 #include <sys/cred.h>
38 #include <sys/policy.h>
39 #include <sys/conf.h>
40 #include <sys/debug.h>
41 #include <sys/proc.h>
42 #include <sys/session.h>
43 #include <sys/kmem.h>
44 #include <sys/cmn_err.h>
45 #include <sys/strsubr.h>
46 #include <sys/fs/snode.h>
47
48 sess_t session0 = {
49 &pid0, /* s_sidp */
50 {0}, /* s_lock */
51 1, /* s_ref */
52 B_FALSE, /* s_sighuped */
53 B_FALSE, /* s_exit */
54 0, /* s_exit_cv */
55 0, /* s_cnt */
56 0, /* s_cnt_cv */
57 NODEV, /* s_dev */
58 NULL, /* s_vp */
59 NULL /* s_cred */
60 };
61
62 void
sess_hold(proc_t * p)63 sess_hold(proc_t *p)
64 {
65 ASSERT(MUTEX_HELD(&pidlock) || MUTEX_HELD(&p->p_splock));
66 mutex_enter(&p->p_sessp->s_lock);
67 p->p_sessp->s_ref++;
68 mutex_exit(&p->p_sessp->s_lock);
69 }
70
71 void
sess_rele(sess_t * sp,boolean_t pidlock_held)72 sess_rele(sess_t *sp, boolean_t pidlock_held)
73 {
74 ASSERT(MUTEX_HELD(&pidlock) || !pidlock_held);
75
76 mutex_enter(&sp->s_lock);
77
78 ASSERT(sp->s_ref != 0);
79 if (--sp->s_ref > 0) {
80 mutex_exit(&sp->s_lock);
81 return;
82 }
83 ASSERT(sp->s_ref == 0);
84
85 /*
86 * It's ok to free this session structure now because we know
87 * that no one else can have a pointer to it. We know this
88 * to be true because the only time that s_ref can possibly
89 * be incremented is when pidlock or p_splock is held AND there
90 * is a proc_t that points to that session structure. In that
91 * case we are guaranteed that the s_ref is at least 1 since there
92 * is a proc_t that points to it. So when s_ref finally drops to
93 * zero then no one else has a reference (and hence pointer) to
94 * this session structure and there is no valid proc_t pointing
95 * to this session structure anymore so, no one can acquire a
96 * reference (and pointer) to this session structure so it's
97 * ok to free it here.
98 */
99
100 if (sp == &session0)
101 panic("sp == &session0");
102
103 /* make sure there are no outstanding holds */
104 ASSERT(sp->s_cnt == 0);
105
106 /* make sure there is no exit in progress */
107 ASSERT(!sp->s_exit);
108
109 /* make sure someone already freed any ctty */
110 ASSERT(sp->s_vp == NULL);
111 ASSERT(sp->s_dev == NODEV);
112
113 if (!pidlock_held)
114 mutex_enter(&pidlock);
115 PID_RELE(sp->s_sidp);
116 if (!pidlock_held)
117 mutex_exit(&pidlock);
118
119 mutex_destroy(&sp->s_lock);
120 cv_destroy(&sp->s_cnt_cv);
121 kmem_free(sp, sizeof (sess_t));
122 }
123
124 sess_t *
tty_hold(void)125 tty_hold(void)
126 {
127 proc_t *p = curproc;
128 sess_t *sp;
129 boolean_t got_sig = B_FALSE;
130
131 /* make sure the caller isn't holding locks they shouldn't */
132 ASSERT(MUTEX_NOT_HELD(&pidlock));
133
134 for (;;) {
135 mutex_enter(&p->p_splock); /* protect p->p_sessp */
136 sp = p->p_sessp;
137 mutex_enter(&sp->s_lock); /* protect sp->* */
138
139 /* make sure the caller isn't holding locks they shouldn't */
140 ASSERT((sp->s_vp == NULL) ||
141 MUTEX_NOT_HELD(&sp->s_vp->v_stream->sd_lock));
142
143 /*
144 * If the session leader process is not exiting (and hence
145 * not trying to release the session's ctty) then we can
146 * safely grab a hold on the current session structure
147 * and return it. If on the other hand the session leader
148 * process is exiting and clearing the ctty then we'll
149 * wait till it's done before we loop around and grab a
150 * hold on the session structure.
151 */
152 if (!sp->s_exit)
153 break;
154
155 /* need to hold the session so it can't be freed */
156 sp->s_ref++;
157 mutex_exit(&p->p_splock);
158
159 /* Wait till the session leader is done */
160 if (!cv_wait_sig(&sp->s_exit_cv, &sp->s_lock))
161 got_sig = B_TRUE;
162
163 /*
164 * Now we need to drop our hold on the session structure,
165 * but we can't hold any locks when we do this because
166 * sess_rele() may need to acquire pidlock.
167 */
168 mutex_exit(&sp->s_lock);
169 sess_rele(sp, B_FALSE);
170
171 if (got_sig)
172 return (NULL);
173 }
174
175 /* whew, we finally got a hold */
176 sp->s_cnt++;
177 sp->s_ref++;
178 mutex_exit(&sp->s_lock);
179 mutex_exit(&p->p_splock);
180 return (sp);
181 }
182
183 void
tty_rele(sess_t * sp)184 tty_rele(sess_t *sp)
185 {
186 /* make sure the caller isn't holding locks they shouldn't */
187 ASSERT(MUTEX_NOT_HELD(&pidlock));
188
189 mutex_enter(&sp->s_lock);
190 if ((--sp->s_cnt) == 0)
191 cv_broadcast(&sp->s_cnt_cv);
192 mutex_exit(&sp->s_lock);
193
194 sess_rele(sp, B_FALSE);
195 }
196
197 void
sess_create(void)198 sess_create(void)
199 {
200 proc_t *p = curproc;
201 sess_t *sp, *old_sp;
202
203 sp = kmem_zalloc(sizeof (sess_t), KM_SLEEP);
204
205 mutex_init(&sp->s_lock, NULL, MUTEX_DEFAULT, NULL);
206 cv_init(&sp->s_cnt_cv, NULL, CV_DEFAULT, NULL);
207
208 /*
209 * we need to grap p_lock to protect p_pgidp because
210 * /proc looks at p_pgidp while holding only p_lock.
211 *
212 * we don't need to hold p->p_sessp->s_lock or get a hold on the
213 * session structure since we're not actually updating any of
214 * the contents of the old session structure.
215 */
216 mutex_enter(&pidlock);
217 mutex_enter(&p->p_lock);
218 mutex_enter(&p->p_splock);
219
220 pgexit(p);
221
222 sp->s_sidp = p->p_pidp;
223 sp->s_ref = 1;
224 sp->s_dev = NODEV;
225
226 old_sp = p->p_sessp;
227 p->p_sessp = sp;
228
229 pgjoin(p, p->p_pidp);
230 PID_HOLD(p->p_pidp);
231
232 mutex_exit(&p->p_splock);
233 mutex_exit(&p->p_lock);
234 mutex_exit(&pidlock);
235
236 sess_rele(old_sp, B_FALSE);
237 }
238
239 /*
240 * Note that sess_ctty_clear() resets all the fields in the session
241 * structure but doesn't release any holds or free any objects
242 * that the session structure might currently point to. it is the
243 * callers responsibility to do this.
244 */
245 static void
sess_ctty_clear(sess_t * sp,stdata_t * stp)246 sess_ctty_clear(sess_t *sp, stdata_t *stp)
247 {
248 /*
249 * Assert that we hold all the necessary locks. We also need
250 * to be holding proc_t->p_splock for the process associated
251 * with this session, but since we don't have a proc pointer
252 * passed in we can't assert this here.
253 */
254 ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) &&
255 MUTEX_HELD(&sp->s_lock));
256
257 /* reset the session structure members to defaults */
258 sp->s_sighuped = B_FALSE;
259 sp->s_dev = NODEV;
260 sp->s_vp = NULL;
261 sp->s_cred = NULL;
262
263 /* reset the stream session and group pointers */
264 stp->sd_pgidp = NULL;
265 stp->sd_sidp = NULL;
266 }
267
268 static void
sess_ctty_set(proc_t * p,sess_t * sp,stdata_t * stp)269 sess_ctty_set(proc_t *p, sess_t *sp, stdata_t *stp)
270 {
271 cred_t *crp;
272
273 /* Assert that we hold all the necessary locks. */
274 ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) &&
275 MUTEX_HELD(&p->p_splock) && MUTEX_HELD(&sp->s_lock));
276
277 /* get holds on structures */
278 mutex_enter(&p->p_crlock);
279 crhold(crp = p->p_cred);
280 mutex_exit(&p->p_crlock);
281 PID_HOLD(sp->s_sidp); /* requires pidlock */
282 PID_HOLD(sp->s_sidp); /* requires pidlock */
283
284 /* update the session structure members */
285 sp->s_vp = makectty(stp->sd_vnode);
286 sp->s_dev = sp->s_vp->v_rdev;
287 sp->s_cred = crp;
288
289 /* update the stream emebers */
290 stp->sd_flag |= STRISTTY; /* just to be sure */
291 stp->sd_sidp = sp->s_sidp;
292 stp->sd_pgidp = sp->s_sidp;
293 }
294
295 int
strctty(stdata_t * stp)296 strctty(stdata_t *stp)
297 {
298 sess_t *sp;
299 proc_t *p = curproc;
300 boolean_t got_sig = B_FALSE;
301
302 /*
303 * We are going to try to make stp the default ctty for the session
304 * associated with curproc. Not only does this require holding a
305 * bunch of locks but it also requires waiting for any outstanding
306 * holds on the session structure (acquired via tty_hold()) to be
307 * released. Hence, we have the following for(;;) loop that will
308 * acquire our locks, do some sanity checks, and wait for the hold
309 * count on the session structure to hit zero. If we get a signal
310 * while waiting for outstanding holds to be released then we abort
311 * the operation and return.
312 */
313 for (;;) {
314 mutex_enter(&stp->sd_lock); /* protects sd_pgidp/sd_sidp */
315 mutex_enter(&pidlock); /* protects p_pidp */
316 mutex_enter(&p->p_splock); /* protects p_sessp */
317 sp = p->p_sessp;
318 mutex_enter(&sp->s_lock); /* protects sp->* */
319
320 if (((stp->sd_flag & (STRHUP|STRDERR|STWRERR|STPLEX)) != 0) ||
321 (stp->sd_sidp != NULL) || /* stp already ctty? */
322 (p->p_pidp != sp->s_sidp) || /* we're not leader? */
323 (sp->s_vp != NULL)) { /* session has ctty? */
324 mutex_exit(&sp->s_lock);
325 mutex_exit(&p->p_splock);
326 mutex_exit(&pidlock);
327 mutex_exit(&stp->sd_lock);
328 return (ENOTTY);
329 }
330
331 /* sanity check. we can't be exiting right now */
332 ASSERT(!sp->s_exit);
333
334 /*
335 * If no one else has a hold on this session structure
336 * then we now have exclusive access to it, so break out
337 * of this loop and update the session structure.
338 */
339 if (sp->s_cnt == 0)
340 break;
341
342 /* need to hold the session so it can't be freed */
343 sp->s_ref++;
344
345 /* ain't locking order fun? */
346 mutex_exit(&p->p_splock);
347 mutex_exit(&pidlock);
348 mutex_exit(&stp->sd_lock);
349
350 if (!cv_wait_sig(&sp->s_cnt_cv, &sp->s_lock))
351 got_sig = B_TRUE;
352 mutex_exit(&sp->s_lock);
353 sess_rele(sp, B_FALSE);
354
355 if (got_sig)
356 return (EINTR);
357 }
358
359 /* set the session ctty bindings */
360 sess_ctty_set(p, sp, stp);
361
362 mutex_exit(&sp->s_lock);
363 mutex_exit(&p->p_splock);
364 mutex_exit(&pidlock);
365 mutex_exit(&stp->sd_lock);
366 return (0);
367 }
368
369 /*
370 * freectty_lock() attempts to acquire the army of locks required to free
371 * the ctty associated with a given session leader process. If it returns
372 * successfully the following locks will be held:
373 * sd_lock, pidlock, p_splock, s_lock
374 *
375 * as a secondary bit of convenience, freectty_lock() will also return
376 * pointers to the session, ctty, and ctty stream associated with the
377 * specified session leader process.
378 */
379 static boolean_t
freectty_lock(proc_t * p,sess_t ** spp,vnode_t ** vpp,stdata_t ** stpp,boolean_t at_exit)380 freectty_lock(proc_t *p, sess_t **spp, vnode_t **vpp, stdata_t **stpp,
381 boolean_t at_exit)
382 {
383 sess_t *sp;
384 vnode_t *vp;
385 stdata_t *stp;
386
387 mutex_enter(&pidlock); /* protect p_pidp */
388 mutex_enter(&p->p_splock); /* protect p->p_sessp */
389 sp = p->p_sessp;
390 mutex_enter(&sp->s_lock); /* protect sp->* */
391
392 if ((sp->s_sidp != p->p_pidp) || /* we're not leader? */
393 (sp->s_vp == NULL)) { /* no ctty? */
394 mutex_exit(&sp->s_lock);
395 mutex_exit(&p->p_splock);
396 mutex_exit(&pidlock);
397 return (B_FALSE);
398 }
399
400 vp = sp->s_vp;
401 stp = sp->s_vp->v_stream;
402
403 if (at_exit) {
404 /* stop anyone else calling tty_hold() */
405 sp->s_exit = B_TRUE;
406 } else {
407 /*
408 * due to locking order we have to grab stp->sd_lock before
409 * grabbing all the other proc/session locks. but after we
410 * drop all our current locks it's possible that someone
411 * could come in and change our current session or close
412 * the current ctty (vp) there by making sp or stp invalid.
413 * (a VN_HOLD on vp won't protect stp because that only
414 * prevents the vnode from being freed not closed.) so
415 * to prevent this we bump s_ref and s_cnt here.
416 *
417 * course this doesn't matter if we're the last thread in
418 * an exiting process that is the session leader, since no
419 * one else can change our session or free our ctty.
420 */
421 sp->s_ref++; /* hold the session structure */
422 sp->s_cnt++; /* protect vp and stp */
423 }
424
425 /* drop our session locks */
426 mutex_exit(&sp->s_lock);
427 mutex_exit(&p->p_splock);
428 mutex_exit(&pidlock);
429
430 /* grab locks in the right order */
431 mutex_enter(&stp->sd_lock); /* protects sd_pgidp/sd_sidp */
432 mutex_enter(&pidlock); /* protect p_pidp */
433 mutex_enter(&p->p_splock); /* protects p->p_sessp */
434 mutex_enter(&sp->s_lock); /* protects sp->* */
435
436 /* if the session has changed, abort mission */
437 if (sp != p->p_sessp) {
438 /*
439 * this can't happen during process exit since we're the
440 * only thread in the process and we sure didn't change
441 * our own session at this point.
442 */
443 ASSERT(!at_exit);
444
445 /* release our locks and holds */
446 mutex_exit(&sp->s_lock);
447 mutex_exit(&p->p_splock);
448 mutex_exit(&pidlock);
449 mutex_exit(&stp->sd_lock);
450 tty_rele(sp);
451 return (B_FALSE);
452 }
453
454 /*
455 * sanity checks. none of this should have changed since we had
456 * holds on the current ctty.
457 */
458 ASSERT(sp->s_sidp == p->p_pidp); /* we're the leader */
459 ASSERT(sp->s_vp != NULL); /* a ctty exists */
460 ASSERT(vp == sp->s_vp);
461 ASSERT(stp == sp->s_vp->v_stream);
462
463 /* release our holds */
464 if (!at_exit) {
465 if ((--(sp)->s_cnt) == 0)
466 cv_broadcast(&sp->s_cnt_cv);
467 sp->s_ref--;
468 ASSERT(sp->s_ref > 0);
469 }
470
471 /* return our pointers */
472 *spp = sp;
473 *vpp = vp;
474 *stpp = stp;
475
476 return (B_TRUE);
477 }
478
479 /*
480 * Returns B_FALSE if no signal is sent to the process group associated with
481 * this ctty. Returns B_TRUE if a signal is sent to the process group.
482 * If it return B_TRUE it also means that all the locks we were holding
483 * were dropped so that we could send the signal.
484 */
485 static boolean_t
freectty_signal(proc_t * p,sess_t * sp,stdata_t * stp,boolean_t at_exit)486 freectty_signal(proc_t *p, sess_t *sp, stdata_t *stp, boolean_t at_exit)
487 {
488 /* Assert that we hold all the necessary locks. */
489 ASSERT(MUTEX_HELD(&stp->sd_lock) && MUTEX_HELD(&pidlock) &&
490 MUTEX_HELD(&p->p_splock) && MUTEX_HELD(&sp->s_lock));
491
492 /* check if we already signaled this group */
493 if (sp->s_sighuped)
494 return (B_FALSE);
495
496 sp->s_sighuped = B_TRUE;
497
498 if (!at_exit) {
499 /*
500 * once again, we're about to drop our army of locks and we
501 * don't want sp or stp to be freed. (see the comment in
502 * freectty_lock())
503 */
504 sp->s_ref++; /* hold the session structure */
505 sp->s_cnt++; /* protect vp and stp */
506 }
507
508 /* can't hold these locks while calling pgsignal() */
509 mutex_exit(&sp->s_lock);
510 mutex_exit(&p->p_splock);
511 mutex_exit(&pidlock);
512
513 /* signal anyone in the foreground process group */
514 pgsignal(stp->sd_pgidp, SIGHUP);
515
516 /* signal anyone blocked in poll on this stream */
517 if (!(stp->sd_flag & STRHUP))
518 strhup(stp);
519
520 mutex_exit(&stp->sd_lock);
521
522 /* release our holds */
523 if (!at_exit)
524 tty_rele(sp);
525
526 return (B_TRUE);
527 }
528
529 int
freectty(boolean_t at_exit)530 freectty(boolean_t at_exit)
531 {
532 proc_t *p = curproc;
533 stdata_t *stp;
534 vnode_t *vp;
535 cred_t *cred;
536 sess_t *sp;
537 struct pid *pgidp, *sidp;
538 boolean_t got_sig = B_FALSE;
539
540 /*
541 * If the current process is a session leader we are going to
542 * try to release the ctty associated our current session. To
543 * do this we need to acquire a bunch of locks, signal any
544 * processes in the forground that are associated with the ctty,
545 * and make sure no one has any outstanding holds on the current
546 * session * structure (acquired via tty_hold()). Hence, we have
547 * the following for(;;) loop that will do all this work for
548 * us and break out when the hold count on the session structure
549 * hits zero.
550 */
551 for (;;) {
552 if (!freectty_lock(p, &sp, &vp, &stp, at_exit))
553 return (EIO);
554
555 if (freectty_signal(p, sp, stp, at_exit)) {
556 /* loop around to re-acquire locks */
557 continue;
558 }
559
560 /*
561 * Only a session leader process can free a ctty. So if
562 * we've made it here we know we're a session leader and
563 * if we're not actively exiting it impossible for another
564 * thread in this process to be exiting. (Because that
565 * thread would have already stopped all other threads
566 * in the current process.)
567 */
568 ASSERT(at_exit || !sp->s_exit);
569
570 /*
571 * If no one else has a hold on this session structure
572 * then we now have exclusive access to it, so break out
573 * of this loop and update the session structure.
574 */
575 if (sp->s_cnt == 0)
576 break;
577
578 if (!at_exit) {
579 /* need to hold the session so it can't be freed */
580 sp->s_ref++;
581 }
582
583 /* ain't locking order fun? */
584 mutex_exit(&p->p_splock);
585 mutex_exit(&pidlock);
586 mutex_exit(&stp->sd_lock);
587
588 if (at_exit) {
589 /*
590 * if we're exiting then we can't allow this operation
591 * to fail so we do a cw_wait() instead of a
592 * cv_wait_sig(). if there are threads with active
593 * holds on this ctty that are blocked, then
594 * they should only be blocked in a cv_wait_sig()
595 * and hopefully they were in the foreground process
596 * group and recieved the SIGHUP we sent above. of
597 * course it's possible that they weren't in the
598 * foreground process group and didn't get our
599 * signal (or they could be stopped by job control
600 * in which case our signal wouldn't matter until
601 * they are restarted). in this case we won't
602 * exit until someone else sends them a signal.
603 */
604 cv_wait(&sp->s_cnt_cv, &sp->s_lock);
605 mutex_exit(&sp->s_lock);
606 continue;
607 }
608
609 if (!cv_wait_sig(&sp->s_cnt_cv, &sp->s_lock)) {
610 got_sig = B_TRUE;
611 }
612
613 mutex_exit(&sp->s_lock);
614 sess_rele(sp, B_FALSE);
615
616 if (got_sig)
617 return (EINTR);
618 }
619 ASSERT(sp->s_cnt == 0);
620
621 /* save some pointers for later */
622 cred = sp->s_cred;
623 pgidp = stp->sd_pgidp;
624 sidp = stp->sd_sidp;
625
626 /* clear the session ctty bindings */
627 sess_ctty_clear(sp, stp);
628
629 /* wake up anyone blocked in tty_hold() */
630 if (at_exit) {
631 ASSERT(sp->s_exit);
632 sp->s_exit = B_FALSE;
633 cv_broadcast(&sp->s_exit_cv);
634 }
635
636 /* we can drop these locks now */
637 mutex_exit(&sp->s_lock);
638 mutex_exit(&p->p_splock);
639 mutex_exit(&pidlock);
640 mutex_exit(&stp->sd_lock);
641
642 /* This is the only remaining thread with access to this vnode */
643 (void) VOP_CLOSE(vp, 0, 1, (offset_t)0, cred, NULL);
644 VN_RELE(vp);
645 crfree(cred);
646
647 /* release our holds on assorted structures and return */
648 mutex_enter(&pidlock);
649 PID_RELE(pgidp);
650 PID_RELE(sidp);
651 mutex_exit(&pidlock);
652
653 return (1);
654 }
655
656 /*
657 * ++++++++++++++++++++++++
658 * ++ SunOS4.1 Buyback ++
659 * ++++++++++++++++++++++++
660 *
661 * vhangup: Revoke access of the current tty by all processes
662 * Used by privileged users to give a "clean" terminal at login
663 */
664 int
vhangup(void)665 vhangup(void)
666 {
667 if (secpolicy_sys_config(CRED(), B_FALSE) != 0)
668 return (set_errno(EPERM));
669 /*
670 * This routine used to call freectty() under a condition that
671 * could never happen. So this code has never actually done
672 * anything, and evidently nobody has ever noticed.
673 */
674 return (0);
675 }
676
677 dev_t
cttydev(proc_t * pp)678 cttydev(proc_t *pp)
679 {
680 sess_t *sp;
681 dev_t dev;
682
683 mutex_enter(&pp->p_splock); /* protects p->p_sessp */
684 sp = pp->p_sessp;
685
686 #ifdef DEBUG
687 mutex_enter(&sp->s_lock); /* protects sp->* */
688 if (sp->s_vp == NULL)
689 ASSERT(sp->s_dev == NODEV);
690 else
691 ASSERT(sp->s_dev != NODEV);
692 mutex_exit(&sp->s_lock);
693 #endif /* DEBUG */
694
695 dev = sp->s_dev;
696 mutex_exit(&pp->p_splock);
697 return (dev);
698 }
699
700 void
ctty_clear_sighuped(void)701 ctty_clear_sighuped(void)
702 {
703 ASSERT(MUTEX_HELD(&pidlock) || MUTEX_HELD(&curproc->p_splock));
704 curproc->p_sessp->s_sighuped = B_FALSE;
705 }
706