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