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