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 /* 23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2015, Joyent, Inc. 25 */ 26 27 #include <sys/atomic.h> 28 #include <sys/door.h> 29 #include <sys/proc.h> 30 #include <sys/cred_impl.h> 31 #include <sys/policy.h> 32 #include <sys/priv.h> 33 #include <sys/klpd.h> 34 #include <sys/errno.h> 35 #include <sys/kmem.h> 36 #include <sys/project.h> 37 #include <sys/systm.h> 38 #include <sys/sysmacros.h> 39 #include <sys/pathname.h> 40 #include <sys/varargs.h> 41 #include <sys/zone.h> 42 #include <netinet/in.h> 43 44 #define ROUNDUP(a, n) (((a) + ((n) - 1)) & ~((n) - 1)) 45 46 static kmutex_t klpd_mutex; 47 48 typedef struct klpd_reg { 49 struct klpd_reg *klpd_next; 50 struct klpd_reg **klpd_refp; 51 door_handle_t klpd_door; 52 pid_t klpd_door_pid; 53 priv_set_t klpd_pset; 54 cred_t *klpd_cred; 55 int klpd_indel; /* Disabled */ 56 uint32_t klpd_ref; 57 } klpd_reg_t; 58 59 60 /* 61 * This data structure hangs off the credential of a process; the 62 * credential is finalized and cannot be changed; but this structure 63 * can be changed when a new door server for the particular group 64 * needs to be registered. It is refcounted and shared between 65 * processes with common ancestry. 66 * 67 * The reference count is atomically updated. 68 * 69 * But the registration probably needs to be updated under a lock. 70 */ 71 typedef struct credklpd { 72 kmutex_t crkl_lock; 73 klpd_reg_t *crkl_reg; 74 uint32_t crkl_ref; 75 } credklpd_t; 76 77 klpd_reg_t *klpd_list; 78 79 static void klpd_unlink(klpd_reg_t *); 80 static int klpd_unreg_dh(door_handle_t); 81 82 static credklpd_t *crklpd_alloc(void); 83 84 void crklpd_setreg(credklpd_t *, klpd_reg_t *); 85 86 extern size_t max_vnode_path; 87 88 void 89 klpd_rele(klpd_reg_t *p) 90 { 91 if (atomic_dec_32_nv(&p->klpd_ref) == 0) { 92 if (p->klpd_refp != NULL) 93 klpd_unlink(p); 94 if (p->klpd_cred != NULL) 95 crfree(p->klpd_cred); 96 door_ki_rele(p->klpd_door); 97 kmem_free(p, sizeof (*p)); 98 } 99 } 100 101 /* 102 * In order to be able to walk the lists, we can't unlink the entry 103 * until the reference count drops to 0. If we remove it too soon, 104 * list walkers will terminate when they happen to call a now orphaned 105 * entry. 106 */ 107 static klpd_reg_t * 108 klpd_rele_next(klpd_reg_t *p) 109 { 110 klpd_reg_t *r = p->klpd_next; 111 112 klpd_rele(p); 113 return (r); 114 } 115 116 117 static void 118 klpd_hold(klpd_reg_t *p) 119 { 120 atomic_inc_32(&p->klpd_ref); 121 } 122 123 /* 124 * Remove registration from where it is registered. Returns next in list. 125 */ 126 static void 127 klpd_unlink(klpd_reg_t *p) 128 { 129 ASSERT(p->klpd_refp == NULL || *p->klpd_refp == p); 130 131 if (p->klpd_refp != NULL) 132 *p->klpd_refp = p->klpd_next; 133 134 if (p->klpd_next != NULL) 135 p->klpd_next->klpd_refp = p->klpd_refp; 136 p->klpd_refp = NULL; 137 } 138 139 /* 140 * Remove all elements of the klpd list and decrement their refcnts. 141 * The lock guarding the list should be held; this function is 142 * called when we are sure we want to destroy the list completely 143 * list but not so sure that the reference counts of all elements have 144 * dropped back to 1. 145 */ 146 void 147 klpd_freelist(klpd_reg_t **pp) 148 { 149 klpd_reg_t *p; 150 151 while ((p = *pp) != NULL) { 152 klpd_unlink(p); 153 klpd_rele(p); 154 } 155 } 156 157 /* 158 * Link new entry in list. The Boolean argument specifies whether this 159 * list can contain only a single item or multiple items. 160 * Returns the entry which needs to be released if single is B_TRUE. 161 */ 162 static klpd_reg_t * 163 klpd_link(klpd_reg_t *p, klpd_reg_t **listp, boolean_t single) 164 { 165 klpd_reg_t *old = *listp; 166 167 ASSERT(p->klpd_ref == 1); 168 169 ASSERT(old == NULL || *old->klpd_refp == old); 170 p->klpd_refp = listp; 171 p->klpd_next = single ? NULL : old; 172 *listp = p; 173 if (old != NULL) { 174 if (single) { 175 ASSERT(old->klpd_next == NULL); 176 old->klpd_refp = NULL; 177 return (old); 178 } else 179 old->klpd_refp = &p->klpd_next; 180 } 181 return (NULL); 182 } 183 184 /* 185 * The typical call consists of: 186 * - priv_set_t 187 * - some integer data (type, value) 188 * for now, it's just one bit. 189 */ 190 static klpd_head_t * 191 klpd_marshall(klpd_reg_t *p, const priv_set_t *rq, va_list ap) 192 { 193 char *tmp; 194 uint_t type; 195 vnode_t *vp; 196 size_t len = sizeof (priv_set_t) + sizeof (klpd_head_t); 197 size_t plen, clen; 198 int proto; 199 200 klpd_arg_t *kap = NULL; 201 klpd_head_t *khp; 202 203 type = va_arg(ap, uint_t); 204 switch (type) { 205 case KLPDARG_NOMORE: 206 khp = kmem_zalloc(len, KM_SLEEP); 207 khp->klh_argoff = 0; 208 break; 209 case KLPDARG_VNODE: 210 len += offsetof(klpd_arg_t, kla_str); 211 vp = va_arg(ap, vnode_t *); 212 if (vp == NULL) 213 return (NULL); 214 215 tmp = va_arg(ap, char *); 216 217 if (tmp != NULL && *tmp != '\0') 218 clen = strlen(tmp) + 1; 219 else 220 clen = 0; 221 222 len += ROUNDUP(MAXPATHLEN, sizeof (uint_t)); 223 khp = kmem_zalloc(len, KM_SLEEP); 224 225 khp->klh_argoff = sizeof (klpd_head_t) + sizeof (priv_set_t); 226 kap = KLH_ARG(khp); 227 228 if (vnodetopath(crgetzone(p->klpd_cred)->zone_rootvp, 229 vp, kap->kla_str, MAXPATHLEN, p->klpd_cred) != 0) { 230 kmem_free(khp, len); 231 return (NULL); 232 } 233 if (clen != 0) { 234 plen = strlen(kap->kla_str); 235 if (plen + clen + 1 >= MAXPATHLEN) { 236 kmem_free(khp, len); 237 return (NULL); 238 } 239 /* Don't make root into a double "/" */ 240 if (plen <= 2) 241 plen = 0; 242 kap->kla_str[plen] = '/'; 243 bcopy(tmp, &kap->kla_str[plen + 1], clen); 244 } 245 break; 246 case KLPDARG_PORT: 247 proto = va_arg(ap, int); 248 switch (proto) { 249 case IPPROTO_TCP: type = KLPDARG_TCPPORT; 250 break; 251 case IPPROTO_UDP: type = KLPDARG_UDPPORT; 252 break; 253 case IPPROTO_SCTP: type = KLPDARG_SCTPPORT; 254 break; 255 case PROTO_SDP: type = KLPDARG_SDPPORT; 256 break; 257 } 258 /* FALLTHROUGH */ 259 case KLPDARG_INT: 260 case KLPDARG_TCPPORT: 261 case KLPDARG_UDPPORT: 262 case KLPDARG_SCTPPORT: 263 case KLPDARG_SDPPORT: 264 len += sizeof (*kap); 265 khp = kmem_zalloc(len, KM_SLEEP); 266 khp->klh_argoff = sizeof (klpd_head_t) + sizeof (priv_set_t); 267 kap = KLH_ARG(khp); 268 kap->kla_int = va_arg(ap, int); 269 break; 270 default: 271 return (NULL); 272 } 273 khp->klh_vers = KLPDCALL_VERS; 274 khp->klh_len = len; 275 khp->klh_privoff = sizeof (*khp); 276 *KLH_PRIVSET(khp) = *rq; 277 if (kap != NULL) { 278 kap->kla_type = type; 279 kap->kla_dlen = len - khp->klh_argoff; 280 } 281 return (khp); 282 } 283 284 static int 285 klpd_do_call(klpd_reg_t *p, const priv_set_t *req, va_list ap) 286 { 287 door_arg_t da; 288 int res; 289 int dres; 290 klpd_head_t *klh; 291 292 if (p->klpd_door_pid == curproc->p_pid) 293 return (-1); 294 295 klh = klpd_marshall(p, req, ap); 296 297 if (klh == NULL) 298 return (-1); 299 300 da.data_ptr = (char *)klh; 301 da.data_size = klh->klh_len; 302 da.desc_ptr = NULL; 303 da.desc_num = 0; 304 da.rbuf = (char *)&res; 305 da.rsize = sizeof (res); 306 307 while ((dres = door_ki_upcall_limited(p->klpd_door, &da, NULL, 308 SIZE_MAX, 0)) != 0) { 309 switch (dres) { 310 case EAGAIN: 311 delay(1); 312 continue; 313 case EINVAL: 314 case EBADF: 315 /* Bad door, don't call it again. */ 316 (void) klpd_unreg_dh(p->klpd_door); 317 /* FALLTHROUGH */ 318 case EINTR: 319 /* Pending signal, nothing we can do. */ 320 /* FALLTHROUGH */ 321 default: 322 kmem_free(klh, klh->klh_len); 323 return (-1); 324 } 325 } 326 kmem_free(klh, klh->klh_len); 327 /* Bogus return value, must be a failure */ 328 if (da.rbuf != (char *)&res) { 329 kmem_free(da.rbuf, da.rsize); 330 return (-1); 331 } 332 return (res); 333 } 334 335 uint32_t klpd_bad_locks; 336 337 int 338 klpd_call(const cred_t *cr, const priv_set_t *req, va_list ap) 339 { 340 klpd_reg_t *p; 341 int rv = -1; 342 credklpd_t *ckp; 343 zone_t *ckzone; 344 345 /* 346 * These locks must not be held when this code is called; 347 * callbacks to userland with these locks held will result 348 * in issues. That said, the code at the call sides was 349 * restructured not to call with any of the locks held and 350 * no policies operate by default on most processes. 351 */ 352 if (mutex_owned(&pidlock) || mutex_owned(&curproc->p_lock) || 353 mutex_owned(&curproc->p_crlock)) { 354 atomic_inc_32(&klpd_bad_locks); 355 return (-1); 356 } 357 358 /* 359 * Enforce the limit set for the call process (still). 360 */ 361 if (!priv_issubset(req, &CR_LPRIV(cr))) 362 return (-1); 363 364 /* Try 1: get the credential specific klpd */ 365 if ((ckp = crgetcrklpd(cr)) != NULL) { 366 mutex_enter(&ckp->crkl_lock); 367 if ((p = ckp->crkl_reg) != NULL && 368 p->klpd_indel == 0 && 369 priv_issubset(req, &p->klpd_pset)) { 370 klpd_hold(p); 371 mutex_exit(&ckp->crkl_lock); 372 rv = klpd_do_call(p, req, ap); 373 mutex_enter(&ckp->crkl_lock); 374 klpd_rele(p); 375 mutex_exit(&ckp->crkl_lock); 376 if (rv != -1) 377 return (rv == 0 ? 0 : -1); 378 } else { 379 mutex_exit(&ckp->crkl_lock); 380 } 381 } 382 383 /* Try 2: get the project specific klpd */ 384 mutex_enter(&klpd_mutex); 385 386 if ((p = curproj->kpj_klpd) != NULL) { 387 klpd_hold(p); 388 mutex_exit(&klpd_mutex); 389 if (p->klpd_indel == 0 && 390 priv_issubset(req, &p->klpd_pset)) { 391 rv = klpd_do_call(p, req, ap); 392 } 393 mutex_enter(&klpd_mutex); 394 klpd_rele(p); 395 mutex_exit(&klpd_mutex); 396 397 if (rv != -1) 398 return (rv == 0 ? 0 : -1); 399 } else { 400 mutex_exit(&klpd_mutex); 401 } 402 403 /* Try 3: get the global klpd list */ 404 ckzone = crgetzone(cr); 405 mutex_enter(&klpd_mutex); 406 407 for (p = klpd_list; p != NULL; ) { 408 zone_t *kkzone = crgetzone(p->klpd_cred); 409 if ((kkzone == &zone0 || kkzone == ckzone) && 410 p->klpd_indel == 0 && 411 priv_issubset(req, &p->klpd_pset)) { 412 klpd_hold(p); 413 mutex_exit(&klpd_mutex); 414 rv = klpd_do_call(p, req, ap); 415 mutex_enter(&klpd_mutex); 416 417 p = klpd_rele_next(p); 418 419 if (rv != -1) 420 break; 421 } else { 422 p = p->klpd_next; 423 } 424 } 425 mutex_exit(&klpd_mutex); 426 return (rv == 0 ? 0 : -1); 427 } 428 429 /* 430 * Register the klpd. 431 * If the pid_t passed in is positive, update the registration for 432 * the specific process; that is only possible if the process already 433 * has a registration on it. This change of registration will affect 434 * all processes which share common ancestry. 435 * 436 * MY_PID (pid 0) can be used to create or change the context for 437 * the current process, typically done after fork(). 438 * 439 * A negative value can be used to register a klpd globally. 440 * 441 * The per-credential klpd needs to be cleaned up when entering 442 * a zone or unsetting the flag. 443 */ 444 int 445 klpd_reg(int did, idtype_t type, id_t id, priv_set_t *psetbuf) 446 { 447 cred_t *cr = CRED(); 448 door_handle_t dh; 449 klpd_reg_t *kpd; 450 priv_set_t pset; 451 door_info_t di; 452 credklpd_t *ckp = NULL; 453 pid_t pid = -1; 454 projid_t proj = -1; 455 kproject_t *kpp = NULL; 456 457 if (CR_FLAGS(cr) & PRIV_XPOLICY) 458 return (set_errno(EINVAL)); 459 460 if (copyin(psetbuf, &pset, sizeof (priv_set_t))) 461 return (set_errno(EFAULT)); 462 463 if (!priv_issubset(&pset, &CR_OEPRIV(cr))) 464 return (set_errno(EPERM)); 465 466 switch (type) { 467 case P_PID: 468 pid = (pid_t)id; 469 if (pid == P_MYPID) 470 pid = curproc->p_pid; 471 if (pid == curproc->p_pid) 472 ckp = crklpd_alloc(); 473 break; 474 case P_PROJID: 475 proj = (projid_t)id; 476 kpp = project_hold_by_id(proj, crgetzone(cr), 477 PROJECT_HOLD_FIND); 478 if (kpp == NULL) 479 return (set_errno(ESRCH)); 480 break; 481 default: 482 return (set_errno(ENOTSUP)); 483 } 484 485 486 /* 487 * Verify the door passed in; it must be a door and we won't 488 * allow processes to be called on their own behalf. 489 */ 490 dh = door_ki_lookup(did); 491 if (dh == NULL || door_ki_info(dh, &di) != 0) { 492 if (ckp != NULL) 493 crklpd_rele(ckp); 494 if (kpp != NULL) 495 project_rele(kpp); 496 return (set_errno(EBADF)); 497 } 498 if (type == P_PID && pid == di.di_target) { 499 if (ckp != NULL) 500 crklpd_rele(ckp); 501 ASSERT(kpp == NULL); 502 return (set_errno(EINVAL)); 503 } 504 505 kpd = kmem_zalloc(sizeof (*kpd), KM_SLEEP); 506 crhold(kpd->klpd_cred = cr); 507 kpd->klpd_door = dh; 508 kpd->klpd_door_pid = di.di_target; 509 kpd->klpd_ref = 1; 510 kpd->klpd_pset = pset; 511 512 if (kpp != NULL) { 513 mutex_enter(&klpd_mutex); 514 kpd = klpd_link(kpd, &kpp->kpj_klpd, B_TRUE); 515 mutex_exit(&klpd_mutex); 516 if (kpd != NULL) 517 klpd_rele(kpd); 518 project_rele(kpp); 519 } else if ((int)pid < 0) { 520 /* Global daemon */ 521 mutex_enter(&klpd_mutex); 522 (void) klpd_link(kpd, &klpd_list, B_FALSE); 523 mutex_exit(&klpd_mutex); 524 } else if (pid == curproc->p_pid) { 525 proc_t *p = curproc; 526 cred_t *newcr = cralloc(); 527 528 /* No need to lock, sole reference to ckp */ 529 kpd = klpd_link(kpd, &ckp->crkl_reg, B_TRUE); 530 531 if (kpd != NULL) 532 klpd_rele(kpd); 533 534 mutex_enter(&p->p_crlock); 535 cr = p->p_cred; 536 crdup_to(cr, newcr); 537 crsetcrklpd(newcr, ckp); 538 p->p_cred = newcr; /* Already held for p_cred */ 539 540 crhold(newcr); /* Hold once for the current thread */ 541 mutex_exit(&p->p_crlock); 542 crfree(cr); /* One for the p_cred */ 543 crset(p, newcr); 544 } else { 545 proc_t *p; 546 cred_t *pcr; 547 mutex_enter(&pidlock); 548 p = prfind(pid); 549 if (p == NULL || !prochasprocperm(p, curproc, CRED())) { 550 mutex_exit(&pidlock); 551 klpd_rele(kpd); 552 return (set_errno(p == NULL ? ESRCH : EPERM)); 553 } 554 mutex_enter(&p->p_crlock); 555 crhold(pcr = p->p_cred); 556 mutex_exit(&pidlock); 557 mutex_exit(&p->p_crlock); 558 /* 559 * We're going to update the credential's ckp in place; 560 * this requires that it exists. 561 */ 562 ckp = crgetcrklpd(pcr); 563 if (ckp == NULL) { 564 crfree(pcr); 565 klpd_rele(kpd); 566 return (set_errno(EINVAL)); 567 } 568 crklpd_setreg(ckp, kpd); 569 crfree(pcr); 570 } 571 572 return (0); 573 } 574 575 static int 576 klpd_unreg_dh(door_handle_t dh) 577 { 578 klpd_reg_t *p; 579 580 mutex_enter(&klpd_mutex); 581 for (p = klpd_list; p != NULL; p = p->klpd_next) { 582 if (p->klpd_door == dh) 583 break; 584 } 585 if (p == NULL) { 586 mutex_exit(&klpd_mutex); 587 return (EINVAL); 588 } 589 if (p->klpd_indel != 0) { 590 mutex_exit(&klpd_mutex); 591 return (EAGAIN); 592 } 593 p->klpd_indel = 1; 594 klpd_rele(p); 595 mutex_exit(&klpd_mutex); 596 return (0); 597 } 598 599 int 600 klpd_unreg(int did, idtype_t type, id_t id) 601 { 602 door_handle_t dh; 603 int res = 0; 604 proc_t *p; 605 pid_t pid; 606 projid_t proj; 607 kproject_t *kpp = NULL; 608 credklpd_t *ckp; 609 610 switch (type) { 611 case P_PID: 612 pid = (pid_t)id; 613 break; 614 case P_PROJID: 615 proj = (projid_t)id; 616 kpp = project_hold_by_id(proj, crgetzone(CRED()), 617 PROJECT_HOLD_FIND); 618 if (kpp == NULL) 619 return (set_errno(ESRCH)); 620 break; 621 default: 622 return (set_errno(ENOTSUP)); 623 } 624 625 dh = door_ki_lookup(did); 626 if (dh == NULL) { 627 if (kpp != NULL) 628 project_rele(kpp); 629 return (set_errno(EINVAL)); 630 } 631 632 if (kpp != NULL) { 633 mutex_enter(&klpd_mutex); 634 if (kpp->kpj_klpd == NULL) 635 res = ESRCH; 636 else 637 klpd_freelist(&kpp->kpj_klpd); 638 mutex_exit(&klpd_mutex); 639 project_rele(kpp); 640 goto out; 641 } else if ((int)pid > 0) { 642 mutex_enter(&pidlock); 643 p = prfind(pid); 644 if (p == NULL) { 645 mutex_exit(&pidlock); 646 door_ki_rele(dh); 647 return (set_errno(ESRCH)); 648 } 649 mutex_enter(&p->p_crlock); 650 mutex_exit(&pidlock); 651 } else if (pid == 0) { 652 p = curproc; 653 mutex_enter(&p->p_crlock); 654 } else { 655 res = klpd_unreg_dh(dh); 656 goto out; 657 } 658 659 ckp = crgetcrklpd(p->p_cred); 660 if (ckp != NULL) { 661 crklpd_setreg(ckp, NULL); 662 } else { 663 res = ESRCH; 664 } 665 mutex_exit(&p->p_crlock); 666 667 out: 668 door_ki_rele(dh); 669 670 if (res != 0) 671 return (set_errno(res)); 672 return (0); 673 } 674 675 void 676 crklpd_hold(credklpd_t *crkpd) 677 { 678 atomic_inc_32(&crkpd->crkl_ref); 679 } 680 681 void 682 crklpd_rele(credklpd_t *crkpd) 683 { 684 if (atomic_dec_32_nv(&crkpd->crkl_ref) == 0) { 685 if (crkpd->crkl_reg != NULL) 686 klpd_rele(crkpd->crkl_reg); 687 mutex_destroy(&crkpd->crkl_lock); 688 kmem_free(crkpd, sizeof (*crkpd)); 689 } 690 } 691 692 static credklpd_t * 693 crklpd_alloc(void) 694 { 695 credklpd_t *res = kmem_alloc(sizeof (*res), KM_SLEEP); 696 697 mutex_init(&res->crkl_lock, NULL, MUTEX_DEFAULT, NULL); 698 res->crkl_ref = 1; 699 res->crkl_reg = NULL; 700 701 return (res); 702 } 703 704 void 705 crklpd_setreg(credklpd_t *crk, klpd_reg_t *new) 706 { 707 klpd_reg_t *old; 708 709 mutex_enter(&crk->crkl_lock); 710 if (new == NULL) { 711 old = crk->crkl_reg; 712 if (old != NULL) 713 klpd_unlink(old); 714 } else { 715 old = klpd_link(new, &crk->crkl_reg, B_TRUE); 716 } 717 mutex_exit(&crk->crkl_lock); 718 719 if (old != NULL) 720 klpd_rele(old); 721 } 722 723 /* Allocate and register the pfexec specific callback */ 724 int 725 pfexec_reg(int did) 726 { 727 door_handle_t dh; 728 int err = secpolicy_pfexec_register(CRED()); 729 klpd_reg_t *pfx; 730 door_info_t di; 731 zone_t *myzone = crgetzone(CRED()); 732 733 if (err != 0) 734 return (set_errno(err)); 735 736 dh = door_ki_lookup(did); 737 if (dh == NULL || door_ki_info(dh, &di) != 0) 738 return (set_errno(EBADF)); 739 740 pfx = kmem_zalloc(sizeof (*pfx), KM_SLEEP); 741 742 pfx->klpd_door = dh; 743 pfx->klpd_door_pid = di.di_target; 744 pfx->klpd_ref = 1; 745 pfx->klpd_cred = NULL; 746 mutex_enter(&myzone->zone_lock); 747 pfx = klpd_link(pfx, &myzone->zone_pfexecd, B_TRUE); 748 mutex_exit(&myzone->zone_lock); 749 if (pfx != NULL) 750 klpd_rele(pfx); 751 752 return (0); 753 } 754 755 int 756 pfexec_unreg(int did) 757 { 758 door_handle_t dh; 759 int err = 0; 760 zone_t *myzone = crgetzone(CRED()); 761 klpd_reg_t *pfd; 762 763 dh = door_ki_lookup(did); 764 if (dh == NULL) 765 return (set_errno(EBADF)); 766 767 mutex_enter(&myzone->zone_lock); 768 pfd = myzone->zone_pfexecd; 769 if (pfd != NULL && pfd->klpd_door == dh) { 770 klpd_unlink(pfd); 771 } else { 772 pfd = NULL; 773 err = EINVAL; 774 } 775 mutex_exit(&myzone->zone_lock); 776 door_ki_rele(dh); 777 /* 778 * crfree() cannot be called with zone_lock held; it is called 779 * indirectly through closing the door handle 780 */ 781 if (pfd != NULL) 782 klpd_rele(pfd); 783 if (err != 0) 784 return (set_errno(err)); 785 return (0); 786 } 787 788 static int 789 get_path(char *buf, const char *path, int len) 790 { 791 size_t lc; 792 char *s; 793 794 if (len < 0) 795 len = strlen(path); 796 797 if (*path == '/' && len < MAXPATHLEN) { 798 (void) strcpy(buf, path); 799 return (0); 800 } 801 /* 802 * Build the pathname using the current directory + resolve pathname. 803 * The resolve pathname either starts with a normal component and 804 * we can just concatenate them or it starts with one 805 * or more ".." component and we can remove those; the 806 * last one cannot be a ".." and the current directory has 807 * more components than the number of ".." in the resolved pathname. 808 */ 809 if (dogetcwd(buf, MAXPATHLEN) != 0) 810 return (-1); 811 812 lc = strlen(buf); 813 814 while (len > 3 && strncmp("../", path, 3) == 0) { 815 len -= 3; 816 path += 3; 817 818 s = strrchr(buf, '/'); 819 if (s == NULL || s == buf) 820 return (-1); 821 822 *s = '\0'; 823 lc = s - buf; 824 } 825 /* Add a "/" and a NUL */ 826 if (lc < 2 || lc + len + 2 >= MAXPATHLEN) 827 return (-1); 828 829 buf[lc] = '/'; 830 (void) strcpy(buf + lc + 1, path); 831 832 return (0); 833 } 834 835 /* 836 * Perform the pfexec upcall. 837 * 838 * The pfexec upcall is different from the klpd_upcall in that a failure 839 * will lead to a denial of execution. 840 */ 841 int 842 pfexec_call(const cred_t *cr, struct pathname *rpnp, cred_t **pfcr, 843 boolean_t *scrub) 844 { 845 klpd_reg_t *pfd; 846 pfexec_arg_t *pap; 847 pfexec_reply_t pr, *prp; 848 door_arg_t da; 849 int dres; 850 cred_t *ncr = NULL; 851 int err = EACCES; 852 priv_set_t *iset; 853 priv_set_t *lset; 854 zone_t *myzone = crgetzone(CRED()); 855 size_t pasize = PFEXEC_ARG_SIZE(MAXPATHLEN); 856 857 /* Find registration */ 858 mutex_enter(&myzone->zone_lock); 859 if ((pfd = myzone->zone_pfexecd) != NULL) 860 klpd_hold(pfd); 861 mutex_exit(&myzone->zone_lock); 862 863 if (pfd == NULL) 864 return (0); 865 866 if (pfd->klpd_door_pid == curproc->p_pid) { 867 klpd_rele(pfd); 868 return (0); 869 } 870 871 pap = kmem_zalloc(pasize, KM_SLEEP); 872 873 if (get_path(pap->pfa_path, rpnp->pn_path, rpnp->pn_pathlen) == -1) 874 goto out1; 875 876 pap->pfa_vers = PFEXEC_ARG_VERS; 877 pap->pfa_call = PFEXEC_EXEC_ATTRS; 878 pap->pfa_len = pasize; 879 pap->pfa_uid = crgetruid(cr); 880 881 da.data_ptr = (char *)pap; 882 da.data_size = pap->pfa_len; 883 da.desc_ptr = NULL; 884 da.desc_num = 0; 885 da.rbuf = (char *)≺ 886 da.rsize = sizeof (pr); 887 888 while ((dres = door_ki_upcall(pfd->klpd_door, &da)) != 0) { 889 switch (dres) { 890 case EAGAIN: 891 delay(1); 892 continue; 893 case EINVAL: 894 case EBADF: 895 /* FALLTHROUGH */ 896 case EINTR: 897 /* FALLTHROUGH */ 898 default: 899 goto out; 900 } 901 } 902 903 prp = (pfexec_reply_t *)da.rbuf; 904 /* 905 * Check the size of the result and the alignment of the 906 * privilege sets. 907 */ 908 if (da.rsize < sizeof (pr) || 909 prp->pfr_ioff > da.rsize - sizeof (priv_set_t) || 910 prp->pfr_loff > da.rsize - sizeof (priv_set_t) || 911 (prp->pfr_loff & (sizeof (priv_chunk_t) - 1)) != 0 || 912 (prp->pfr_ioff & (sizeof (priv_chunk_t) - 1)) != 0) 913 goto out; 914 915 /* 916 * Get results: 917 * allow/allow with additional credentials/disallow[*] 918 * 919 * euid, uid, egid, gid, privs, and limitprivs 920 * We now have somewhat more flexibility we could even set E and P 921 * judiciously but that would break some currently valid assumptions 922 * [*] Disallow is not readily supported by always including 923 * the Basic Solaris User profile in all user's profiles. 924 */ 925 926 if (!prp->pfr_allowed) { 927 err = EACCES; 928 goto out; 929 } 930 if (!prp->pfr_setcred) { 931 err = 0; 932 goto out; 933 } 934 ncr = crdup((cred_t *)cr); 935 936 /* 937 * Generate the new credential set scrubenv if ruid != euid (or set) 938 * the "I'm set-uid flag" but that is not inherited so scrubbing 939 * the environment is a requirement. 940 */ 941 /* Set uids or gids, note that -1 will do the right thing */ 942 if (crsetresuid(ncr, prp->pfr_ruid, prp->pfr_euid, prp->pfr_euid) != 0) 943 goto out; 944 if (crsetresgid(ncr, prp->pfr_rgid, prp->pfr_egid, prp->pfr_egid) != 0) 945 goto out; 946 947 *scrub = prp->pfr_scrubenv; 948 949 if (prp->pfr_clearflag) 950 CR_FLAGS(ncr) &= ~PRIV_PFEXEC; 951 952 /* We cannot exceed our Limit set, no matter what */ 953 iset = PFEXEC_REPLY_IPRIV(prp); 954 955 if (iset != NULL) { 956 if (!priv_issubset(iset, &CR_LPRIV(ncr))) 957 goto out; 958 priv_union(iset, &CR_IPRIV(ncr)); 959 } 960 961 /* Nor can we increate our Limit set itself */ 962 lset = PFEXEC_REPLY_LPRIV(prp); 963 964 if (lset != NULL) { 965 if (!priv_issubset(lset, &CR_LPRIV(ncr))) 966 goto out; 967 CR_LPRIV(ncr) = *lset; 968 } 969 970 /* Exec will do the standard set operations */ 971 972 err = 0; 973 out: 974 if (da.rbuf != (char *)&pr) 975 kmem_free(da.rbuf, da.rsize); 976 out1: 977 kmem_free(pap, pasize); 978 klpd_rele(pfd); 979 if (ncr != NULL) { 980 if (err == 0) 981 *pfcr = ncr; 982 else 983 crfree(ncr); 984 } 985 return (err); 986 } 987 988 int 989 get_forced_privs(const cred_t *cr, const char *respn, priv_set_t *set) 990 { 991 klpd_reg_t *pfd; 992 pfexec_arg_t *pap; 993 door_arg_t da; 994 int dres; 995 int err = -1; 996 priv_set_t *fset, pmem; 997 cred_t *zkcr; 998 zone_t *myzone = crgetzone(cr); 999 size_t pasize = PFEXEC_ARG_SIZE(MAXPATHLEN); 1000 1001 mutex_enter(&myzone->zone_lock); 1002 if ((pfd = myzone->zone_pfexecd) != NULL) 1003 klpd_hold(pfd); 1004 mutex_exit(&myzone->zone_lock); 1005 1006 if (pfd == NULL) 1007 return (-1); 1008 1009 if (pfd->klpd_door_pid == curproc->p_pid) { 1010 klpd_rele(pfd); 1011 return (0); 1012 } 1013 1014 pap = kmem_zalloc(pasize, KM_SLEEP); 1015 1016 if (get_path(pap->pfa_path, respn, -1) == -1) 1017 goto out1; 1018 1019 pap->pfa_vers = PFEXEC_ARG_VERS; 1020 pap->pfa_call = PFEXEC_FORCED_PRIVS; 1021 pap->pfa_len = pasize; 1022 pap->pfa_uid = (uid_t)-1; /* Not relevant */ 1023 1024 da.data_ptr = (char *)pap; 1025 da.data_size = pap->pfa_len; 1026 da.desc_ptr = NULL; 1027 da.desc_num = 0; 1028 da.rbuf = (char *)&pmem; 1029 da.rsize = sizeof (pmem); 1030 1031 while ((dres = door_ki_upcall(pfd->klpd_door, &da)) != 0) { 1032 switch (dres) { 1033 case EAGAIN: 1034 delay(1); 1035 continue; 1036 case EINVAL: 1037 case EBADF: 1038 case EINTR: 1039 default: 1040 goto out; 1041 } 1042 } 1043 1044 /* 1045 * Check the size of the result, it's a privilege set. 1046 */ 1047 if (da.rsize != sizeof (priv_set_t)) 1048 goto out; 1049 1050 fset = (priv_set_t *)da.rbuf; 1051 1052 /* 1053 * We restrict the forced privileges with whatever is available in 1054 * the current zone. 1055 */ 1056 zkcr = zone_kcred(); 1057 priv_intersect(&CR_LPRIV(zkcr), fset); 1058 1059 /* 1060 * But we fail if the forced privileges are not found in the current 1061 * Limit set. 1062 */ 1063 if (!priv_issubset(fset, &CR_LPRIV(cr))) { 1064 err = EACCES; 1065 } else if (!priv_isemptyset(fset)) { 1066 err = 0; 1067 *set = *fset; 1068 } 1069 out: 1070 if (da.rbuf != (char *)&pmem) 1071 kmem_free(da.rbuf, da.rsize); 1072 out1: 1073 kmem_free(pap, pasize); 1074 klpd_rele(pfd); 1075 return (err); 1076 } 1077 1078 int 1079 check_user_privs(const cred_t *cr, const priv_set_t *set) 1080 { 1081 klpd_reg_t *pfd; 1082 pfexec_arg_t *pap; 1083 door_arg_t da; 1084 int dres; 1085 int err = -1; 1086 zone_t *myzone = crgetzone(cr); 1087 size_t pasize = PFEXEC_ARG_SIZE(sizeof (priv_set_t)); 1088 uint32_t res; 1089 1090 mutex_enter(&myzone->zone_lock); 1091 if ((pfd = myzone->zone_pfexecd) != NULL) 1092 klpd_hold(pfd); 1093 mutex_exit(&myzone->zone_lock); 1094 1095 if (pfd == NULL) 1096 return (-1); 1097 1098 if (pfd->klpd_door_pid == curproc->p_pid) { 1099 klpd_rele(pfd); 1100 return (0); 1101 } 1102 1103 pap = kmem_zalloc(pasize, KM_SLEEP); 1104 1105 *(priv_set_t *)&pap->pfa_buf = *set; 1106 1107 pap->pfa_vers = PFEXEC_ARG_VERS; 1108 pap->pfa_call = PFEXEC_USER_PRIVS; 1109 pap->pfa_len = pasize; 1110 pap->pfa_uid = crgetruid(cr); 1111 1112 da.data_ptr = (char *)pap; 1113 da.data_size = pap->pfa_len; 1114 da.desc_ptr = NULL; 1115 da.desc_num = 0; 1116 da.rbuf = (char *)&res; 1117 da.rsize = sizeof (res); 1118 1119 while ((dres = door_ki_upcall(pfd->klpd_door, &da)) != 0) { 1120 switch (dres) { 1121 case EAGAIN: 1122 delay(1); 1123 continue; 1124 case EINVAL: 1125 case EBADF: 1126 case EINTR: 1127 default: 1128 goto out; 1129 } 1130 } 1131 1132 /* 1133 * Check the size of the result. 1134 */ 1135 if (da.rsize != sizeof (res)) 1136 goto out; 1137 1138 if (*(uint32_t *)da.rbuf == 1) 1139 err = 0; 1140 out: 1141 if (da.rbuf != (char *)&res) 1142 kmem_free(da.rbuf, da.rsize); 1143 out1: 1144 kmem_free(pap, pasize); 1145 klpd_rele(pfd); 1146 return (err); 1147 } 1148