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 (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 26 /* All Rights Reserved */ 27 28 /* 29 * University Copyright- Copyright (c) 1982, 1986, 1988 30 * The Regents of the University of California 31 * All Rights Reserved 32 * 33 * University Acknowledgment- Portions of this document are derived from 34 * software developed by the University of California, Berkeley, and its 35 * contributors. 36 */ 37 38 #include <sys/types.h> 39 #include <sys/sysmacros.h> 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/cred_impl.h> 43 #include <sys/policy.h> 44 #include <sys/vnode.h> 45 #include <sys/errno.h> 46 #include <sys/kmem.h> 47 #include <sys/user.h> 48 #include <sys/proc.h> 49 #include <sys/syscall.h> 50 #include <sys/debug.h> 51 #include <sys/atomic.h> 52 #include <sys/ucred.h> 53 #include <sys/prsystm.h> 54 #include <sys/modctl.h> 55 #include <sys/avl.h> 56 #include <sys/door.h> 57 #include <c2/audit.h> 58 #include <sys/zone.h> 59 #include <sys/tsol/label.h> 60 #include <sys/sid.h> 61 #include <sys/idmap.h> 62 #include <sys/klpd.h> 63 #include <sys/varargs.h> 64 #include <sys/sysconf.h> 65 #include <util/qsort.h> 66 67 68 /* Ephemeral IDs Zones specific data */ 69 typedef struct ephemeral_zsd { 70 uid_t min_uid; 71 uid_t last_uid; 72 gid_t min_gid; 73 gid_t last_gid; 74 kmutex_t eph_lock; 75 cred_t *eph_nobody; 76 } ephemeral_zsd_t; 77 78 static void crgrphold(credgrp_t *); 79 80 #define CREDGRPSZ(ngrp) (sizeof (credgrp_t) + ((ngrp - 1) * sizeof (gid_t))) 81 82 static kmutex_t ephemeral_zone_mutex; 83 static zone_key_t ephemeral_zone_key; 84 85 static struct kmem_cache *cred_cache; 86 static size_t crsize = 0; 87 static int audoff = 0; 88 uint32_t ucredsize; 89 cred_t *kcred; 90 static cred_t *dummycr; 91 92 int rstlink; /* link(2) restricted to files owned by user? */ 93 94 static int get_c2audit_load(void); 95 96 #define CR_AUINFO(c) (auditinfo_addr_t *)((audoff == 0) ? NULL : \ 97 ((char *)(c)) + audoff) 98 99 #define REMOTE_PEER_CRED(c) ((c)->cr_gid == -1) 100 101 #define BIN_GROUP_SEARCH_CUTOFF 16 102 103 static boolean_t hasephids = B_FALSE; 104 105 static ephemeral_zsd_t * 106 get_ephemeral_zsd(zone_t *zone) 107 { 108 ephemeral_zsd_t *eph_zsd; 109 110 eph_zsd = zone_getspecific(ephemeral_zone_key, zone); 111 if (eph_zsd != NULL) { 112 return (eph_zsd); 113 } 114 115 mutex_enter(&ephemeral_zone_mutex); 116 eph_zsd = zone_getspecific(ephemeral_zone_key, zone); 117 if (eph_zsd == NULL) { 118 eph_zsd = kmem_zalloc(sizeof (ephemeral_zsd_t), KM_SLEEP); 119 eph_zsd->min_uid = MAXUID; 120 eph_zsd->last_uid = IDMAP_WK__MAX_UID; 121 eph_zsd->min_gid = MAXUID; 122 eph_zsd->last_gid = IDMAP_WK__MAX_GID; 123 mutex_init(&eph_zsd->eph_lock, NULL, MUTEX_DEFAULT, NULL); 124 125 /* 126 * nobody is used to map SID containing CRs. 127 */ 128 eph_zsd->eph_nobody = crdup(zone->zone_kcred); 129 (void) crsetugid(eph_zsd->eph_nobody, UID_NOBODY, GID_NOBODY); 130 CR_FLAGS(eph_zsd->eph_nobody) = 0; 131 eph_zsd->eph_nobody->cr_zone = zone; 132 133 (void) zone_setspecific(ephemeral_zone_key, zone, eph_zsd); 134 } 135 mutex_exit(&ephemeral_zone_mutex); 136 return (eph_zsd); 137 } 138 139 static cred_t *crdup_flags(const cred_t *, int); 140 static cred_t *cralloc_flags(int); 141 142 /* 143 * This function is called when a zone is destroyed 144 */ 145 static void 146 /* ARGSUSED */ 147 destroy_ephemeral_zsd(zoneid_t zone_id, void *arg) 148 { 149 ephemeral_zsd_t *eph_zsd = arg; 150 if (eph_zsd != NULL) { 151 mutex_destroy(&eph_zsd->eph_lock); 152 crfree(eph_zsd->eph_nobody); 153 kmem_free(eph_zsd, sizeof (ephemeral_zsd_t)); 154 } 155 } 156 157 158 159 /* 160 * Initialize credentials data structures. 161 */ 162 163 void 164 cred_init(void) 165 { 166 priv_init(); 167 168 crsize = sizeof (cred_t); 169 170 if (get_c2audit_load() > 0) { 171 #ifdef _LP64 172 /* assure audit context is 64-bit aligned */ 173 audoff = (crsize + 174 sizeof (int64_t) - 1) & ~(sizeof (int64_t) - 1); 175 #else /* _LP64 */ 176 audoff = crsize; 177 #endif /* _LP64 */ 178 crsize = audoff + sizeof (auditinfo_addr_t); 179 crsize = (crsize + sizeof (int) - 1) & ~(sizeof (int) - 1); 180 } 181 182 cred_cache = kmem_cache_create("cred_cache", crsize, 0, 183 NULL, NULL, NULL, NULL, NULL, 0); 184 185 /* 186 * dummycr is used to copy initial state for creds. 187 */ 188 dummycr = cralloc(); 189 bzero(dummycr, crsize); 190 dummycr->cr_ref = 1; 191 dummycr->cr_uid = (uid_t)-1; 192 dummycr->cr_gid = (gid_t)-1; 193 dummycr->cr_ruid = (uid_t)-1; 194 dummycr->cr_rgid = (gid_t)-1; 195 dummycr->cr_suid = (uid_t)-1; 196 dummycr->cr_sgid = (gid_t)-1; 197 198 199 /* 200 * kcred is used by anything that needs all privileges; it's 201 * also the template used for crget as it has all the compatible 202 * sets filled in. 203 */ 204 kcred = cralloc(); 205 206 bzero(kcred, crsize); 207 kcred->cr_ref = 1; 208 209 /* kcred is never freed, so we don't need zone_cred_hold here */ 210 kcred->cr_zone = &zone0; 211 212 priv_fillset(&CR_LPRIV(kcred)); 213 CR_IPRIV(kcred) = *priv_basic; 214 215 /* Not a basic privilege, if chown is not restricted add it to I0 */ 216 if (!rstchown) 217 priv_addset(&CR_IPRIV(kcred), PRIV_FILE_CHOWN_SELF); 218 219 /* Basic privilege, if link is restricted remove it from I0 */ 220 if (rstlink) 221 priv_delset(&CR_IPRIV(kcred), PRIV_FILE_LINK_ANY); 222 223 CR_EPRIV(kcred) = CR_PPRIV(kcred) = CR_IPRIV(kcred); 224 225 CR_FLAGS(kcred) = NET_MAC_AWARE; 226 227 /* 228 * Set up credentials of p0. 229 */ 230 ttoproc(curthread)->p_cred = kcred; 231 curthread->t_cred = kcred; 232 233 ucredsize = UCRED_SIZE; 234 235 mutex_init(&ephemeral_zone_mutex, NULL, MUTEX_DEFAULT, NULL); 236 zone_key_create(&ephemeral_zone_key, NULL, NULL, destroy_ephemeral_zsd); 237 } 238 239 /* 240 * Allocate (nearly) uninitialized cred_t. 241 */ 242 static cred_t * 243 cralloc_flags(int flgs) 244 { 245 cred_t *cr = kmem_cache_alloc(cred_cache, flgs); 246 247 if (cr == NULL) 248 return (NULL); 249 250 cr->cr_ref = 1; /* So we can crfree() */ 251 cr->cr_zone = NULL; 252 cr->cr_label = NULL; 253 cr->cr_ksid = NULL; 254 cr->cr_klpd = NULL; 255 cr->cr_grps = NULL; 256 return (cr); 257 } 258 259 cred_t * 260 cralloc(void) 261 { 262 return (cralloc_flags(KM_SLEEP)); 263 } 264 265 /* 266 * As cralloc but prepared for ksid change (if appropriate). 267 */ 268 cred_t * 269 cralloc_ksid(void) 270 { 271 cred_t *cr = cralloc(); 272 if (hasephids) 273 cr->cr_ksid = kcrsid_alloc(); 274 return (cr); 275 } 276 277 /* 278 * Allocate a initialized cred structure and crhold() it. 279 * Initialized means: all ids 0, group count 0, L=Full, E=P=I=I0 280 */ 281 cred_t * 282 crget(void) 283 { 284 cred_t *cr = kmem_cache_alloc(cred_cache, KM_SLEEP); 285 286 bcopy(kcred, cr, crsize); 287 cr->cr_ref = 1; 288 zone_cred_hold(cr->cr_zone); 289 if (cr->cr_label) 290 label_hold(cr->cr_label); 291 ASSERT(cr->cr_klpd == NULL); 292 ASSERT(cr->cr_grps == NULL); 293 return (cr); 294 } 295 296 /* 297 * Broadcast the cred to all the threads in the process. 298 * The current thread's credentials can be set right away, but other 299 * threads must wait until the start of the next system call or trap. 300 * This avoids changing the cred in the middle of a system call. 301 * 302 * The cred has already been held for the process and the thread (2 holds), 303 * and p->p_cred set. 304 * 305 * p->p_crlock shouldn't be held here, since p_lock must be acquired. 306 */ 307 void 308 crset(proc_t *p, cred_t *cr) 309 { 310 kthread_id_t t; 311 kthread_id_t first; 312 cred_t *oldcr; 313 314 ASSERT(p == curproc); /* assumes p_lwpcnt can't change */ 315 316 /* 317 * DTrace accesses t_cred in probe context. t_cred must always be 318 * either NULL, or point to a valid, allocated cred structure. 319 */ 320 t = curthread; 321 oldcr = t->t_cred; 322 t->t_cred = cr; /* the cred is held by caller for this thread */ 323 crfree(oldcr); /* free the old cred for the thread */ 324 325 /* 326 * Broadcast to other threads, if any. 327 */ 328 if (p->p_lwpcnt > 1) { 329 mutex_enter(&p->p_lock); /* to keep thread list safe */ 330 first = curthread; 331 for (t = first->t_forw; t != first; t = t->t_forw) 332 t->t_pre_sys = 1; /* so syscall will get new cred */ 333 mutex_exit(&p->p_lock); 334 } 335 } 336 337 /* 338 * Put a hold on a cred structure. 339 */ 340 void 341 crhold(cred_t *cr) 342 { 343 ASSERT(cr->cr_ref != 0xdeadbeef && cr->cr_ref != 0); 344 atomic_add_32(&cr->cr_ref, 1); 345 } 346 347 /* 348 * Release previous hold on a cred structure. Free it if refcnt == 0. 349 * If cred uses label different from zone label, free it. 350 */ 351 void 352 crfree(cred_t *cr) 353 { 354 ASSERT(cr->cr_ref != 0xdeadbeef && cr->cr_ref != 0); 355 if (atomic_add_32_nv(&cr->cr_ref, -1) == 0) { 356 ASSERT(cr != kcred); 357 if (cr->cr_label) 358 label_rele(cr->cr_label); 359 if (cr->cr_klpd) 360 crklpd_rele(cr->cr_klpd); 361 if (cr->cr_zone) 362 zone_cred_rele(cr->cr_zone); 363 if (cr->cr_ksid) 364 kcrsid_rele(cr->cr_ksid); 365 if (cr->cr_grps) 366 crgrprele(cr->cr_grps); 367 368 kmem_cache_free(cred_cache, cr); 369 } 370 } 371 372 /* 373 * Copy a cred structure to a new one and free the old one. 374 * The new cred will have two references. One for the calling process, 375 * and one for the thread. 376 */ 377 cred_t * 378 crcopy(cred_t *cr) 379 { 380 cred_t *newcr; 381 382 newcr = cralloc(); 383 bcopy(cr, newcr, crsize); 384 if (newcr->cr_zone) 385 zone_cred_hold(newcr->cr_zone); 386 if (newcr->cr_label) 387 label_hold(newcr->cr_label); 388 if (newcr->cr_ksid) 389 kcrsid_hold(newcr->cr_ksid); 390 if (newcr->cr_klpd) 391 crklpd_hold(newcr->cr_klpd); 392 if (newcr->cr_grps) 393 crgrphold(newcr->cr_grps); 394 crfree(cr); 395 newcr->cr_ref = 2; /* caller gets two references */ 396 return (newcr); 397 } 398 399 /* 400 * Copy a cred structure to a new one and free the old one. 401 * The new cred will have two references. One for the calling process, 402 * and one for the thread. 403 * This variation on crcopy uses a pre-allocated structure for the 404 * "new" cred. 405 */ 406 void 407 crcopy_to(cred_t *oldcr, cred_t *newcr) 408 { 409 credsid_t *nkcr = newcr->cr_ksid; 410 411 bcopy(oldcr, newcr, crsize); 412 if (newcr->cr_zone) 413 zone_cred_hold(newcr->cr_zone); 414 if (newcr->cr_label) 415 label_hold(newcr->cr_label); 416 if (newcr->cr_klpd) 417 crklpd_hold(newcr->cr_klpd); 418 if (newcr->cr_grps) 419 crgrphold(newcr->cr_grps); 420 if (nkcr) { 421 newcr->cr_ksid = nkcr; 422 kcrsidcopy_to(oldcr->cr_ksid, newcr->cr_ksid); 423 } else if (newcr->cr_ksid) 424 kcrsid_hold(newcr->cr_ksid); 425 crfree(oldcr); 426 newcr->cr_ref = 2; /* caller gets two references */ 427 } 428 429 /* 430 * Dup a cred struct to a new held one. 431 * The old cred is not freed. 432 */ 433 static cred_t * 434 crdup_flags(const cred_t *cr, int flgs) 435 { 436 cred_t *newcr; 437 438 newcr = cralloc_flags(flgs); 439 440 if (newcr == NULL) 441 return (NULL); 442 443 bcopy(cr, newcr, crsize); 444 if (newcr->cr_zone) 445 zone_cred_hold(newcr->cr_zone); 446 if (newcr->cr_label) 447 label_hold(newcr->cr_label); 448 if (newcr->cr_klpd) 449 crklpd_hold(newcr->cr_klpd); 450 if (newcr->cr_ksid) 451 kcrsid_hold(newcr->cr_ksid); 452 if (newcr->cr_grps) 453 crgrphold(newcr->cr_grps); 454 newcr->cr_ref = 1; 455 return (newcr); 456 } 457 458 cred_t * 459 crdup(cred_t *cr) 460 { 461 return (crdup_flags(cr, KM_SLEEP)); 462 } 463 464 /* 465 * Dup a cred struct to a new held one. 466 * The old cred is not freed. 467 * This variation on crdup uses a pre-allocated structure for the 468 * "new" cred. 469 */ 470 void 471 crdup_to(cred_t *oldcr, cred_t *newcr) 472 { 473 credsid_t *nkcr = newcr->cr_ksid; 474 475 bcopy(oldcr, newcr, crsize); 476 if (newcr->cr_zone) 477 zone_cred_hold(newcr->cr_zone); 478 if (newcr->cr_label) 479 label_hold(newcr->cr_label); 480 if (newcr->cr_klpd) 481 crklpd_hold(newcr->cr_klpd); 482 if (newcr->cr_grps) 483 crgrphold(newcr->cr_grps); 484 if (nkcr) { 485 newcr->cr_ksid = nkcr; 486 kcrsidcopy_to(oldcr->cr_ksid, newcr->cr_ksid); 487 } else if (newcr->cr_ksid) 488 kcrsid_hold(newcr->cr_ksid); 489 newcr->cr_ref = 1; 490 } 491 492 /* 493 * Return the (held) credentials for the current running process. 494 */ 495 cred_t * 496 crgetcred(void) 497 { 498 cred_t *cr; 499 proc_t *p; 500 501 p = ttoproc(curthread); 502 mutex_enter(&p->p_crlock); 503 crhold(cr = p->p_cred); 504 mutex_exit(&p->p_crlock); 505 return (cr); 506 } 507 508 /* 509 * Backward compatibility check for suser(). 510 * Accounting flag is now set in the policy functions; auditing is 511 * done through use of privilege in the audit trail. 512 */ 513 int 514 suser(cred_t *cr) 515 { 516 return (PRIV_POLICY(cr, PRIV_SYS_SUSER_COMPAT, B_FALSE, EPERM, NULL) 517 == 0); 518 } 519 520 /* 521 * Determine whether the supplied group id is a member of the group 522 * described by the supplied credentials. 523 */ 524 int 525 groupmember(gid_t gid, const cred_t *cr) 526 { 527 if (gid == cr->cr_gid) 528 return (1); 529 return (supgroupmember(gid, cr)); 530 } 531 532 /* 533 * As groupmember but only check against the supplemental groups. 534 */ 535 int 536 supgroupmember(gid_t gid, const cred_t *cr) 537 { 538 int hi, lo; 539 credgrp_t *grps = cr->cr_grps; 540 const gid_t *gp, *endgp; 541 542 if (grps == NULL) 543 return (0); 544 545 /* For a small number of groups, use sequentials search. */ 546 if (grps->crg_ngroups <= BIN_GROUP_SEARCH_CUTOFF) { 547 endgp = &grps->crg_groups[grps->crg_ngroups]; 548 for (gp = grps->crg_groups; gp < endgp; gp++) 549 if (*gp == gid) 550 return (1); 551 return (0); 552 } 553 554 /* We use binary search when we have many groups. */ 555 lo = 0; 556 hi = grps->crg_ngroups - 1; 557 gp = grps->crg_groups; 558 559 do { 560 int m = (lo + hi) / 2; 561 562 if (gid > gp[m]) 563 lo = m + 1; 564 else if (gid < gp[m]) 565 hi = m - 1; 566 else 567 return (1); 568 } while (lo <= hi); 569 570 return (0); 571 } 572 573 /* 574 * This function is called to check whether the credentials set 575 * "scrp" has permission to act on credentials set "tcrp". It enforces the 576 * permission requirements needed to send a signal to a process. 577 * The same requirements are imposed by other system calls, however. 578 * 579 * The rules are: 580 * (1) if the credentials are the same, the check succeeds 581 * (2) if the zone ids don't match, and scrp is not in the global zone or 582 * does not have the PRIV_PROC_ZONE privilege, the check fails 583 * (3) if the real or effective user id of scrp matches the real or saved 584 * user id of tcrp or scrp has the PRIV_PROC_OWNER privilege, the check 585 * succeeds 586 * (4) otherwise, the check fails 587 */ 588 int 589 hasprocperm(const cred_t *tcrp, const cred_t *scrp) 590 { 591 if (scrp == tcrp) 592 return (1); 593 if (scrp->cr_zone != tcrp->cr_zone && 594 (scrp->cr_zone != global_zone || 595 secpolicy_proc_zone(scrp) != 0)) 596 return (0); 597 if (scrp->cr_uid == tcrp->cr_ruid || 598 scrp->cr_ruid == tcrp->cr_ruid || 599 scrp->cr_uid == tcrp->cr_suid || 600 scrp->cr_ruid == tcrp->cr_suid || 601 !PRIV_POLICY(scrp, PRIV_PROC_OWNER, B_FALSE, EPERM, "hasprocperm")) 602 return (1); 603 return (0); 604 } 605 606 /* 607 * This interface replaces hasprocperm; it works like hasprocperm but 608 * additionally returns success if the proc_t's match 609 * It is the preferred interface for most uses. 610 * And it will acquire p_crlock itself, so it assert's that it shouldn't 611 * be held. 612 */ 613 int 614 prochasprocperm(proc_t *tp, proc_t *sp, const cred_t *scrp) 615 { 616 int rets; 617 cred_t *tcrp; 618 619 ASSERT(MUTEX_NOT_HELD(&tp->p_crlock)); 620 621 if (tp == sp) 622 return (1); 623 624 if (tp->p_sessp != sp->p_sessp && secpolicy_basic_proc(scrp) != 0) 625 return (0); 626 627 mutex_enter(&tp->p_crlock); 628 crhold(tcrp = tp->p_cred); 629 mutex_exit(&tp->p_crlock); 630 rets = hasprocperm(tcrp, scrp); 631 crfree(tcrp); 632 633 return (rets); 634 } 635 636 /* 637 * This routine is used to compare two credentials to determine if 638 * they refer to the same "user". If the pointers are equal, then 639 * they must refer to the same user. Otherwise, the contents of 640 * the credentials are compared to see whether they are equivalent. 641 * 642 * This routine returns 0 if the credentials refer to the same user, 643 * 1 if they do not. 644 */ 645 int 646 crcmp(const cred_t *cr1, const cred_t *cr2) 647 { 648 credgrp_t *grp1, *grp2; 649 650 if (cr1 == cr2) 651 return (0); 652 653 if (cr1->cr_uid == cr2->cr_uid && 654 cr1->cr_gid == cr2->cr_gid && 655 cr1->cr_ruid == cr2->cr_ruid && 656 cr1->cr_rgid == cr2->cr_rgid && 657 cr1->cr_zone == cr2->cr_zone && 658 ((grp1 = cr1->cr_grps) == (grp2 = cr2->cr_grps) || 659 (grp1 != NULL && grp2 != NULL && 660 grp1->crg_ngroups == grp2->crg_ngroups && 661 bcmp(grp1->crg_groups, grp2->crg_groups, 662 grp1->crg_ngroups * sizeof (gid_t)) == 0))) { 663 return (!priv_isequalset(&CR_OEPRIV(cr1), &CR_OEPRIV(cr2))); 664 } 665 return (1); 666 } 667 668 /* 669 * Read access functions to cred_t. 670 */ 671 uid_t 672 crgetuid(const cred_t *cr) 673 { 674 return (cr->cr_uid); 675 } 676 677 uid_t 678 crgetruid(const cred_t *cr) 679 { 680 return (cr->cr_ruid); 681 } 682 683 uid_t 684 crgetsuid(const cred_t *cr) 685 { 686 return (cr->cr_suid); 687 } 688 689 gid_t 690 crgetgid(const cred_t *cr) 691 { 692 return (cr->cr_gid); 693 } 694 695 gid_t 696 crgetrgid(const cred_t *cr) 697 { 698 return (cr->cr_rgid); 699 } 700 701 gid_t 702 crgetsgid(const cred_t *cr) 703 { 704 return (cr->cr_sgid); 705 } 706 707 const auditinfo_addr_t * 708 crgetauinfo(const cred_t *cr) 709 { 710 return ((const auditinfo_addr_t *)CR_AUINFO(cr)); 711 } 712 713 auditinfo_addr_t * 714 crgetauinfo_modifiable(cred_t *cr) 715 { 716 return (CR_AUINFO(cr)); 717 } 718 719 zoneid_t 720 crgetzoneid(const cred_t *cr) 721 { 722 return (cr->cr_zone == NULL ? 723 (cr->cr_uid == -1 ? (zoneid_t)-1 : GLOBAL_ZONEID) : 724 cr->cr_zone->zone_id); 725 } 726 727 projid_t 728 crgetprojid(const cred_t *cr) 729 { 730 return (cr->cr_projid); 731 } 732 733 zone_t * 734 crgetzone(const cred_t *cr) 735 { 736 return (cr->cr_zone); 737 } 738 739 struct ts_label_s * 740 crgetlabel(const cred_t *cr) 741 { 742 return (cr->cr_label ? 743 cr->cr_label : 744 (cr->cr_zone ? cr->cr_zone->zone_slabel : NULL)); 745 } 746 747 boolean_t 748 crisremote(const cred_t *cr) 749 { 750 return (REMOTE_PEER_CRED(cr)); 751 } 752 753 #define BADUID(x, zn) ((x) != -1 && !VALID_UID((x), (zn))) 754 #define BADGID(x, zn) ((x) != -1 && !VALID_GID((x), (zn))) 755 756 int 757 crsetresuid(cred_t *cr, uid_t r, uid_t e, uid_t s) 758 { 759 zone_t *zone = crgetzone(cr); 760 761 ASSERT(cr->cr_ref <= 2); 762 763 if (BADUID(r, zone) || BADUID(e, zone) || BADUID(s, zone)) 764 return (-1); 765 766 if (r != -1) 767 cr->cr_ruid = r; 768 if (e != -1) 769 cr->cr_uid = e; 770 if (s != -1) 771 cr->cr_suid = s; 772 773 return (0); 774 } 775 776 int 777 crsetresgid(cred_t *cr, gid_t r, gid_t e, gid_t s) 778 { 779 zone_t *zone = crgetzone(cr); 780 781 ASSERT(cr->cr_ref <= 2); 782 783 if (BADGID(r, zone) || BADGID(e, zone) || BADGID(s, zone)) 784 return (-1); 785 786 if (r != -1) 787 cr->cr_rgid = r; 788 if (e != -1) 789 cr->cr_gid = e; 790 if (s != -1) 791 cr->cr_sgid = s; 792 793 return (0); 794 } 795 796 int 797 crsetugid(cred_t *cr, uid_t uid, gid_t gid) 798 { 799 zone_t *zone = crgetzone(cr); 800 801 ASSERT(cr->cr_ref <= 2); 802 803 if (!VALID_UID(uid, zone) || !VALID_GID(gid, zone)) 804 return (-1); 805 806 cr->cr_uid = cr->cr_ruid = cr->cr_suid = uid; 807 cr->cr_gid = cr->cr_rgid = cr->cr_sgid = gid; 808 809 return (0); 810 } 811 812 static int 813 gidcmp(const void *v1, const void *v2) 814 { 815 gid_t g1 = *(gid_t *)v1; 816 gid_t g2 = *(gid_t *)v2; 817 818 if (g1 < g2) 819 return (-1); 820 else if (g1 > g2) 821 return (1); 822 else 823 return (0); 824 } 825 826 int 827 crsetgroups(cred_t *cr, int n, gid_t *grp) 828 { 829 ASSERT(cr->cr_ref <= 2); 830 831 if (n > ngroups_max || n < 0) 832 return (-1); 833 834 if (cr->cr_grps != NULL) 835 crgrprele(cr->cr_grps); 836 837 if (n > 0) { 838 cr->cr_grps = kmem_alloc(CREDGRPSZ(n), KM_SLEEP); 839 bcopy(grp, cr->cr_grps->crg_groups, n * sizeof (gid_t)); 840 cr->cr_grps->crg_ref = 1; 841 cr->cr_grps->crg_ngroups = n; 842 qsort(cr->cr_grps->crg_groups, n, sizeof (gid_t), gidcmp); 843 } else { 844 cr->cr_grps = NULL; 845 } 846 847 return (0); 848 } 849 850 void 851 crsetprojid(cred_t *cr, projid_t projid) 852 { 853 ASSERT(projid >= 0 && projid <= MAXPROJID); 854 cr->cr_projid = projid; 855 } 856 857 /* 858 * This routine returns the pointer to the first element of the crg_groups 859 * array. It can move around in an implementation defined way. 860 * Note that when we have no grouplist, we return one element but the 861 * caller should never reference it. 862 */ 863 const gid_t * 864 crgetgroups(const cred_t *cr) 865 { 866 return (cr->cr_grps == NULL ? &cr->cr_gid : cr->cr_grps->crg_groups); 867 } 868 869 int 870 crgetngroups(const cred_t *cr) 871 { 872 return (cr->cr_grps == NULL ? 0 : cr->cr_grps->crg_ngroups); 873 } 874 875 void 876 cred2prcred(const cred_t *cr, prcred_t *pcrp) 877 { 878 pcrp->pr_euid = cr->cr_uid; 879 pcrp->pr_ruid = cr->cr_ruid; 880 pcrp->pr_suid = cr->cr_suid; 881 pcrp->pr_egid = cr->cr_gid; 882 pcrp->pr_rgid = cr->cr_rgid; 883 pcrp->pr_sgid = cr->cr_sgid; 884 pcrp->pr_groups[0] = 0; /* in case ngroups == 0 */ 885 pcrp->pr_ngroups = cr->cr_grps == NULL ? 0 : cr->cr_grps->crg_ngroups; 886 887 if (pcrp->pr_ngroups != 0) 888 bcopy(cr->cr_grps->crg_groups, pcrp->pr_groups, 889 sizeof (gid_t) * pcrp->pr_ngroups); 890 } 891 892 static int 893 cred2ucaud(const cred_t *cr, auditinfo64_addr_t *ainfo, const cred_t *rcr) 894 { 895 auditinfo_addr_t *ai; 896 au_tid_addr_t tid; 897 898 if (secpolicy_audit_getattr(rcr, B_TRUE) != 0) 899 return (-1); 900 901 ai = CR_AUINFO(cr); /* caller makes sure this is non-NULL */ 902 tid = ai->ai_termid; 903 904 ainfo->ai_auid = ai->ai_auid; 905 ainfo->ai_mask = ai->ai_mask; 906 ainfo->ai_asid = ai->ai_asid; 907 908 ainfo->ai_termid.at_type = tid.at_type; 909 bcopy(&tid.at_addr, &ainfo->ai_termid.at_addr, 4 * sizeof (uint_t)); 910 911 ainfo->ai_termid.at_port.at_major = (uint32_t)getmajor(tid.at_port); 912 ainfo->ai_termid.at_port.at_minor = (uint32_t)getminor(tid.at_port); 913 914 return (0); 915 } 916 917 void 918 cred2uclabel(const cred_t *cr, bslabel_t *labelp) 919 { 920 ts_label_t *tslp; 921 922 if ((tslp = crgetlabel(cr)) != NULL) 923 bcopy(&tslp->tsl_label, labelp, sizeof (bslabel_t)); 924 } 925 926 /* 927 * Convert a credential into a "ucred". Allow the caller to specify 928 * and aligned buffer, e.g., in an mblk, so we don't have to allocate 929 * memory and copy it twice. 930 * 931 * This function may call cred2ucaud(), which calls CRED(). Since this 932 * can be called from an interrupt thread, receiver's cred (rcr) is needed 933 * to determine whether audit info should be included. 934 */ 935 struct ucred_s * 936 cred2ucred(const cred_t *cr, pid_t pid, void *buf, const cred_t *rcr) 937 { 938 struct ucred_s *uc; 939 uint32_t realsz = ucredminsize(cr); 940 ts_label_t *tslp = is_system_labeled() ? crgetlabel(cr) : NULL; 941 942 /* The structure isn't always completely filled in, so zero it */ 943 if (buf == NULL) { 944 uc = kmem_zalloc(realsz, KM_SLEEP); 945 } else { 946 bzero(buf, realsz); 947 uc = buf; 948 } 949 uc->uc_size = realsz; 950 uc->uc_pid = pid; 951 uc->uc_projid = cr->cr_projid; 952 uc->uc_zoneid = crgetzoneid(cr); 953 954 if (REMOTE_PEER_CRED(cr)) { 955 /* 956 * Other than label, the rest of cred info about a 957 * remote peer isn't available. Copy the label directly 958 * after the header where we generally copy the prcred. 959 * That's why we use sizeof (struct ucred_s). The other 960 * offset fields are initialized to 0. 961 */ 962 uc->uc_labeloff = tslp == NULL ? 0 : sizeof (struct ucred_s); 963 } else { 964 uc->uc_credoff = UCRED_CRED_OFF; 965 uc->uc_privoff = UCRED_PRIV_OFF; 966 uc->uc_audoff = UCRED_AUD_OFF; 967 uc->uc_labeloff = tslp == NULL ? 0 : UCRED_LABEL_OFF; 968 969 cred2prcred(cr, UCCRED(uc)); 970 cred2prpriv(cr, UCPRIV(uc)); 971 972 if (audoff == 0 || cred2ucaud(cr, UCAUD(uc), rcr) != 0) 973 uc->uc_audoff = 0; 974 } 975 if (tslp != NULL) 976 bcopy(&tslp->tsl_label, UCLABEL(uc), sizeof (bslabel_t)); 977 978 return (uc); 979 } 980 981 /* 982 * Don't allocate the non-needed group entries. Note: this function 983 * must match the code in cred2ucred; they must agree about the 984 * minimal size of the ucred. 985 */ 986 uint32_t 987 ucredminsize(const cred_t *cr) 988 { 989 int ndiff; 990 991 if (cr == NULL) 992 return (ucredsize); 993 994 if (REMOTE_PEER_CRED(cr)) { 995 if (is_system_labeled()) 996 return (sizeof (struct ucred_s) + sizeof (bslabel_t)); 997 else 998 return (sizeof (struct ucred_s)); 999 } 1000 1001 if (cr->cr_grps == NULL) 1002 ndiff = ngroups_max - 1; /* Needs one for prcred_t */ 1003 else 1004 ndiff = ngroups_max - cr->cr_grps->crg_ngroups; 1005 1006 return (ucredsize - ndiff * sizeof (gid_t)); 1007 } 1008 1009 /* 1010 * Get the "ucred" of a process. 1011 */ 1012 struct ucred_s * 1013 pgetucred(proc_t *p) 1014 { 1015 cred_t *cr; 1016 struct ucred_s *uc; 1017 1018 mutex_enter(&p->p_crlock); 1019 cr = p->p_cred; 1020 crhold(cr); 1021 mutex_exit(&p->p_crlock); 1022 1023 uc = cred2ucred(cr, p->p_pid, NULL, CRED()); 1024 crfree(cr); 1025 1026 return (uc); 1027 } 1028 1029 /* 1030 * If the reply status is NFSERR_EACCES, it may be because we are 1031 * root (no root net access). Check the real uid, if it isn't root 1032 * make that the uid instead and retry the call. 1033 * Private interface for NFS. 1034 */ 1035 cred_t * 1036 crnetadjust(cred_t *cr) 1037 { 1038 if (cr->cr_uid == 0 && cr->cr_ruid != 0) { 1039 cr = crdup(cr); 1040 cr->cr_uid = cr->cr_ruid; 1041 return (cr); 1042 } 1043 return (NULL); 1044 } 1045 1046 /* 1047 * The reference count is of interest when you want to check 1048 * whether it is ok to modify the credential in place. 1049 */ 1050 uint_t 1051 crgetref(const cred_t *cr) 1052 { 1053 return (cr->cr_ref); 1054 } 1055 1056 static int 1057 get_c2audit_load(void) 1058 { 1059 static int gotit = 0; 1060 static int c2audit_load; 1061 1062 if (gotit) 1063 return (c2audit_load); 1064 c2audit_load = 1; /* set default value once */ 1065 if (mod_sysctl(SYS_CHECK_EXCLUDE, "c2audit") != 0) 1066 c2audit_load = 0; 1067 gotit++; 1068 1069 return (c2audit_load); 1070 } 1071 1072 int 1073 get_audit_ucrsize(void) 1074 { 1075 return (get_c2audit_load() ? sizeof (auditinfo64_addr_t) : 0); 1076 } 1077 1078 /* 1079 * Set zone pointer in credential to indicated value. First adds a 1080 * hold for the new zone, then drops the hold on previous zone (if any). 1081 * This is done in this order in case the old and new zones are the 1082 * same. 1083 */ 1084 void 1085 crsetzone(cred_t *cr, zone_t *zptr) 1086 { 1087 zone_t *oldzptr = cr->cr_zone; 1088 1089 ASSERT(cr != kcred); 1090 ASSERT(cr->cr_ref <= 2); 1091 cr->cr_zone = zptr; 1092 zone_cred_hold(zptr); 1093 if (oldzptr) 1094 zone_cred_rele(oldzptr); 1095 } 1096 1097 /* 1098 * Create a new cred based on the supplied label 1099 */ 1100 cred_t * 1101 newcred_from_bslabel(bslabel_t *blabel, uint32_t doi, int flags) 1102 { 1103 ts_label_t *lbl = labelalloc(blabel, doi, flags); 1104 cred_t *cr = NULL; 1105 1106 if (lbl != NULL) { 1107 if ((cr = crdup_flags(dummycr, flags)) != NULL) { 1108 cr->cr_label = lbl; 1109 } else { 1110 label_rele(lbl); 1111 } 1112 } 1113 1114 return (cr); 1115 } 1116 1117 /* 1118 * Derive a new cred from the existing cred, but with a different label. 1119 * To be used when a cred is being shared, but the label needs to be changed 1120 * by a caller without affecting other users 1121 */ 1122 cred_t * 1123 copycred_from_tslabel(const cred_t *cr, ts_label_t *label, int flags) 1124 { 1125 cred_t *newcr = NULL; 1126 1127 if ((newcr = crdup_flags(cr, flags)) != NULL) { 1128 if (newcr->cr_label != NULL) 1129 label_rele(newcr->cr_label); 1130 label_hold(label); 1131 newcr->cr_label = label; 1132 } 1133 1134 return (newcr); 1135 } 1136 1137 /* 1138 * Derive a new cred from the existing cred, but with a different label. 1139 */ 1140 cred_t * 1141 copycred_from_bslabel(const cred_t *cr, bslabel_t *blabel, 1142 uint32_t doi, int flags) 1143 { 1144 ts_label_t *lbl = labelalloc(blabel, doi, flags); 1145 cred_t *newcr = NULL; 1146 1147 if (lbl != NULL) { 1148 newcr = copycred_from_tslabel(cr, lbl, flags); 1149 label_rele(lbl); 1150 } 1151 1152 return (newcr); 1153 } 1154 1155 /* 1156 * This function returns a pointer to the kcred-equivalent in the current zone. 1157 */ 1158 cred_t * 1159 zone_kcred(void) 1160 { 1161 zone_t *zone; 1162 1163 if ((zone = CRED()->cr_zone) != NULL) 1164 return (zone->zone_kcred); 1165 else 1166 return (kcred); 1167 } 1168 1169 boolean_t 1170 valid_ephemeral_uid(zone_t *zone, uid_t id) 1171 { 1172 ephemeral_zsd_t *eph_zsd; 1173 if (id <= IDMAP_WK__MAX_UID) 1174 return (B_TRUE); 1175 1176 eph_zsd = get_ephemeral_zsd(zone); 1177 ASSERT(eph_zsd != NULL); 1178 membar_consumer(); 1179 return (id > eph_zsd->min_uid && id <= eph_zsd->last_uid); 1180 } 1181 1182 boolean_t 1183 valid_ephemeral_gid(zone_t *zone, gid_t id) 1184 { 1185 ephemeral_zsd_t *eph_zsd; 1186 if (id <= IDMAP_WK__MAX_GID) 1187 return (B_TRUE); 1188 1189 eph_zsd = get_ephemeral_zsd(zone); 1190 ASSERT(eph_zsd != NULL); 1191 membar_consumer(); 1192 return (id > eph_zsd->min_gid && id <= eph_zsd->last_gid); 1193 } 1194 1195 int 1196 eph_uid_alloc(zone_t *zone, int flags, uid_t *start, int count) 1197 { 1198 ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone); 1199 1200 ASSERT(eph_zsd != NULL); 1201 1202 mutex_enter(&eph_zsd->eph_lock); 1203 1204 /* Test for unsigned integer wrap around */ 1205 if (eph_zsd->last_uid + count < eph_zsd->last_uid) { 1206 mutex_exit(&eph_zsd->eph_lock); 1207 return (-1); 1208 } 1209 1210 /* first call or idmap crashed and state corrupted */ 1211 if (flags != 0) 1212 eph_zsd->min_uid = eph_zsd->last_uid; 1213 1214 hasephids = B_TRUE; 1215 *start = eph_zsd->last_uid + 1; 1216 atomic_add_32(&eph_zsd->last_uid, count); 1217 mutex_exit(&eph_zsd->eph_lock); 1218 return (0); 1219 } 1220 1221 int 1222 eph_gid_alloc(zone_t *zone, int flags, gid_t *start, int count) 1223 { 1224 ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone); 1225 1226 ASSERT(eph_zsd != NULL); 1227 1228 mutex_enter(&eph_zsd->eph_lock); 1229 1230 /* Test for unsigned integer wrap around */ 1231 if (eph_zsd->last_gid + count < eph_zsd->last_gid) { 1232 mutex_exit(&eph_zsd->eph_lock); 1233 return (-1); 1234 } 1235 1236 /* first call or idmap crashed and state corrupted */ 1237 if (flags != 0) 1238 eph_zsd->min_gid = eph_zsd->last_gid; 1239 1240 hasephids = B_TRUE; 1241 *start = eph_zsd->last_gid + 1; 1242 atomic_add_32(&eph_zsd->last_gid, count); 1243 mutex_exit(&eph_zsd->eph_lock); 1244 return (0); 1245 } 1246 1247 /* 1248 * IMPORTANT.The two functions get_ephemeral_data() and set_ephemeral_data() 1249 * are project private functions that are for use of the test system only and 1250 * are not to be used for other purposes. 1251 */ 1252 1253 void 1254 get_ephemeral_data(zone_t *zone, uid_t *min_uid, uid_t *last_uid, 1255 gid_t *min_gid, gid_t *last_gid) 1256 { 1257 ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone); 1258 1259 ASSERT(eph_zsd != NULL); 1260 1261 mutex_enter(&eph_zsd->eph_lock); 1262 1263 *min_uid = eph_zsd->min_uid; 1264 *last_uid = eph_zsd->last_uid; 1265 *min_gid = eph_zsd->min_gid; 1266 *last_gid = eph_zsd->last_gid; 1267 1268 mutex_exit(&eph_zsd->eph_lock); 1269 } 1270 1271 1272 void 1273 set_ephemeral_data(zone_t *zone, uid_t min_uid, uid_t last_uid, 1274 gid_t min_gid, gid_t last_gid) 1275 { 1276 ephemeral_zsd_t *eph_zsd = get_ephemeral_zsd(zone); 1277 1278 ASSERT(eph_zsd != NULL); 1279 1280 mutex_enter(&eph_zsd->eph_lock); 1281 1282 if (min_uid != 0) 1283 eph_zsd->min_uid = min_uid; 1284 if (last_uid != 0) 1285 eph_zsd->last_uid = last_uid; 1286 if (min_gid != 0) 1287 eph_zsd->min_gid = min_gid; 1288 if (last_gid != 0) 1289 eph_zsd->last_gid = last_gid; 1290 1291 mutex_exit(&eph_zsd->eph_lock); 1292 } 1293 1294 /* 1295 * If the credential user SID or group SID is mapped to an ephemeral 1296 * ID, map the credential to nobody. 1297 */ 1298 cred_t * 1299 crgetmapped(const cred_t *cr) 1300 { 1301 ephemeral_zsd_t *eph_zsd; 1302 /* 1303 * Someone incorrectly passed a NULL cred to a vnode operation 1304 * either on purpose or by calling CRED() in interrupt context. 1305 */ 1306 if (cr == NULL) 1307 return (NULL); 1308 1309 if (cr->cr_ksid != NULL) { 1310 if (cr->cr_ksid->kr_sidx[KSID_USER].ks_id > MAXUID) { 1311 eph_zsd = get_ephemeral_zsd(crgetzone(cr)); 1312 return (eph_zsd->eph_nobody); 1313 } 1314 1315 if (cr->cr_ksid->kr_sidx[KSID_GROUP].ks_id > MAXUID) { 1316 eph_zsd = get_ephemeral_zsd(crgetzone(cr)); 1317 return (eph_zsd->eph_nobody); 1318 } 1319 } 1320 1321 return ((cred_t *)cr); 1322 } 1323 1324 /* index should be in range for a ksidindex_t */ 1325 void 1326 crsetsid(cred_t *cr, ksid_t *ksp, int index) 1327 { 1328 ASSERT(cr->cr_ref <= 2); 1329 ASSERT(index >= 0 && index < KSID_COUNT); 1330 if (cr->cr_ksid == NULL && ksp == NULL) 1331 return; 1332 cr->cr_ksid = kcrsid_setsid(cr->cr_ksid, ksp, index); 1333 } 1334 1335 void 1336 crsetsidlist(cred_t *cr, ksidlist_t *ksl) 1337 { 1338 ASSERT(cr->cr_ref <= 2); 1339 if (cr->cr_ksid == NULL && ksl == NULL) 1340 return; 1341 cr->cr_ksid = kcrsid_setsidlist(cr->cr_ksid, ksl); 1342 } 1343 1344 ksid_t * 1345 crgetsid(const cred_t *cr, int i) 1346 { 1347 ASSERT(i >= 0 && i < KSID_COUNT); 1348 if (cr->cr_ksid != NULL && cr->cr_ksid->kr_sidx[i].ks_domain) 1349 return ((ksid_t *)&cr->cr_ksid->kr_sidx[i]); 1350 return (NULL); 1351 } 1352 1353 ksidlist_t * 1354 crgetsidlist(const cred_t *cr) 1355 { 1356 if (cr->cr_ksid != NULL) 1357 return (cr->cr_ksid->kr_sidlist); 1358 return (NULL); 1359 } 1360 1361 /* 1362 * Interface to set the effective and permitted privileges for 1363 * a credential; this interface does no security checks and is 1364 * intended for kernel (file)servers creating credentials with 1365 * specific privileges. 1366 */ 1367 int 1368 crsetpriv(cred_t *cr, ...) 1369 { 1370 va_list ap; 1371 const char *privnm; 1372 1373 ASSERT(cr->cr_ref <= 2); 1374 1375 priv_set_PA(cr); 1376 1377 va_start(ap, cr); 1378 1379 while ((privnm = va_arg(ap, const char *)) != NULL) { 1380 int priv = priv_getbyname(privnm, 0); 1381 if (priv < 0) 1382 return (-1); 1383 1384 priv_addset(&CR_PPRIV(cr), priv); 1385 priv_addset(&CR_EPRIV(cr), priv); 1386 } 1387 priv_adjust_PA(cr); 1388 va_end(ap); 1389 return (0); 1390 } 1391 1392 /* 1393 * Interface to effectively set the PRIV_ALL for 1394 * a credential; this interface does no security checks and is 1395 * intended for kernel (file)servers to extend the user credentials 1396 * to be ALL, like either kcred or zcred. 1397 */ 1398 void 1399 crset_zone_privall(cred_t *cr) 1400 { 1401 zone_t *zone = crgetzone(cr); 1402 1403 priv_fillset(&CR_LPRIV(cr)); 1404 CR_EPRIV(cr) = CR_PPRIV(cr) = CR_IPRIV(cr) = CR_LPRIV(cr); 1405 priv_intersect(zone->zone_privset, &CR_LPRIV(cr)); 1406 priv_intersect(zone->zone_privset, &CR_EPRIV(cr)); 1407 priv_intersect(zone->zone_privset, &CR_IPRIV(cr)); 1408 priv_intersect(zone->zone_privset, &CR_PPRIV(cr)); 1409 } 1410 1411 struct credklpd * 1412 crgetcrklpd(const cred_t *cr) 1413 { 1414 return (cr->cr_klpd); 1415 } 1416 1417 void 1418 crsetcrklpd(cred_t *cr, struct credklpd *crklpd) 1419 { 1420 ASSERT(cr->cr_ref <= 2); 1421 1422 if (cr->cr_klpd != NULL) 1423 crklpd_rele(cr->cr_klpd); 1424 cr->cr_klpd = crklpd; 1425 } 1426 1427 credgrp_t * 1428 crgrpcopyin(int n, gid_t *gidset) 1429 { 1430 credgrp_t *mem; 1431 size_t sz = CREDGRPSZ(n); 1432 1433 ASSERT(n > 0); 1434 1435 mem = kmem_alloc(sz, KM_SLEEP); 1436 1437 if (copyin(gidset, mem->crg_groups, sizeof (gid_t) * n)) { 1438 kmem_free(mem, sz); 1439 return (NULL); 1440 } 1441 mem->crg_ref = 1; 1442 mem->crg_ngroups = n; 1443 return (mem); 1444 } 1445 1446 const gid_t * 1447 crgetggroups(const credgrp_t *grps) 1448 { 1449 return (grps->crg_groups); 1450 } 1451 1452 void 1453 crsetcredgrp(cred_t *cr, credgrp_t *grps) 1454 { 1455 ASSERT(cr->cr_ref <= 2); 1456 1457 if (cr->cr_grps != NULL) 1458 crgrprele(cr->cr_grps); 1459 1460 cr->cr_grps = grps; 1461 } 1462 1463 void 1464 crgrprele(credgrp_t *grps) 1465 { 1466 if (atomic_add_32_nv(&grps->crg_ref, -1) == 0) 1467 kmem_free(grps, CREDGRPSZ(grps->crg_ngroups)); 1468 } 1469 1470 static void 1471 crgrphold(credgrp_t *grps) 1472 { 1473 atomic_add_32(&grps->crg_ref, 1); 1474 } 1475