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