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