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