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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 31 /* 32 * STREAMS Administrative Driver 33 * 34 * Currently only handles autopush and module name verification. 35 */ 36 37 #include <sys/types.h> 38 #include <sys/param.h> 39 #include <sys/errno.h> 40 #include <sys/stream.h> 41 #include <sys/stropts.h> 42 #include <sys/strsubr.h> 43 #include <sys/strsun.h> 44 #include <sys/conf.h> 45 #include <sys/sad.h> 46 #include <sys/cred.h> 47 #include <sys/debug.h> 48 #include <sys/ddi.h> 49 #include <sys/sunddi.h> 50 #include <sys/stat.h> 51 #include <sys/cmn_err.h> 52 #include <sys/systm.h> 53 #include <sys/modctl.h> 54 #include <sys/sysmacros.h> 55 #include <sys/zone.h> 56 #include <sys/policy.h> 57 58 static int sadopen(queue_t *, dev_t *, int, int, cred_t *); 59 static int sadclose(queue_t *, int, cred_t *); 60 static int sadwput(queue_t *qp, mblk_t *mp); 61 62 static int sad_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 63 static int sad_attach(dev_info_t *, ddi_attach_cmd_t); 64 65 static void apush_ioctl(), apush_iocdata(); 66 static void vml_ioctl(), vml_iocdata(); 67 static int valid_major(major_t); 68 69 static dev_info_t *sad_dip; /* private copy of devinfo pointer */ 70 71 static struct module_info sad_minfo = { 72 0x7361, "sad", 0, INFPSZ, 0, 0 73 }; 74 75 static struct qinit sad_rinit = { 76 NULL, NULL, sadopen, sadclose, NULL, &sad_minfo, NULL 77 }; 78 79 static struct qinit sad_winit = { 80 sadwput, NULL, NULL, NULL, NULL, &sad_minfo, NULL 81 }; 82 83 struct streamtab sadinfo = { 84 &sad_rinit, &sad_winit, NULL, NULL 85 }; 86 87 DDI_DEFINE_STREAM_OPS(sad_ops, nulldev, nulldev, sad_attach, 88 nodev, nodev, sad_info, 89 D_MP | D_MTPERQ | D_MTOUTPERIM | D_MTOCEXCL, &sadinfo, 90 ddi_quiesce_not_supported); 91 92 /* 93 * Module linkage information for the kernel. 94 */ 95 96 static struct modldrv modldrv = { 97 &mod_driverops, /* Type of module. This one is a pseudo driver */ 98 "STREAMS Administrative Driver 'sad'", 99 &sad_ops, /* driver ops */ 100 }; 101 102 static struct modlinkage modlinkage = { 103 MODREV_1, &modldrv, NULL 104 }; 105 106 int 107 _init(void) 108 { 109 return (mod_install(&modlinkage)); 110 } 111 112 int 113 _fini(void) 114 { 115 return (mod_remove(&modlinkage)); 116 } 117 118 int 119 _info(struct modinfo *modinfop) 120 { 121 return (mod_info(&modlinkage, modinfop)); 122 } 123 124 static int 125 sad_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 126 { 127 int instance = ddi_get_instance(devi); 128 129 if (cmd != DDI_ATTACH) 130 return (DDI_FAILURE); 131 132 ASSERT(instance == 0); 133 if (instance != 0) 134 return (DDI_FAILURE); 135 136 if (ddi_create_minor_node(devi, "user", S_IFCHR, 137 0, DDI_PSEUDO, 0) == DDI_FAILURE) { 138 return (DDI_FAILURE); 139 } 140 if (ddi_create_minor_node(devi, "admin", S_IFCHR, 141 1, DDI_PSEUDO, 0) == DDI_FAILURE) { 142 ddi_remove_minor_node(devi, NULL); 143 return (DDI_FAILURE); 144 } 145 sad_dip = devi; 146 return (DDI_SUCCESS); 147 } 148 149 /* ARGSUSED */ 150 static int 151 sad_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 152 { 153 int error; 154 155 switch (infocmd) { 156 case DDI_INFO_DEVT2DEVINFO: 157 if (sad_dip == NULL) { 158 error = DDI_FAILURE; 159 } else { 160 *result = sad_dip; 161 error = DDI_SUCCESS; 162 } 163 break; 164 case DDI_INFO_DEVT2INSTANCE: 165 *result = (void *)0; 166 error = DDI_SUCCESS; 167 break; 168 default: 169 error = DDI_FAILURE; 170 } 171 return (error); 172 } 173 174 175 /* 176 * sadopen() - 177 * Allocate a sad device. Only one 178 * open at a time allowed per device. 179 */ 180 /* ARGSUSED */ 181 static int 182 sadopen( 183 queue_t *qp, /* pointer to read queue */ 184 dev_t *devp, /* major/minor device of stream */ 185 int flag, /* file open flags */ 186 int sflag, /* stream open flags */ 187 cred_t *credp) /* user credentials */ 188 { 189 int i; 190 netstack_t *ns; 191 str_stack_t *ss; 192 193 if (sflag) /* no longer called from clone driver */ 194 return (EINVAL); 195 196 /* Only privileged process can access ADMINDEV */ 197 if (getminor(*devp) == ADMMIN) { 198 int err; 199 200 err = secpolicy_sadopen(credp); 201 202 if (err != 0) 203 return (err); 204 } 205 206 ns = netstack_find_by_cred(credp); 207 ASSERT(ns != NULL); 208 ss = ns->netstack_str; 209 ASSERT(ss != NULL); 210 211 /* 212 * Both USRMIN and ADMMIN are clone interfaces. 213 */ 214 for (i = 0; i < ss->ss_sadcnt; i++) 215 if (ss->ss_saddev[i].sa_qp == NULL) 216 break; 217 if (i >= ss->ss_sadcnt) { /* no such device */ 218 netstack_rele(ss->ss_netstack); 219 return (ENXIO); 220 } 221 switch (getminor(*devp)) { 222 case USRMIN: /* mere mortal */ 223 ss->ss_saddev[i].sa_flags = 0; 224 break; 225 226 case ADMMIN: /* privileged user */ 227 ss->ss_saddev[i].sa_flags = SADPRIV; 228 break; 229 230 default: 231 netstack_rele(ss->ss_netstack); 232 return (EINVAL); 233 } 234 235 ss->ss_saddev[i].sa_qp = qp; 236 ss->ss_saddev[i].sa_ss = ss; 237 qp->q_ptr = (caddr_t)&ss->ss_saddev[i]; 238 WR(qp)->q_ptr = (caddr_t)&ss->ss_saddev[i]; 239 240 /* 241 * NOTE: should the ADMMIN or USRMIN minors change 242 * then so should the offset of 2 below 243 * Both USRMIN and ADMMIN are clone interfaces and 244 * therefore their minor numbers (0 and 1) are reserved. 245 */ 246 *devp = makedevice(getemajor(*devp), i + 2); 247 qprocson(qp); 248 return (0); 249 } 250 251 /* 252 * sadclose() - 253 * Clean up the data structures. 254 */ 255 /* ARGSUSED */ 256 static int 257 sadclose( 258 queue_t *qp, /* pointer to read queue */ 259 int flag, /* file open flags */ 260 cred_t *credp) /* user credentials */ 261 { 262 struct saddev *sadp; 263 264 qprocsoff(qp); 265 sadp = (struct saddev *)qp->q_ptr; 266 sadp->sa_qp = NULL; 267 sadp->sa_addr = NULL; 268 netstack_rele(sadp->sa_ss->ss_netstack); 269 sadp->sa_ss = NULL; 270 qp->q_ptr = NULL; 271 WR(qp)->q_ptr = NULL; 272 return (0); 273 } 274 275 /* 276 * sadwput() - 277 * Write side put procedure. 278 */ 279 static int 280 sadwput( 281 queue_t *qp, /* pointer to write queue */ 282 mblk_t *mp) /* message pointer */ 283 { 284 struct iocblk *iocp; 285 286 switch (mp->b_datap->db_type) { 287 case M_FLUSH: 288 if (*mp->b_rptr & FLUSHR) { 289 *mp->b_rptr &= ~FLUSHW; 290 qreply(qp, mp); 291 } else 292 freemsg(mp); 293 break; 294 295 case M_IOCTL: 296 iocp = (struct iocblk *)mp->b_rptr; 297 switch (SAD_CMD(iocp->ioc_cmd)) { 298 case SAD_CMD(SAD_SAP): 299 case SAD_CMD(SAD_GAP): 300 apush_ioctl(qp, mp); 301 break; 302 303 case SAD_VML: 304 vml_ioctl(qp, mp); 305 break; 306 307 default: 308 miocnak(qp, mp, 0, EINVAL); 309 break; 310 } 311 break; 312 313 case M_IOCDATA: 314 iocp = (struct iocblk *)mp->b_rptr; 315 switch (SAD_CMD(iocp->ioc_cmd)) { 316 case SAD_CMD(SAD_SAP): 317 case SAD_CMD(SAD_GAP): 318 apush_iocdata(qp, mp); 319 break; 320 321 case SAD_VML: 322 vml_iocdata(qp, mp); 323 break; 324 325 default: 326 cmn_err(CE_WARN, 327 "sadwput: invalid ioc_cmd in case M_IOCDATA: %d", 328 iocp->ioc_cmd); 329 freemsg(mp); 330 break; 331 } 332 break; 333 334 default: 335 freemsg(mp); 336 break; 337 } /* switch (db_type) */ 338 return (0); 339 } 340 341 /* 342 * apush_ioctl() - 343 * Handle the M_IOCTL messages associated with 344 * the autopush feature. 345 */ 346 static void 347 apush_ioctl( 348 queue_t *qp, /* pointer to write queue */ 349 mblk_t *mp) /* message pointer */ 350 { 351 struct iocblk *iocp; 352 struct saddev *sadp; 353 uint_t size; 354 355 iocp = (struct iocblk *)mp->b_rptr; 356 if (iocp->ioc_count != TRANSPARENT) { 357 miocnak(qp, mp, 0, EINVAL); 358 return; 359 } 360 if (SAD_VER(iocp->ioc_cmd) > AP_VERSION) { 361 miocnak(qp, mp, 0, EINVAL); 362 return; 363 } 364 365 sadp = (struct saddev *)qp->q_ptr; 366 switch (SAD_CMD(iocp->ioc_cmd)) { 367 case SAD_CMD(SAD_SAP): 368 if (!(sadp->sa_flags & SADPRIV)) { 369 miocnak(qp, mp, 0, EPERM); 370 break; 371 } 372 /* FALLTHRU */ 373 374 case SAD_CMD(SAD_GAP): 375 sadp->sa_addr = (caddr_t)*(uintptr_t *)mp->b_cont->b_rptr; 376 if (SAD_VER(iocp->ioc_cmd) == 1) 377 size = STRAPUSH_V1_LEN; 378 else 379 size = STRAPUSH_V0_LEN; 380 mcopyin(mp, (void *)GETSTRUCT, size, NULL); 381 qreply(qp, mp); 382 break; 383 384 default: 385 ASSERT(0); 386 miocnak(qp, mp, 0, EINVAL); 387 break; 388 } /* switch (ioc_cmd) */ 389 } 390 391 /* 392 * apush_iocdata() - 393 * Handle the M_IOCDATA messages associated with 394 * the autopush feature. 395 */ 396 static void 397 apush_iocdata( 398 queue_t *qp, /* pointer to write queue */ 399 mblk_t *mp) /* message pointer */ 400 { 401 int i, ret; 402 struct copyresp *csp; 403 struct strapush *sap = NULL; 404 struct autopush *ap, *ap_tmp; 405 struct saddev *sadp; 406 uint_t size; 407 dev_t dev; 408 str_stack_t *ss; 409 410 sadp = (struct saddev *)qp->q_ptr; 411 ss = sadp->sa_ss; 412 413 csp = (struct copyresp *)mp->b_rptr; 414 if (csp->cp_rval) { /* if there was an error */ 415 freemsg(mp); 416 return; 417 } 418 if (mp->b_cont) { 419 /* 420 * sap needed only if mp->b_cont is set. figure out the 421 * size of the expected sap structure and make sure 422 * enough data was supplied. 423 */ 424 if (SAD_VER(csp->cp_cmd) == 1) 425 size = STRAPUSH_V1_LEN; 426 else 427 size = STRAPUSH_V0_LEN; 428 if (MBLKL(mp->b_cont) < size) { 429 miocnak(qp, mp, 0, EINVAL); 430 return; 431 } 432 sap = (struct strapush *)mp->b_cont->b_rptr; 433 dev = makedevice(sap->sap_major, sap->sap_minor); 434 } 435 switch (SAD_CMD(csp->cp_cmd)) { 436 case SAD_CMD(SAD_SAP): 437 438 /* currently we only support one SAD_SAP command */ 439 if (((long)csp->cp_private) != GETSTRUCT) { 440 cmn_err(CE_WARN, 441 "apush_iocdata: cp_private bad in SAD_SAP: %p", 442 (void *)csp->cp_private); 443 miocnak(qp, mp, 0, EINVAL); 444 return; 445 } 446 447 switch (sap->sap_cmd) { 448 default: 449 miocnak(qp, mp, 0, EINVAL); 450 return; 451 case SAP_ONE: 452 case SAP_RANGE: 453 case SAP_ALL: 454 /* allocate and initialize a new config */ 455 ap = sad_ap_alloc(); 456 ap->ap_common = sap->sap_common; 457 if (SAD_VER(csp->cp_cmd) > 0) 458 ap->ap_anchor = sap->sap_anchor; 459 for (i = 0; i < MIN(sap->sap_npush, MAXAPUSH); i++) 460 (void) strncpy(ap->ap_list[i], 461 sap->sap_list[i], FMNAMESZ); 462 463 /* sanity check the request */ 464 if (((ret = sad_ap_verify(ap)) != 0) || 465 ((ret = valid_major(ap->ap_major)) != 0)) { 466 sad_ap_rele(ap, ss); 467 miocnak(qp, mp, 0, ret); 468 return; 469 } 470 471 /* check for overlapping configs */ 472 mutex_enter(&ss->ss_sad_lock); 473 ap_tmp = sad_ap_find(&ap->ap_common, ss); 474 if (ap_tmp != NULL) { 475 /* already configured */ 476 mutex_exit(&ss->ss_sad_lock); 477 sad_ap_rele(ap_tmp, ss); 478 sad_ap_rele(ap, ss); 479 miocnak(qp, mp, 0, EEXIST); 480 return; 481 } 482 483 /* add the new config to our hash */ 484 sad_ap_insert(ap, ss); 485 mutex_exit(&ss->ss_sad_lock); 486 miocack(qp, mp, 0, 0); 487 return; 488 489 case SAP_CLEAR: 490 /* sanity check the request */ 491 if (ret = valid_major(sap->sap_major)) { 492 miocnak(qp, mp, 0, ret); 493 return; 494 } 495 496 /* search for a matching config */ 497 if ((ap = sad_ap_find_by_dev(dev, ss)) == NULL) { 498 /* no config found */ 499 miocnak(qp, mp, 0, ENODEV); 500 return; 501 } 502 503 /* 504 * If we matched a SAP_RANGE config 505 * the minor passed in must match the 506 * beginning of the range exactly. 507 */ 508 if ((ap->ap_type == SAP_RANGE) && 509 (ap->ap_minor != sap->sap_minor)) { 510 sad_ap_rele(ap, ss); 511 miocnak(qp, mp, 0, ERANGE); 512 return; 513 } 514 515 /* 516 * If we matched a SAP_ALL config 517 * the minor passed in must be 0. 518 */ 519 if ((ap->ap_type == SAP_ALL) && 520 (sap->sap_minor != 0)) { 521 sad_ap_rele(ap, ss); 522 miocnak(qp, mp, 0, EINVAL); 523 return; 524 } 525 526 /* 527 * make sure someone else hasn't already 528 * removed this config from the hash. 529 */ 530 mutex_enter(&ss->ss_sad_lock); 531 ap_tmp = sad_ap_find(&ap->ap_common, ss); 532 if (ap_tmp != ap) { 533 mutex_exit(&ss->ss_sad_lock); 534 sad_ap_rele(ap_tmp, ss); 535 sad_ap_rele(ap, ss); 536 miocnak(qp, mp, 0, ENODEV); 537 return; 538 } 539 540 /* remove the config from the hash and return */ 541 sad_ap_remove(ap, ss); 542 mutex_exit(&ss->ss_sad_lock); 543 544 /* 545 * Release thrice, once for sad_ap_find_by_dev(), 546 * once for sad_ap_find(), and once to free. 547 */ 548 sad_ap_rele(ap, ss); 549 sad_ap_rele(ap, ss); 550 sad_ap_rele(ap, ss); 551 miocack(qp, mp, 0, 0); 552 return; 553 } /* switch (sap_cmd) */ 554 /*NOTREACHED*/ 555 556 case SAD_CMD(SAD_GAP): 557 switch ((long)csp->cp_private) { 558 559 case GETSTRUCT: 560 /* sanity check the request */ 561 if (ret = valid_major(sap->sap_major)) { 562 miocnak(qp, mp, 0, ret); 563 return; 564 } 565 566 /* search for a matching config */ 567 if ((ap = sad_ap_find_by_dev(dev, ss)) == NULL) { 568 /* no config found */ 569 miocnak(qp, mp, 0, ENODEV); 570 return; 571 } 572 573 /* copy out the contents of the config */ 574 sap->sap_common = ap->ap_common; 575 if (SAD_VER(csp->cp_cmd) > 0) 576 sap->sap_anchor = ap->ap_anchor; 577 for (i = 0; i < ap->ap_npush; i++) 578 (void) strcpy(sap->sap_list[i], ap->ap_list[i]); 579 for (; i < MAXAPUSH; i++) 580 bzero(sap->sap_list[i], FMNAMESZ + 1); 581 582 /* release our hold on the config */ 583 sad_ap_rele(ap, ss); 584 585 /* copyout the results */ 586 if (SAD_VER(csp->cp_cmd) == 1) 587 size = STRAPUSH_V1_LEN; 588 else 589 size = STRAPUSH_V0_LEN; 590 591 mcopyout(mp, (void *)GETRESULT, size, sadp->sa_addr, 592 NULL); 593 qreply(qp, mp); 594 return; 595 case GETRESULT: 596 miocack(qp, mp, 0, 0); 597 return; 598 599 default: 600 cmn_err(CE_WARN, 601 "apush_iocdata: cp_private bad case SAD_GAP: %p", 602 (void *)csp->cp_private); 603 freemsg(mp); 604 return; 605 } /* switch (cp_private) */ 606 /*NOTREACHED*/ 607 default: /* can't happen */ 608 ASSERT(0); 609 freemsg(mp); 610 return; 611 } /* switch (cp_cmd) */ 612 } 613 614 /* 615 * vml_ioctl() - 616 * Handle the M_IOCTL message associated with a request 617 * to validate a module list. 618 */ 619 static void 620 vml_ioctl( 621 queue_t *qp, /* pointer to write queue */ 622 mblk_t *mp) /* message pointer */ 623 { 624 struct iocblk *iocp; 625 626 iocp = (struct iocblk *)mp->b_rptr; 627 if (iocp->ioc_count != TRANSPARENT) { 628 miocnak(qp, mp, 0, EINVAL); 629 return; 630 } 631 ASSERT(SAD_CMD(iocp->ioc_cmd) == SAD_VML); 632 mcopyin(mp, (void *)GETSTRUCT, 633 SIZEOF_STRUCT(str_list, iocp->ioc_flag), NULL); 634 qreply(qp, mp); 635 } 636 637 /* 638 * vml_iocdata() - 639 * Handle the M_IOCDATA messages associated with 640 * a request to validate a module list. 641 */ 642 static void 643 vml_iocdata( 644 queue_t *qp, /* pointer to write queue */ 645 mblk_t *mp) /* message pointer */ 646 { 647 long i; 648 int nmods; 649 struct copyresp *csp; 650 struct str_mlist *lp; 651 STRUCT_HANDLE(str_list, slp); 652 struct saddev *sadp; 653 654 csp = (struct copyresp *)mp->b_rptr; 655 if (csp->cp_rval) { /* if there was an error */ 656 freemsg(mp); 657 return; 658 } 659 660 ASSERT(SAD_CMD(csp->cp_cmd) == SAD_VML); 661 sadp = (struct saddev *)qp->q_ptr; 662 switch ((long)csp->cp_private) { 663 case GETSTRUCT: 664 STRUCT_SET_HANDLE(slp, csp->cp_flag, 665 (struct str_list *)mp->b_cont->b_rptr); 666 nmods = STRUCT_FGET(slp, sl_nmods); 667 if (nmods <= 0) { 668 miocnak(qp, mp, 0, EINVAL); 669 break; 670 } 671 sadp->sa_addr = (caddr_t)(uintptr_t)nmods; 672 673 mcopyin(mp, (void *)GETLIST, nmods * sizeof (struct str_mlist), 674 STRUCT_FGETP(slp, sl_modlist)); 675 qreply(qp, mp); 676 break; 677 678 case GETLIST: 679 lp = (struct str_mlist *)mp->b_cont->b_rptr; 680 for (i = 0; i < (long)sadp->sa_addr; i++, lp++) { 681 lp->l_name[FMNAMESZ] = '\0'; 682 if (fmodsw_find(lp->l_name, FMODSW_LOAD) == NULL) { 683 miocack(qp, mp, 0, 1); 684 return; 685 } 686 } 687 miocack(qp, mp, 0, 0); 688 break; 689 690 default: 691 cmn_err(CE_WARN, "vml_iocdata: invalid cp_private value: %p", 692 (void *)csp->cp_private); 693 freemsg(mp); 694 break; 695 } /* switch (cp_private) */ 696 } 697 698 /* 699 * Validate a major number and also verify if 700 * it is a STREAMS device. 701 * Return values: 0 if a valid STREAMS dev 702 * error code otherwise 703 */ 704 static int 705 valid_major(major_t major) 706 { 707 int ret = 0; 708 709 if (etoimajor(major) == -1) 710 return (EINVAL); 711 712 /* 713 * attempt to load the driver 'major' and verify that 714 * it is a STREAMS driver. 715 */ 716 if (ddi_hold_driver(major) == NULL) 717 return (EINVAL); 718 719 if (!STREAMSTAB(major)) 720 ret = ENOSTR; 721 722 ddi_rele_driver(major); 723 724 return (ret); 725 } 726