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